def _Suggest(self, unknown_args):
        """Error out with a suggestion based on text distance for each unknown."""
        messages = []
        suggester = usage_text.TextChoiceSuggester()
        # pylint:disable=protected-access, This is an instance of this class.
        for flag in self._calliope_command.GetAllAvailableFlags():
            options = flag.option_strings
            if options:
                # This is a flag, add all its names as choices.
                suggester.AddChoices(options)
                # Add any aliases as choices as well, but suggest the primary name.
                aliases = getattr(flag, 'suggestion_aliases', None)
                if aliases:
                    suggester.AddAliases(aliases, options[0])

        suggestions = {}
        for arg in unknown_args:
            # Only do this for flag names.
            if arg.startswith('--'):
                # Strip the flag value if any from the suggestion.
                flag = arg.split('=')[0]
                suggestion = suggester.GetSuggestion(flag)
            else:
                suggestion = None
            if suggestion:
                suggestions[arg] = suggestion
                messages.append(arg +
                                " (did you mean '{0}'?)".format(suggestion))
            else:
                messages.append(arg)

        # If there is a single arg, put it on the same line.  If there are multiple
        # add each on it's own line for better clarity.
        separator = u'\n  ' if len(messages) > 1 else u' '
        # This try-except models the real parse_args() pathway to self.error().
        try:
            raise parser_errors.UnrecognizedArgumentsError(
                u'unrecognized arguments:{0}{1}'.format(
                    separator, separator.join(messages)),
                parser=self,
                total_unrecognized=len(unknown_args),
                total_suggestions=len(suggestions),
                suggestions=suggestions,
            )
        except argparse.ArgumentError as e:
            self.error(e.message)
    def ParseRemainingArgs(self, remaining_args, namespace, original_args):
        """Parses the unrecognized args from the end of the remaining_args.

    This method identifies all unrecognized arguments after the last argument
    recognized by a parser (but before --). It then either logs a warning and
    binds them to the namespace or raises an error, depending on strictness.

    Args:
      remaining_args: A list of arguments that the parsers did not recognize.
      namespace: The Namespace to bind to.
      original_args: The full list of arguments given to the top parser,

    Raises:
      ArgumentError: If there were remaining arguments after the last recognized
      argument and this action is strict.

    Returns:
      A tuple of the updated namespace and unrecognized arguments (before the
      last recognized argument).
    """
        # Only parse consecutive unknown args from the end of the original args.
        # Strip out everything after '--'
        if '--' in original_args:
            original_args, _ = self._SplitOnDash(original_args)
        # Find common suffix between remaining_args and original_args
        split_index = 0
        for i, (arg1, arg2) in enumerate(
                zip(reversed(remaining_args), reversed(original_args))):
            if arg1 != arg2:
                split_index = len(remaining_args) - i
                break
        pass_through_args = remaining_args[split_index:]
        remaining_args = remaining_args[:split_index]

        if pass_through_args:
            msg = (u'unrecognized args: {args}\n' +
                   self.explanation).format(args=u' '.join(pass_through_args))
            raise parser_errors.UnrecognizedArgumentsError(msg)
        self(None, namespace, pass_through_args)
        return namespace, remaining_args
Exemple #3
0
    def parse_args(self, args=None, namespace=None):
        """Overrides argparse.ArgumentParser's .parse_args method."""
        namespace, unknown_args = self.parse_known_args(args, namespace)
        if not unknown_args:
            return namespace

        # Content of these lines differs from argparser's parse_args().
        # pylint:disable=protected-access
        deepest_parser = namespace._deepest_parser or self
        deepest_parser._specified_args = namespace._specified_args
        if deepest_parser._remainder_action:
            # Assume the user wanted to pass all arguments after last recognized
            # arguments into _remainder_action. Either do this with a warning or
            # fail depending on strictness.
            # pylint:disable=protected-access
            try:
                namespace, unknown_args = (
                    deepest_parser._remainder_action.ParseRemainingArgs(
                        unknown_args, namespace, args))
                # There still may be unknown_args that came before the last known arg.
                if not unknown_args:
                    return namespace
            except parser_errors.UnrecognizedArgumentsError as e:
                # In the case of UnrecognizedArgumentsError, we want to just let it
                # continue so that we can get the nicer error handling.
                pass

        # There is at least one parsing error. Add a message for each unknown
        # argument.  For each, try to come up with a suggestion based on text
        # distance.  If one is close enough, print a 'did you mean' message along
        # with that argument.
        messages = []
        suggester = usage_text.TextChoiceSuggester()
        # pylint:disable=protected-access, This is an instance of this class.
        for flag in deepest_parser._calliope_command.GetAllAvailableFlags():
            options = flag.option_strings
            if options:
                # This is a flag, add all its names as choices.
                suggester.AddChoices(options)
                # Add any aliases as choices as well, but suggest the primary name.
                aliases = getattr(flag, 'suggestion_aliases', None)
                if aliases:
                    suggester.AddAliases(aliases, options[0])

        suggestions = {}
        for arg in unknown_args:
            # Only do this for flag names.
            if arg.startswith('--'):
                # Strip the flag value if any from the suggestion.
                flag = arg.split('=')[0]
                suggestion = suggester.GetSuggestion(flag)
            else:
                suggestion = None
            if suggestion:
                suggestions[arg] = suggestion
                messages.append(arg +
                                " (did you mean '{0}'?)".format(suggestion))
            else:
                messages.append(arg)

        # If there is a single arg, put it on the same line.  If there are multiple
        # add each on it's own line for better clarity.
        separator = u'\n  ' if len(messages) > 1 else u' '
        # This try-except models the real parse_args() pathway to self.error().
        try:
            raise parser_errors.UnrecognizedArgumentsError(
                u'unrecognized arguments:{0}{1}'.format(
                    separator, separator.join(messages)),
                parser=deepest_parser,
                total_unrecognized=len(unknown_args),
                total_suggestions=len(suggestions),
                suggestions=suggestions,
            )
        except argparse.ArgumentError as e:
            deepest_parser.error(e.message)