From 05d1af29f24fcc2ab831b5cbe6e3233e17e7ac90 Mon Sep 17 00:00:00 2001 From: ChrisLR Date: Tue, 7 Jun 2022 12:29:22 -0400 Subject: [PATCH 1/3] Added support to retrieve and remove commands from Commandsets using the key --- evennia/commands/cmdset.py | 45 ++++++++++++++++++++++++++++++-------- evennia/commands/tests.py | 18 +++++++++++++++ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/evennia/commands/cmdset.py b/evennia/commands/cmdset.py index 1a0aa952b0..2bab1b7512 100644 --- a/evennia/commands/cmdset.py +++ b/evennia/commands/cmdset.py @@ -211,6 +211,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): if key: self.key = key self.commands = [] + self.commands_by_key = {} self.system_commands = [] self.actual_mergetype = self.mergetype self.cmdsetobj = cmdsetobj @@ -243,9 +244,13 @@ class CmdSet(object, metaclass=_CmdSetMeta): # we make copies, not refs by use of [:] cmdset_c.commands = cmdset_a.commands[:] if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority: - cmdset_c.commands.extend(cmdset_b.commands) + new_cmds = cmdset_b.commands else: - cmdset_c.commands.extend([cmd for cmd in cmdset_b if cmd not in cmdset_a]) + new_cmds = [cmd for cmd in cmdset_b if cmd not in cmdset_a] + + cmdset_c.commands.extend(new_cmds) + cmdset_c.commands_by_key.update({cmd.key: cmd for cmd in new_cmds}) + return cmdset_c def _intersect(self, cmdset_a, cmdset_b): @@ -272,7 +277,10 @@ class CmdSet(object, metaclass=_CmdSetMeta): cmdset_c.add(cmd) cmdset_c.add(cmdset_b.get(cmd)) else: - cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b] + new_cmds = [cmd for cmd in cmdset_a if cmd in cmdset_b] + cmdset_c.commands = new_cmds + cmdset_c.commands_by_key = {cmd.key: cmd for cmd in new_cmds} + return cmdset_c def _replace(self, cmdset_a, cmdset_b): @@ -291,7 +299,10 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ cmdset_c = cmdset_a._duplicate() - cmdset_c.commands = cmdset_a.commands[:] + commands = cmdset_a.commands[:] + cmdset_c.commands = commands + cmdset_c.commands_by_key = {cmd.key: cmd for cmd in commands} + return cmdset_c def _remove(self, cmdset_a, cmdset_b): @@ -311,7 +322,10 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ cmdset_c = cmdset_a._duplicate() - cmdset_c.commands = [cmd for cmd in cmdset_b if cmd not in cmdset_a] + new_cmds = [cmd for cmd in cmdset_b if cmd not in cmdset_a] + cmdset_c.commands = new_cmds + cmdset_c.commands_by_key = {cmd.key: cmd for cmd in new_cmds} + return cmdset_c def _instantiate(self, cmd): @@ -546,10 +560,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): commands[ic] = cmd # replace except ValueError: commands.append(cmd) - self.commands = commands - if not allow_duplicates: - # extra run to make sure to avoid doublets - self.commands = list(set(self.commands)) + # add system_command to separate list as well, # for quick look-up if cmd.key.startswith("__"): @@ -559,6 +570,13 @@ class CmdSet(object, metaclass=_CmdSetMeta): except ValueError: system_commands.append(cmd) + self.commands = commands + if not allow_duplicates: + # extra run to make sure to avoid doublets + self.commands = list(set(self.commands)) + + self.commands_by_key = {cmd.key: cmd for cmd in self.commands} + def remove(self, cmd): """ Remove a command instance from the cmdset. @@ -568,6 +586,9 @@ class CmdSet(object, metaclass=_CmdSetMeta): or the key of such a command. """ + if isinstance(cmd, str): + cmd = self.commands_by_key.get(cmd) + cmd = self._instantiate(cmd) if cmd.key.startswith("__"): try: @@ -578,6 +599,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): pass else: self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd] + self.commands_by_key = {cmd.key: cmd for cmd in self.commands} def get(self, cmd): """ @@ -591,6 +613,9 @@ class CmdSet(object, metaclass=_CmdSetMeta): cmd (Command): The first matching Command in the set. """ + if isinstance(cmd, str): + cmd = self.commands_by_key.get(cmd) + cmd = self._instantiate(cmd) for thiscmd in self.commands: if thiscmd == cmd: @@ -649,7 +674,9 @@ class CmdSet(object, metaclass=_CmdSetMeta): unique[cmd.key] = cmd else: unique[cmd.key] = cmd + self.commands = list(unique.values()) + self.commands_by_key = {cmd.key: cmd for cmd in self.commands} def get_all_cmd_keys_and_aliases(self, caller=None): """ diff --git a/evennia/commands/tests.py b/evennia/commands/tests.py index c06962da84..c422a69a81 100644 --- a/evennia/commands/tests.py +++ b/evennia/commands/tests.py @@ -1199,3 +1199,21 @@ class TestCmdSetNesting(BaseEvenniaTest): cmd = self.char1.cmdset.cmdset_stack[-1].commands[0] self.assertEqual(cmd.obj, self.char1) + + +class TestCmdSet(BaseEvenniaTest): + """ + General tests for cmdsets + """ + + def test_cmdset_remove_by_key(self): + test_cmd_set = _CmdSetTest() + test_cmd_set.remove("another command") + + self.assertNotIn(_CmdTest2, test_cmd_set.commands) + + def test_cmdset_gets_by_key(self): + test_cmd_set = _CmdSetTest() + result = test_cmd_set.get("another command") + + self.assertIsInstance(result, _CmdTest2) From 0985dff3310623db62e4e4798153fa474d6f9565 Mon Sep 17 00:00:00 2001 From: ChrisLR Date: Mon, 27 Jun 2022 12:48:28 -0400 Subject: [PATCH 2/3] Rollback code related to commands_by_key --- evennia/commands/cmdset.py | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/evennia/commands/cmdset.py b/evennia/commands/cmdset.py index 2bab1b7512..98dc999e22 100644 --- a/evennia/commands/cmdset.py +++ b/evennia/commands/cmdset.py @@ -211,7 +211,6 @@ class CmdSet(object, metaclass=_CmdSetMeta): if key: self.key = key self.commands = [] - self.commands_by_key = {} self.system_commands = [] self.actual_mergetype = self.mergetype self.cmdsetobj = cmdsetobj @@ -244,13 +243,9 @@ class CmdSet(object, metaclass=_CmdSetMeta): # we make copies, not refs by use of [:] cmdset_c.commands = cmdset_a.commands[:] if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority: - new_cmds = cmdset_b.commands + cmdset_c.commands.extend(cmdset_b.commands) else: - new_cmds = [cmd for cmd in cmdset_b if cmd not in cmdset_a] - - cmdset_c.commands.extend(new_cmds) - cmdset_c.commands_by_key.update({cmd.key: cmd for cmd in new_cmds}) - + cmdset_c.commands.extend([cmd for cmd in cmdset_b if cmd not in cmdset_a]) return cmdset_c def _intersect(self, cmdset_a, cmdset_b): @@ -277,10 +272,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): cmdset_c.add(cmd) cmdset_c.add(cmdset_b.get(cmd)) else: - new_cmds = [cmd for cmd in cmdset_a if cmd in cmdset_b] - cmdset_c.commands = new_cmds - cmdset_c.commands_by_key = {cmd.key: cmd for cmd in new_cmds} - + cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b] return cmdset_c def _replace(self, cmdset_a, cmdset_b): @@ -299,10 +291,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ cmdset_c = cmdset_a._duplicate() - commands = cmdset_a.commands[:] - cmdset_c.commands = commands - cmdset_c.commands_by_key = {cmd.key: cmd for cmd in commands} - + cmdset_c.commands = cmdset_a.commands[:] return cmdset_c def _remove(self, cmdset_a, cmdset_b): @@ -322,10 +311,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ cmdset_c = cmdset_a._duplicate() - new_cmds = [cmd for cmd in cmdset_b if cmd not in cmdset_a] - cmdset_c.commands = new_cmds - cmdset_c.commands_by_key = {cmd.key: cmd for cmd in new_cmds} - + cmdset_c.commands = [cmd for cmd in cmdset_b if cmd not in cmdset_a] return cmdset_c def _instantiate(self, cmd): @@ -575,8 +561,6 @@ class CmdSet(object, metaclass=_CmdSetMeta): # extra run to make sure to avoid doublets self.commands = list(set(self.commands)) - self.commands_by_key = {cmd.key: cmd for cmd in self.commands} - def remove(self, cmd): """ Remove a command instance from the cmdset. @@ -587,7 +571,9 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ if isinstance(cmd, str): - cmd = self.commands_by_key.get(cmd) + cmd = next((cmd for cmd in self.commands if cmd.key == cmd), None) + if cmd is None: + return None cmd = self._instantiate(cmd) if cmd.key.startswith("__"): @@ -599,7 +585,6 @@ class CmdSet(object, metaclass=_CmdSetMeta): pass else: self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd] - self.commands_by_key = {cmd.key: cmd for cmd in self.commands} def get(self, cmd): """ @@ -614,7 +599,9 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ if isinstance(cmd, str): - cmd = self.commands_by_key.get(cmd) + cmd = next((cmd for cmd in self.commands if cmd.key == cmd), None) + if cmd is None: + return None cmd = self._instantiate(cmd) for thiscmd in self.commands: @@ -674,9 +661,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): unique[cmd.key] = cmd else: unique[cmd.key] = cmd - self.commands = list(unique.values()) - self.commands_by_key = {cmd.key: cmd for cmd in self.commands} def get_all_cmd_keys_and_aliases(self, caller=None): """ From 01f21591984b1a2db9aba482fd32a64321cc47b2 Mon Sep 17 00:00:00 2001 From: ChrisLR Date: Sun, 24 Jul 2022 10:51:19 -0400 Subject: [PATCH 3/3] Avoid potential shadowing issue --- evennia/commands/cmdset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/commands/cmdset.py b/evennia/commands/cmdset.py index 98dc999e22..9d8877a679 100644 --- a/evennia/commands/cmdset.py +++ b/evennia/commands/cmdset.py @@ -571,7 +571,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ if isinstance(cmd, str): - cmd = next((cmd for cmd in self.commands if cmd.key == cmd), None) + cmd = next((_cmd for _cmd in self.commands if _cmd.key == cmd), None) if cmd is None: return None @@ -599,7 +599,7 @@ class CmdSet(object, metaclass=_CmdSetMeta): """ if isinstance(cmd, str): - cmd = next((cmd for cmd in self.commands if cmd.key == cmd), None) + cmd = next((_cmd for _cmd in self.commands if _cmd.key == cmd), None) if cmd is None: return None