def _update_args(self, args, mixin_args, context): destinations = self.get_destinations() for mixin_key, mixin_value in mixin_args.items(): if mixin_key not in destinations: logger.warning( "Mixin key '{mixin_key}' is not a valid argument for " "'{context}'".format_map(locals())) continue arg_key = destinations[mixin_key] arg_value = getattr(args, arg_key) if arg_value is None or is_default_value(arg_value): logger.debug( "Replacing default value of '{arg_key}' with mixin value: " '{mixin_value}'.format_map(locals())) setattr(args, arg_key, mixin_value) elif isinstance(arg_value, list): combined_value = mixin_value + arg_value logger.debug( "Updating argument '{arg_key}' by prepending mixin value " "'{mixin_value}' to command line argument " "'{arg_value}'".format_map(locals())) setattr(args, arg_key, combined_value) else: logger.debug( "Skipping mixin key '{mixin_key}' which was passed " 'explicitly as a command line argument'.format_map( locals()))
def parse_known_args(self, *args, **kwargs): """Unwrap default values.""" known_args, remaining_args = self._parser.parse_known_args( *args, **kwargs) # undo default value wrapping injected in the add_argument() method for k, v in known_args.__dict__.items(): if is_default_value(v): setattr(known_args, k, _custom_unwrap_default_value(v)) return (known_args, remaining_args)
def _custom_unwrap_default_value(value): assert is_default_value(value) try: delattr(value, '_mixin_argument_already_default_value') # don't unwrap default values which haven't been wrapped by # _custom_wrap_default_value except AttributeError: value = unwrap_default_value(value) return value
def test_argument_default(): values = [ True, [1, 2, 3], 'foo', ] for value in values: assert not is_default_value(value) with pytest.raises(ValueError): unwrap_default_value(value) default_value = wrap_default_value(value) assert is_default_value(default_value) assert type(default_value) != type(value) with pytest.raises(ValueError): wrap_default_value(default_value) unwrapped_value = unwrap_default_value(default_value) assert value == unwrapped_value value = 42 unchanged_value = wrap_default_value(value) assert type(unchanged_value) == type(value) assert unchanged_value == value
def parse_args(self, *args, **kwargs): """Add mixin argument for each parser.""" global VERB_BLOCKLIST # mapping of all "leaf" verbs to parsers def collect_parsers_by_verb(root, parsers, parent_verbs=()): found_any = False for sp in root._subparsers: for name, p in sp._parsers.items(): verbs = parent_verbs + (name, ) found_children = collect_parsers_by_verb(p, parsers, verbs) # only add verbs which don't have subverbs if not found_children: parsers[verbs] = p found_any = True return found_any parsers = {} collect_parsers_by_verb(self, parsers) mixins_by_verb = get_mixins() # add mixin arguments to these parsers # doing this here instead of in the add_parser() method makes sure # the arguments are documented at the very end of the help message groups = {} for k, p in parsers.items(): # match all slices starting from index 0 of k against the blocklist # e.g. k=(a,b,c) it checks against (a), (a,b), (a,b,c) k_prefixes = {k[0:index] for index in range(1, len(k) + 1)} if not k_prefixes & VERB_BLOCKLIST: groups[p] = self._add_mixin_argument_group(p) # add dummy --mixin argument to prevent parse_known_args to interpret # --mixin arguments as --mixin-files mixin_arguments = {} for verb, p in parsers.items(): if p in groups: mixin_arguments[verb] = self._add_mixin_argument( p, groups[p], verb) with SuppressUsageOutput([self._parser] + list(parsers.values())): known_args, _ = self._parser.parse_known_args(*args, **kwargs) for mixin_file in (getattr(known_args, 'mixin_files', None) or []): # add mixins from explicitly provided file add_mixins(Path(mixin_file), mixins_by_verb) # update the --mixin argument help and completer with available mixins for verb, argument in mixin_arguments.items(): self._update_mixin_argument(argument, mixins_by_verb.get(verb, {})) args = self._parser.parse_args(*args, **kwargs) # update args based on selected mixins if 'mixin_verb' in args: mixins = mixins_by_verb.get(args.mixin_verb, {}) for mixin in args.mixin or (): if mixin not in mixins: context = '.'.join(args.mixin_verb) self._parser.error( "Mixin '{mixin}' is not available for '{context}'". format_map(locals())) mixin_args = mixins[mixin] logger.debug("Using mixin '{mixin}': {mixin_args}".format_map( locals())) self._update_args(args, mixin_args, '.'.join(args.mixin_verb)) # undo default value wrapping injected in the add_argument() method for k, v in args.__dict__.items(): if is_default_value(v): setattr(args, k, _custom_unwrap_default_value(v)) return args
def has_parameters(self, *, args): # noqa: D102 return not is_default_value(args.mp_base_paths) and \ bool(args.mp_base_paths)