def testHelpTextFunctionWithKwargsAndDefaults(self):
     component = tc.fn_with_kwarg_and_defaults
     help_screen = helptext.HelpText(component=component,
                                     trace=trace.FireTrace(component,
                                                           name='text'))
     self.assertIn('NAME\n    text', help_screen)
     self.assertIn('SYNOPSIS\n    text ARG1 ARG2 <flags>', help_screen)
     self.assertIn('DESCRIPTION\n    Function with kwarg', help_screen)
     self.assertIn(
         'FLAGS\n    --opt=OPT\n        Default: True\n'
         '    The following flags are also accepted.'
         '\n    --arg3\n        Description of arg3.\n    '
         'Additional undocumented flags may also be accepted.', help_screen)
Example #2
0
 def testHelpTextNoDefaultsObject(self):
   component = tc.NoDefaults()
   help_screen = helptext.HelpText(
       component=component,
       trace=trace.FireTrace(component, name='NoDefaults'))
   self.assertIn('NAME\n    NoDefaults', help_screen)
   self.assertIn('SYNOPSIS\n    NoDefaults COMMAND', help_screen)
   self.assertNotIn('DESCRIPTION', help_screen)
   self.assertIn('COMMANDS\n    COMMAND is one of the following:',
                 help_screen)
   self.assertIn('double', help_screen)
   self.assertIn('triple', help_screen)
   self.assertNotIn('NOTES', help_screen)
Example #3
0
 def testHelpTextFunctionWithTypesAndDefaultNone(self):
   component = tc.py3p5.WithDefaultsAndTypes().get_int
   help_screen = helptext.HelpText(
       component=component,
       trace=trace.FireTrace(component, name='get_int'))
   self.assertIn('NAME\n    get_int', help_screen)
   self.assertIn('SYNOPSIS\n    get_int <flags>', help_screen)
   self.assertNotIn('DESCRIPTION', help_screen)
   self.assertIn(
       'FLAGS\n    --value=VALUE\n'
       '        Type: Optional[int]\n        Default: None',
       help_screen)
   self.assertNotIn('NOTES', help_screen)
 def testHelpTextInt(self):
     component = 7
     help_screen = helptext.HelpText(component=component,
                                     trace=trace.FireTrace(component, '7'))
     self.assertIn('NAME\n    7', help_screen)
     self.assertIn('SYNOPSIS\n    7 COMMAND | VALUE', help_screen)
     # TODO(zuhaochen): Change assertion after implementing custom
     # description for int.
     self.assertNotIn('DESCRIPTION', help_screen)
     self.assertIn('COMMANDS\n    COMMAND is one of the following:\n',
                   help_screen)
     self.assertIn('VALUES\n    VALUE is one of the following:\n',
                   help_screen)
Example #5
0
 def testHelpTextNoDefaults(self):
   component = tc.NoDefaults
   # TODO(joejoevictor): We should have inspectutils.Info to generate
   # info['docstring_info'] as well.
   info = inspectutils.Info(component)
   info['docstring_info'] = docstrings.parse(info['docstring'])
   help_screen = helptext.HelpText(
       component=component,
       info=info,
       trace=trace.FireTrace(component, name='NoDefaults'))
   self.assertIn('NAME\n    NoDefaults', help_screen)
   self.assertIn('SYNOPSIS\n    NoDefaults', help_screen)
   self.assertNotIn('DESCRIPTION', help_screen)
   self.assertNotIn('NOTES', help_screen)
Example #6
0
 def testHelpTextObjectWithGroupAndValues(self):
   component = tc.TypedProperties()
   t = trace.FireTrace(component, name='TypedProperties')
   help_screen = helptext.HelpText(
       component=component, trace=t, verbose=True)
   print(help_screen)
   self.assertIn('GROUPS', help_screen)
   self.assertIn('GROUP is one of the following:', help_screen)
   self.assertIn(
       'charlie\n       Class with functions that have default arguments.',
       help_screen)
   self.assertIn('VALUES', help_screen)
   self.assertIn('VALUE is one of the following:', help_screen)
   self.assertIn('alpha', help_screen)
Example #7
0
 def testHelpTextFunctionWithTypes(self):
   component = tc.py3.WithTypes().double  # pytype: disable=module-attr
   help_screen = helptext.HelpText(
       component=component,
       trace=trace.FireTrace(component, name='double'))
   self.assertIn('NAME\n    double', help_screen)
   self.assertIn('SYNOPSIS\n    double COUNT', help_screen)
   self.assertIn('DESCRIPTION', help_screen)
   self.assertIn(
       'POSITIONAL ARGUMENTS\n    COUNT\n        Type: float',
       help_screen)
   self.assertIn(
       'NOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS',
       help_screen)
Example #8
0
 def testHelpTextEmptyList(self):
     component = []
     help_screen = helptext.HelpText(component=component,
                                     trace=trace.FireTrace(
                                         component, 'list'))
     self.assertIn('NAME\n    list', help_screen)
     self.assertIn('SYNOPSIS\n    list COMMAND', help_screen)
     # We don't check description content here since the content could be python
     # version dependent.
     self.assertIn('DESCRIPTION\n', help_screen)
     # We don't check the listed commands either since the list API could
     # potentially change between Python versions.
     self.assertIn('COMMANDS\n    COMMAND is one of the following:\n',
                   help_screen)
Example #9
0
 def testHelpTextFunctionWithLongDefaults(self):
   component = tc.WithDefaults().text
   help_screen = helptext.HelpText(
       component=component,
       trace=trace.FireTrace(component, name='text'))
   self.assertIn('NAME\n    text', help_screen)
   self.assertIn('SYNOPSIS\n    text <flags>', help_screen)
   self.assertNotIn('DESCRIPTION', help_screen)
   self.assertIn(
       'FLAGS\n    --string=STRING\n'
       '        Default: \'0001020304050607080910'
       '1112131415161718192021222324252627282...',
       help_screen)
   self.assertNotIn('NOTES', help_screen)
Example #10
0
 def testHelpTextFunction(self):
     component = tc.NoDefaults().double
     info = inspectutils.Info(component)
     help_screen = helptext.HelpText(component=component,
                                     info=info,
                                     trace=trace.FireTrace(component,
                                                           name='double'))
     self.assertIn('NAME\n    double', help_screen)
     self.assertIn('SYNOPSIS\n    double COUNT', help_screen)
     self.assertNotIn('DESCRIPTION', help_screen)
     self.assertIn('POSITIONAL ARGUMENTS\n    COUNT', help_screen)
     self.assertIn(
         'NOTES\n    You could also use flags syntax for POSITIONAL ARGUMENTS',
         help_screen)
Example #11
0
 def testHelpTextEmptyList(self):
     component = []
     help_screen = helptext.HelpText(component=component,
                                     trace=trace.FireTrace(
                                         component, 'list'))
     self.assertIn('NAME\n    list', help_screen)
     self.assertIn('SYNOPSIS\n    list COMMAND', help_screen)
     # TODO(zuhaochen): Change assertion after custom description is
     # implemented for list type.
     self.assertNotIn('DESCRIPTION', help_screen)
     # We don't check the listed commands either since the list API could
     # potentially change between Python versions.
     self.assertIn('COMMANDS\n    COMMAND is one of the following:\n',
                   help_screen)
Example #12
0
 def testHelpTextFunctionWithTypesAndDefaultNone(self):
     component = tc.py3.WithDefaultsAndTypes().get_int  # pytype: disable=module-attr
     help_screen = helptext.HelpText(
         component=component, trace=trace.FireTrace(component, name="get_int")
     )
     self.assertIn("NAME\n    get_int", help_screen)
     self.assertIn("SYNOPSIS\n    get_int <flags>", help_screen)
     self.assertNotIn("DESCRIPTION", help_screen)
     self.assertIn(
         "FLAGS\n    --value=VALUE\n"
         "        Type: Optional[int]\n        Default: None",
         help_screen,
     )
     self.assertNotIn("NOTES", help_screen)
Example #13
0
 def testHelpTextFunctionWithLongDefaults(self):
     component = tc.WithDefaults().text
     help_screen = helptext.HelpText(
         component=component, trace=trace.FireTrace(component, name="text")
     )
     self.assertIn("NAME\n    text", help_screen)
     self.assertIn("SYNOPSIS\n    text <flags>", help_screen)
     self.assertNotIn("DESCRIPTION", help_screen)
     self.assertIn(
         "FLAGS\n    --string=STRING\n"
         "        Default: '0001020304050607080910"
         "1112131415161718192021222324252627282...",
         help_screen,
     )
     self.assertNotIn("NOTES", help_screen)
Example #14
0
 def testHelpTextFunctionWithLongTypes(self):
   component = tc.py3p5.WithTypes().long_type
   help_screen = helptext.HelpText(
       component=component,
       trace=trace.FireTrace(component, name='long_type'))
   self.assertIn('NAME\n    long_type', help_screen)
   self.assertIn('SYNOPSIS\n    long_type LONG_OBJ', help_screen)
   self.assertNotIn('DESCRIPTION', help_screen)
   self.assertIn(
       'POSITIONAL ARGUMENTS\n    LONG_OBJ\n'
       '        Type: typing.Tuple[typing.Tuple['
       'typing.Tuple[typing.Tuple[typing.Tupl...',
       help_screen)
   self.assertIn(
       'NOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS',
       help_screen)
Example #15
0
    def testHelpTextShortList(self):
        component = [10]
        help_screen = helptext.HelpText(component=component,
                                        trace=trace.FireTrace(
                                            component, 'list'))
        self.assertIn('NAME\n    list', help_screen)
        self.assertIn('SYNOPSIS\n    list COMMAND', help_screen)
        # The list docstring is messy, so it is not shown.
        self.assertNotIn('DESCRIPTION', help_screen)

        # We don't check the listed commands comprehensively since the list API
        # could potentially change between Python versions. Check a few
        # functions(command) that we're confident likely remain available.
        self.assertIn('COMMANDS\n    COMMAND is one of the following:\n',
                      help_screen)
        self.assertIn('     append\n', help_screen)
Example #16
0
    def testHelpTextShortList(self):
        component = [10]
        help_screen = helptext.HelpText(
            component=component, trace=trace.FireTrace(component, "list")
        )
        self.assertIn("NAME\n    list", help_screen)
        self.assertIn("SYNOPSIS\n    list COMMAND", help_screen)
        # TODO(zuhaochen): Change assertion after custom description is
        # implemented for list type.
        self.assertNotIn("DESCRIPTION", help_screen)

        # We don't check the listed commands comprehensively since the list API
        # could potentially change between Python versions. Check a few
        # functions(command) that we're confident likely remain available.
        self.assertIn("COMMANDS\n    COMMAND is one of the following:\n", help_screen)
        self.assertIn("     append\n", help_screen)
Example #17
0
 def testHelpTextNoDefaultsObject(self):
   component = tc.NoDefaults()
   info = inspectutils.Info(component)
   info['docstring_info'] = docstrings.parse(info['docstring'])
   help_screen = helptext.HelpText(
       component=component,
       info=info,
       trace=trace.FireTrace(component, name='NoDefaults'))
   self.assertIn('NAME\n    NoDefaults', help_screen)
   self.assertIn('SYNOPSIS\n    NoDefaults COMMAND', help_screen)
   self.assertNotIn('DESCRIPTION', help_screen)
   self.assertIn('COMMANDS\n    COMMAND is one of the followings:',
                 help_screen)
   self.assertIn('double', help_screen)
   self.assertIn('triple', help_screen)
   self.assertNotIn('NOTES', help_screen)
Example #18
0
 def testHelpTextFunctionWithLongTypes(self):
     component = tc.py3.WithTypes().long_type
     help_screen = helptext.HelpText(component=component,
                                     trace=trace.FireTrace(
                                         component, name='long_type'))
     self.assertIn('NAME\n    long_type', help_screen)
     self.assertIn('SYNOPSIS\n    long_type LONG_OBJ', help_screen)
     self.assertNotIn('DESCRIPTION', help_screen)
     # TODO(dbieber): Assert type is displayed correctly. Type displays
     # differently in Travis vs in Google.
     # self.assertIn(
     #     'POSITIONAL ARGUMENTS\n    LONG_OBJ\n'
     #     '        Type: typing.Tuple[typing.Tuple['
     #     'typing.Tuple[typing.Tuple[typing.Tupl...',
     #     help_screen)
     self.assertIn(
         'NOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS',
         help_screen)
Example #19
0
    def testHelpScreenForFunctionFunctionWithDefaultArgs(self):
        component = tc.WithDefaults().double
        t = trace.FireTrace(component, name='double')
        help_output = helptext.HelpText(component, t)
        expected_output = """
    NAME
        double - Returns the input multiplied by 2.

    SYNOPSIS
        double [--count=COUNT]

    DESCRIPTION
        Returns the input multiplied by 2.

    FLAGS
        --count
          Input number that you want to double."""
        self.assertEqual(
            textwrap.dedent(expected_output).strip(), help_output.strip())
Example #20
0
    def testHelpTextShortList(self):
        component = [10]
        info = inspectutils.Info(component)
        help_screen = helptext.HelpText(component=component,
                                        info=info,
                                        trace=trace.FireTrace(
                                            component, 'list'))
        self.assertIn('NAME\n    list', help_screen)
        self.assertIn('SYNOPSIS\n    list COMMAND', help_screen)
        # We don't check description content here since the content could be python
        # version dependent.
        self.assertIn('DESCRIPTION\n', help_screen)

        # We don't check the listed commands comprehensively since the list API
        # could potentially change between Python versions. Check a few
        # functions(command) that we're confident likely remain available.
        self.assertIn('COMMANDS\n    COMMAND is one of the followings:\n',
                      help_screen)
        self.assertIn('     append\n', help_screen)
Example #21
0
def _PrintResult(component_trace, verbose=False):
    """Prints the result of the Fire call to stdout in a human readable way."""
    # TODO(dbieber): Design human readable deserializable serialization method
    # and move serialization to its own module.
    result = component_trace.GetResult()

    if isinstance(result, (list, set, types.GeneratorType)):
        for i in result:
            print(_OneLineResult(i))
    elif inspect.isgeneratorfunction(result):
        raise NotImplementedError
    elif isinstance(result, dict):
        print(_DictAsString(result, verbose))
    elif isinstance(result, tuple):
        print(_OneLineResult(result))
    elif isinstance(result, value_types.VALUE_TYPES):
        print(result)
    elif result is not None:
        help_text = helptext.HelpText(result, component_trace, verbose)
        output = [help_text]
        Display(output, out=sys.stdout)
Example #22
0
    def testHelpScreenForFunctionDocstringWithLineBreak(self):
        component = tc.ClassWithMultilineDocstring.example_generator
        t = trace.FireTrace(component, name="example_generator")
        help_output = helptext.HelpText(component, t)
        expected_output = """
    NAME
        example_generator - Generators have a ``Yields`` section instead of a ``Returns`` section.

    SYNOPSIS
        example_generator N

    DESCRIPTION
        Generators have a ``Yields`` section instead of a ``Returns`` section.

    POSITIONAL ARGUMENTS
        N
            The upper limit of the range to generate, from 0 to `n` - 1.

    NOTES
        You can also use flags syntax for POSITIONAL ARGUMENTS"""
        self.assertEqual(textwrap.dedent(expected_output).strip(), help_output.strip())
Example #23
0
def _PrintResult(component_trace, verbose=False, serialize=None):
  """Prints the result of the Fire call to stdout in a human readable way."""
  # TODO(dbieber): Design human readable deserializable serialization method
  # and move serialization to its own module.
  result = component_trace.GetResult()

  # Allow users to modify the return value of the component and provide
  # custom formatting.
  if serialize:
    if not callable(serialize):
      raise FireError(
          'The argument `serialize` must be empty or callable:', serialize)
    result = serialize(result)

  if value_types.HasCustomStr(result):
    # If the object has a custom __str__ method, rather than one inherited from
    # object, then we use that to serialize the object.
    print(str(result))
    return

  if isinstance(result, (list, set, frozenset, types.GeneratorType)):
    for i in result:
      print(_OneLineResult(i))
  elif inspect.isgeneratorfunction(result):
    raise NotImplementedError
  elif isinstance(result, dict) and value_types.IsSimpleGroup(result):
    print(_DictAsString(result, verbose))
  elif isinstance(result, tuple):
    print(_OneLineResult(result))
  elif isinstance(result, value_types.VALUE_TYPES):
    if result is not None:
      print(result)
  else:
    help_text = helptext.HelpText(
        result, trace=component_trace, verbose=verbose)
    output = [help_text]
    Display(output, out=sys.stdout)
Example #24
0
  def testHelpScreenForFunctionFunctionWithDefaultArgs(self):
    component = tc.WithDefaults().double
    t = trace.FireTrace(component, name='double')
    info = inspectutils.Info(component)
    info['docstring_info'] = docstrings.parse(info['docstring'])
    help_output = helptext.HelpText(component, info, t)
    expected_output = """
    NAME
        double - Returns the input multiplied by 2.

    SYNOPSIS
        double [--count=COUNT]

    DESCRIPTION
        Returns the input multiplied by 2.

    FLAGS
        --count
            Input number that you want to double.

    NOTES
        You could also use flags syntax for POSITIONAL ARGUMENTS
    """
    self.assertEqual(textwrap.dedent(expected_output).lstrip('\n'), help_output)
Example #25
0
def Fire(component=None, command=None, name=None):
    """This function, Fire, is the main entrypoint for Python Fire.

  Executes a command either from the `command` argument or from sys.argv by
  recursively traversing the target object `component`'s members consuming
  arguments, evaluating functions, and instantiating classes as it goes.

  When building a CLI with Fire, your main method should call this function.

  Args:
    component: The initial target component.
    command: Optional. If supplied, this is the command executed. If not
        supplied, then the command is taken from sys.argv instead. This can be
        a string or a list of strings; a list of strings is preferred.
    name: Optional. The name of the command as entered at the command line.
        Used in interactive mode and for generating the completion script.
  Returns:
    The result of executing the Fire command. Execution begins with the initial
    target component. The component is updated by using the command arguments
    to either access a member of the current component, call the current
    component (if it's a function), or instantiate the current component (if
    it's a class). When all arguments are consumed and there's no function left
    to call or class left to instantiate, the resulting current component is
    the final result.
  Raises:
    ValueError: If the command argument is supplied, but not a string or a
        sequence of arguments.
    FireExit: When Fire encounters a FireError, Fire will raise a FireExit with
        code 2. When used with the help or trace flags, Fire will raise a
        FireExit with code 0 if successful.
  """
    name = name or os.path.basename(sys.argv[0])

    # Get args as a list.
    if isinstance(command, six.string_types):
        args = shlex.split(command)
    elif isinstance(command, (list, tuple)):
        args = command
    elif command is None:
        # Use the command line args by default if no command is specified.
        args = sys.argv[1:]
    else:
        raise ValueError(
            'The command argument must be a string or a sequence of '
            'arguments.')

    args, flag_args = parser.SeparateFlagArgs(args)

    argparser = parser.CreateParser()
    parsed_flag_args, unused_args = argparser.parse_known_args(flag_args)

    context = {}
    if parsed_flag_args.interactive or component is None:
        # Determine the calling context.
        caller = inspect.stack()[1]
        caller_frame = caller[0]
        caller_globals = caller_frame.f_globals
        caller_locals = caller_frame.f_locals
        context.update(caller_globals)
        context.update(caller_locals)

    component_trace = _Fire(component, args, parsed_flag_args, context, name)

    if component_trace.HasError():
        _DisplayError(component_trace)
        raise FireExit(2, component_trace)
    if component_trace.show_trace and component_trace.show_help:
        output = ['Fire trace:\n{trace}\n'.format(trace=component_trace)]
        result = component_trace.GetResult()
        help_text = helptext.HelpText(result,
                                      trace=component_trace,
                                      verbose=component_trace.verbose)
        output.append(help_text)
        Display(output, out=sys.stderr)
        raise FireExit(0, component_trace)
    if component_trace.show_trace:
        output = ['Fire trace:\n{trace}'.format(trace=component_trace)]
        Display(output, out=sys.stderr)
        raise FireExit(0, component_trace)
    if component_trace.show_help:
        result = component_trace.GetResult()
        help_text = helptext.HelpText(result,
                                      trace=component_trace,
                                      verbose=component_trace.verbose)
        output = [help_text]
        Display(output, out=sys.stderr)
        raise FireExit(0, component_trace)

    # The command succeeded normally; print the result.
    _PrintResult(component_trace, verbose=component_trace.verbose)
    result = component_trace.GetResult()
    return result
Example #26
0
 def testHelpTextKeywordOnlyArgumentsWithoutDefault(self):
     component = tc.py3.KeywordOnly.double  # pytype: disable=module-attr
     output = helptext.HelpText(component=component,
                                trace=trace.FireTrace(component, 'double'))
     self.assertIn('NAME\n    double', output)
     self.assertIn('FLAGS\n    --count=COUNT (required)', output)
Example #27
0
 def testHelpTextKeywordOnlyArgumentsWithDefault(self):
   component = tc.py3.KeywordOnly.with_default  # pytype: disable=module-attr
   output = helptext.HelpText(
       component=component, trace=trace.FireTrace(component, 'with_default'))
   self.assertIn('NAME\n    with_default', output)
   self.assertIn('FLAGS\n    --x=X', output)