diff options
| author | 2018-04-13 00:40:42 +0200 | |
|---|---|---|
| committer | 2018-04-13 00:40:42 +0200 | |
| commit | bd130375a84e611da256ffce1b68a8ce2de3e5ba (patch) | |
| tree | f09cc0f406f644ff05add1d18b1e4412b5d6736c | |
| parent | Allow using double quotes within triple double quotes. (#47) (diff) | |
Allow `__getitem__` / `__setitem__`-like command access (#48)
* Allow using double quotes within triple double quotes.
* Add getitem / setitem-like command access.
* Add notes about possible `SyntaxError`s.
* Add comments describing how this works.
* Address style issues addressed by Aperture.
* Use single quotes, clarify comment.
* A little bit of whitespace by my line
a little bit of whitespace is all I need
a little readable code is what lemon sees
a little bit of it makes the code good, man
* Add several `trace` logs.
* Escape single quotes in the key.
* Fix a flake8 violation.
| -rw-r--r-- | bot/__init__.py | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/bot/__init__.py b/bot/__init__.py index 76cab5a74..40c4eefdc 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -95,7 +95,7 @@ def _get_word(self) -> str: while not self.eof: try: current = self.buffer[self.index + pos] - if current.isspace() or current == "(": + if current.isspace() or current == "(" or current == "[": break pos += 1 except IndexError: @@ -171,6 +171,61 @@ def _get_word(self) -> str: result = self.buffer[self.previous:self.index + (pos+2)] self.index += 2 + # Check if a command in the form of `bot.tags['ask']` + # or alternatively `bot.tags['ask'] = 'whatever'` was used. + elif current == "[": + def clean_argument(arg: str) -> str: + """Helper function to remove any characters we don't care about.""" + + return arg.strip("[]'\" ").replace('"', '\\"') + + log.trace(f"Got a command candidate for getitem / setitem mimick: {self.buffer}") + # Syntax is `bot.tags['ask']` => mimic `getattr` + if self.buffer.endswith("]"): + # Key: The first argument, specified `bot.tags[here]` + key = clean_argument(self.buffer[self.index:]) + log.trace(f"Command mimicks getitem. Key: {key!r}") + + # note: if not key, this corresponds to an empty argument + # so this should throw / return a SyntaxError ? + args = f'"{key}"' + + # Use the cog's `get` command. + result = self.buffer[self.previous:self.index] + ".get" + + # Syntax is `bot.tags['ask'] = 'whatever'` => mimic `setattr` + elif "=" in self.buffer and not self.buffer.endswith("="): + equals_pos = self.buffer.find("=") + + # Key: The first argument, specified `bot.tags[here]` + key = clean_argument(self.buffer[self.index:equals_pos]) + + # Value: The second argument, specified after the `=` + value = ( + clean_argument( + self.buffer.split("=")[1] + ) + .replace("'", "\\'") # escape any unescaped quotes + ) + log.trace(f"Command mimicks setitem. Key: {key!r}, value: {value!r}.") + + # Use the cog's `set` command. + result = self.buffer[self.previous:self.index] + ".set" + args = f'"{key}" "{value}"' + + # Syntax is god knows what, pass it along + # in the future, this should probably return / throw SyntaxError + else: + result = self.buffer + args = '' + log.trace(f"Command is of unknown syntax: {self.buffer}") + + # Reconstruct valid discord.py syntax + self.buffer = f"{result} {args}" + self.index = len(result) + self.end = len(self.buffer) + log.trace(f"Mimicked command: {self.buffer}") + if isinstance(result, str): return result.lower() # Case insensitivity, baby return result |