diff options
author | Eric Lin <anselor@gmail.com> | 2018-04-24 16:17:25 -0400 |
---|---|---|
committer | Eric Lin <anselor@gmail.com> | 2018-04-24 16:17:25 -0400 |
commit | 0a1c41ce7048b45fc7ef9b0176d988c26861224e (patch) | |
tree | df27473d38566e24dbf6bb5179cf32bb5f966193 /cmd2/pyscript_bridge.py | |
parent | f11b06374aaf56b755de33a763220140d36eab64 (diff) | |
download | cmd2-git-0a1c41ce7048b45fc7ef9b0176d988c26861224e.tar.gz |
Initial approach to the pyscript revamp.
Doesn't handle all argparse argument options yet (nargs, append, flag, probably more)
For #368
Diffstat (limited to 'cmd2/pyscript_bridge.py')
-rw-r--r-- | cmd2/pyscript_bridge.py | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/cmd2/pyscript_bridge.py b/cmd2/pyscript_bridge.py new file mode 100644 index 00000000..88e12bfb --- /dev/null +++ b/cmd2/pyscript_bridge.py @@ -0,0 +1,107 @@ +"""Bridges calls made inside of pyscript with the Cmd2 host app while maintaining a reasonable +degree of isolation between the two""" + +import argparse + +class ArgparseFunctor: + def __init__(self, cmd2_app, item, parser): + self._cmd2_app = cmd2_app + self._item = item + self._parser = parser + + self._args = {} + self.__current_subcommand_parser = parser + + def __getattr__(self, item): + # look for sub-command + for action in self.__current_subcommand_parser._actions: + if not action.option_strings and isinstance(action, argparse._SubParsersAction): + if item in action.choices: + # item matches the a sub-command, save our position in argparse, + # save the sub-command, return self to allow next level of traversal + self.__current_subcommand_parser = action.choices[item] + self._args[action.dest] = item + return self + return super().__getatttr__(item) + + def __call__(self, *args, **kwargs): + next_pos_index = 0 + + has_subcommand = False + consumed_kw = [] + for action in self.__current_subcommand_parser._actions: + # is this a flag option? + if action.option_strings: + if action.dest in kwargs: + self._args[action.dest] = kwargs[action.dest] + consumed_kw.append(action.dest) + else: + if not isinstance(action, argparse._SubParsersAction): + if next_pos_index < len(args): + self._args[action.dest] = args[next_pos_index] + next_pos_index += 1 + else: + has_subcommand = True + + for kw in kwargs: + if kw not in consumed_kw: + raise TypeError('{}() got an unexpected keyword argument \'{}\''.format( + self.__current_subcommand_parser.prog, kw)) + + if has_subcommand: + return self + else: + return self._run() + + def _run(self): + # look up command function + func = getattr(self._cmd2_app, 'do_' + self._item) + + # reconstruct the cmd2 command from the python call + cmd_str = [''] + + def traverse_parser(parser): + for action in parser._actions: + # was something provided for the argument + if action.dest in self._args: + # was the argument a flag? + # TODO: Handle 'narg' and 'append' options + if action.option_strings: + cmd_str[0] += '"{}" "{}" '.format(action.option_strings[0], self._args[action.dest]) + else: + cmd_str[0] += '"{}" '.format(self._args[action.dest]) + + if isinstance(action, argparse._SubParsersAction): + traverse_parser(action.choices[self._args[action.dest]]) + traverse_parser(self._parser) + + func(cmd_str[0]) + return self._cmd2_app._last_result + + +class PyscriptBridge(object): + def __init__(self, cmd2_app): + self._cmd2_app = cmd2_app + self._last_result = None + + def __getattr__(self, item: str): + commands = self._cmd2_app.get_all_commands() + if item in commands: + func = getattr(self._cmd2_app, 'do_' + item) + + try: + parser = getattr(func, 'argparser') + except AttributeError: + def wrap_func(args=''): + func(args) + return self._cmd2_app._last_result + return wrap_func + else: + return ArgparseFunctor(self._cmd2_app, item, parser) + + return super().__getattr__(item) + + def __call__(self, args): + self._cmd2_app.onecmd_plus_hooks(args + '\n') + self._last_result = self._cmd2_app._last_result + return self._cmd2_app._last_result |