yoloserv/awesome_venv/lib/python3.10/site-packages/fire/helptext_test.py

626 lines
23 KiB
Python

# Copyright (C) 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for the helptext module."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import textwrap
from fire import formatting
from fire import helptext
from fire import test_components as tc
from fire import testutils
from fire import trace
import six
class HelpTest(testutils.BaseTestCase):
def setUp(self):
super(HelpTest, self).setUp()
os.environ['ANSI_COLORS_DISABLED'] = '1'
def testHelpTextNoDefaults(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', help_screen)
self.assertNotIn('DESCRIPTION', help_screen)
self.assertNotIn('NOTES', help_screen)
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)
def testHelpTextFunction(self):
component = tc.NoDefaults().double
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.assertNotIn('DESCRIPTION', help_screen)
self.assertIn('POSITIONAL ARGUMENTS\n COUNT', help_screen)
self.assertIn(
'NOTES\n You can also use flags syntax for POSITIONAL ARGUMENTS',
help_screen)
def testHelpTextFunctionWithDefaults(self):
component = tc.WithDefaults().triple
help_screen = helptext.HelpText(
component=component,
trace=trace.FireTrace(component, name='triple'))
self.assertIn('NAME\n triple', help_screen)
self.assertIn('SYNOPSIS\n triple <flags>', help_screen)
self.assertNotIn('DESCRIPTION', help_screen)
self.assertIn(
'FLAGS\n -c, --count=COUNT\n Default: 0',
help_screen)
self.assertNotIn('NOTES', help_screen)
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 -s, --string=STRING\n'
' Default: \'0001020304050607080910'
'1112131415161718192021222324252627282...',
help_screen)
self.assertNotIn('NOTES', help_screen)
def testHelpTextFunctionWithKwargs(self):
component = tc.fn_with_kwarg
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 --arg3\n Description of arg3.\n '
'Additional undocumented flags may also be accepted.',
help_screen)
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 -o, --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)
@testutils.skipIf(
sys.version_info[0:2] < (3, 5),
'Python < 3.5 does not support type hints.')
def testHelpTextFunctionWithDefaultsAndTypes(self):
component = (
tc.py3.WithDefaultsAndTypes().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 <flags>', help_screen)
self.assertIn('DESCRIPTION', help_screen)
self.assertIn(
'FLAGS\n -c, --count=COUNT\n Type: float\n Default: 0',
help_screen)
self.assertNotIn('NOTES', help_screen)
@testutils.skipIf(
sys.version_info[0:2] < (3, 5),
'Python < 3.5 does not support type hints.')
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 -v, --value=VALUE\n'
' Type: Optional[int]\n Default: None',
help_screen)
self.assertNotIn('NOTES', help_screen)
@testutils.skipIf(
sys.version_info[0:2] < (3, 5),
'Python < 3.5 does not support type hints.')
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)
@testutils.skipIf(
sys.version_info[0:2] < (3, 5),
'Python < 3.5 does not support type hints.')
def testHelpTextFunctionWithLongTypes(self):
component = tc.py3.WithTypes().long_type # pytype: disable=module-attr
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 displayed
# 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)
def testHelpTextFunctionWithBuiltin(self):
component = 'test'.upper
help_screen = helptext.HelpText(
component=component,
trace=trace.FireTrace(component, 'upper'))
self.assertIn('NAME\n upper', help_screen)
self.assertIn('SYNOPSIS\n upper', help_screen)
# We don't check description content here since the content is python
# version dependent.
self.assertIn('DESCRIPTION\n', help_screen)
self.assertNotIn('NOTES', help_screen)
def testHelpTextFunctionIntType(self):
component = int
help_screen = helptext.HelpText(
component=component, trace=trace.FireTrace(component, 'int'))
self.assertIn('NAME\n int', help_screen)
self.assertIn('SYNOPSIS\n int', help_screen)
# We don't check description content here since the content is python
# version dependent.
self.assertIn('DESCRIPTION\n', help_screen)
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)
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)
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)
def testHelpTextNoInit(self):
component = tc.OldStyleEmpty
help_screen = helptext.HelpText(
component=component,
trace=trace.FireTrace(component, 'OldStyleEmpty'))
self.assertIn('NAME\n OldStyleEmpty', help_screen)
self.assertIn('SYNOPSIS\n OldStyleEmpty', help_screen)
@testutils.skipIf(
six.PY2, 'Python 2 does not support keyword-only arguments.')
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=X', output)
@testutils.skipIf(
six.PY2, 'Python 2 does not support keyword-only arguments.')
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 -c, --count=COUNT (required)', output)
@testutils.skipIf(
six.PY2,
'Python 2 does not support required name-only arguments.')
def testHelpTextFunctionMixedDefaults(self):
component = tc.py3.HelpTextComponent().identity
t = trace.FireTrace(component, name='FunctionMixedDefaults')
output = helptext.HelpText(component, trace=t)
self.assertIn('NAME\n FunctionMixedDefaults', output)
self.assertIn('FunctionMixedDefaults <flags>', output)
self.assertIn('--alpha=ALPHA (required)', output)
self.assertIn('--beta=BETA\n Default: \'0\'', output)
def testHelpScreen(self):
component = tc.ClassWithDocstring()
t = trace.FireTrace(component, name='ClassWithDocstring')
help_output = helptext.HelpText(component, t)
expected_output = """
NAME
ClassWithDocstring - Test class for testing help text output.
SYNOPSIS
ClassWithDocstring COMMAND | VALUE
DESCRIPTION
This is some detail description of this test class.
COMMANDS
COMMAND is one of the following:
print_msg
Prints a message.
VALUES
VALUE is one of the following:
message
The default message to print."""
self.assertEqual(textwrap.dedent(expected_output).strip(),
help_output.strip())
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())
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 <flags>
DESCRIPTION
Returns the input multiplied by 2.
FLAGS
-c, --count=COUNT
Default: 0
Input number that you want to double."""
self.assertEqual(textwrap.dedent(expected_output).strip(),
help_output.strip())
def testHelpTextUnderlineFlag(self):
component = tc.WithDefaults().triple
t = trace.FireTrace(component, name='triple')
help_screen = helptext.HelpText(component, t)
self.assertIn(formatting.Bold('NAME') + '\n triple', help_screen)
self.assertIn(
formatting.Bold('SYNOPSIS') + '\n triple <flags>',
help_screen)
self.assertIn(
formatting.Bold('FLAGS') + '\n -c, --' +
formatting.Underline('count'),
help_screen)
def testHelpTextBoldCommandName(self):
component = tc.ClassWithDocstring()
t = trace.FireTrace(component, name='ClassWithDocstring')
help_screen = helptext.HelpText(component, t)
self.assertIn(
formatting.Bold('NAME') + '\n ClassWithDocstring', help_screen)
self.assertIn(formatting.Bold('COMMANDS') + '\n', help_screen)
self.assertIn(
formatting.BoldUnderline('COMMAND') + ' is one of the following:\n',
help_screen)
self.assertIn(formatting.Bold('print_msg') + '\n', help_screen)
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)
def testHelpTextNameSectionCommandWithSeparator(self):
component = 9
t = trace.FireTrace(component, name='int', separator='-')
t.AddSeparator()
help_screen = helptext.HelpText(component=component, trace=t, verbose=False)
self.assertIn('int -', help_screen)
self.assertNotIn('int - -', help_screen)
def testHelpTextNameSectionCommandWithSeparatorVerbose(self):
component = tc.WithDefaults().double
t = trace.FireTrace(component, name='double', separator='-')
t.AddSeparator()
help_screen = helptext.HelpText(component=component, trace=t, verbose=True)
self.assertIn('double -', help_screen)
self.assertIn('double - -', help_screen)
def testHelpTextMultipleKeywoardArgumentsWithShortArgs(self):
component = tc.fn_with_multiple_defaults
t = trace.FireTrace(component, name='shortargs')
help_screen = helptext.HelpText(component, t)
self.assertIn(formatting.Bold('NAME') + '\n shortargs', help_screen)
self.assertIn(
formatting.Bold('SYNOPSIS') + '\n shortargs <flags>',
help_screen)
self.assertIn(
formatting.Bold('FLAGS') + '\n -f, --first',
help_screen)
self.assertIn('\n --last', help_screen)
self.assertIn('\n --late', help_screen)
class UsageTest(testutils.BaseTestCase):
def testUsageOutput(self):
component = tc.NoDefaults()
t = trace.FireTrace(component, name='NoDefaults')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: NoDefaults <command>
available commands: double | triple
For detailed information on this command, run:
NoDefaults --help"""
self.assertEqual(
usage_output,
textwrap.dedent(expected_output).lstrip('\n'))
def testUsageOutputVerbose(self):
component = tc.NoDefaults()
t = trace.FireTrace(component, name='NoDefaults')
usage_output = helptext.UsageText(component, trace=t, verbose=True)
expected_output = """
Usage: NoDefaults <command>
available commands: double | triple
For detailed information on this command, run:
NoDefaults --help"""
self.assertEqual(
usage_output,
textwrap.dedent(expected_output).lstrip('\n'))
def testUsageOutputMethod(self):
component = tc.NoDefaults().double
t = trace.FireTrace(component, name='NoDefaults')
t.AddAccessedProperty(component, 'double', ['double'], None, None)
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: NoDefaults double COUNT
For detailed information on this command, run:
NoDefaults double --help"""
self.assertEqual(
usage_output,
textwrap.dedent(expected_output).lstrip('\n'))
def testUsageOutputFunctionWithHelp(self):
component = tc.function_with_help
t = trace.FireTrace(component, name='function_with_help')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: function_with_help <flags>
optional flags: --help
For detailed information on this command, run:
function_with_help -- --help"""
self.assertEqual(
usage_output,
textwrap.dedent(expected_output).lstrip('\n'))
def testUsageOutputFunctionWithDocstring(self):
component = tc.multiplier_with_docstring
t = trace.FireTrace(component, name='multiplier_with_docstring')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: multiplier_with_docstring NUM <flags>
optional flags: --rate
For detailed information on this command, run:
multiplier_with_docstring --help"""
self.assertEqual(
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)
@testutils.skipIf(
six.PY2,
'Python 2 does not support required name-only arguments.')
def testUsageOutputFunctionMixedDefaults(self):
component = tc.py3.HelpTextComponent().identity
t = trace.FireTrace(component, name='FunctionMixedDefaults')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: FunctionMixedDefaults <flags>
optional flags: --beta
required flags: --alpha
For detailed information on this command, run:
FunctionMixedDefaults --help"""
expected_output = textwrap.dedent(expected_output).lstrip('\n')
self.assertEqual(expected_output, usage_output)
def testUsageOutputCallable(self):
# This is both a group and a command.
component = tc.CallableWithKeywordArgument()
t = trace.FireTrace(component, name='CallableWithKeywordArgument',
separator='@')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: CallableWithKeywordArgument <command> | <flags>
available commands: print_msg
flags are accepted
For detailed information on this command, run:
CallableWithKeywordArgument -- --help"""
self.assertEqual(
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)
def testUsageOutputConstructorWithParameter(self):
component = tc.InstanceVars
t = trace.FireTrace(component, name='InstanceVars')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = """
Usage: InstanceVars --arg1=ARG1 --arg2=ARG2
For detailed information on this command, run:
InstanceVars --help"""
self.assertEqual(
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)
def testUsageOutputConstructorWithParameterVerbose(self):
component = tc.InstanceVars
t = trace.FireTrace(component, name='InstanceVars')
usage_output = helptext.UsageText(component, trace=t, verbose=True)
expected_output = """
Usage: InstanceVars <command> | --arg1=ARG1 --arg2=ARG2
available commands: run
For detailed information on this command, run:
InstanceVars --help"""
self.assertEqual(
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)
def testUsageOutputEmptyDict(self):
component = {}
t = trace.FireTrace(component, name='EmptyDict')
usage_output = helptext.UsageText(component, trace=t, verbose=True)
expected_output = """
Usage: EmptyDict
For detailed information on this command, run:
EmptyDict --help"""
self.assertEqual(
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)
def testUsageOutputNone(self):
component = None
t = trace.FireTrace(component, name='None')
usage_output = helptext.UsageText(component, trace=t, verbose=True)
expected_output = """
Usage: None
For detailed information on this command, run:
None --help"""
self.assertEqual(
textwrap.dedent(expected_output).lstrip('\n'),
usage_output)
def testInitRequiresFlagSyntaxSubclassNamedTuple(self):
component = tc.SubPoint
t = trace.FireTrace(component, name='SubPoint')
usage_output = helptext.UsageText(component, trace=t, verbose=False)
expected_output = 'Usage: SubPoint --x=X --y=Y'
self.assertIn(expected_output, usage_output)
if __name__ == '__main__':
testutils.main()