diff options
Diffstat (limited to 'cmd2.py')
-rwxr-xr-x | cmd2.py | 66 |
1 files changed, 41 insertions, 25 deletions
@@ -832,6 +832,7 @@ class AddSubmenu(object): reformat_prompt="{super_prompt}>> {sub_prompt}", shared_attributes=None, require_predefined_shares=True, + preserve_shares=False, create_subclass=False ): """Set up the class decorator @@ -867,15 +868,37 @@ class AddSubmenu(object): raise ValueError("reformat_prompt should be either a format string or None") self.reformat_prompt = reformat_prompt + self.shared_attributes = {} if shared_attributes is None else shared_attributes if require_predefined_shares: - for attr in shared_attributes.keys(): + for attr in self.shared_attributes.keys(): if not hasattr(submenu, attr): raise AttributeError("The shared attribute '{attr}' is not defined in {cmd}. Either define {attr} " "in {cmd} or set require_predefined_shares=False." .format(cmd=submenu.__class__.__name__, attr=attr)) - self.shared_attributes = {} if shared_attributes is None else shared_attributes self.create_subclass = create_subclass + self.preserve_shares = preserve_shares + + def _get_original_attributes(self): + return { + attr: getattr(self.submenu, attr, AddSubmenu._Nonexistent) + for attr in self.shared_attributes.keys() + } + + def _copy_in_shared_attrs(self, parent_cmd): + for sub_attr, par_attr in self.shared_attributes.items(): + setattr(self.submenu, sub_attr, getattr(parent_cmd, par_attr)) + + def _copy_out_shared_attrs(self, parent_cmd, original_attributes): + if self.preserve_shares: + for sub_attr, par_attr in self.shared_attributes.items(): + setattr(parent_cmd, par_attr, getattr(self.submenu, sub_attr)) + else: + for attr, value in original_attributes.items(): + if attr is not AddSubmenu._Nonexistent: + setattr(self.submenu, attr, value) + else: + delattr(self.submenu, attr) def __call__(self, cmd_obj): """Creates a subclass of Cmd wherein the given submenu can be accessed via the given command""" @@ -885,13 +908,11 @@ class AddSubmenu(object): submenu. """ submenu = self.submenu - original_attributes = {attr: getattr(submenu, attr, AddSubmenu._Nonexistent) - for attr in self.shared_attributes.keys() - } + original_attributes = self._get_original_attributes() + try: # copy over any shared attributes - for sub_attr, par_attr in self.shared_attributes.items(): - setattr(submenu, sub_attr, getattr(parent_cmd, par_attr)) + self._copy_in_shared_attrs(parent_cmd) if line.parsed.args: # Remove the menu argument and execute the command in the submenu @@ -915,34 +936,21 @@ class AddSubmenu(object): _push_readline_history(history) finally: # copy back original attributes - for attr, value in original_attributes.items(): - if attr is not AddSubmenu._Nonexistent: - setattr(submenu, attr, value) - else: - delattr(submenu, attr) + self._copy_out_shared_attrs(parent_cmd, original_attributes) def complete_submenu(_self, text, line, begidx, endidx): """ This function will be bound to complete_<submenu> and will perform the complete commands of the submenu. """ submenu = self.submenu - original_attributes = { - attr: getattr(submenu, attr, AddSubmenu._Nonexistent) - for attr in self.shared_attributes.keys() - } + original_attributes = self._get_original_attributes() try: # copy over any shared attributes - for sub_attr, par_attr in self.shared_attributes.items(): - setattr(submenu, sub_attr, getattr(_self, par_attr)) - + self._copy_in_shared_attrs(_self) return _complete_from_cmd(submenu, text, line, begidx, endidx) finally: # copy back original attributes - for attr, value in original_attributes.items(): - if attr is not AddSubmenu._Nonexistent: - setattr(submenu, attr, value) - else: - delattr(submenu, attr) + self._copy_out_shared_attrs(_self, original_attributes) original_do_help = cmd_obj.do_help original_complete_help = cmd_obj.complete_help @@ -1016,6 +1024,7 @@ class Cmd(cmd.Cmd): allow_cli_args = True # Should arguments passed on the command-line be processed as commands? allow_redirection = True # Should output redirection and pipes be allowed default_to_shell = False # Attempt to run unrecognized commands as shell commands + quit_on_sigint = True # Quit the loop on interrupt instead of just resetting prompt reserved_words = [] # Attributes which ARE dynamically settable at runtime @@ -1889,7 +1898,14 @@ class Cmd(cmd.Cmd): self.poutput('{}{}'.format(self.prompt, line)) else: # Otherwise, read a command from stdin - line = self.pseudo_raw_input(self.prompt) + if not self.quit_on_sigint: + try: + line = self.pseudo_raw_input(self.prompt) + except KeyboardInterrupt: + self.poutput('^C') + line = '' + else: + line = self.pseudo_raw_input(self.prompt) # Run the command along with all associated pre and post hooks stop = self.onecmd_plus_hooks(line) |