Ejemplo n.º 1
0
def _IsHelpShortcut(component_trace, remaining_args):
    """Determines if the user is trying to access help without '--' separator.

  For example, mycmd.py --help instead of mycmd.py -- --help.

  Args:
    component_trace: (FireTrace) The trace for the Fire command.
    remaining_args: List of remaining args that haven't been consumed yet.
  Returns:
    True if help is requested, False otherwise.
  """
    show_help = False
    if remaining_args:
        target = remaining_args[0]
        if target == '-h':
            show_help = True
        elif target == '--help':
            # Check if --help would be consumed as a keyword argument, or is a member.
            component = component_trace.GetResult()
            if inspect.isclass(component) or inspect.isroutine(component):
                fn_spec = inspectutils.GetFullArgSpec(component)
                _, remaining_kwargs, _ = _ParseKeywordArgs(
                    remaining_args, fn_spec)
                show_help = target in remaining_kwargs
            else:
                members = dict(inspect.getmembers(component))
                show_help = target not in members

    if show_help:
        component_trace.show_help = True
        command = '{cmd} -- --help'.format(cmd=component_trace.GetCommand())
        print('INFO: Showing help with the command {cmd}.\n'.format(
            cmd=pipes.quote(command)),
              file=sys.stderr)
    return show_help
Ejemplo n.º 2
0
def Completions(component, verbose=False):
    """Gives possible Fire command completions for the component.

  A completion is a string that can be appended to a command to continue that
  command. These are used for TAB-completions in Bash for Fire CLIs.

  Args:
    component: The component whose completions to list.
    verbose: Whether to include all completions, even private members.
  Returns:
    A list of completions for a command that would so far return the component.
  """
    if inspect.isroutine(component) or inspect.isclass(component):
        spec = inspectutils.GetFullArgSpec(component)
        return _CompletionsFromArgs(spec.args + spec.kwonlyargs)

    if isinstance(component, (tuple, list)):
        return [str(index) for index in range(len(component))]

    if inspect.isgenerator(component):
        # TODO(dbieber): There are currently no commands available for generators.
        return []

    return [
        _FormatForCommand(member_name)
        for member_name, _ in VisibleMembers(component, verbose=verbose)
    ]
Ejemplo n.º 3
0
 def testGetFullArgSpecFromBuiltin(self):
     spec = inspectutils.GetFullArgSpec('test'.upper)
     self.assertEqual(spec.args, [])
     self.assertEqual(spec.defaults, ())
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {})
Ejemplo n.º 4
0
def UsageTextForFunction(component, trace=None):
    """Returns usage text for function objects.

  Args:
    component: The component to determine the usage text for.
    trace: The Fire trace object containing all metadata of current execution.

  Returns:
    String suitable for display in an error screen.
  """
    output_template = """Usage: {current_command} {args_and_flags}
{availability_lines}
For detailed information on this command, run:
  {current_command}{hyphen_hyphen} --help"""

    if trace:
        command = trace.GetCommand()
        needs_separating_hyphen_hyphen = trace.NeedsSeparatingHyphenHyphen()
    else:
        command = None
        needs_separating_hyphen_hyphen = False

    if not command:
        command = ''

    spec = inspectutils.GetFullArgSpec(component)
    args = spec.args
    if spec.defaults is None:
        num_defaults = 0
    else:
        num_defaults = len(spec.defaults)
    args_with_no_defaults = args[:len(args) - num_defaults]
    args_with_defaults = args[len(args) - num_defaults:]
    flags = args_with_defaults + spec.kwonlyargs

    # Check if positional args are allowed. If not, show flag syntax for args.
    metadata = decorators.GetMetadata(component)
    accepts_positional_args = metadata.get(decorators.ACCEPTS_POSITIONAL_ARGS)
    if not accepts_positional_args:
        items = [
            '--{arg}={upper}'.format(arg=arg, upper=arg.upper())
            for arg in args_with_no_defaults
        ]
    else:
        items = [arg.upper() for arg in args_with_no_defaults]

    if flags:
        items.append('<flags>')
        availability_lines = ('\nAvailable flags: ' +
                              ' | '.join('--' + flag for flag in flags) + '\n')
    else:
        availability_lines = ''
    args_and_flags = ' '.join(items)

    hyphen_hyphen = ' --' if needs_separating_hyphen_hyphen else ''

    return output_template.format(current_command=command,
                                  args_and_flags=args_and_flags,
                                  availability_lines=availability_lines,
                                  hyphen_hyphen=hyphen_hyphen)
Ejemplo n.º 5
0
def UsageString(component, trace=None, verbose=False):
    """Returns a string showing how to use the component as a Fire command."""
    if trace:
        command = trace.GetCommand()
    else:
        command = None

    if command:
        command += ' '
    else:
        command = ''

    if inspect.isroutine(component) or inspect.isclass(component):
        spec = inspectutils.GetFullArgSpec(component)
        return _UsageStringFromFullArgSpec(command, spec)

    if isinstance(component, (list, tuple)):
        length = len(component)
        if length == 0:
            return command
        if length == 1:
            return command + '[0]'
        return command + '[0..{cap}]'.format(cap=length - 1)

    completions = completion.Completions(component, verbose)
    if command:
        completions = [''] + completions
    return '\n'.join(command + end for end in completions)
Ejemplo n.º 6
0
def _MakeParseFn(fn):
    """Creates a parse function for fn.

  Args:
    fn: The function or class to create the parse function for.
  Returns:
    A parse function for fn. The parse function accepts a list of arguments
    and returns (varargs, kwargs), remaining_args. The original function fn
    can then be called with fn(*varargs, **kwargs). The remaining_args are
    the leftover args from the arguments to the parse function.
  """
    fn_spec = inspectutils.GetFullArgSpec(fn)
    all_args = fn_spec.args + fn_spec.kwonlyargs
    metadata = decorators.GetMetadata(fn)

    # Note: num_required_args is the number of positional arguments without
    # default values. All of these arguments are required.
    num_required_args = len(fn_spec.args) - len(fn_spec.defaults)
    required_kwonly = set(fn_spec.kwonlyargs) - set(fn_spec.kwonlydefaults)

    def _ParseFn(args):
        """Parses the list of `args` into (varargs, kwargs), remaining_args."""
        kwargs, remaining_kwargs, remaining_args = _ParseKeywordArgs(
            args, all_args, fn_spec.varkw)

        # Note: _ParseArgs modifies kwargs.
        parsed_args, kwargs, remaining_args, capacity = _ParseArgs(
            fn_spec.args, fn_spec.defaults, num_required_args, kwargs,
            remaining_args, metadata)

        if fn_spec.varargs or fn_spec.varkw:
            # If we're allowed *varargs or **kwargs, there's always capacity.
            capacity = True

        extra_kw = set(kwargs) - set(fn_spec.kwonlyargs)
        if fn_spec.varkw is None and extra_kw:
            raise FireError('Unexpected kwargs present:', extra_kw)

        missing_kwonly = set(required_kwonly) - set(kwargs)
        if missing_kwonly:
            raise FireError('Missing required flags:', missing_kwonly)

        # If we accept *varargs, then use all remaining arguments for *varargs.
        if fn_spec.varargs is not None:
            varargs, remaining_args = remaining_args, []
        else:
            varargs = []

        for index, value in enumerate(varargs):
            varargs[index] = _ParseValue(value, None, None, metadata)

        varargs = parsed_args + varargs
        remaining_args += remaining_kwargs

        consumed_args = args[:len(args) - len(remaining_args)]
        return (varargs, kwargs), consumed_args, remaining_args, capacity

    return _ParseFn
Ejemplo n.º 7
0
 def testGetFullArgSpec(self):
     spec = inspectutils.GetFullArgSpec(tc.identity)
     self.assertEqual(spec.args, ["arg1", "arg2", "arg3", "arg4"])
     self.assertEqual(spec.defaults, (10, 20))
     self.assertEqual(spec.varargs, "arg5")
     self.assertEqual(spec.varkw, "arg6")
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {"arg2": int, "arg4": int})
Ejemplo n.º 8
0
 def testGetFullArgSpecFromMethod(self):
     spec = inspectutils.GetFullArgSpec(tc.NoDefaults().double)
     self.assertEqual(spec.args, ['count'])
     self.assertEqual(spec.defaults, ())
     self.assertEqual(spec.varargs, None)
     self.assertEqual(spec.varkw, None)
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {})
Ejemplo n.º 9
0
 def testGetFullArgSpecFromClassNoInit(self):
     spec = inspectutils.GetFullArgSpec(tc.OldStyleEmpty)
     self.assertEqual(spec.args, [])
     self.assertEqual(spec.defaults, ())
     self.assertEqual(spec.varargs, None)
     self.assertEqual(spec.varkw, None)
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {})
Ejemplo n.º 10
0
 def testGetFullArgSpecFromSlotWrapper(self):
     spec = inspectutils.GetFullArgSpec(tc.NoDefaults)
     self.assertEqual(spec.args, [])
     self.assertEqual(spec.defaults, ())
     self.assertEqual(spec.varargs, None)
     self.assertEqual(spec.varkw, None)
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {})
Ejemplo n.º 11
0
 def testGetFullArgSpec(self):
     spec = inspectutils.GetFullArgSpec(tc.identity)
     self.assertEqual(spec.args, ['arg1', 'arg2', 'arg3', 'arg4'])
     self.assertEqual(spec.defaults, (10, 20))
     self.assertEqual(spec.varargs, 'arg5')
     self.assertEqual(spec.varkw, 'arg6')
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {'arg2': int, 'arg4': int})
Ejemplo n.º 12
0
 def testGetFullArgSpecFromNamedTupleSubclass(self):
     spec = inspectutils.GetFullArgSpec(tc.SubPoint)
     self.assertEqual(spec.args, ['x', 'y'])
     self.assertEqual(spec.defaults, ())
     self.assertEqual(spec.varargs, None)
     self.assertEqual(spec.varkw, None)
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {})
Ejemplo n.º 13
0
 def testGetFullArgSpecFromNamedTuple(self):
     spec = inspectutils.GetFullArgSpec(tc.NamedTuplePoint)
     self.assertEqual(spec.args, ["x", "y"])
     self.assertEqual(spec.defaults, ())
     self.assertEqual(spec.varargs, None)
     self.assertEqual(spec.varkw, None)
     self.assertEqual(spec.kwonlyargs, [])
     self.assertEqual(spec.kwonlydefaults, {})
     self.assertEqual(spec.annotations, {})
Ejemplo n.º 14
0
 def testGetFullArgSpecPy3(self):
   spec = inspectutils.GetFullArgSpec(tc.py3.identity)
   self.assertEqual(spec.args, ['arg1', 'arg2', 'arg3', 'arg4'])
   self.assertEqual(spec.defaults, (10, 20))
   self.assertEqual(spec.varargs, 'arg5')
   self.assertEqual(spec.varkw, 'arg10')
   self.assertEqual(spec.kwonlyargs, ['arg6', 'arg7', 'arg8', 'arg9'])
   self.assertEqual(spec.kwonlydefaults, {'arg8': 30, 'arg9': 40})
   self.assertEqual(spec.annotations,
                    {'arg2': int, 'arg4': int, 'arg7': int, 'arg9': int})
Ejemplo n.º 15
0
def UsageTextForFunction(component, trace=None):
  """Returns usage text for function objects.

  Args:
    component: The component to determine the usage text for.
    trace: The Fire trace object containing all metadata of current execution.

  Returns:
    String suitable for display in error screen.
  """

  output_template = """Usage: {current_command} {args_and_flags}
{availability_lines}
For detailed information on this command, run:
{current_command}{hyphen_hyphen} --help
"""

  if trace:
    command = trace.GetCommand()
    is_help_an_arg = trace.NeedsSeparatingHyphenHyphen()
  else:
    command = None
    is_help_an_arg = False

  if not command:
    command = ''

  spec = inspectutils.GetFullArgSpec(component)
  args = spec.args

  if spec.defaults is None:
    num_defaults = 0
  else:
    num_defaults = len(spec.defaults)
  args_with_no_defaults = args[:len(args) - num_defaults]
  args_with_defaults = args[len(args) - num_defaults:]
  flags = args_with_defaults + spec.kwonlyargs

  items = [arg.upper() for arg in args_with_no_defaults]
  if flags:
    items.append('<flags>')
    availability_lines = (
        '\nAvailable flags: '
        + ' | '.join('--' + flag for flag in flags) + '\n')
  else:
    availability_lines = ''
  args_and_flags = ' '.join(items)

  hyphen_hyphen = ' --' if is_help_an_arg else ''

  return output_template.format(
      current_command=command,
      args_and_flags=args_and_flags,
      availability_lines=availability_lines,
      hyphen_hyphen=hyphen_hyphen)
Ejemplo n.º 16
0
 def testGetFullArgSpecPy3(self):
     spec = inspectutils.GetFullArgSpec(tc.py3.identity)
     self.assertEqual(spec.args, ["arg1", "arg2", "arg3", "arg4"])
     self.assertEqual(spec.defaults, (10, 20))
     self.assertEqual(spec.varargs, "arg5")
     self.assertEqual(spec.varkw, "arg10")
     self.assertEqual(spec.kwonlyargs, ["arg6", "arg7", "arg8", "arg9"])
     self.assertEqual(spec.kwonlydefaults, {"arg8": 30, "arg9": 40})
     self.assertEqual(
         spec.annotations, {"arg2": int, "arg4": int, "arg7": int, "arg9": int}
     )
Ejemplo n.º 17
0
def GetArgsAngFlags(component):
    """Returns all types of arguments and flags of a component."""
    spec = inspectutils.GetFullArgSpec(component)
    args = spec.args
    if spec.defaults is None:
        num_defaults = 0
    else:
        num_defaults = len(spec.defaults)
    args_with_no_defaults = args[:len(args) - num_defaults]
    args_with_defaults = args[len(args) - num_defaults:]
    flags = args_with_defaults + spec.kwonlyargs
    return args_with_no_defaults, args_with_defaults, flags
Ejemplo n.º 18
0
def HelpText(component, trace=None, verbose=False):
  """Gets the help string for the current component, suitalbe for a help screen.

  Args:
    component: The component to construct the help string for.
    trace: The Fire trace of the command so far. The command executed so far
      can be extracted from this trace.
    verbose: Whether to include private members in the help screen.

  Returns:
    The full help screen as a string.
  """
  # Preprocessing needed to create the sections:
  info = inspectutils.Info(component)
  actions_grouped_by_kind = _GetActionsGroupedByKind(component, verbose=verbose)
  spec = inspectutils.GetFullArgSpec(component)
  metadata = decorators.GetMetadata(component)

  # Sections:
  name_section = _NameSection(component, info, trace=trace, verbose=verbose)
  synopsis_section = _SynopsisSection(
      component, actions_grouped_by_kind, spec, metadata, trace=trace)
  description_section = _DescriptionSection(component, info)
  # TODO(dbieber): Add returns and raises sections for functions.

  if inspect.isroutine(component) or inspect.isclass(component):
    # For functions (ARGUMENTS / POSITIONAL ARGUMENTS, FLAGS)
    args_and_flags_sections, notes_sections = _ArgsAndFlagsSections(
        info, spec, metadata)
    usage_details_sections = []
  else:
    # For objects (GROUPS, COMMANDS, VALUES, INDEXES)
    # TODO(dbieber): Show callable function usage in help text.
    args_and_flags_sections = []
    notes_sections = []
    usage_details_sections = _UsageDetailsSections(component,
                                                   actions_grouped_by_kind)

  sections = (
      [name_section, synopsis_section, description_section]
      + args_and_flags_sections
      + usage_details_sections
      + notes_sections
  )
  return '\n\n'.join(
      _CreateOutputSection(*section)
      for section in sections if section is not None
  )
Ejemplo n.º 19
0
    def NeedsSeparatingHyphenHyphen(self, flag="help"):
        """Returns whether a the trace need '--' before '--help'.

        '--' is needed when the component takes keyword arguments, when the value of
        flag matches one of the argument of the component, or the component takes in
        keyword-only arguments(e.g. argument with default value).

        Args:
          flag: the flag available for the trace

        Returns:
          True for needed '--', False otherwise.

        """
        element = self.GetLastHealthyElement()
        component = element.component
        spec = inspectutils.GetFullArgSpec(component)
        return spec.varkw is not None or flag in spec.args or flag in spec.kwonlyargs
Ejemplo n.º 20
0
def HelpTextForFunction(component, info, trace=None, verbose=False):
  """Returns detail help text for a function component.

  Args:
    component: Current component to generate help text for.
    info: Info containing metadata of component.
    trace: FireTrace object that leads to current component.
    verbose: Whether to display help text in verbose mode.

  Returns:
    Formatted help text for display.
  """
  # TODO(joejoevictor): Implement verbose related output
  del verbose

  current_command = GetCurrentCommand(trace)
  summary, description = GetSummaryAndDescription(info['docstring_info'])
  spec = inspectutils.GetFullArgSpec(component)
  args = spec.args

  args_with_no_defaults, args_with_defaults, flags = GetArgsAngFlags(component)
  del args_with_defaults

  # Name section
  name_section_template = '{current_command}{command_summary}'
  command_summary_str = ' - ' + summary if summary else ''
  name_section = name_section_template.format(
      current_command=current_command, command_summary=command_summary_str)

  args_and_flags = ''
  if args_with_no_defaults:
    items = [arg.upper() for arg in args_with_no_defaults]
    args_and_flags = ' '.join(items)

  synopsis_flag_template = '[--{flag_name}={flag_name_upper}]'
  if flags:
    items = [
        synopsis_flag_template.format(
            flag_name=flag, flag_name_upper=flag.upper()) for flag in flags
    ]
    args_and_flags = args_and_flags + ' '.join(items)

  # Synopsis section
  synopsis_section_template = '{current_command} {args_and_flags}'
  positional_arguments = '|'.join(args)
  if positional_arguments:
    positional_arguments = ' ' + positional_arguments
  synopsis_section = synopsis_section_template.format(
      current_command=current_command, args_and_flags=args_and_flags)

  # Description section
  command_description = GetDescriptionSectionText(summary, description)
  description_sections = []
  if command_description:
    description_sections.append(('DESCRIPTION', command_description))

  # Positional arguments and flags section
  docstring_info = info['docstring_info']
  args_and_flags_sections = []
  notes_sections = []

  pos_arg_items = []
  pos_arg_items = [
      _CreatePositionalArgItem(arg, docstring_info)
      for arg in args_with_no_defaults
  ]
  if pos_arg_items:
    positional_arguments_section = ('POSITIONAL ARGUMENTS',
                                    '\n'.join(pos_arg_items).rstrip('\n'))
    args_and_flags_sections.append(positional_arguments_section)
    notes_sections.append(
        ('NOTES', 'You could also use flags syntax for POSITIONAL ARGUMENTS')
    )

  flag_items = [
      _CreateFlagItem(flag, docstring_info)
      for flag in flags
  ]

  if flag_items:
    flags_section = ('FLAGS', '\n'.join(flag_items))
    args_and_flags_sections.append(flags_section)

  output_sections = [
      ('NAME', name_section),
      ('SYNOPSIS', synopsis_section),
  ] + description_sections + args_and_flags_sections + notes_sections

  return '\n\n'.join(
      _CreateOutputSection(name, content)
      for name, content in output_sections
  )
Ejemplo n.º 21
0
def HelpTextForFunction(component, info, trace=None, verbose=False):
    """Returns detail help text for a function component.

  Args:
    component: Current component to generate help text for.
    info: Info containing metadata of component.
    trace: FireTrace object that leads to current component.
    verbose: Whether to display help text in verbose mode.

  Returns:
    Formatted help text for display.
  """
    # TODO(joejoevictor): Implement verbose related output
    del verbose

    current_command = GetCurrentCommand(trace)
    summary, description = GetSummaryAndDescription(info['docstring_info'])
    spec = inspectutils.GetFullArgSpec(component)
    args = spec.args

    if spec.defaults is None:
        num_defaults = 0
    else:
        num_defaults = len(spec.defaults)
    args_with_no_defaults = args[:len(args) - num_defaults]

    # TODO(joejoevictor): Generate flag section using these
    # args_with_defaults = args[len(args) - num_defaults:]
    # flags = args_with_defaults + spec.kwonlyargs

    output_template = """NAME
    {name_section}

SYNOPSIS
    {synopsis_section}

DESCRIPTION
    {description_section}
{args_and_flags_section}
NOTES
    You could also use flags syntax for POSITIONAL ARGUMENTS
"""

    # Name section
    name_section_template = '{current_command}{command_summary}'
    command_summary_str = ' - ' + summary if summary else ''
    name_section = name_section_template.format(
        current_command=current_command, command_summary=command_summary_str)

    items = [arg.upper() for arg in args_with_no_defaults]
    args_and_flags = ' '.join(items)

    # Synopsis section
    synopsis_section_template = '{current_command} {args_and_flags}'
    positional_arguments = '|'.join(args)
    if positional_arguments:
        positional_arguments = ' ' + positional_arguments
    synopsis_section = synopsis_section_template.format(
        current_command=current_command, args_and_flags=args_and_flags)

    # Description section
    description_section = description if description else summary

    args_and_flags_section = ''

    # Positional arguments and flags section

    pos_arg_template = """
POSITIONAL ARGUMENTS
{items}
"""
    pos_arg_items = []
    for arg in args_with_no_defaults:
        item_template = '    {arg_name}\n        {arg_description}\n'
        arg_description = None
        for arg_in_docstring in info['docstring_info'].args:
            if arg_in_docstring.name == arg:
                arg_description = arg_in_docstring.description

        item = item_template.format(arg_name=arg.upper(),
                                    arg_description=arg_description)
        pos_arg_items.append(item)
    if pos_arg_items:
        args_and_flags_section += pos_arg_template.format(
            items='\n'.join(pos_arg_items).rstrip('\n'))

    return output_template.format(
        name_section=name_section,
        synopsis_section=synopsis_section,
        description_section=description_section,
        args_and_flags_section=args_and_flags_section)
Ejemplo n.º 22
0
def UsageTextForFunction(component, trace=None, verbose=False):
  """Returns usage text for function objects.

  Args:
    component: The component to determine the usage text for.
    trace: The Fire trace object containing all metadata of current execution.
    verbose: Whether to display the usage text in verbose mode.

  Returns:
    String suitable for display in an error screen.
  """
  del verbose  # Unused.

  output_template = """Usage: {current_command} {args_and_flags}
{availability_lines}
For detailed information on this command, run:
  {current_command}{hyphen_hyphen} --help"""

  if trace:
    command = trace.GetCommand()
    needs_separating_hyphen_hyphen = trace.NeedsSeparatingHyphenHyphen()
  else:
    command = None
    needs_separating_hyphen_hyphen = False

  if not command:
    command = ''

  spec = inspectutils.GetFullArgSpec(component)
  args_with_no_defaults = spec.args[:len(spec.args) - len(spec.defaults)]
  args_with_defaults = spec.args[len(spec.args) - len(spec.defaults):]

  # Check if positional args are allowed. If not, show flag syntax for args.
  metadata = decorators.GetMetadata(component)
  accepts_positional_args = metadata.get(decorators.ACCEPTS_POSITIONAL_ARGS)
  if not accepts_positional_args:
    items = ['--{arg}={upper}'.format(arg=arg, upper=arg.upper())
             for arg in args_with_no_defaults]
  else:
    items = [arg.upper() for arg in args_with_no_defaults]

  # If there are any arguments that are treated as flags:
  if args_with_defaults or spec.kwonlyargs or spec.varkw:
    items.append('<flags>')

  optional_flags = [('--' + flag) for flag in args_with_defaults]
  required_flags = [('--' + flag) for flag in spec.kwonlyargs]

  # Flags section:
  availability_lines = []
  if optional_flags:
    availability_lines.append(
        _CreateAvailabilityLine(header='Optional flags:', items=optional_flags,
                                header_indent=0))
  if required_flags:
    availability_lines.append(
        _CreateAvailabilityLine(header='Required flags:', items=required_flags,
                                header_indent=0))
  if spec.varkw:
    additional_flags = ('Additional flags are accepted.'
                        if optional_flags or required_flags else
                        'Flags are accepted.')
    availability_lines.append(additional_flags + '\n')

  if availability_lines:
    # Start the section with blank lines.
    availability_lines.insert(0, '\n')

  if spec.varargs:
    items.append('[{varargs}]...'.format(varargs=spec.varargs.upper()))

  args_and_flags = ' '.join(items)

  hyphen_hyphen = ' --' if needs_separating_hyphen_hyphen else ''

  return output_template.format(
      current_command=command,
      args_and_flags=args_and_flags,
      availability_lines=''.join(availability_lines),
      hyphen_hyphen=hyphen_hyphen)
Ejemplo n.º 23
0
def UsageText(component, trace=None, verbose=False):
  """Returns usage text for the given component.

  Args:
    component: The component to determine the usage text for.
    trace: The Fire trace object containing all metadata of current execution.
    verbose: Whether to display the usage text in verbose mode.

  Returns:
    String suitable for display in an error screen.
  """
  output_template = """Usage: {continued_command}
{availability_lines}
For detailed information on this command, run:
  {help_command}"""

  # Get the command so far:
  if trace:
    command = trace.GetCommand()
    needs_separating_hyphen_hyphen = trace.NeedsSeparatingHyphenHyphen()
  else:
    command = None
    needs_separating_hyphen_hyphen = False

  if not command:
    command = ''

  # Build the continuations for the command:
  continued_command = command

  spec = inspectutils.GetFullArgSpec(component)
  metadata = decorators.GetMetadata(component)

  # Usage for objects.
  actions_grouped_by_kind = _GetActionsGroupedByKind(component, verbose=verbose)
  possible_actions = _GetPossibleActions(actions_grouped_by_kind)

  continuations = []
  if possible_actions:
    continuations.append(_GetPossibleActionsUsageString(possible_actions))

  availability_lines = _UsageAvailabilityLines(actions_grouped_by_kind)

  if callable(component):
    callable_items = _GetCallableUsageItems(spec, metadata)
    if callable_items:
      continuations.append(' '.join(callable_items))
    elif trace:
      continuations.append(trace.separator)
    availability_lines.extend(_GetCallableAvailabilityLines(spec))

  if continuations:
    continued_command += ' ' + ' | '.join(continuations)
  help_command = (
      command
      + (' -- ' if needs_separating_hyphen_hyphen else ' ')
      + '--help'
  )

  return output_template.format(
      continued_command=continued_command,
      availability_lines=''.join(availability_lines),
      help_command=help_command)