예제 #1
0
    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()))
예제 #2
0
 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)
예제 #3
0
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
예제 #4
0
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
예제 #5
0
    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)