From d36a79b2ccaa42d4527ec3ff0182daa0c63f15ed Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 6 Feb 2012 00:59:41 +0100 Subject: [PATCH] Went over the Command class' basic methods, cleaning up and optimizing while still trying to keep things clean, such as using cleverer loops and try...except instead of if statements. Also cleaned up the way attributes are retrieved. Results in roughly a halving of the time that the code spends in the command.py module. --- src/commands/cmdset.py | 50 ++++++++++++++++------------------------- src/commands/command.py | 12 +++++----- src/utils/utils.py | 11 +-------- 3 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/commands/cmdset.py b/src/commands/cmdset.py index b6e8b9cee9..45d3f26395 100644 --- a/src/commands/cmdset.py +++ b/src/commands/cmdset.py @@ -50,8 +50,7 @@ def union(cmdset_a, cmdset_b, duplicates=False): if duplicates and cmdset_a.priority == cmdset_b.priority: cmdset_c.commands.extend(cmdset_b.commands) else: - cmdset_c.commands.extend([cmd for cmd in cmdset_b - if not cmd in cmdset_a]) + cmdset_c.commands.extend([cmd for cmd in cmdset_b if not cmd in cmdset_a]) return cmdset_c def intersect(cmdset_a, cmdset_b, duplicates=False): @@ -68,7 +67,7 @@ def intersect(cmdset_a, cmdset_b, duplicates=False): def replace(cmdset_a, cmdset_b, cmdset_c): "C = A + B where the result is A." cmdset_c = cmdset_a.copy_this() - cmdset_c.commands = cmdset_a.commands[:] + cmdset_c.commands = cmdset_a.commands[:] return cmdset_c def remove(cmdset_a, cmdset_b, cmdset_c): @@ -83,13 +82,10 @@ def instantiate(cmd): and not, say a cmdclass. If it is, instantiate it. Other types, like strings, are passed through. """ - if callable(cmd): - # this is a valid check since Command *instances* - # don't implement __call__, so this will catch - # Command *classes* and instantiate them. + try: return cmd() - return cmd - + except TypeError: + return cmd class CmdSet(object): """ @@ -223,11 +219,9 @@ class CmdSet(object): """ if inherits_from(cmd, "src.commands.cmdset.CmdSet"): - # this is a command set so merge all commands in that set - # to this one. We are not protecting against recursive - # loops (adding a cmdset that itself adds this cmdset here - # since such an error will be very visible and lead to a - # traceback at startup anyway. + # cmd is a command set so merge all commands in that set + # to this one. We raise a visible error if we created + # an infinite loop (adding cmdset to itself somehow) try: cmd = instantiate(cmd) except RuntimeError, e: @@ -242,7 +236,7 @@ class CmdSet(object): for cmd in cmds: # add all commands if not hasattr(cmd, 'obj'): - cmd.obj = self.cmdsetobj + cmd.obj = self.cmdsetobj try: ic = self.commands.index(cmd) self.commands[ic] = cmd # replace @@ -258,8 +252,7 @@ class CmdSet(object): cmd can be either a cmd instance or a key string. """ cmd = instantiate(cmd) - self.commands = [oldcmd for oldcmd in self.commands - if oldcmd != cmd] + self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd] def get(self, cmd): """ @@ -268,10 +261,9 @@ class CmdSet(object): a key string. """ cmd = instantiate(cmd) - if cmd: - for thiscmd in self.commands: - if thiscmd == cmd: - return thiscmd + for thiscmd in self.commands: + if thiscmd == cmd: + return thiscmd def count(self): "Return number of commands in set" @@ -283,8 +275,7 @@ class CmdSet(object): commands starting with double underscore __. These are excempt from merge operations. """ - return [cmd for cmd in self.commands - if len(cmd.key) > 2 and cmd.key[:2] == '__'] + return [cmd for cmd in self.commands if cmd.key.startswith('__')] def copy_this(self): """ @@ -300,7 +291,7 @@ class CmdSet(object): cmdset.mergetype = self.mergetype cmdset.priority = self.priority cmdset.duplicates = self.duplicates - cmdset.key_mergetypes = copy.deepcopy(self.key_mergetypes) + cmdset.key_mergetypes = self.key_mergetypes.copy() #copy.deepcopy(self.key_mergetypes) return cmdset def make_unique(self, caller): @@ -340,7 +331,7 @@ class CmdSet(object): """ Returns True if this cmdset contains the given command (as defined by command name and aliases). This allows for things like 'if cmd in cmdset' - """ + """ return any(cmd == othercmd for cmd in self.commands) def __add__(self, cmdset_b): @@ -367,8 +358,7 @@ class CmdSet(object): if self.priority >= cmdset_b.priority: # A higher or equal priority than B - mergetype = self.key_mergetypes.get(cmdset_b.key, - self.mergetype) + mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype) if mergetype == "Intersect": cmdset_c = intersect(self, cmdset_b, cmdset_b.duplicates) elif mergetype == "Replace": @@ -379,8 +369,7 @@ class CmdSet(object): cmdset_c = union(self, cmdset_b, cmdset_b.duplicates) else: # B higher priority than A - mergetype = cmdset_b.key_mergetypes.get(self.key, - cmdset_b.mergetype) + mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype) if mergetype == "Intersect": cmdset_c = intersect(cmdset_b, self, self.duplicates) elif mergetype == "Replace": @@ -396,7 +385,6 @@ class CmdSet(object): cmdset_c.actual_mergetype = mergetype # return the system commands to the cmdset - for cmd in sys_commands: - cmdset_c.add(cmd) + cmdset_c.add(sys_commands) return cmdset_c diff --git a/src/commands/command.py b/src/commands/command.py index 20eba4f9b9..7491e31128 100644 --- a/src/commands/command.py +++ b/src/commands/command.py @@ -105,9 +105,10 @@ class Command(object): key and aliases. input can be either a cmd object or the name of a command. """ - if type(cmd) != self: + try: + return self.match(cmd.key) + except AttributeError: # got a string return self.match(cmd) - return self.match(cmd.key) def __contains__(self, query): """ @@ -117,10 +118,11 @@ class Command(object): input can be either a command object or a command name. """ - if type(query) == type(Command()): + try: query = query.key - return (query in self.key) or \ - (sum([query in alias for alias in self.aliases]) > 0) + except AttributeError: # we got a string + pass + return (query in self.key) or any(query in alias for alias in self.aliases) def match(self, cmdname): """ diff --git a/src/utils/utils.py b/src/utils/utils.py index 9d360ddbea..bd0b13ca8a 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -24,15 +24,6 @@ def is_iter(iterable): """ return hasattr(iterable, '__iter__') - # if isinstance(iterable, basestring): - # # skip all forms of strings (str, unicode etc) - # return False - # try: - # # check if object implements iter protocol - # return iter(iterable) - # except TypeError: - # return False - def fill(text, width=78, indent=0): """ Safely wrap text to a certain number of characters. @@ -396,7 +387,7 @@ def inherits_from(obj, parent): parent_path = "%s.%s" % (parent.__module__, parent.__name__) else: parent_path = "%s.%s" % (parent.__class__.__module__, parent.__class__.__name__) - return any(True for obj_path in obj_paths if obj_path == parent_path) + return any(1 for obj_path in obj_paths if obj_path == parent_path) def format_table(table, extra_space=1):