diff --git a/Lib/cmd.py b/Lib/cmd.py index 859e91096d..4ec0966803 100644 --- a/Lib/cmd.py +++ b/Lib/cmd.py @@ -41,14 +41,27 @@ The data members `self.doc_header', `self.misc_header', and listings of documented functions, miscellaneous topics, and undocumented functions respectively. """ - +import inspect +import json +import shlex import string, sys +from itertools import filterfalse, tee + + __all__ = ["Cmd"] PROMPT = '(Cmd) ' IDENTCHARS = string.ascii_letters + string.digits + '_' + +def partition(pred, iterable): + 'Use a predicate to partition entries into false entries and true entries' + # partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9 + t1, t2 = tee(iterable) + return list(filterfalse(pred, t1)), list(filter(pred, t2)) + + class Cmd: """A simple framework for writing line-oriented command interpreters. @@ -200,21 +213,43 @@ class Cmd: """ cmd, arg, line = self.parseline(line) + if not line: return self.emptyline() if cmd is None: return self.default(line) self.lastcmd = line - if line == 'EOF' : + if line == 'EOF': self.lastcmd = '' if cmd == '': return self.default(line) - else: + + arg = shlex.split(arg) + arg, args_with_val = partition(lambda x: "=" in x, arg) + if not arg: + arg = [''] + di = {} + for item in args_with_val: + name, val = item.split('=') + di[name] = val + + try: + func = getattr(self, 'do_' + cmd) + except AttributeError: + return self.default(line) + + sig = inspect.getfullargspec(func) + + if sig.varkw: try: - func = getattr(self, 'do_' + cmd) - except AttributeError: - return self.default(line) - return func(arg) + kwargs = json.loads(di.pop(sig.varkw)) + di.update(kwargs) + except json.decoder.JSONDecodeError: + pass + try: + return func(*arg, **di) + except TypeError: + return self.default(line) def emptyline(self): """Called when an empty line is entered in response to the prompt.