import argparse class MyParserAction(argparse._SubParsersAction): def __call__(self, parser, namespace, values, option_string=None): parser_name = values[0] arg_strings = values[1:] # set the parser name if requested if self.dest is not argparse.SUPPRESS: setattr(namespace, self.dest, parser_name) # select the parser try: parser = self._name_parser_map[parser_name] except KeyError: args = {'parser_name': parser_name, 'choices': ', '.join(self._name_parser_map)} msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args raise ArgumentError(self, msg) # parse all the remaining options into the namespace # store any unrecognized options on the object, so that the top # level parser can decide what to do with them # ORIGINAL namespace, arg_strings = parser.parse_known_args(arg_strings, namespace) # issue 9351 change ## In case this subparser defines new defaults, we parse them ## in a new namespace object and then update the original ## namespace for the relevant parts. #subnamespace, arg_strings = parser.parse_known_args(arg_strings, None) #for key, value in vars(subnamespace).items(): # setattr(namespace, key, value) if arg_strings: vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) # issue 27859 example p = argparse.ArgumentParser() # chg which Action class is used for subparsers p.register('action', 'parsers', MyParserAction) p.add_argument('--foo', action='store_true', default=False) sp = p.add_subparsers() sp1 = sp.add_parser('first') # Add custom action class BarAction(argparse.Action): def __call__(self, parser, namespace, value, option_string=None): """ Try and access the `foo` variable """ # Just to highlight the current namespace print(namespace) # Perform action dependent on foo (this will error out as # the parent name-space is not passed... :() # if namespace.foo: # better access namespace as rest of argparse does foo = getattr(namespace, 'foo', None) print('foo:',foo) sp1.add_argument('--bar', nargs=0, action=BarAction) args = p.parse_args() print(args) """ # with new class: 0906:~/mypy/argdev$ python3 issue27859test.py first --bar Namespace(bar=None, foo=False) foo: False Namespace(bar=None, foo=False) 0909:~/mypy/argdev$ python3 issue27859test.py --foo first --bar Namespace(bar=None, foo=True) foo: True Namespace(bar=None, foo=True) # without registry change 0909:~/mypy/argdev$ python3 issue27859test.py first --bar Namespace(bar=None) foo: None Namespace(bar=None, foo=False) 0910:~/mypy/argdev$ python3 issue27859test.py --foo first --bar Namespace(bar=None) foo: None Namespace(bar=None, foo=True) """