From bd130375a84e611da256ffce1b68a8ce2de3e5ba Mon Sep 17 00:00:00 2001 From: Volcyy Date: Fri, 13 Apr 2018 00:40:42 +0200 Subject: 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. --- bot/__init__.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) 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 -- cgit v1.2.3