From ed44d8b801fc24e40729abef11b2dcbf6588d361 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 17 Jun 2021 11:02:53 -0700 Subject: [PATCH 01/86] Fix typos in test component docstrings. PiperOrigin-RevId: 379999792 Change-Id: I2594db4540cfe20820951bae479d16c167ba391a --- fire/test_components.py | 2 +- fire/test_components_py3.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fire/test_components.py b/fire/test_components.py index eee9a07c..027a6b19 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -98,7 +98,7 @@ def double(self, count=0): count: Input number that you want to double. Returns: - A number that is the double of count.s + A number that is the double of count. """ return 2 * count diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index 3c21f4ba..b6c78c84 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -67,7 +67,7 @@ def double(self, count: float) -> float: count: Input number that you want to double. Returns: - A number that is the double of count.s + A number that is the double of count. """ return 2 * count @@ -89,7 +89,7 @@ def double(self, count: float = 0) -> float: count: Input number that you want to double. Returns: - A number that is the double of count.s + A number that is the double of count. """ return 2 * count From 703f8a2d59cfea11c5f816b785ae7b2ced31876c Mon Sep 17 00:00:00 2001 From: Yilei Yang Date: Thu, 14 Apr 2022 07:52:52 -0700 Subject: [PATCH 02/86] Remove unused comments related to Python 2 compatibility. PiperOrigin-RevId: 441760209 Change-Id: I32e87cdbd00d99ba2eb015c5709c2acceb38e53d --- fire/__main__.py | 1 - fire/test_components_py3.py | 1 - fire/testutils.py | 1 - 3 files changed, 3 deletions(-) diff --git a/fire/__main__.py b/fire/__main__.py index 30d556e4..c7248e29 100644 --- a/fire/__main__.py +++ b/fire/__main__.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Lint as: python2, python3 # pylint: disable=invalid-name """Enables use of Python Fire as a "main" function (i.e. "python -m fire"). diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index b6c78c84..9f7590a0 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Lint as: python3 """This module has components that use Python 3 specific syntax.""" import asyncio diff --git a/fire/testutils.py b/fire/testutils.py index 31a2badb..ea410e82 100644 --- a/fire/testutils.py +++ b/fire/testutils.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Lint as: python2, python3 """Utilities for Python Fire's tests.""" from __future__ import absolute_import From 21ae57c38d00d8ba3594b94944bcd955977939df Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 16 Apr 2022 15:58:07 -0400 Subject: [PATCH 03/86] Remove testing for Python 3.4 (#388) * Removes testing from CI for Python 3.4 * Adds lint disabling for new linter checks that have been added. --- .github/scripts/build.sh | 2 +- .github/workflows/build.yml | 2 +- fire/__main__.py | 2 +- fire/custom_descriptions.py | 4 ++-- fire/main_test.py | 4 ++-- pylintrc | 2 +- setup.py | 1 - 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index 2d5fcd10..ed75b37b 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -39,6 +39,6 @@ if [[ ${PYTHON_VERSION} == 2.7 ]]; then fire/inspectutils_test.py \ fire/test_components_py3.py; elif [[ ${PYTHON_VERSION} == 3.7 ]]; then - pytype; + pytype -x fire/test_components_py3.py; fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b87d1f8a..b934b759 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [2.7, 3.4, 3.5, 3.7, 3.8, 3.9] + python-version: [2.7, 3.5, 3.7, 3.8, 3.9] steps: # Checkout the repo. diff --git a/fire/__main__.py b/fire/__main__.py index c7248e29..2ad217d6 100644 --- a/fire/__main__.py +++ b/fire/__main__.py @@ -80,7 +80,7 @@ def import_from_file_path(path): spec.loader.exec_module(module) # pytype: disable=attribute-error else: - import imp # pylint: disable=g-import-not-at-top,import-outside-toplevel + import imp # pylint: disable=g-import-not-at-top,import-outside-toplevel,deprecated-module module = imp.load_source(module_name, path) return module, module_name diff --git a/fire/custom_descriptions.py b/fire/custom_descriptions.py index 191e8b29..865a528e 100644 --- a/fire/custom_descriptions.py +++ b/fire/custom_descriptions.py @@ -137,7 +137,7 @@ def GetStringTypeDescription(obj, available_space, line_length): def GetSummary(obj, available_space, line_length): obj_type_name = type(obj).__name__ - if obj_type_name in CUSTOM_DESC_SUM_FN_DICT.keys(): + if obj_type_name in CUSTOM_DESC_SUM_FN_DICT: return CUSTOM_DESC_SUM_FN_DICT.get(obj_type_name)[0](obj, available_space, line_length) return None @@ -145,7 +145,7 @@ def GetSummary(obj, available_space, line_length): def GetDescription(obj, available_space, line_length): obj_type_name = type(obj).__name__ - if obj_type_name in CUSTOM_DESC_SUM_FN_DICT.keys(): + if obj_type_name in CUSTOM_DESC_SUM_FN_DICT: return CUSTOM_DESC_SUM_FN_DICT.get(obj_type_name)[1](obj, available_space, line_length) return None diff --git a/fire/main_test.py b/fire/main_test.py index 41699ac6..a0184620 100644 --- a/fire/main_test.py +++ b/fire/main_test.py @@ -44,11 +44,11 @@ class MainModuleFileTest(testutils.BaseTestCase): def setUp(self): super(MainModuleFileTest, self).setUp() - self.file = tempfile.NamedTemporaryFile(suffix='.py') + self.file = tempfile.NamedTemporaryFile(suffix='.py') # pylint: disable=consider-using-with self.file.write(b'class Foo:\n def double(self, n):\n return 2 * n\n') self.file.flush() - self.file2 = tempfile.NamedTemporaryFile() + self.file2 = tempfile.NamedTemporaryFile() # pylint: disable=consider-using-with def testFileNameFire(self): # Confirm that the file is correctly imported and doubles the number. diff --git a/pylintrc b/pylintrc index 1b1c5cc2..fa054fb5 100644 --- a/pylintrc +++ b/pylintrc @@ -32,7 +32,7 @@ enable=indexing-exception,old-raise-syntax # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time. -disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return,super-with-arguments,raise-missing-from +disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return,super-with-arguments,raise-missing-from,consider-using-f-string,unspecified-encoding [REPORTS] diff --git a/setup.py b/setup.py index 1cc64a07..e1efe1ab 100644 --- a/setup.py +++ b/setup.py @@ -66,7 +66,6 @@ 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', From 09f836e8db7147472192b6c5468f0b7bc997cfad Mon Sep 17 00:00:00 2001 From: Xavier Figueroa Date: Sat, 16 Apr 2022 15:20:32 -0500 Subject: [PATCH 04/86] Fix #315 Change the _KeywordOnlyArguments filtering condition (#316) * Change the _KeywordOnlyArguments filtering condition * Add test case for usage output of function with mixed defaults Signed-off-by: Xavier Figueroa --- fire/helptext.py | 2 +- fire/helptext_test.py | 14 ++++++++++++++ fire/test_components.py | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/fire/helptext.py b/fire/helptext.py index b1d10b44..5098b26b 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -700,7 +700,7 @@ def _GetCallableUsageItems(spec, metadata): def _KeywordOnlyArguments(spec, required=True): return (flag for flag in spec.kwonlyargs - if required == (flag in spec.kwonlydefaults)) + if required != (flag in spec.kwonlydefaults)) def _GetCallableAvailabilityLines(spec): diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 29250cec..81600965 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -497,6 +497,20 @@ def testUsageOutputFunctionWithDocstring(self): textwrap.dedent(expected_output).lstrip('\n'), usage_output) + def testUsageOutputFunctionMixedDefaults(self): + component = tc.MixedDefaults().identity2 + t = trace.FireTrace(component, name='FunctionMixedDefaults') + usage_output = helptext.UsageText(component, trace=t, verbose=False) + expected_output = """ + Usage: FunctionMixedDefaults + 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() diff --git a/fire/test_components.py b/fire/test_components.py index 027a6b19..f29021a9 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -133,6 +133,9 @@ def sum(self, alpha=0, beta=0): def identity(self, alpha, beta='0'): return alpha, beta + def identity2(self, *, alpha, beta='0'): + return alpha, beta + class SimilarArgNames(object): From 8469e487dcb9392856a513f6f861eaf86da80595 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 16 Apr 2022 16:42:02 -0400 Subject: [PATCH 05/86] Move python 3 only component to test_components_py3.py (#389) * #316 adds a test using Python 3 only features; this CL makes that test only run for Python 3 versions. --- .github/scripts/build.sh | 12 +++--------- fire/helptext_test.py | 5 ++++- fire/test_components.py | 3 --- fire/test_components_py3.py | 6 ++++++ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index ed75b37b..c05ea1c3 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -29,16 +29,10 @@ python -m pytest # Run the tests without IPython. pip install ipython python -m pytest # Now run the tests with IPython. pylint fire --ignore=test_components_py3.py,parser_fuzz_test.py,console -if [[ ${PYTHON_VERSION} == 2.7 || ${PYTHON_VERSION} == 3.7 ]]; then +if [[ ${PYTHON_VERSION} == 3.7 ]]; then pip install pytype; fi -# Run type-checking, excluding files that define or use py3 features in py2. -if [[ ${PYTHON_VERSION} == 2.7 ]]; then - pytype -x \ - fire/fire_test.py \ - fire/inspectutils_test.py \ - fire/test_components_py3.py; -elif [[ ${PYTHON_VERSION} == 3.7 ]]; then +# Run type-checking. +if [[ ${PYTHON_VERSION} == 3.7 ]]; then pytype -x fire/test_components_py3.py; fi - diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 81600965..03ade4a5 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -497,8 +497,11 @@ def testUsageOutputFunctionWithDocstring(self): 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.MixedDefaults().identity2 + component = tc.py3.HelpTextComponent().identity t = trace.FireTrace(component, name='FunctionMixedDefaults') usage_output = helptext.UsageText(component, trace=t, verbose=False) expected_output = """ diff --git a/fire/test_components.py b/fire/test_components.py index f29021a9..027a6b19 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -133,9 +133,6 @@ def sum(self, alpha=0, beta=0): def identity(self, alpha, beta='0'): return alpha, beta - def identity2(self, *, alpha, beta='0'): - return alpha, beta - class SimilarArgNames(object): diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index 9f7590a0..5140921d 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -25,6 +25,12 @@ def identity(arg1, arg2: int, arg3=10, arg4: int = 20, *arg5, return arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +class HelpTextComponent: + + def identity(self, *, alpha, beta='0'): + return alpha, beta + + class KeywordOnly(object): def double(self, *, count): From 8bddeec6bd9c78b9b5ad20e9a58625cbd3096fe9 Mon Sep 17 00:00:00 2001 From: Bea Steers Date: Sat, 16 Apr 2022 17:21:05 -0400 Subject: [PATCH 06/86] Add custom formatter for Fire result (#345) Fixes #344 (see issue for more details) This lets you define a function that will take the result from the Fire component and allows the user to alter it before fire looks at it to render it. --- fire/core.py | 13 ++++++++++--- fire/core_test.py | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/fire/core.py b/fire/core.py index 8ca142c7..6fd1bf7a 100644 --- a/fire/core.py +++ b/fire/core.py @@ -78,7 +78,7 @@ def main(argv): import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error -def Fire(component=None, command=None, name=None): +def Fire(component=None, command=None, name=None, serialize=None): """This function, Fire, is the main entrypoint for Python Fire. Executes a command either from the `command` argument or from sys.argv by @@ -164,7 +164,7 @@ def Fire(component=None, command=None, name=None): raise FireExit(0, component_trace) # The command succeeded normally; print the result. - _PrintResult(component_trace, verbose=component_trace.verbose) + _PrintResult(component_trace, verbose=component_trace.verbose, serialize=serialize) result = component_trace.GetResult() return result @@ -241,12 +241,19 @@ def _IsHelpShortcut(component_trace, remaining_args): return show_help -def _PrintResult(component_trace, verbose=False): +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("serialize argument {} must be empty or callable.".format(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. diff --git a/fire/core_test.py b/fire/core_test.py index 27c9f418..a0576ee9 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -194,6 +194,30 @@ def testClassMethod(self): 7, ) + def testCustomSerialize(self): + def serialize(x): + if isinstance(x, list): + return ', '.join(str(xi) for xi in x) + if isinstance(x, dict): + return ', '.join('{}={!r}'.format(k, v) for k, v in x.items()) + if x == 'special': + return ['SURPRISE!!', "I'm a list!"] + return x + + ident = lambda x: x + + with self.assertOutputMatches(stdout='a, b', stderr=None): + result = core.Fire(ident, command=['[a,b]'], serialize=serialize) + with self.assertOutputMatches(stdout='a=5, b=6', stderr=None): + result = core.Fire(ident, command=['{a:5,b:6}'], serialize=serialize) + with self.assertOutputMatches(stdout='asdf', stderr=None): + result = core.Fire(ident, command=['asdf'], serialize=serialize) + with self.assertOutputMatches(stdout="SURPRISE!!\nI'm a list!\n", stderr=None): + result = core.Fire(ident, command=['special'], serialize=serialize) + with self.assertRaises(core.FireError): + core.Fire(ident, command=['asdf'], serialize=55) + + @testutils.skipIf(six.PY2, 'lru_cache is Python 3 only.') def testLruCacheDecoratorBoundArg(self): self.assertEqual( From 37c4305194ff3d0a63f435f08a40e14b1978bd4e Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 16 Apr 2022 18:20:08 -0400 Subject: [PATCH 07/86] Lint error cleanup following #345 (#390) * Lint error cleanup following #345 * Makes new serialize= test deterministic --- fire/core.py | 8 +++++--- fire/core_test.py | 15 ++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fire/core.py b/fire/core.py index 6fd1bf7a..4546b273 100644 --- a/fire/core.py +++ b/fire/core.py @@ -164,7 +164,8 @@ def Fire(component=None, command=None, name=None, serialize=None): raise FireExit(0, component_trace) # The command succeeded normally; print the result. - _PrintResult(component_trace, verbose=component_trace.verbose, serialize=serialize) + _PrintResult( + component_trace, verbose=component_trace.verbose, serialize=serialize) result = component_trace.GetResult() return result @@ -247,11 +248,12 @@ def _PrintResult(component_trace, verbose=False, serialize=None): # and move serialization to its own module. result = component_trace.GetResult() - # Allow users to modify the return value of the component and provide + # Allow users to modify the return value of the component and provide # custom formatting. if serialize: if not callable(serialize): - raise FireError("serialize argument {} must be empty or callable.".format(serialize)) + raise FireError( + 'The argument `serialize` must be empty or callable:', serialize) result = serialize(result) if value_types.HasCustomStr(result): diff --git a/fire/core_test.py b/fire/core_test.py index a0576ee9..0d11467e 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -199,21 +199,22 @@ def serialize(x): if isinstance(x, list): return ', '.join(str(xi) for xi in x) if isinstance(x, dict): - return ', '.join('{}={!r}'.format(k, v) for k, v in x.items()) + return ', '.join('{}={!r}'.format(k, v) for k, v in sorted(x.items())) if x == 'special': return ['SURPRISE!!', "I'm a list!"] return x ident = lambda x: x - + with self.assertOutputMatches(stdout='a, b', stderr=None): - result = core.Fire(ident, command=['[a,b]'], serialize=serialize) + _ = core.Fire(ident, command=['[a,b]'], serialize=serialize) with self.assertOutputMatches(stdout='a=5, b=6', stderr=None): - result = core.Fire(ident, command=['{a:5,b:6}'], serialize=serialize) + _ = core.Fire(ident, command=['{a:5,b:6}'], serialize=serialize) with self.assertOutputMatches(stdout='asdf', stderr=None): - result = core.Fire(ident, command=['asdf'], serialize=serialize) - with self.assertOutputMatches(stdout="SURPRISE!!\nI'm a list!\n", stderr=None): - result = core.Fire(ident, command=['special'], serialize=serialize) + _ = core.Fire(ident, command=['asdf'], serialize=serialize) + with self.assertOutputMatches( + stdout="SURPRISE!!\nI'm a list!\n", stderr=None): + _ = core.Fire(ident, command=['special'], serialize=serialize) with self.assertRaises(core.FireError): core.Fire(ident, command=['asdf'], serialize=55) From c367ce99aa9b8e69abb48d3296cac45b33638bb8 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 28 Nov 2022 16:09:56 -0500 Subject: [PATCH 08/86] Bring continuous integration to working state (#415) Contained in this PR: * Use latest versions of checkout and python setup GitHub actions * Fix Ubuntu version since not all Python versions are available on ubuntu-latest * Lint fixes: use setattr directly instead of via dunder-method, and ignore unnecessary lambda lint warnings. * Loosen formatting tests --- .github/workflows/build.yml | 6 +++--- fire/core.py | 3 ++- fire/formatting_test.py | 4 ++-- fire/parser.py | 2 +- pylintrc | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b934b759..bc5e0405 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: [push] jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: python-version: [2.7, 3.5, 3.7, 3.8, 3.9] @@ -12,11 +12,11 @@ jobs: steps: # Checkout the repo. - name: Checkout Python Fire repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Set up Python environment. - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/fire/core.py b/fire/core.py index 4546b273..c1e97367 100644 --- a/fire/core.py +++ b/fire/core.py @@ -525,7 +525,8 @@ def _Fire(component, args, parsed_flag_args, context, name=None): # The target isn't present in the dict as a string key, but maybe it is # a key as another type. # TODO(dbieber): Consider alternatives for accessing non-string keys. - for key, value in component_dict.items(): + for key, value in ( + component_dict.items()): # pytype: disable=attribute-error if target == str(key): component = value handled = True diff --git a/fire/formatting_test.py b/fire/formatting_test.py index 61cce0e8..05a88c49 100644 --- a/fire/formatting_test.py +++ b/fire/formatting_test.py @@ -28,11 +28,11 @@ class FormattingTest(testutils.BaseTestCase): def test_bold(self): text = formatting.Bold('hello') - self.assertEqual('\x1b[1mhello\x1b[0m', text) + self.assertIn(text, ['hello', '\x1b[1mhello\x1b[0m']) def test_underline(self): text = formatting.Underline('hello') - self.assertEqual('\x1b[4mhello\x1b[0m', text) + self.assertIn(text, ['hello', '\x1b[4mhello\x1b[0m']) def test_indent(self): text = formatting.Indent('hello', spaces=2) diff --git a/fire/parser.py b/fire/parser.py index 404e18e7..2aff8bd7 100644 --- a/fire/parser.py +++ b/fire/parser.py @@ -106,7 +106,7 @@ def _LiteralEval(value): elif isinstance(child, ast.Name): replacement = _Replacement(child) - node.__setattr__(field, replacement) + setattr(node, field, replacement) # ast.literal_eval supports the following types: # strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None diff --git a/pylintrc b/pylintrc index fa054fb5..b89b16d1 100644 --- a/pylintrc +++ b/pylintrc @@ -32,7 +32,7 @@ enable=indexing-exception,old-raise-syntax # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time. -disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return,super-with-arguments,raise-missing-from,consider-using-f-string,unspecified-encoding +disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return,super-with-arguments,raise-missing-from,consider-using-f-string,unspecified-encoding,unnecessary-lambda-assignment [REPORTS] From c4bd14b45a3a68574cd30ce6699312ebf66ae0b3 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 28 Nov 2022 16:13:34 -0500 Subject: [PATCH 09/86] Python Fire Version Bump (#416) Bumps version to 0.5.0 in preparation for next release --- .github/scripts/build.sh | 4 +--- fire/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index c05ea1c3..6fd8f73b 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -30,9 +30,7 @@ pip install ipython python -m pytest # Now run the tests with IPython. pylint fire --ignore=test_components_py3.py,parser_fuzz_test.py,console if [[ ${PYTHON_VERSION} == 3.7 ]]; then + # Run type-checking. pip install pytype; -fi -# Run type-checking. -if [[ ${PYTHON_VERSION} == 3.7 ]]; then pytype -x fire/test_components_py3.py; fi diff --git a/fire/__init__.py b/fire/__init__.py index 9c34a5af..4cc76210 100644 --- a/fire/__init__.py +++ b/fire/__init__.py @@ -21,4 +21,4 @@ from fire.core import Fire __all__ = ['Fire'] -__version__ = '0.4.0' +__version__ = '0.5.0' diff --git a/setup.py b/setup.py index e1efe1ab..f1f91103 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ 'python-Levenshtein', ] -VERSION = '0.4.0' +VERSION = '0.5.0' URL = 'https://github.com/google/python-fire' setup( From a49184782c37746278e42e8a175dfab4fe89db8a Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 28 Nov 2022 16:46:26 -0500 Subject: [PATCH 10/86] Show default values for kwonly arguments in help text (#414) Fixes #410 * Shows default values for kwonly arguments in help text * Adds test verifying that default values are shown for kwonly args --- fire/helptext.py | 2 ++ fire/helptext_test.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/fire/helptext.py b/fire/helptext.py index 5098b26b..331b6649 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -524,6 +524,8 @@ def _GetArgDefault(flag, spec): for arg, default in zip(args_with_defaults, spec.defaults): if arg == flag: return repr(default) + if flag in spec.kwonlydefaults: + return repr(spec.kwonlydefaults[flag]) return '' diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 03ade4a5..14e0874a 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -296,6 +296,18 @@ def testHelpTextKeywordOnlyArgumentsWithoutDefault(self): self.assertIn('NAME\n double', output) self.assertIn('FLAGS\n --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 ', 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') From 82e2d87f0e2a01e9c01e958dd2d2ec510a77fc6d Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 28 Nov 2022 16:49:17 -0500 Subject: [PATCH 11/86] Remove extra newline (#417) Remove extra newline in core_test.py #417 --- fire/core_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fire/core_test.py b/fire/core_test.py index 0d11467e..75b76998 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -218,7 +218,6 @@ def serialize(x): with self.assertRaises(core.FireError): core.Fire(ident, command=['asdf'], serialize=55) - @testutils.skipIf(six.PY2, 'lru_cache is Python 3 only.') def testLruCacheDecoratorBoundArg(self): self.assertEqual( From e5b33f6a15b3a2ded83f924079b9c2645983bd05 Mon Sep 17 00:00:00 2001 From: kpakda <5531544+khodadadp@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:16:49 -0500 Subject: [PATCH 12/86] Update guide.md (#387) Should either print the returned value or join and return. Otherwise, the output in the example won't get generated. --- docs/guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index d5da3212..8e3f03c9 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -318,8 +318,8 @@ class Pipeline(object): self.digestion = DigestionStage() def run(self): - self.ingestion.run() - self.digestion.run() + print(self.ingestion.run()) + print(self.digestion.run()) return 'Pipeline complete' if __name__ == '__main__': From 1eec95480568e4f67a0ce287b10c977d269a5c49 Mon Sep 17 00:00:00 2001 From: Martin Gruber Date: Fri, 9 Dec 2022 21:18:54 +0100 Subject: [PATCH 13/86] Interactive mode: Mention IPython REPL requirement (#383) Mention that the ipython package is an optional requirement for using the IPython REPL, as described in the [source file](https://github.com/google/python-fire/blob/master/fire/interact.py#L17). --- docs/using-cli.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/using-cli.md b/docs/using-cli.md index 0f369a9a..ba1c35dc 100644 --- a/docs/using-cli.md +++ b/docs/using-cli.md @@ -137,6 +137,9 @@ will put you in an IPython REPL, with the variable `widget` already defined. You can then explore the Python object that `widget` corresponds to interactively using Python. +Note: if you want fire to start the IPython REPL instead of the regular Python one, +the `ipython` package needs to be installed in your environment. + ### `--completion`: Generating a completion script From c3703f443c7ae5603538eb4fa4354787b9fb7c88 Mon Sep 17 00:00:00 2001 From: Martin Gruber Date: Fri, 9 Dec 2022 21:19:49 +0100 Subject: [PATCH 14/86] Interactive mode: Mention IPython REPL requirement (#383) Mention that the ipython package is an optional requirement for using the IPython REPL, as described in the [source file](https://github.com/google/python-fire/blob/master/fire/interact.py#L17). From 0ad057143b326f78398fbc9a3840d9d6b378e0be Mon Sep 17 00:00:00 2001 From: Conor Sheehan Date: Fri, 9 Dec 2022 20:31:12 +0000 Subject: [PATCH 15/86] Fix #317 Help text short args (#318) * Add short args to help text for all types of kwargs. * Updates tests to reflect new help text. --- fire/helptext.py | 58 +++++++++++++++++++++++++++++++++++------ fire/helptext_test.py | 36 ++++++++++++++++++------- fire/test_components.py | 10 +++++++ 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/fire/helptext.py b/fire/helptext.py index 331b6649..6e7fbb07 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -33,6 +33,7 @@ from __future__ import division from __future__ import print_function +import collections import itertools import sys @@ -172,9 +173,25 @@ def _DescriptionSection(component, info): return None -def _CreateKeywordOnlyFlagItem(flag, docstring_info, spec): +def _CreateKeywordOnlyFlagItem(flag, docstring_info, spec, short_arg): return _CreateFlagItem( - flag, docstring_info, spec, required=flag not in spec.kwonlydefaults) + flag, docstring_info, spec, required=flag not in spec.kwonlydefaults, + short_arg=short_arg) + + +def _GetShortFlags(flags): + """Gets a list of single-character flags that uniquely identify a flag. + + Args: + flags: list of strings representing flags + + Returns: + List of single character short flags, + where the character occurred at the start of a flag once. + """ + short_flags = [f[0] for f in flags] + short_flag_counts = collections.Counter(short_flags) + return [v for v in short_flags if short_flag_counts[v] == 1] def _ArgsAndFlagsSections(info, spec, metadata): @@ -209,25 +226,47 @@ def _ArgsAndFlagsSections(info, spec, metadata): ('NOTES', 'You can also use flags syntax for POSITIONAL ARGUMENTS') ) + unique_short_args = _GetShortFlags(args_with_defaults) positional_flag_items = [ - _CreateFlagItem(flag, docstring_info, spec, required=False) + _CreateFlagItem( + flag, docstring_info, spec, required=False, + short_arg=flag[0] in unique_short_args + ) for flag in args_with_defaults ] + + unique_short_kwonly_flags = _GetShortFlags(spec.kwonlyargs) kwonly_flag_items = [ - _CreateKeywordOnlyFlagItem(flag, docstring_info, spec) + _CreateKeywordOnlyFlagItem( + flag, docstring_info, spec, + short_arg=flag[0] in unique_short_kwonly_flags + ) for flag in spec.kwonlyargs ] flag_items = positional_flag_items + kwonly_flag_items if spec.varkw: # Include kwargs documented via :key param: - flag_string = '--{name}' documented_kwargs = [] - for flag in docstring_info.args or []: + flag_string = '--{name}' + short_flag_string = '-{short_name}, --{name}' + + # add short flags if possible + flags = docstring_info.args or [] + flag_names = [f.name for f in flags] + unique_short_flags = _GetShortFlags(flag_names) + for flag in flags: if isinstance(flag, docstrings.KwargInfo): + if flag.name[0] in unique_short_flags: + flag_string = short_flag_string.format( + name=flag.name, short_name=flag.name[0] + ) + else: + flag_string = flag_string.format(name=flag.name) + flag_item = _CreateFlagItem( flag.name, docstring_info, spec, - flag_string=flag_string.format(name=flag.name)) + flag_string=flag_string) documented_kwargs.append(flag_item) if documented_kwargs: # Separate documented kwargs from other flags using a message @@ -422,7 +461,7 @@ def _CreateArgItem(arg, docstring_info, spec): def _CreateFlagItem(flag, docstring_info, spec, required=False, - flag_string=None): + flag_string=None, short_arg=False): """Returns a string describing a flag using docstring and FullArgSpec info. Args: @@ -434,6 +473,7 @@ def _CreateFlagItem(flag, docstring_info, spec, required=False, required: Whether the flag is required. flag_string: If provided, use this string for the flag, rather than constructing one from the flag name. + short_arg: Whether the flag has a short variation or not. Returns: A string to be used in constructing the help screen for the function. """ @@ -455,6 +495,8 @@ def _CreateFlagItem(flag, docstring_info, spec, required=False, flag_name_upper=formatting.Underline(flag.upper())) if required: flag_string += ' (required)' + if short_arg: + flag_string = '-{short_flag}, '.format(short_flag=flag[0]) + flag_string arg_type = _GetArgType(flag, spec) arg_default = _GetArgDefault(flag, spec) diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 14e0874a..404d9812 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -81,7 +81,9 @@ def testHelpTextFunctionWithDefaults(self): self.assertIn('NAME\n triple', help_screen) self.assertIn('SYNOPSIS\n triple ', help_screen) self.assertNotIn('DESCRIPTION', help_screen) - self.assertIn('FLAGS\n --count=COUNT\n Default: 0', help_screen) + self.assertIn( + 'FLAGS\n -c, --count=COUNT\n Default: 0', + help_screen) self.assertNotIn('NOTES', help_screen) def testHelpTextFunctionWithLongDefaults(self): @@ -93,7 +95,7 @@ def testHelpTextFunctionWithLongDefaults(self): self.assertIn('SYNOPSIS\n text ', help_screen) self.assertNotIn('DESCRIPTION', help_screen) self.assertIn( - 'FLAGS\n --string=STRING\n' + 'FLAGS\n -s, --string=STRING\n' ' Default: \'0001020304050607080910' '1112131415161718192021222324252627282...', help_screen) @@ -121,7 +123,7 @@ def testHelpTextFunctionWithKwargsAndDefaults(self): self.assertIn('SYNOPSIS\n text ARG1 ARG2 ', help_screen) self.assertIn('DESCRIPTION\n Function with kwarg', help_screen) self.assertIn( - 'FLAGS\n --opt=OPT\n Default: True\n' + '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.', @@ -140,7 +142,7 @@ def testHelpTextFunctionWithDefaultsAndTypes(self): self.assertIn('SYNOPSIS\n double ', help_screen) self.assertIn('DESCRIPTION', help_screen) self.assertIn( - 'FLAGS\n --count=COUNT\n Type: float\n Default: 0', + 'FLAGS\n -c, --count=COUNT\n Type: float\n Default: 0', help_screen) self.assertNotIn('NOTES', help_screen) @@ -157,7 +159,7 @@ def testHelpTextFunctionWithTypesAndDefaultNone(self): self.assertIn('SYNOPSIS\n get_int ', help_screen) self.assertNotIn('DESCRIPTION', help_screen) self.assertIn( - 'FLAGS\n --value=VALUE\n' + 'FLAGS\n -v, --value=VALUE\n' ' Type: Optional[int]\n Default: None', help_screen) self.assertNotIn('NOTES', help_screen) @@ -285,7 +287,7 @@ def testHelpTextKeywordOnlyArgumentsWithDefault(self): 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) + self.assertIn('FLAGS\n -x, --x=X', output) @testutils.skipIf( six.PY2, 'Python 2 does not support keyword-only arguments.') @@ -294,7 +296,7 @@ def testHelpTextKeywordOnlyArgumentsWithoutDefault(self): output = helptext.HelpText( component=component, trace=trace.FireTrace(component, 'double')) self.assertIn('NAME\n double', output) - self.assertIn('FLAGS\n --count=COUNT (required)', output) + self.assertIn('FLAGS\n -c, --count=COUNT (required)', output) @testutils.skipIf( six.PY2, @@ -374,7 +376,7 @@ def testHelpScreenForFunctionFunctionWithDefaultArgs(self): Returns the input multiplied by 2. FLAGS - --count=COUNT + -c, --count=COUNT Default: 0 Input number that you want to double.""" self.assertEqual(textwrap.dedent(expected_output).strip(), @@ -389,7 +391,8 @@ def testHelpTextUnderlineFlag(self): formatting.Bold('SYNOPSIS') + '\n triple ', help_screen) self.assertIn( - formatting.Bold('FLAGS') + '\n --' + formatting.Underline('count'), + formatting.Bold('FLAGS') + '\n -c, --' + + formatting.Underline('count'), help_screen) def testHelpTextBoldCommandName(self): @@ -435,6 +438,21 @@ def testHelpTextNameSectionCommandWithSeparatorVerbose(self): 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 ', + 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): diff --git a/fire/test_components.py b/fire/test_components.py index 027a6b19..5fcb056e 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -563,3 +563,13 @@ def fn_with_kwarg_and_defaults(arg1, arg2, opt=True, **kwargs): del arg1, arg2, opt return kwargs.get('arg3') # pylint: enable=g-doc-args,g-doc-return-or-yield + +def fn_with_multiple_defaults(first='first', last='last', late='late'): + """Function with kwarg and defaults. + + :key first: Description of first. + :key last: Description of last. + :key late: Description of late. + """ + del last, late + return first From eda25f878900146d929c32d9ac2a87656c6e974a Mon Sep 17 00:00:00 2001 From: Martial Himanshu <66832784+mhimanshu0101@users.noreply.github.com> Date: Sat, 10 Dec 2022 02:15:14 +0530 Subject: [PATCH 16/86] Small docs improvement for using CLI (#372) * Updated the formatting of the text to improve the documentation. --- docs/using-cli.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/using-cli.md b/docs/using-cli.md index ba1c35dc..bdfcb7db 100644 --- a/docs/using-cli.md +++ b/docs/using-cli.md @@ -57,7 +57,7 @@ If your command corresponds to a list or tuple, you can extend your command by adding the index of an element of the component to your command as an argument. For example, `widget function-that-returns-list 2` will correspond to item 2 of -the result of function_that_returns_list. +the result of `function_that_returns_list`. ### Calling a function @@ -90,7 +90,7 @@ See also the section on [Changing the Separator](#separator-flag). ### Instantiating a class If your command corresponds to a class, you can extend your command by adding -the arguments of the class's \_\_init\_\_ function. Arguments must be specified +the arguments of the class's `__init__` function. Arguments must be specified by name, using the flags syntax. See the section on [calling a function](#calling-a-function) for more details. @@ -105,8 +105,8 @@ after the final standalone `--` argument. (If there is no `--` argument, then no arguments are used for flags.) For example, to set the alsologtostderr flag, you could run the command: -`widget bang --noise=boom -- --alsologtostderr`. The --noise argument is -consumed by Fire, but the --alsologtostderr argument is treated as a normal +`widget bang --noise=boom -- --alsologtostderr`. The `--noise` argument is +consumed by Fire, but the `--alsologtostderr` argument is treated as a normal Flag. All CLIs built with Python Fire share some flags, as described in the next @@ -146,7 +146,7 @@ the `ipython` package needs to be installed in your environment. Call `widget -- --completion` to generate a completion script for the Fire CLI `widget`. To save the completion script to your home directory, you could e.g. run `widget -- --completion > ~/.widget-completion`. You should then source this -file; to get permanent completion, source this file from your .bashrc file. +file; to get permanent completion, source this file from your `.bashrc` file. Call `widget -- --completion fish` to generate a completion script for the Fish shell. Source this file from your fish.config. @@ -177,7 +177,7 @@ corresponds to, as well as usage information for how to extend that command. ### `--trace`: Getting a Fire trace In order to understand what is happening when you call Python Fire, it can be -useful to request a trace. This is done via the --trace flag, e.g. +useful to request a trace. This is done via the `--trace` flag, e.g. `widget whack 5 -- --trace`. A trace provides step by step information about how the Fire command was From 7b5d4f713ba4c252cc34f523811a49a6bb15f681 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Sat, 10 Dec 2022 07:53:52 +1100 Subject: [PATCH 17/86] docs: Fix a few typos (#399) There are small typos in: - fire/console/console_attr.py - fire/custom_descriptions.py Fixes: - Should read `support` rather than `suport`. - Should read `pertinent` rather than `pertinant`. - Should read `environment` rather than `envrionment`. --- fire/console/console_attr.py | 4 ++-- fire/custom_descriptions.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fire/console/console_attr.py b/fire/console/console_attr.py index 35c10fba..f88d5788 100644 --- a/fire/console/console_attr.py +++ b/fire/console/console_attr.py @@ -288,7 +288,7 @@ def __init__(self, encoding=None, suppress_output=False): elif self._encoding == 'cp437' and not is_screen_reader: self._box_line_characters = BoxLineCharactersUnicode() self._bullets = self._BULLETS_WINDOWS - # Windows does not suport the unicode characters used for the spinner. + # Windows does not support the unicode characters used for the spinner. self._progress_tracker_symbols = ProgressTrackerSymbolsAscii() else: self._box_line_characters = BoxLineCharactersAscii() @@ -456,7 +456,7 @@ def GetRawKey(self): return self._get_raw_key[0]() def GetTermIdentifier(self): - """Returns the TERM envrionment variable for the console. + """Returns the TERM environment variable for the console. Returns: str: A str that describes the console's text capabilities diff --git a/fire/custom_descriptions.py b/fire/custom_descriptions.py index 865a528e..266671f1 100644 --- a/fire/custom_descriptions.py +++ b/fire/custom_descriptions.py @@ -28,7 +28,7 @@ dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2) -As you can see, this docstring is more pertinant to the function `dict` and +As you can see, this docstring is more pertinent to the function `dict` and would be suitable as the result of `dict.__doc__`, but is wholely unsuitable as a description for the dict `{'key': 'value'}`. From b2415b9331268050fbfe4da7ea377333aa4cf9cd Mon Sep 17 00:00:00 2001 From: Wei-Chung Liao Date: Fri, 9 Dec 2022 16:16:15 -0500 Subject: [PATCH 18/86] Fix completion for Fire(fn) (#336) --- fire/completion.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fire/completion.py b/fire/completion.py index ed7a1b61..9659ec6a 100644 --- a/fire/completion.py +++ b/fire/completion.py @@ -156,7 +156,11 @@ def _GetOptsAssignmentTemplate(command): return opts_assignment_subcommand_template lines = [] - for command in set(subcommands_map.keys()).union(set(options_map.keys())): + commands_set = set() + commands_set.add(name) + commands_set = commands_set.union(set(subcommands_map.keys())) + commands_set = commands_set.union(set(options_map.keys())) + for command in commands_set: opts_assignment = _GetOptsAssignmentTemplate(command).format( options=' '.join( sorted(options_map[command].union(subcommands_map[command])) From 2cb16f66c52562dd8f4ad7ae8513d78ae6c0a659 Mon Sep 17 00:00:00 2001 From: Wei-Chung Liao Date: Fri, 9 Dec 2022 16:20:13 -0500 Subject: [PATCH 19/86] Modify the grouping example to fit the output (#334) Co-authored-by: David Bieber --- docs/guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index 8e3f03c9..cb2c07db 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -318,9 +318,9 @@ class Pipeline(object): self.digestion = DigestionStage() def run(self): - print(self.ingestion.run()) - print(self.digestion.run()) - return 'Pipeline complete' + ingestion_output = self.ingestion.run() + digestion_output = self.digestion.run() + return [ingestion_output, digestion_output] if __name__ == '__main__': fire.Fire(Pipeline) From 51afa538b9dc3df50cb15970b19aece54480f851 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Fri, 9 Dec 2022 17:11:58 -0500 Subject: [PATCH 20/86] Update documentation to show new serialize kwarg and to clean up misformatted tables (#419) * Shows new serialize kwarg * Cleans up misformatted tables --- docs/api.md | 59 ++++++++++++-------------------------------- docs/guide.md | 13 +++++++++- docs/index.md | 3 ++- docs/installation.md | 4 +-- 4 files changed, 32 insertions(+), 47 deletions(-) diff --git a/docs/api.md b/docs/api.md index 66451071..aae92cd6 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,37 +1,23 @@ ## Python Fire Quick Reference | Setup | Command | Notes -| :------ | :------------------ | :--------- -| install | `pip install fire` | +| ------- | ------------------- | ---------- +| install | `pip install fire` | Installs fire from pypi | Creating a CLI | Command | Notes -| :--------------| :--------------------- | :--------- +| ---------------| ---------------------- | ---------- | import | `import fire` | | Call | `fire.Fire()` | Turns the current module into a Fire CLI. | Call | `fire.Fire(component)` | Turns `component` into a Fire CLI. -| Using a CLI | Command | Notes | -| :----------------------------------------- | :------------- | :------------- | -| [Help](using-cli.md#help-flag) | `command | Show the help | -: : --help` : screen. : -| [REPL](using-cli.md#interactive-flag) | `command -- | Enters | -: : --interactive` : interactive : -: : : mode. : -| [Separator](using-cli.md#separator-flag) | `command -- | This sets the | -: : --separator=X` : separator to : -: : : `X`. The : -: : : default : -: : : separator is : -: : : `-`. : -| [Completion](using-cli.md#completion-flag) | `command -- | Generate a | -: : --completion : completion : -: : [shell]` : script for the : -: : : CLI. : -| [Trace](using-cli.md#trace-flag) | `command -- | Gets a Fire | -: : --trace` : trace for the : -: : : command. : -| [Verbose](using-cli.md#verbose-flag) | `command -- | | -: : --verbose` : : +| Using a CLI | Command | Notes | +| ------------------------------------------ | ----------------- | -------------- | +| [Help](using-cli.md#help-flag) | `command --help` | Show the help screen. | +| [REPL](using-cli.md#interactive-flag) | `command -- --interactive` | Enters interactive mode. | +| [Separator](using-cli.md#separator-flag) | `command -- --separator=X` | This sets the separator to `X`. The default separator is `-`. | +| [Completion](using-cli.md#completion-flag) | `command -- --completion [shell]` | Generate a completion script for the CLI. | +| [Trace](using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command. | +| [Verbose](using-cli.md#verbose-flag) | `command -- --verbose` | | _Note that flags are separated from the Fire command by an isolated `--` arg. Help is an exception; the isolated `--` is optional for getting help._ @@ -39,24 +25,11 @@ Help is an exception; the isolated `--` is optional for getting help._ ## Arguments for Calling fire.Fire() | Argument | Usage | Notes | -| :-------- | :------------------------ | :----------------------------------- | -| component | `fire.Fire(component)` | If omitted, defaults to a dict of | -: : : all locals and globals. : -| command | `fire.Fire(command='hello | Either a string or a list of | -: : --name=5')` : arguments. If a string is provided, : -: : : it is split to determine the : -: : : arguments. If a list or tuple is : -: : : provided, they are the arguments. If : -: : : `command` is omitted, then : -: : : `sys.argv[1\:]` (the arguments from : -: : : the command line) are used by : -: : : default. : -| name | `fire.Fire(name='tool')` | The name of the CLI, ideally the | -: : : name users will enter to run the : -: : : CLI. This name will be used in the : -: : : CLI's help screens. If the argument : -: : : is omitted, it will be inferred : -: : : automatically. : +| --------- | ------------------------- | ------------------------------------ | +| component | `fire.Fire(component)` | If omitted, defaults to a dict of all locals and globals. | +| command | `fire.Fire(command='hello --name=5')` | Either a string or a list of arguments. If a string is provided, it is split to determine the arguments. If a list or tuple is provided, they are the arguments. If `command` is omitted, then `sys.argv[1:]` (the arguments from the command line) are used by default. | +| name | `fire.Fire(name='tool')` | The name of the CLI, ideally the name users will enter to run the CLI. This name will be used in the CLI's help screens. If the argument is omitted, it will be inferred automatically.| +| serialize | `fire.Fire(serialize=custom_serializer)` | If omitted, simple types are serialized via their builtin str method, and any objects that define a custom `__str__` method are serialized with that. If specified, all objects are serialized to text via the provided method. | ## Using a Fire CLI without modifying any code diff --git a/docs/guide.md b/docs/guide.md index cb2c07db..44d8a46d 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -742,7 +742,18 @@ The complete set of flags available is shown below, in the reference section. | [Trace](using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command. | [Verbose](using-cli.md#verbose-flag) | `command -- --verbose` | Include private members in the output. -_Note that flags are separated from the Fire command by an isolated `--` arg._ +_Note that flags are separated from the Fire command by an isolated `--` arg. +Help is an exception; the isolated `--` is optional for getting help._ + + +##### Arguments for Calling fire.Fire() + +| Argument | Usage | Notes | +| --------- | ------------------------- | ------------------------------------ | +| component | `fire.Fire(component)` | If omitted, defaults to a dict of all locals and globals. | +| command | `fire.Fire(command='hello --name=5')` | Either a string or a list of arguments. If a string is provided, it is split to determine the arguments. If a list or tuple is provided, they are the arguments. If `command` is omitted, then `sys.argv[1:]` (the arguments from the command line) are used by default. | +| name | `fire.Fire(name='tool')` | The name of the CLI, ideally the name users will enter to run the CLI. This name will be used in the CLI's help screens. If the argument is omitted, it will be inferred automatically.| +| serialize | `fire.Fire(serialize=custom_serializer)` | If omitted, simple types are serialized via their builtin str method, and any objects that define a custom `__str__` method are serialized with that. If specified, all objects are serialized to text via the provided method. | ### Disclaimer diff --git a/docs/index.md b/docs/index.md index 4eb114b1..8dcc5db6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -106,7 +106,8 @@ Please see [The Python Fire Guide](guide.md). | [Trace](using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command. | [Verbose](using-cli.md#verbose-flag) | `command -- --verbose` | -_Note that these flags are separated from the Fire command by an isolated `--`._ +_Note that flags are separated from the Fire command by an isolated `--` arg. +Help is an exception; the isolated `--` is optional for getting help._ ## License diff --git a/docs/installation.md b/docs/installation.md index 614243af..7e4cccb8 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -4,5 +4,5 @@ To install Python Fire with pip, run: `pip install fire` To install Python Fire with conda, run: `conda install fire -c conda-forge` -To install Python Fire from source, first clone the repository and then run: -`python setup.py install` +To install Python Fire from source, first clone the repository and then run +`python setup.py install`. To install from source for development, instead run `python setup.py develop`. From e1e95ffe2454f7e9887640883e35c01543f54139 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 12 Dec 2022 15:43:49 -0500 Subject: [PATCH 21/86] Change mkdocs from pages to nav (#421) "pages" has been deprecated in favor of "nav" --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index bb815e37..bbe1e848 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ site_name: Python Fire theme: readthedocs markdown_extensions: [fenced_code] -pages: +nav: - Overview: index.md - Installation: installation.md - Benefits: benefits.md From 2d2fa6196e5a8ce4ddcbabc565bacad163323b0f Mon Sep 17 00:00:00 2001 From: David Bieber Date: Wed, 1 Feb 2023 10:53:09 -0800 Subject: [PATCH 22/86] Use literal dict (#430) Use literal dict to satisfy linter --- fire/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/decorators.py b/fire/decorators.py index 9e56d6df..b2e9b322 100644 --- a/fire/decorators.py +++ b/fire/decorators.py @@ -111,5 +111,5 @@ def GetMetadata(fn): def GetParseFns(fn): # type: (...) -> dict metadata = GetMetadata(fn) - default = dict(default=None, positional=[], named={}) + default = {"default": None, "positional": [], "named": {}} return metadata.get(FIRE_PARSE_FNS, default) From 396ef1c4efa1d977217e52267855b8acdc8d5a62 Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Thu, 2 Feb 2023 04:47:53 +0900 Subject: [PATCH 23/86] freeze CI requirements (#431) * freeze CI requirements, including pylint --- .github/scripts/build.sh | 6 +----- .github/scripts/requirements.txt | 10 ++++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 .github/scripts/requirements.txt diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index 6fd8f73b..958bc677 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -19,11 +19,7 @@ set -e PYTHON_VERSION=${PYTHON_VERSION:-2.7} -pip install --upgrade setuptools pip -pip install --upgrade pylint pytest pytest-pylint pytest-runner -pip install termcolor -pip install hypothesis python-Levenshtein -pip install mock +pip install -U -r requirements.txt python setup.py develop python -m pytest # Run the tests without IPython. pip install ipython diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 00000000..9e48e20d --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1,10 @@ +setuptools <65.7.0 +pip <23.0 +pylint <2.15.10 +pytest <=7.2.1 +pytest-pylint <=1.1.2 +pytest-runner <6.0.0 +termcolor <2.2.0 +hypothesis <6.62.0 +python-Levenshtein <0.20.9 +mock <5.0.0 \ No newline at end of file From 910b1f8a9448d305f3a4107a294c1963de18bddf Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 1 Feb 2023 22:34:49 +0200 Subject: [PATCH 24/86] Fix path to requirements.txt (#433) --- .github/scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index 958bc677..1f9ed766 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -19,7 +19,7 @@ set -e PYTHON_VERSION=${PYTHON_VERSION:-2.7} -pip install -U -r requirements.txt +pip install -U -r .github/scripts/requirements.txt python setup.py develop python -m pytest # Run the tests without IPython. pip install ipython From 0438367c157c3ff9b46c68fad0b7d66903e7b3a1 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 1 Feb 2023 22:36:20 +0200 Subject: [PATCH 25/86] Fix deprecation warning: LICENSE is autodetected (#434) --- setup.cfg | 3 --- 1 file changed, 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 7a980136..977056b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,3 @@ -[metadata] -license-file = LICENSE - [wheel] universal = 1 From c29b923133668a86b802d7451e83aa92ed648de1 Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Tue, 7 Feb 2023 00:41:38 +0900 Subject: [PATCH 26/86] adding python 3.10 [tag & CI] (#428) * adding python 3.10 --- .github/workflows/build.yml | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc5e0405..9bf78e8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: [2.7, 3.5, 3.7, 3.8, 3.9] + python-version: ["2.7", "3.5", "3.7", "3.8", "3.9", "3.10"] steps: # Checkout the repo. diff --git a/setup.py b/setup.py index f1f91103..8e95f414 100644 --- a/setup.py +++ b/setup.py @@ -71,6 +71,7 @@ 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Operating System :: OS Independent', 'Operating System :: POSIX', From 71743b6fbaa2c1ca35a229ad3cc3e4638606bb35 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Tue, 7 Feb 2023 01:43:43 +1000 Subject: [PATCH 27/86] docs: fix brand name `Github` -> `GitHub` (#425) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3c758e1..baae1a6e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,7 @@ Python versions < 3.5. ## Testing -Python Fire uses [Github Actions](https://github.com/google/python-fire/actions) to run tests on each pull request. You can run +Python Fire uses [GitHub Actions](https://github.com/google/python-fire/actions) to run tests on each pull request. You can run these tests yourself as well. To do this, first install the test dependencies listed in setup.py (e.g. pytest, mock, termcolor, and hypothesis). Then run the tests by running `pytest` in the root directory of the repository. From 527e3d056ecc134531f1ef3ed45d46581b5844b9 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Mon, 13 Feb 2023 14:20:46 -0500 Subject: [PATCH 28/86] Fix typos in console and tests (#436) --- fire/console/console_attr.py | 6 +++--- fire/console/console_attr_os.py | 2 +- fire/console/console_pager.py | 2 +- fire/docstrings_test.py | 12 ++++++------ fire/parser_test.py | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fire/console/console_attr.py b/fire/console/console_attr.py index f88d5788..815e16b8 100644 --- a/fire/console/console_attr.py +++ b/fire/console/console_attr.py @@ -268,7 +268,7 @@ def __init__(self, encoding=None, suppress_output=False): # ANSI "standard" attributes. if self.SupportsAnsi(): - # Select Graphic Rendition paramaters from + # Select Graphic Rendition parameters from # http://en.wikipedia.org/wiki/ANSI_escape_code#graphics # Italic '3' would be nice here but its not widely supported. self._csi = '\x1b[' @@ -394,7 +394,7 @@ def GetControlSequenceIndicator(self): """Returns the control sequence indicator string. Returns: - The conrol sequence indicator string or None if control sequences are not + The control sequence indicator string or None if control sequences are not supported. """ return self._csi @@ -408,7 +408,7 @@ def GetControlSequenceLen(self, buf): buf: The string to check for a control sequence. Returns: - The conrol sequence length at the beginning of buf or 0 if buf does not + The control sequence length at the beginning of buf or 0 if buf does not start with a control sequence. """ if not self._csi or not buf.startswith(self._csi): diff --git a/fire/console/console_attr_os.py b/fire/console/console_attr_os.py index 8482c7bc..869c5949 100644 --- a/fire/console/console_attr_os.py +++ b/fire/console/console_attr_os.py @@ -123,7 +123,7 @@ def _GetTermSizeEnvironment(): def _GetTermSizeTput(): - """Returns the terminal x and y dimemsions from tput(1).""" + """Returns the terminal x and y dimensions from tput(1).""" import subprocess # pylint: disable=g-import-not-at-top output = encoding.Decode(subprocess.check_output(['tput', 'cols'], stderr=subprocess.STDOUT)) diff --git a/fire/console/console_pager.py b/fire/console/console_pager.py index 044fcb37..565c7e1e 100644 --- a/fire/console/console_pager.py +++ b/fire/console/console_pager.py @@ -94,7 +94,7 @@ def __init__(self, contents, out=None, prompt=None): Args: contents: The entire contents of the text lines to page. out: The output stream, log.out (effectively) if None. - prompt: The page break prompt, a defalt prompt is used if None.. + prompt: The page break prompt, a default prompt is used if None.. """ self._contents = contents self._out = out or sys.stdout diff --git a/fire/docstrings_test.py b/fire/docstrings_test.py index 2328ef16..0d6e5d18 100644 --- a/fire/docstrings_test.py +++ b/fire/docstrings_test.py @@ -50,12 +50,12 @@ def test_one_line_simple_whitespace(self): def test_one_line_too_long(self): # pylint: disable=line-too-long - docstring = """A one line docstring thats both a little too verbose and a little too long so it keeps going well beyond a reasonable length for a one-liner. + docstring = """A one line docstring that is both a little too verbose and a little too long so it keeps going well beyond a reasonable length for a one-liner. """ # pylint: enable=line-too-long docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( - summary='A one line docstring thats both a little too verbose and ' + summary='A one line docstring that is both a little too verbose and ' 'a little too long so it keeps going well beyond a reasonable length ' 'for a one-liner.', ) @@ -63,25 +63,25 @@ def test_one_line_too_long(self): def test_one_line_runs_over(self): # pylint: disable=line-too-long - docstring = """A one line docstring thats both a little too verbose and a little too long + docstring = """A one line docstring that is both a little too verbose and a little too long so it runs onto a second line. """ # pylint: enable=line-too-long docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( - summary='A one line docstring thats both a little too verbose and ' + summary='A one line docstring that is both a little too verbose and ' 'a little too long so it runs onto a second line.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_one_line_runs_over_whitespace(self): docstring = """ - A one line docstring thats both a little too verbose and a little too long + A one line docstring that is both a little too verbose and a little too long so it runs onto a second line. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( - summary='A one line docstring thats both a little too verbose and ' + summary='A one line docstring that is both a little too verbose and ' 'a little too long so it runs onto a second line.', ) self.assertEqual(expected_docstring_info, docstring_info) diff --git a/fire/parser_test.py b/fire/parser_test.py index 0257be28..6b6b79b1 100644 --- a/fire/parser_test.py +++ b/fire/parser_test.py @@ -117,8 +117,8 @@ def testDefaultParseValueBareWordsTuple(self): def testDefaultParseValueNestedContainers(self): self.assertEqual( - parser.DefaultParseValue('[(A, 2, "3"), 5, {alph: 10.2, beta: "cat"}]'), - [('A', 2, '3'), 5, {'alph': 10.2, 'beta': 'cat'}]) + parser.DefaultParseValue('[(A, 2, "3"), 5, {alpha: 10.2, beta: "cat"}]'), + [('A', 2, '3'), 5, {'alpha': 10.2, 'beta': 'cat'}]) def testDefaultParseValueComments(self): self.assertEqual(parser.DefaultParseValue('"0#comments"'), '0#comments') From 6e485c971f4998175b841c775edcd980f2fb55ea Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 13 Feb 2023 15:24:46 -0500 Subject: [PATCH 29/86] Split too long line, fixing lint #437 --- fire/parser_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fire/parser_test.py b/fire/parser_test.py index 6b6b79b1..8aeabc61 100644 --- a/fire/parser_test.py +++ b/fire/parser_test.py @@ -117,7 +117,8 @@ def testDefaultParseValueBareWordsTuple(self): def testDefaultParseValueNestedContainers(self): self.assertEqual( - parser.DefaultParseValue('[(A, 2, "3"), 5, {alpha: 10.2, beta: "cat"}]'), + parser.DefaultParseValue( + '[(A, 2, "3"), 5, {alpha: 10.2, beta: "cat"}]'), [('A', 2, '3'), 5, {'alpha': 10.2, 'beta': 'cat'}]) def testDefaultParseValueComments(self): From 1bcb5d1a265ed78e02b57174171aae9d813dbcf5 Mon Sep 17 00:00:00 2001 From: Panagiotis Simakis Date: Thu, 5 Oct 2023 18:39:58 +0300 Subject: [PATCH 30/86] Add missing parameter description (#462) --- fire/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fire/core.py b/fire/core.py index c1e97367..6367262d 100644 --- a/fire/core.py +++ b/fire/core.py @@ -94,6 +94,8 @@ def Fire(component=None, command=None, name=None, serialize=None): 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. + serialize: Optional. If supplied, all objects are serialized to text via + the provided callable. Returns: The result of executing the Fire command. Execution begins with the initial target component. The component is updated by using the command arguments From d44d33d4ac9389854b046ca0270c112693b309e6 Mon Sep 17 00:00:00 2001 From: Max <4649120+maximehk@users.noreply.github.com> Date: Mon, 13 Nov 2023 19:49:58 +0100 Subject: [PATCH 31/86] Fix missing `$` sign in bash completion (#472) Related issue https://github.com/google/python-fire/issues/64 Co-authored-by: Max Hacker --- fire/completion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/completion.py b/fire/completion.py index 9659ec6a..4393880d 100644 --- a/fire/completion.py +++ b/fire/completion.py @@ -104,7 +104,7 @@ def _BashScript(name, commands, default_options=None): option_already_entered() {{ local opt - for opt in ${{COMP_WORDS[@]:0:COMP_CWORD}} + for opt in ${{COMP_WORDS[@]:0:$COMP_CWORD}} do if [ $1 == $opt ]; then return 0 From 1d8a137893222b977fc23764ad6e56293cf83a32 Mon Sep 17 00:00:00 2001 From: Hai Zhu <35182391+cocolato@users.noreply.github.com> Date: Wed, 3 Jan 2024 04:25:30 +0800 Subject: [PATCH 32/86] remove asyncio.coroutine (#440) --- fire/test_components_py3.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index 5140921d..17fb932c 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -57,8 +57,7 @@ def lru_cache_decorated(arg1): class WithAsyncio(object): - @asyncio.coroutine - def double(self, count=0): + async def double(self, count=0): return 2 * count From ffb8121ab8d342bad2e613df41fe406b2ed5e133 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Tue, 2 Jan 2024 15:45:49 -0500 Subject: [PATCH 33/86] Update build.yml dropping Python 2.7 (#479) We'll want to reenable later. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bf78e8b..9864ae98 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: ["2.7", "3.5", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.5", "3.7", "3.8", "3.9", "3.10"] steps: # Checkout the repo. From 8a41c91a474209b38d58839437f5711190fd3cee Mon Sep 17 00:00:00 2001 From: eXcript Date: Tue, 9 Jan 2024 15:22:03 -0300 Subject: [PATCH 34/86] Update formatting_windows.py (#477) Add a check if 'isatty' member exists in the object, required for packaging with PyInstaller. --- fire/formatting_windows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/formatting_windows.py b/fire/formatting_windows.py index 2b85820d..4bcf82e0 100644 --- a/fire/formatting_windows.py +++ b/fire/formatting_windows.py @@ -35,7 +35,7 @@ def initialize_or_disable(): """Enables ANSI processing on Windows or disables it as needed.""" if HAS_COLORAMA: wrap = True - if sys.stdout.isatty() and platform.release() == '10': + if hasattr(sys.stdout, "isatty") and sys.stdout.isatty() and platform.release() == '10': # Enables native ANSI sequences in console. # Windows 10, 2016, and 2019 only. From 343e6b6cec2d174d511e99dec7e5a24849121c2e Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 13:07:41 -0500 Subject: [PATCH 35/86] Add Python 3.11 and Python 3.12 to build workflow (#485) This change brings github actions back into the green. --- .github/scripts/requirements.txt | 11 +++++++---- .github/workflows/build.yml | 2 +- fire/__init__.py | 2 +- fire/__main__.py | 2 +- fire/console/encoding.py | 12 ++++++------ fire/formatting_windows.py | 4 +++- fire/inspectutils.py | 4 ++-- fire/testutils.py | 2 +- pylintrc | 2 +- setup.py | 4 +++- 10 files changed, 26 insertions(+), 19 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 9e48e20d..13880c9c 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,10 +1,13 @@ -setuptools <65.7.0 -pip <23.0 +setuptools <65.7.0 ; python_version == '2.7' +setuptools <=69.1.1 ; python_version >= '3.8' +pip <23.0 ; python_version == '2.7' +pip ; python_version >= '3.5' pylint <2.15.10 pytest <=7.2.1 pytest-pylint <=1.1.2 pytest-runner <6.0.0 termcolor <2.2.0 hypothesis <6.62.0 -python-Levenshtein <0.20.9 -mock <5.0.0 \ No newline at end of file +python-Levenshtein <0.20.9 ; python_version == '2.7' +levenshtein <=0.25.0 ; python_version >= '3.5' +mock <5.0.0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9864ae98..eb510f03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: ["3.5", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.5", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: # Checkout the repo. diff --git a/fire/__init__.py b/fire/__init__.py index 4cc76210..fae18489 100644 --- a/fire/__init__.py +++ b/fire/__init__.py @@ -21,4 +21,4 @@ from fire.core import Fire __all__ = ['Fire'] -__version__ = '0.5.0' +__version__ = '0.6.0' diff --git a/fire/__main__.py b/fire/__main__.py index 2ad217d6..9d8227ad 100644 --- a/fire/__main__.py +++ b/fire/__main__.py @@ -80,7 +80,7 @@ def import_from_file_path(path): spec.loader.exec_module(module) # pytype: disable=attribute-error else: - import imp # pylint: disable=g-import-not-at-top,import-outside-toplevel,deprecated-module + import imp # pylint: disable=g-import-not-at-top,import-outside-toplevel,deprecated-module,import-error module = imp.load_source(module_name, path) return module, module_name diff --git a/fire/console/encoding.py b/fire/console/encoding.py index 780e5a28..41bda634 100644 --- a/fire/console/encoding.py +++ b/fire/console/encoding.py @@ -86,7 +86,7 @@ def Decode(data, encoding=None): try: # Just return the string if its pure ASCII. - return string.decode('ascii') + return string.decode('ascii') # pytype: disable=attribute-error except UnicodeError: # The string is not ASCII encoded. pass @@ -94,7 +94,7 @@ def Decode(data, encoding=None): # Try the suggested encoding if specified. if encoding: try: - return string.decode(encoding) + return string.decode(encoding) # pytype: disable=attribute-error except UnicodeError: # Bad suggestion. pass @@ -103,21 +103,21 @@ def Decode(data, encoding=None): # be exceptional if a valid extended ascii encoding with extended chars # were also a valid UITF-8 encoding. try: - return string.decode('utf8') + return string.decode('utf8') # pytype: disable=attribute-error except UnicodeError: # Not a UTF-8 encoding. pass # Try the filesystem encoding. try: - return string.decode(sys.getfilesystemencoding()) + return string.decode(sys.getfilesystemencoding()) # pytype: disable=attribute-error except UnicodeError: # string is not encoded for filesystem paths. pass # Try the system default encoding. try: - return string.decode(sys.getdefaultencoding()) + return string.decode(sys.getdefaultencoding()) # pytype: disable=attribute-error except UnicodeError: # string is not encoded using the default encoding. pass @@ -137,7 +137,7 @@ def Decode(data, encoding=None): # string = '\xdc' # string = string.decode('iso-8859-1') # string = string.encode('ascii', 'backslashreplace') - return string.decode('iso-8859-1') + return string.decode('iso-8859-1') # pytype: disable=attribute-error def GetEncodedValue(env, name, default=None): diff --git a/fire/formatting_windows.py b/fire/formatting_windows.py index 4bcf82e0..ce0f677d 100644 --- a/fire/formatting_windows.py +++ b/fire/formatting_windows.py @@ -35,7 +35,9 @@ def initialize_or_disable(): """Enables ANSI processing on Windows or disables it as needed.""" if HAS_COLORAMA: wrap = True - if hasattr(sys.stdout, "isatty") and sys.stdout.isatty() and platform.release() == '10': + if (hasattr(sys.stdout, "isatty") + and sys.stdout.isatty() + and platform.release() == '10'): # Enables native ANSI sequences in console. # Windows 10, 2016, and 2019 only. diff --git a/fire/inspectutils.py b/fire/inspectutils.py index 0fa8e7d3..15f32f91 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -98,10 +98,10 @@ class with an __init__ method. def Py2GetArgSpec(fn): """A wrapper around getargspec that tries both fn and fn.__call__.""" try: - return inspect.getargspec(fn) # pylint: disable=deprecated-method + return inspect.getargspec(fn) # pylint: disable=deprecated-method,no-member except TypeError: if hasattr(fn, '__call__'): - return inspect.getargspec(fn.__call__) # pylint: disable=deprecated-method + return inspect.getargspec(fn.__call__) # pylint: disable=deprecated-method,no-member raise diff --git a/fire/testutils.py b/fire/testutils.py index ea410e82..5f875147 100644 --- a/fire/testutils.py +++ b/fire/testutils.py @@ -74,7 +74,7 @@ def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True): def assertRaisesRegex(self, *args, **kwargs): # pylint: disable=arguments-differ if sys.version_info.major == 2: - return super(BaseTestCase, self).assertRaisesRegexp(*args, **kwargs) # pylint: disable=deprecated-method + return super(BaseTestCase, self).assertRaisesRegexp(*args, **kwargs) # pylint: disable=deprecated-method,no-member else: return super(BaseTestCase, self).assertRaisesRegex(*args, **kwargs) # pylint: disable=no-member diff --git a/pylintrc b/pylintrc index b89b16d1..558d3ba2 100644 --- a/pylintrc +++ b/pylintrc @@ -32,7 +32,7 @@ enable=indexing-exception,old-raise-syntax # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time. -disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return,super-with-arguments,raise-missing-from,consider-using-f-string,unspecified-encoding,unnecessary-lambda-assignment +disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return,super-with-arguments,raise-missing-from,consider-using-f-string,unspecified-encoding,unnecessary-lambda-assignment,wrong-import-position,ungrouped-imports,deprecated-module [REPORTS] diff --git a/setup.py b/setup.py index 8e95f414..24e0e325 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ 'python-Levenshtein', ] -VERSION = '0.5.0' +VERSION = '0.6.0' URL = 'https://github.com/google/python-fire' setup( @@ -72,6 +72,8 @@ 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Operating System :: OS Independent', 'Operating System :: POSIX', From 3c230d8c347225cb4430a823464c5336a01b36a6 Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Mon, 11 Mar 2024 21:34:50 +0100 Subject: [PATCH 36/86] Adding GitHub dependabot (#432) Co-authored-by: Hugo van Kemenade --- .github/dependabot.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..17c20d04 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +# Basic dependabot.yml file with minimum configuration for two package managers + +version: 2 +updates: + # Enable version updates for python + - package-ecosystem: "pip" + directory: ".github/scripts/" + schedule: + interval: "monthly" + labels: ["ci"] + pull-request-branch-name: + separator: "-" + open-pull-requests-limit: 5 + reviewers: + - "dbieber" + + # Enable version updates for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + groups: + pip: + patterns: + - "*" # Check all dependencies + labels: ["ci"] + pull-request-branch-name: + separator: "-" + open-pull-requests-limit: 5 + reviewers: + - "dbieber" From db3fcaf737f917d61015f3b408a6fac0898b2030 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:43:24 -0400 Subject: [PATCH 37/86] 2 dependabot updates (#491) 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-python](https://github.com/actions/setup-python). Updates `actions/checkout` from 3 to 4 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) Updates `actions/setup-python` from 4 to 5 - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major dependency-group: pip - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major dependency-group: pip ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb510f03..f5562820 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,11 +12,11 @@ jobs: steps: # Checkout the repo. - name: Checkout Python Fire repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Set up Python environment. - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} From c417aec195cee982d24f85223e7831f71fa5adc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:44:16 -0400 Subject: [PATCH 38/86] Update hypothesis requirement in /.github/scripts (#492) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.99.4) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 13880c9c..493ad0f0 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -7,7 +7,7 @@ pytest <=7.2.1 pytest-pylint <=1.1.2 pytest-runner <6.0.0 termcolor <2.2.0 -hypothesis <6.62.0 +hypothesis <6.100.0 python-Levenshtein <0.20.9 ; python_version == '2.7' levenshtein <=0.25.0 ; python_version >= '3.5' mock <5.0.0 From 027c50272911e92f02be7ae93c60b4559c98a1a1 Mon Sep 17 00:00:00 2001 From: Vladimir Pestov <92364726+BasedDepartment1@users.noreply.github.com> Date: Tue, 12 Mar 2024 01:47:19 +0500 Subject: [PATCH 39/86] #444: Removed pipes dependency (#447) Co-authored-by: Svayp11 --- fire/core.py | 5 ++--- fire/trace.py | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/fire/core.py b/fire/core.py index 6367262d..fada01b1 100644 --- a/fire/core.py +++ b/fire/core.py @@ -56,7 +56,6 @@ def main(argv): import inspect import json import os -import pipes import re import shlex import sys @@ -240,7 +239,7 @@ def _IsHelpShortcut(component_trace, remaining_args): 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) + cmd=shlex.quote(command)), file=sys.stderr) return show_help @@ -296,7 +295,7 @@ def _DisplayError(component_trace): if show_help: 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) + cmd=shlex.quote(command)), file=sys.stderr) help_text = helptext.HelpText(result, trace=component_trace, verbose=component_trace.verbose) output.append(help_text) diff --git a/fire/trace.py b/fire/trace.py index 7174f994..4c9674e3 100644 --- a/fire/trace.py +++ b/fire/trace.py @@ -29,7 +29,7 @@ from __future__ import division from __future__ import print_function -import pipes +import shlex from fire import inspectutils @@ -166,8 +166,8 @@ def display(arg1, arg2='!'): def _Quote(self, arg): if arg.startswith('--') and '=' in arg: prefix, value = arg.split('=', 1) - return pipes.quote(prefix) + '=' + pipes.quote(value) - return pipes.quote(arg) + return shlex.quote(prefix) + '=' + shlex.quote(value) + return shlex.quote(arg) def GetCommand(self, include_separators=True): """Returns the command representing the trace up to this point. From 8beb85e4e3192d1ec0c5614ce2f8a10450670e82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:51:50 -0400 Subject: [PATCH 40/86] Update termcolor requirement from <2.2.0 to <2.5.0 in /.github/scripts (#493) Updates the requirements on [termcolor](https://github.com/termcolor/termcolor) to permit the latest version. - [Release notes](https://github.com/termcolor/termcolor/releases) - [Changelog](https://github.com/termcolor/termcolor/blob/main/CHANGES.md) - [Commits](https://github.com/termcolor/termcolor/compare/0.1...2.4.0) --- updated-dependencies: - dependency-name: termcolor dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 493ad0f0..31238e4d 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -6,7 +6,7 @@ pylint <2.15.10 pytest <=7.2.1 pytest-pylint <=1.1.2 pytest-runner <6.0.0 -termcolor <2.2.0 +termcolor <2.5.0 hypothesis <6.100.0 python-Levenshtein <0.20.9 ; python_version == '2.7' levenshtein <=0.25.0 ; python_version >= '3.5' From 595239ec7c096d8d95822153ee61190e8985f7bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:54:31 -0400 Subject: [PATCH 41/86] Update mock requirement from <5.0.0 to <6.0.0 in /.github/scripts (#495) Updates the requirements on [mock](https://github.com/testing-cabal/mock) to permit the latest version. - [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst) - [Commits](https://github.com/testing-cabal/mock/compare/release-0.5.0...5.1.0) --- updated-dependencies: - dependency-name: mock dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 31238e4d..b4efe7a9 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -10,4 +10,4 @@ termcolor <2.5.0 hypothesis <6.100.0 python-Levenshtein <0.20.9 ; python_version == '2.7' levenshtein <=0.25.0 ; python_version >= '3.5' -mock <5.0.0 +mock <6.0.0 From ab310cf8847b0c47216b37525cd54a6d358f9fc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:02:02 -0400 Subject: [PATCH 42/86] Update pytest requirement from <=7.2.1 to <=8.1.1 in /.github/scripts (#494) Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/1.0.0b3...8.1.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index b4efe7a9..8cb6ad15 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -3,7 +3,7 @@ setuptools <=69.1.1 ; python_version >= '3.8' pip <23.0 ; python_version == '2.7' pip ; python_version >= '3.5' pylint <2.15.10 -pytest <=7.2.1 +pytest <=8.1.1 pytest-pylint <=1.1.2 pytest-runner <6.0.0 termcolor <2.5.0 From 014a637f668db5fcfb81c1d426995b08e2b2ade7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:02:46 -0400 Subject: [PATCH 43/86] Update pytest-runner requirement in /.github/scripts (#496) Updates the requirements on [pytest-runner](https://github.com/pytest-dev/pytest-runner) to permit the latest version. - [Release notes](https://github.com/pytest-dev/pytest-runner/releases) - [Changelog](https://github.com/pytest-dev/pytest-runner/blob/main/CHANGES.rst) - [Commits](https://github.com/pytest-dev/pytest-runner/compare/1.0a1...v6.0.1) --- updated-dependencies: - dependency-name: pytest-runner dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 8cb6ad15..654f6079 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,7 +5,7 @@ pip ; python_version >= '3.5' pylint <2.15.10 pytest <=8.1.1 pytest-pylint <=1.1.2 -pytest-runner <6.0.0 +pytest-runner <7.0.0 termcolor <2.5.0 hypothesis <6.100.0 python-Levenshtein <0.20.9 ; python_version == '2.7' From f332cb1fe60c3a381d1ef5dc23c6e6d2142117df Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:02:23 +0100 Subject: [PATCH 44/86] Fix typo in dependabot github actions group (#497) --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 17c20d04..d31b409b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,7 +20,7 @@ updates: schedule: interval: "monthly" groups: - pip: + gh-actions: patterns: - "*" # Check all dependencies labels: ["ci"] From de2852a41746538e9077d8ab2586875cffd3dc57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:11:36 -0400 Subject: [PATCH 45/86] Update setuptools requirement in /.github/scripts (#500) Updates the requirements on [setuptools](https://github.com/pypa/setuptools) to permit the latest version. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/0.6...v69.2.0) --- updated-dependencies: - dependency-name: setuptools dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 654f6079..98111196 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,5 +1,5 @@ setuptools <65.7.0 ; python_version == '2.7' -setuptools <=69.1.1 ; python_version >= '3.8' +setuptools <=69.2.0 ; python_version >= '3.8' pip <23.0 ; python_version == '2.7' pip ; python_version >= '3.5' pylint <2.15.10 From 6902939a317dca9d41446168d8e88f108e0c0f11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:21:26 -0400 Subject: [PATCH 46/86] Update hypothesis requirement in /.github/scripts (#506) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.100.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 98111196..15d2b017 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -7,7 +7,7 @@ pytest <=8.1.1 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.5.0 -hypothesis <6.100.0 +hypothesis <6.101.0 python-Levenshtein <0.20.9 ; python_version == '2.7' levenshtein <=0.25.0 ; python_version >= '3.5' mock <6.0.0 From e9f49b0fa9d5ee627e80a15e74624fcd41a34add Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:15:45 -0400 Subject: [PATCH 47/86] Update levenshtein requirement in /.github/scripts (#510) Updates the requirements on [levenshtein](https://github.com/rapidfuzz/Levenshtein) to permit the latest version. - [Release notes](https://github.com/rapidfuzz/Levenshtein/releases) - [Changelog](https://github.com/rapidfuzz/Levenshtein/blob/main/HISTORY.md) - [Commits](https://github.com/rapidfuzz/Levenshtein/compare/v0.13.0...v0.25.1) --- updated-dependencies: - dependency-name: levenshtein dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 15d2b017..f7d3cacd 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -9,5 +9,5 @@ pytest-runner <7.0.0 termcolor <2.5.0 hypothesis <6.101.0 python-Levenshtein <0.20.9 ; python_version == '2.7' -levenshtein <=0.25.0 ; python_version >= '3.5' +levenshtein <=0.25.1 ; python_version >= '3.5' mock <6.0.0 From a59f6bad3f72ae6035b076504744d3e9f619afea Mon Sep 17 00:00:00 2001 From: Weida Hong Date: Sat, 10 Aug 2024 04:16:48 +0800 Subject: [PATCH 48/86] Use ast.Constant for recent Python versions (#526) ast.Str is planned to removed in Python 3.14, use ast.Constant instead whenever the later is available. --- fire/parser.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fire/parser.py b/fire/parser.py index 2aff8bd7..bdf3cdbf 100644 --- a/fire/parser.py +++ b/fire/parser.py @@ -20,7 +20,12 @@ import argparse import ast +import sys +if sys.version_info[0:2] < (3, 8): + _StrNode = ast.Str +else: + _StrNode = ast.Constant def CreateParser(): parser = argparse.ArgumentParser(add_help=False) @@ -127,4 +132,4 @@ def _Replacement(node): # These are the only builtin constants supported by literal_eval. if value in ('True', 'False', 'None'): return node - return ast.Str(value) + return _StrNode(value) From 8b063b952fba6dec79dfbc8688a9edf047de3b6c Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 20:20:44 -0400 Subject: [PATCH 49/86] Remove future imports now that we've dropped support for Python 2 (#539) * Remove future imports now that we've dropped support for Python 2 * Keep future imports for use in MemberVisible * Drop support for Python 3.5 * Remove indications of support for Python <3.7 and bump version number. --- .github/scripts/build.sh | 2 +- .github/workflows/build.yml | 2 +- fire/__init__.py | 4 ---- fire/__main__.py | 4 ---- fire/completion_test.py | 4 ---- fire/console/console_io.py | 4 ---- fire/core.py | 4 ---- fire/core_test.py | 4 ---- fire/custom_descriptions.py | 4 ---- fire/custom_descriptions_test.py | 4 ---- fire/decorators.py | 4 ---- fire/decorators_test.py | 4 ---- fire/docstrings.py | 4 ---- fire/docstrings_fuzz_test.py | 4 ---- fire/docstrings_test.py | 4 ---- fire/fire_test.py | 4 ---- fire/formatting.py | 4 ---- fire/formatting_test.py | 4 ---- fire/formatting_windows.py | 4 ---- fire/helptext.py | 4 ---- fire/helptext_test.py | 4 ---- fire/inspectutils.py | 4 ---- fire/inspectutils_test.py | 4 ---- fire/interact.py | 4 ---- fire/interact_test.py | 4 ---- fire/parser.py | 4 ---- fire/parser_fuzz_test.py | 4 ---- fire/parser_test.py | 4 ---- fire/test_components.py | 4 ---- fire/test_components_bin.py | 4 ---- fire/test_components_test.py | 4 ---- fire/testutils.py | 4 ---- fire/testutils_test.py | 4 ---- fire/trace.py | 4 ---- fire/trace_test.py | 4 ---- fire/value_types.py | 4 ---- setup.py | 6 +----- 37 files changed, 3 insertions(+), 143 deletions(-) diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index 1f9ed766..111257ae 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -17,7 +17,7 @@ # Exit when any command fails. set -e -PYTHON_VERSION=${PYTHON_VERSION:-2.7} +PYTHON_VERSION=${PYTHON_VERSION:-3.7} pip install -U -r .github/scripts/requirements.txt python setup.py develop diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5562820..7f5225c5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: ["3.5", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: # Checkout the repo. diff --git a/fire/__init__.py b/fire/__init__.py index fae18489..742b03ac 100644 --- a/fire/__init__.py +++ b/fire/__init__.py @@ -14,10 +14,6 @@ """The Python Fire module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire.core import Fire __all__ = ['Fire'] diff --git a/fire/__main__.py b/fire/__main__.py index 9d8227ad..15a9d6c8 100644 --- a/fire/__main__.py +++ b/fire/__main__.py @@ -18,10 +18,6 @@ This allows using Fire with third-party libraries without modifying their code. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import importlib import os import sys diff --git a/fire/completion_test.py b/fire/completion_test.py index 582e5bbc..5bafc279 100644 --- a/fire/completion_test.py +++ b/fire/completion_test.py @@ -14,10 +14,6 @@ """Tests for the completion module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import completion from fire import test_components as tc from fire import testutils diff --git a/fire/console/console_io.py b/fire/console/console_io.py index 3d3b9f81..ec0858d9 100644 --- a/fire/console/console_io.py +++ b/fire/console/console_io.py @@ -15,10 +15,6 @@ """General console printing utilities used by the Cloud SDK.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import signal import subprocess diff --git a/fire/core.py b/fire/core.py index fada01b1..0a6dae7d 100644 --- a/fire/core.py +++ b/fire/core.py @@ -49,10 +49,6 @@ def main(argv): --trace: Get the Fire Trace for the command. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import inspect import json import os diff --git a/fire/core_test.py b/fire/core_test.py index 75b76998..b9033c22 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -14,10 +14,6 @@ """Tests for the core module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import core from fire import test_components as tc from fire import testutils diff --git a/fire/custom_descriptions.py b/fire/custom_descriptions.py index 266671f1..f7df90b0 100644 --- a/fire/custom_descriptions.py +++ b/fire/custom_descriptions.py @@ -36,10 +36,6 @@ descriptions for primitive typed values. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import formatting import six diff --git a/fire/custom_descriptions_test.py b/fire/custom_descriptions_test.py index 79d7c7a1..6cff2d5d 100644 --- a/fire/custom_descriptions_test.py +++ b/fire/custom_descriptions_test.py @@ -14,10 +14,6 @@ """Tests for custom description module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import custom_descriptions from fire import testutils diff --git a/fire/decorators.py b/fire/decorators.py index b2e9b322..eb5b0d20 100644 --- a/fire/decorators.py +++ b/fire/decorators.py @@ -18,10 +18,6 @@ command line arguments to client code. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import inspect FIRE_METADATA = 'FIRE_METADATA' diff --git a/fire/decorators_test.py b/fire/decorators_test.py index cc7d6203..a316b79f 100644 --- a/fire/decorators_test.py +++ b/fire/decorators_test.py @@ -14,10 +14,6 @@ """Tests for the decorators module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import core from fire import decorators from fire import testutils diff --git a/fire/docstrings.py b/fire/docstrings.py index 1cfadea9..2d7c7e63 100644 --- a/fire/docstrings.py +++ b/fire/docstrings.py @@ -49,10 +49,6 @@ - "True | False" indicates bool type. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import collections import enum import re diff --git a/fire/docstrings_fuzz_test.py b/fire/docstrings_fuzz_test.py index 7609f4f8..66be8006 100644 --- a/fire/docstrings_fuzz_test.py +++ b/fire/docstrings_fuzz_test.py @@ -14,10 +14,6 @@ """Fuzz tests for the docstring parser module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import docstrings from fire import testutils diff --git a/fire/docstrings_test.py b/fire/docstrings_test.py index 0d6e5d18..ce516944 100644 --- a/fire/docstrings_test.py +++ b/fire/docstrings_test.py @@ -14,10 +14,6 @@ """Tests for fire docstrings module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import docstrings from fire import testutils diff --git a/fire/fire_test.py b/fire/fire_test.py index 8b904c29..6b9a2fa2 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -14,10 +14,6 @@ """Tests for the fire module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys diff --git a/fire/formatting.py b/fire/formatting.py index faef8047..68484c27 100644 --- a/fire/formatting.py +++ b/fire/formatting.py @@ -14,10 +14,6 @@ """Formatting utilities for use in creating help text.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import formatting_windows # pylint: disable=unused-import import termcolor diff --git a/fire/formatting_test.py b/fire/formatting_test.py index 05a88c49..e0f6699d 100644 --- a/fire/formatting_test.py +++ b/fire/formatting_test.py @@ -14,10 +14,6 @@ """Tests for formatting.py.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import formatting from fire import testutils diff --git a/fire/formatting_windows.py b/fire/formatting_windows.py index ce0f677d..f8241eaa 100644 --- a/fire/formatting_windows.py +++ b/fire/formatting_windows.py @@ -14,10 +14,6 @@ """This module is used for enabling formatting on Windows.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import ctypes import os import platform diff --git a/fire/helptext.py b/fire/helptext.py index 6e7fbb07..93072897 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -29,10 +29,6 @@ information. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import collections import itertools import sys diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 404d9812..9a0f4f6d 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -14,10 +14,6 @@ """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 diff --git a/fire/inspectutils.py b/fire/inspectutils.py index 15f32f91..ca51a9a5 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -14,10 +14,6 @@ """Inspection utility functions for Python Fire.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import inspect import sys import types diff --git a/fire/inspectutils_test.py b/fire/inspectutils_test.py index ea8eb0e2..bb62f402 100644 --- a/fire/inspectutils_test.py +++ b/fire/inspectutils_test.py @@ -14,10 +14,6 @@ """Tests for the inspectutils module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import unittest diff --git a/fire/interact.py b/fire/interact.py index 7df32841..7bdeb9a7 100644 --- a/fire/interact.py +++ b/fire/interact.py @@ -20,10 +20,6 @@ InteractiveConsole class. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import inspect diff --git a/fire/interact_test.py b/fire/interact_test.py index 29fa7597..99cde285 100644 --- a/fire/interact_test.py +++ b/fire/interact_test.py @@ -14,10 +14,6 @@ """Tests for the interact module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import interact from fire import testutils diff --git a/fire/parser.py b/fire/parser.py index bdf3cdbf..c4708455 100644 --- a/fire/parser.py +++ b/fire/parser.py @@ -14,10 +14,6 @@ """Provides parsing functionality used by Python Fire.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import argparse import ast import sys diff --git a/fire/parser_fuzz_test.py b/fire/parser_fuzz_test.py index af0be038..38e17725 100644 --- a/fire/parser_fuzz_test.py +++ b/fire/parser_fuzz_test.py @@ -14,10 +14,6 @@ """Fuzz tests for the parser module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import parser from fire import testutils from hypothesis import example diff --git a/fire/parser_test.py b/fire/parser_test.py index 8aeabc61..a404eea2 100644 --- a/fire/parser_test.py +++ b/fire/parser_test.py @@ -14,10 +14,6 @@ """Tests for the parser module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import parser from fire import testutils diff --git a/fire/test_components.py b/fire/test_components.py index 5fcb056e..e50f647c 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -14,10 +14,6 @@ """This module has components that are used for testing Python Fire.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import collections import enum import functools diff --git a/fire/test_components_bin.py b/fire/test_components_bin.py index fbb41952..62afdf11 100644 --- a/fire/test_components_bin.py +++ b/fire/test_components_bin.py @@ -17,10 +17,6 @@ This file is useful for replicating test results manually. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import fire from fire import test_components diff --git a/fire/test_components_test.py b/fire/test_components_test.py index f35d7ab5..531f882c 100644 --- a/fire/test_components_test.py +++ b/fire/test_components_test.py @@ -14,10 +14,6 @@ """Tests for the test_components module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import test_components as tc from fire import testutils diff --git a/fire/testutils.py b/fire/testutils.py index 5f875147..76faa3f4 100644 --- a/fire/testutils.py +++ b/fire/testutils.py @@ -14,10 +14,6 @@ """Utilities for Python Fire's tests.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import contextlib import os import re diff --git a/fire/testutils_test.py b/fire/testutils_test.py index ad604193..0999a4c8 100644 --- a/fire/testutils_test.py +++ b/fire/testutils_test.py @@ -14,10 +14,6 @@ """Test the test utilities for Fire's tests.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import sys from fire import testutils diff --git a/fire/trace.py b/fire/trace.py index 4c9674e3..2145186e 100644 --- a/fire/trace.py +++ b/fire/trace.py @@ -25,10 +25,6 @@ component will be None. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import shlex from fire import inspectutils diff --git a/fire/trace_test.py b/fire/trace_test.py index 1621a593..1f858f5e 100644 --- a/fire/trace_test.py +++ b/fire/trace_test.py @@ -14,10 +14,6 @@ """Tests for the trace module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from fire import testutils from fire import trace diff --git a/fire/value_types.py b/fire/value_types.py index c0a137fd..b2d0a0b3 100644 --- a/fire/value_types.py +++ b/fire/value_types.py @@ -14,10 +14,6 @@ """Types of values.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import inspect from fire import inspectutils diff --git a/setup.py b/setup.py index 24e0e325..f861f9a5 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ 'python-Levenshtein', ] -VERSION = '0.6.0' +VERSION = '0.7.0' URL = 'https://github.com/google/python-fire' setup( @@ -63,11 +63,7 @@ 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', From 5d0706d814e8c9297f078fabc0a1638c34c1ef30 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 20:57:15 -0400 Subject: [PATCH 50/86] remove six: Replace six.string_types and six.integer_types, etc. (#541) This commit includes: * assuming Python 3 for test skipping * assuming Python 3 for fire's various type checks * assuming Python 3 for imports (like asyncio) * assuming Python 3 for getting function signatures * six is no longer considered a hidden module (and so if a user of fire has six in their globals when they call Fire(), six will now show up where it used to be hidden) This commit does not remove six from console/ code. --- fire/completion.py | 21 +++++++-------------- fire/core.py | 8 +++----- fire/core_test.py | 4 ---- fire/custom_descriptions.py | 9 +++------ fire/fire_test.py | 3 --- fire/helptext_test.py | 11 ----------- fire/inspectutils.py | 27 ++++----------------------- fire/inspectutils_test.py | 9 +-------- fire/parser_fuzz_test.py | 7 +++---- fire/test_components.py | 5 +---- fire/testutils.py | 11 ++++------- fire/testutils_test.py | 8 +++----- fire/value_types.py | 3 +-- 13 files changed, 30 insertions(+), 96 deletions(-) diff --git a/fire/completion.py b/fire/completion.py index 4393880d..3aa8ab11 100644 --- a/fire/completion.py +++ b/fire/completion.py @@ -23,7 +23,6 @@ import inspect from fire import inspectutils -import six def Script(name, component, default_options=None, shell='bash'): @@ -308,7 +307,7 @@ def MemberVisible(component, name, member, class_attrs=None, verbose=False): Returns A boolean value indicating whether the member should be included. """ - if isinstance(name, six.string_types) and name.startswith('__'): + if isinstance(name, str) and name.startswith('__'): return False if verbose: return True @@ -316,10 +315,11 @@ def MemberVisible(component, name, member, class_attrs=None, verbose=False): or member is division or member is print_function): return False - if isinstance(member, type(absolute_import)) and six.PY34: + if isinstance(member, type(absolute_import)): return False - if inspect.ismodule(member) and member is six: - # TODO(dbieber): Determine more generally which modules to hide. + # TODO(dbieber): Determine more generally which modules to hide. + modules_to_hide = [] + if inspect.ismodule(member) and member in modules_to_hide: return False if inspect.isclass(component): # If class_attrs has not been provided, compute it. @@ -336,14 +336,7 @@ def MemberVisible(component, name, member, class_attrs=None, verbose=False): tuplegetter = getattr(collections, '_tuplegetter', type(None)) if isinstance(class_attr.object, tuplegetter): return False - if (six.PY2 and inspect.isfunction(component) - and name in ('func_closure', 'func_code', 'func_defaults', - 'func_dict', 'func_doc', 'func_globals', 'func_name')): - return False - if (six.PY2 and inspect.ismethod(component) - and name in ('im_class', 'im_func', 'im_self')): - return False - if isinstance(name, six.string_types): + if isinstance(name, str): return not name.startswith('_') return True # Default to including the member @@ -438,7 +431,7 @@ def _FormatForCommand(token): Returns: The transformed token. """ - if not isinstance(token, six.string_types): + if not isinstance(token, str): token = str(token) if token.startswith('_'): diff --git a/fire/core.py b/fire/core.py index 0a6dae7d..c61a8b57 100644 --- a/fire/core.py +++ b/fire/core.py @@ -67,10 +67,8 @@ def main(argv): from fire import trace from fire import value_types from fire.console import console_io -import six -if six.PY34: - import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error +import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error def Fire(component=None, command=None, name=None, serialize=None): @@ -109,7 +107,7 @@ def Fire(component=None, command=None, name=None, serialize=None): name = name or os.path.basename(sys.argv[0]) # Get args as a list. - if isinstance(command, six.string_types): + if isinstance(command, str): args = shlex.split(command) elif isinstance(command, (list, tuple)): args = command @@ -344,7 +342,7 @@ def _DictAsString(result, verbose=False): def _OneLineResult(result): """Returns result serialized to a single line string.""" # TODO(dbieber): Ensure line is fewer than eg 120 characters. - if isinstance(result, six.string_types): + if isinstance(result, str): return str(result).replace('\n', ' ') # TODO(dbieber): Show a small amount of usage information about the function diff --git a/fire/core_test.py b/fire/core_test.py index b9033c22..9e1f7dba 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -20,8 +20,6 @@ from fire import trace import mock -import six - class CoreTest(testutils.BaseTestCase): @@ -214,13 +212,11 @@ def serialize(x): with self.assertRaises(core.FireError): core.Fire(ident, command=['asdf'], serialize=55) - @testutils.skipIf(six.PY2, 'lru_cache is Python 3 only.') def testLruCacheDecoratorBoundArg(self): self.assertEqual( core.Fire(tc.py3.LruCacheDecoratedMethod, # pytype: disable=module-attr command=['lru_cache_in_class', 'foo']), 'foo') - @testutils.skipIf(six.PY2, 'lru_cache is Python 3 only.') def testLruCacheDecorator(self): self.assertEqual( core.Fire(tc.py3.lru_cache_decorated, # pytype: disable=module-attr diff --git a/fire/custom_descriptions.py b/fire/custom_descriptions.py index f7df90b0..768f0e23 100644 --- a/fire/custom_descriptions.py +++ b/fire/custom_descriptions.py @@ -37,7 +37,6 @@ """ from fire import formatting -import six TWO_DOUBLE_QUOTES = '""' STRING_DESC_PREFIX = 'The string ' @@ -60,13 +59,11 @@ def NeedsCustomDescription(component): Whether the component should use a custom description and summary. """ type_ = type(component) - if (type_ in six.string_types - or type_ in six.integer_types - or type_ is six.text_type - or type_ is six.binary_type + if ( + type_ in (str, int, bytes) or type_ in (float, complex, bool) or type_ in (dict, tuple, list, set, frozenset) - ): + ): return True return False diff --git a/fire/fire_test.py b/fire/fire_test.py index 6b9a2fa2..74b3bb25 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -22,7 +22,6 @@ from fire import testutils import mock -import six class FireTest(testutils.BaseTestCase): @@ -180,7 +179,6 @@ def testFireAnnotatedArgs(self): self.assertEqual(fire.Fire(tc.Annotations, command=['double', '5']), 10) self.assertEqual(fire.Fire(tc.Annotations, command=['triple', '5']), 15) - @testutils.skipIf(six.PY2, 'Keyword-only arguments not in Python 2.') def testFireKeywordOnlyArgs(self): with self.assertRaisesFireExit(2): # Keyword arguments must be passed with flag syntax. @@ -717,7 +715,6 @@ def testHelpKwargsDecorator(self): with self.assertRaisesFireExit(0): fire.Fire(tc.decorated_method, command=['--help']) - @testutils.skipIf(six.PY2, 'Asyncio not available in Python 2.') def testFireAsyncio(self): self.assertEqual(fire.Fire(tc.py3.WithAsyncio, command=['double', '--count', '10']), 20) diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 9a0f4f6d..2250f199 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -23,7 +23,6 @@ from fire import test_components as tc from fire import testutils from fire import trace -import six class HelpTest(testutils.BaseTestCase): @@ -276,8 +275,6 @@ def testHelpTextNoInit(self): 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( @@ -285,8 +282,6 @@ def testHelpTextKeywordOnlyArgumentsWithDefault(self): 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( @@ -294,9 +289,6 @@ def testHelpTextKeywordOnlyArgumentsWithoutDefault(self): 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') @@ -523,9 +515,6 @@ def testUsageOutputFunctionWithDocstring(self): 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') diff --git a/fire/inspectutils.py b/fire/inspectutils.py index ca51a9a5..0d0b048d 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -20,10 +20,7 @@ from fire import docstrings -import six - -if six.PY34: - import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error +import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error class FullArgSpec(object): @@ -74,8 +71,6 @@ class with an __init__ method. if inspect.isclass(fn): # If the function is a class, we try to use its init method. skip_arg = True - if six.PY2 and hasattr(fn, '__init__'): - fn = fn.__init__ elif inspect.ismethod(fn): # If the function is a bound method, we skip the `self` argument. skip_arg = fn.__self__ is not None @@ -91,16 +86,6 @@ class with an __init__ method. return fn, skip_arg -def Py2GetArgSpec(fn): - """A wrapper around getargspec that tries both fn and fn.__call__.""" - try: - return inspect.getargspec(fn) # pylint: disable=deprecated-method,no-member - except TypeError: - if hasattr(fn, '__call__'): - return inspect.getargspec(fn.__call__) # pylint: disable=deprecated-method,no-member - raise - - def Py3GetFullArgSpec(fn): """A alternative to the builtin getfullargspec. @@ -185,13 +170,9 @@ def GetFullArgSpec(fn): if sys.version_info[0:2] >= (3, 5): (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations) = Py3GetFullArgSpec(fn) - elif six.PY3: # Specifically Python 3.4. + else: # Specifically Python 3.4. (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations) = inspect.getfullargspec(fn) # pylint: disable=deprecated-method,no-member - else: # six.PY2 - args, varargs, varkw, defaults = Py2GetArgSpec(fn) - kwonlyargs = kwonlydefaults = None - annotations = getattr(fn, '__annotations__', None) except TypeError: # If we can't get the argspec, how do we know if the fn should take args? @@ -221,7 +202,7 @@ def GetFullArgSpec(fn): return FullArgSpec() # In Python 3.5+ Py3GetFullArgSpec uses skip_bound_arg=True already. - skip_arg_required = six.PY2 or sys.version_info[0:2] == (3, 4) + skip_arg_required = sys.version_info[0:2] == (3, 4) if skip_arg_required and skip_arg and args: args.pop(0) # Remove 'self' or 'cls' from the list of arguments. return FullArgSpec(args, varargs, varkw, defaults, @@ -363,6 +344,6 @@ def GetClassAttrsDict(component): def IsCoroutineFunction(fn): try: - return six.PY34 and asyncio.iscoroutinefunction(fn) + return asyncio.iscoroutinefunction(fn) except: # pylint: disable=bare-except return False diff --git a/fire/inspectutils_test.py b/fire/inspectutils_test.py index bb62f402..47de7e72 100644 --- a/fire/inspectutils_test.py +++ b/fire/inspectutils_test.py @@ -15,14 +15,11 @@ """Tests for the inspectutils module.""" import os -import unittest from fire import inspectutils from fire import test_components as tc from fire import testutils -import six - class InspectUtilsTest(testutils.BaseTestCase): @@ -36,7 +33,6 @@ def testGetFullArgSpec(self): self.assertEqual(spec.kwonlydefaults, {}) self.assertEqual(spec.annotations, {'arg2': int, 'arg4': int}) - @unittest.skipIf(six.PY2, 'No keyword arguments in python 2') def testGetFullArgSpecPy3(self): spec = inspectutils.GetFullArgSpec(tc.py3.identity) self.assertEqual(spec.args, ['arg1', 'arg2', 'arg3', 'arg4']) @@ -121,10 +117,7 @@ def testInfoClass(self): def testInfoClassNoInit(self): info = inspectutils.Info(tc.OldStyleEmpty) - if six.PY2: - self.assertEqual(info.get('type_name'), 'classobj') - else: - self.assertEqual(info.get('type_name'), 'type') + self.assertEqual(info.get('type_name'), 'type') self.assertIn(os.path.join('fire', 'test_components.py'), info.get('file')) self.assertGreater(info.get('line'), 0) diff --git a/fire/parser_fuzz_test.py b/fire/parser_fuzz_test.py index 38e17725..9739ec4e 100644 --- a/fire/parser_fuzz_test.py +++ b/fire/parser_fuzz_test.py @@ -21,7 +21,6 @@ from hypothesis import settings from hypothesis import strategies as st import Levenshtein -import six class ParserFuzzTest(testutils.BaseTestCase): @@ -64,8 +63,8 @@ def testDefaultParseValueFuzz(self, value): raise try: - uvalue = six.text_type(value) - uresult = six.text_type(result) + uvalue = str(value) + uresult = str(result) except UnicodeDecodeError: # This is not what we're testing. return @@ -82,7 +81,7 @@ def testDefaultParseValueFuzz(self, value): if '#' in value: max_distance += len(value) - value.index('#') - if not isinstance(result, six.string_types): + if not isinstance(result, str): max_distance += value.count('0') # Leading 0s are stripped. # Note: We don't check distance for dicts since item order can be changed. diff --git a/fire/test_components.py b/fire/test_components.py index e50f647c..540a9e16 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -18,10 +18,7 @@ import enum import functools -import six - -if six.PY3: - from fire import test_components_py3 as py3 # pylint: disable=unused-import,no-name-in-module,g-import-not-at-top +from fire import test_components_py3 as py3 # pylint: disable=unused-import,no-name-in-module,g-import-not-at-top def identity(arg1, arg2, arg3=10, arg4=20, *arg5, **arg6): # pylint: disable=keyword-arg-before-vararg diff --git a/fire/testutils.py b/fire/testutils.py index 76faa3f4..fa1ca86d 100644 --- a/fire/testutils.py +++ b/fire/testutils.py @@ -15,6 +15,7 @@ """Utilities for Python Fire's tests.""" import contextlib +import io import os import re import sys @@ -24,7 +25,6 @@ from fire import trace import mock -import six class BaseTestCase(unittest.TestCase): @@ -45,8 +45,8 @@ def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True): Yields: Yields to the wrapped context. """ - stdout_fp = six.StringIO() - stderr_fp = six.StringIO() + stdout_fp = io.StringIO() + stderr_fp = io.StringIO() try: with mock.patch.object(sys, 'stdout', stdout_fp): with mock.patch.object(sys, 'stderr', stderr_fp): @@ -69,10 +69,7 @@ def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True): (name, value, regexp)) def assertRaisesRegex(self, *args, **kwargs): # pylint: disable=arguments-differ - if sys.version_info.major == 2: - return super(BaseTestCase, self).assertRaisesRegexp(*args, **kwargs) # pylint: disable=deprecated-method,no-member - else: - return super(BaseTestCase, self).assertRaisesRegex(*args, **kwargs) # pylint: disable=no-member + return super(BaseTestCase, self).assertRaisesRegex(*args, **kwargs) # pylint: disable=no-member @contextlib.contextmanager def assertRaisesFireExit(self, code, regexp='.*'): diff --git a/fire/testutils_test.py b/fire/testutils_test.py index 0999a4c8..4cfc0937 100644 --- a/fire/testutils_test.py +++ b/fire/testutils_test.py @@ -18,8 +18,6 @@ from fire import testutils -import six - class TestTestUtils(testutils.BaseTestCase): """Let's get meta.""" @@ -30,15 +28,15 @@ def testNoCheckOnException(self): raise ValueError() def testCheckStdoutOrStderrNone(self): - with six.assertRaisesRegex(self, AssertionError, 'stdout:'): + with self.assertRaisesRegex(AssertionError, 'stdout:'): with self.assertOutputMatches(stdout=None): print('blah') - with six.assertRaisesRegex(self, AssertionError, 'stderr:'): + with self.assertRaisesRegex(AssertionError, 'stderr:'): with self.assertOutputMatches(stderr=None): print('blah', file=sys.stderr) - with six.assertRaisesRegex(self, AssertionError, 'stderr:'): + with self.assertRaisesRegex(AssertionError, 'stderr:'): with self.assertOutputMatches(stdout='apple', stderr=None): print('apple') print('blah', file=sys.stderr) diff --git a/fire/value_types.py b/fire/value_types.py index b2d0a0b3..81308973 100644 --- a/fire/value_types.py +++ b/fire/value_types.py @@ -17,10 +17,9 @@ import inspect from fire import inspectutils -import six -VALUE_TYPES = (bool, six.string_types, six.integer_types, float, complex, +VALUE_TYPES = (bool, str, bytes, int, float, complex, type(Ellipsis), type(None), type(NotImplemented)) From b13c13bf1767caf80bf38349dd5fbf0dd08e18b8 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 21:08:42 -0400 Subject: [PATCH 51/86] Remove sys.version_info checks (#542) * Remove sys.version_info checks where no longer needed --- fire/__main__.py | 25 ++++++------------------- fire/fire_test.py | 2 -- fire/helptext.py | 5 +---- fire/helptext_test.py | 13 ------------- fire/parser.py | 1 + 5 files changed, 8 insertions(+), 38 deletions(-) diff --git a/fire/__main__.py b/fire/__main__.py index 15a9d6c8..11fb1b42 100644 --- a/fire/__main__.py +++ b/fire/__main__.py @@ -19,6 +19,7 @@ """ import importlib +from importlib import util import os import sys @@ -57,27 +58,13 @@ def import_from_file_path(path): module_name = os.path.basename(path) - if sys.version_info.major == 3 and sys.version_info.minor < 5: - loader = importlib.machinery.SourceFileLoader( # pylint: disable=no-member - fullname=module_name, - path=path, - ) + spec = util.spec_from_file_location(module_name, path) - module = loader.load_module(module_name) # pylint: disable=deprecated-method + if spec is None: + raise IOError('Unable to load module from specified path.') - elif sys.version_info.major == 3: - from importlib import util # pylint: disable=g-import-not-at-top,import-outside-toplevel,no-name-in-module - spec = util.spec_from_file_location(module_name, path) - - if spec is None: - raise IOError('Unable to load module from specified path.') - - module = util.module_from_spec(spec) # pylint: disable=no-member - spec.loader.exec_module(module) # pytype: disable=attribute-error - - else: - import imp # pylint: disable=g-import-not-at-top,import-outside-toplevel,deprecated-module,import-error - module = imp.load_source(module_name, path) + module = util.module_from_spec(spec) # pylint: disable=no-member + spec.loader.exec_module(module) # pytype: disable=attribute-error return module, module_name diff --git a/fire/fire_test.py b/fire/fire_test.py index 74b3bb25..74f1f6e6 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -706,8 +706,6 @@ def testClassWithInvalidProperty(self): fire.Fire(tc.InvalidProperty, command=['double', '10']), 20 ) - @testutils.skipIf(sys.version_info[0:2] <= (3, 4), - 'Cannot inspect wrapped signatures in Python 2 or 3.4.') def testHelpKwargsDecorator(self): # Issue #190, follow the wrapped method instead of crashing. with self.assertRaisesFireExit(0): diff --git a/fire/helptext.py b/fire/helptext.py index 93072897..1c0cb626 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -31,7 +31,6 @@ import collections import itertools -import sys from fire import completion from fire import custom_descriptions @@ -533,9 +532,7 @@ def _GetArgType(arg, spec): if arg in spec.annotations: arg_type = spec.annotations[arg] try: - if sys.version_info[0:2] >= (3, 3): - return arg_type.__qualname__ - return arg_type.__name__ + return arg_type.__qualname__ except AttributeError: # Some typing objects, such as typing.Union do not have either a __name__ # or __qualname__ attribute. diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 2250f199..4d35dc0a 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -15,7 +15,6 @@ """Tests for the helptext module.""" import os -import sys import textwrap from fire import formatting @@ -124,9 +123,6 @@ def testHelpTextFunctionWithKwargsAndDefaults(self): '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 @@ -141,9 +137,6 @@ def testHelpTextFunctionWithDefaultsAndTypes(self): 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 @@ -159,9 +152,6 @@ def testHelpTextFunctionWithTypesAndDefaultNone(self): 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( @@ -177,9 +167,6 @@ def testHelpTextFunctionWithTypes(self): '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( diff --git a/fire/parser.py b/fire/parser.py index c4708455..d945b8ce 100644 --- a/fire/parser.py +++ b/fire/parser.py @@ -23,6 +23,7 @@ else: _StrNode = ast.Constant + def CreateParser(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--verbose', '-v', action='store_true') From 2d950337499156ccb9a17dbf5f389d0c7d10ec24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:09:02 -0400 Subject: [PATCH 52/86] Update setuptools requirement in /.github/scripts (#540) Updates the requirements on [setuptools](https://github.com/pypa/setuptools) to permit the latest version. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/0.6...v75.1.0) --- updated-dependencies: - dependency-name: setuptools dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index f7d3cacd..1932f53d 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,5 +1,5 @@ setuptools <65.7.0 ; python_version == '2.7' -setuptools <=69.2.0 ; python_version >= '3.8' +setuptools <=75.1.0 ; python_version >= '3.8' pip <23.0 ; python_version == '2.7' pip ; python_version >= '3.5' pylint <2.15.10 From f012df240f16bd7e1c3eb90e96472ef5051ac5e2 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 21:20:37 -0400 Subject: [PATCH 53/86] Simplify requirements.txt by assuming Python 3 (#543) * Remove universal=1 line * Update setup.py * Update requirements.txt --- .github/scripts/requirements.txt | 9 +++------ setup.cfg | 3 --- setup.py | 3 +-- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 1932f53d..d0344221 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,13 +1,10 @@ -setuptools <65.7.0 ; python_version == '2.7' -setuptools <=75.1.0 ; python_version >= '3.8' -pip <23.0 ; python_version == '2.7' -pip ; python_version >= '3.5' +setuptools <=75.1.0 +pip pylint <2.15.10 pytest <=8.1.1 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.5.0 hypothesis <6.101.0 -python-Levenshtein <0.20.9 ; python_version == '2.7' -levenshtein <=0.25.1 ; python_version >= '3.5' +levenshtein <=0.25.1 mock <6.0.0 diff --git a/setup.cfg b/setup.cfg index 977056b0..ed53d83b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,3 @@ -[wheel] -universal = 1 - [aliases] test = pytest diff --git a/setup.py b/setup.py index f861f9a5..6adbef46 100644 --- a/setup.py +++ b/setup.py @@ -31,13 +31,12 @@ DEPENDENCIES = [ 'six', 'termcolor', - 'enum34; python_version < "3.4"' ] TEST_DEPENDENCIES = [ 'hypothesis', 'mock', - 'python-Levenshtein', + 'levenshtein', ] VERSION = '0.7.0' From 9825623bd5c66692be16126087d3492eed9a0161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:26:51 -0400 Subject: [PATCH 54/86] Update hypothesis requirement in /.github/scripts (#544) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.112.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index d0344221..669f09e1 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,6 +5,6 @@ pytest <=8.1.1 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.5.0 -hypothesis <6.101.0 +hypothesis <6.113.0 levenshtein <=0.25.1 mock <6.0.0 From b83fa05b72d8b225182043740e35cd0c28a29293 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 21:30:54 -0400 Subject: [PATCH 55/86] Remove mock in favor of unittest.mock (#545) * Remove mock in favor of unittest.mock --- .github/scripts/requirements.txt | 1 - fire/core_test.py | 3 ++- fire/fire_import_test.py | 2 +- fire/fire_test.py | 3 +-- fire/interact_test.py | 4 ++-- fire/testutils.py | 3 +-- setup.py | 1 - 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 669f09e1..8c0a5dcc 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -7,4 +7,3 @@ pytest-runner <7.0.0 termcolor <2.5.0 hypothesis <6.113.0 levenshtein <=0.25.1 -mock <6.0.0 diff --git a/fire/core_test.py b/fire/core_test.py index 9e1f7dba..90b7f466 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -14,11 +14,12 @@ """Tests for the core module.""" +from unittest import mock + from fire import core from fire import test_components as tc from fire import testutils from fire import trace -import mock class CoreTest(testutils.BaseTestCase): diff --git a/fire/fire_import_test.py b/fire/fire_import_test.py index c5975681..a6b4acc3 100644 --- a/fire/fire_import_test.py +++ b/fire/fire_import_test.py @@ -15,10 +15,10 @@ """Tests importing the fire module.""" import sys +from unittest import mock import fire from fire import testutils -import mock class FireImportTest(testutils.BaseTestCase): diff --git a/fire/fire_test.py b/fire/fire_test.py index 74f1f6e6..99b4a7c6 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -16,13 +16,12 @@ import os import sys +from unittest import mock import fire from fire import test_components as tc from fire import testutils -import mock - class FireTest(testutils.BaseTestCase): diff --git a/fire/interact_test.py b/fire/interact_test.py index 99cde285..2f286824 100644 --- a/fire/interact_test.py +++ b/fire/interact_test.py @@ -14,11 +14,11 @@ """Tests for the interact module.""" +from unittest import mock + from fire import interact from fire import testutils -import mock - try: import IPython # pylint: disable=unused-import, g-import-not-at-top diff --git a/fire/testutils.py b/fire/testutils.py index fa1ca86d..816551b5 100644 --- a/fire/testutils.py +++ b/fire/testutils.py @@ -20,12 +20,11 @@ import re import sys import unittest +from unittest import mock from fire import core from fire import trace -import mock - class BaseTestCase(unittest.TestCase): """Shared test case for Python Fire tests.""" diff --git a/setup.py b/setup.py index 6adbef46..53f3381a 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,6 @@ TEST_DEPENDENCIES = [ 'hypothesis', - 'mock', 'levenshtein', ] From 374d8c60787f66b803aab7590fc7ab5e4307d84a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:36:29 -0400 Subject: [PATCH 56/86] Update pytest requirement from <=8.1.1 to <=8.3.3 in /.github/scripts (#546) Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/1.0.0b3...8.3.3) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 8c0a5dcc..b9cd377e 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,7 +1,7 @@ setuptools <=75.1.0 pip pylint <2.15.10 -pytest <=8.1.1 +pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.5.0 From 32b5142151789d5c64618db1ea5b0a47eb27a6c0 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 21:41:22 -0400 Subject: [PATCH 57/86] Update label used by dependabot (#547) --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d31b409b..ba1b7f19 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,7 +7,7 @@ updates: directory: ".github/scripts/" schedule: interval: "monthly" - labels: ["ci"] + labels: ["dependabot"] pull-request-branch-name: separator: "-" open-pull-requests-limit: 5 @@ -23,7 +23,7 @@ updates: gh-actions: patterns: - "*" # Check all dependencies - labels: ["ci"] + labels: ["dependabot"] pull-request-branch-name: separator: "-" open-pull-requests-limit: 5 From 9c9e8c63f745da0aeb6332a1f027b05972f579d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 18:59:27 -0700 Subject: [PATCH 58/86] Update levenshtein requirement in /.github/scripts (#548) Updates the requirements on [levenshtein](https://github.com/rapidfuzz/Levenshtein) to permit the latest version. - [Release notes](https://github.com/rapidfuzz/Levenshtein/releases) - [Changelog](https://github.com/rapidfuzz/Levenshtein/blob/main/HISTORY.md) - [Commits](https://github.com/rapidfuzz/Levenshtein/compare/v0.13.0...v0.26.0) --- updated-dependencies: - dependency-name: levenshtein dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index b9cd377e..157c77b2 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -6,4 +6,4 @@ pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.5.0 hypothesis <6.113.0 -levenshtein <=0.25.1 +levenshtein <=0.26.0 From f9293c9da7fe6645a25448537d40b563d970b2f4 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 22:06:38 -0400 Subject: [PATCH 59/86] Upgrade pylint version (#549) * Upgrade pylint * Fixing lint errors like removing a useless super call * Merging bad-names lists and other modernization in pylintrc --- .github/scripts/requirements.txt | 2 +- fire/core.py | 1 + fire/test_components.py | 3 +-- fire/testutils.py | 3 --- pylintrc | 22 ++-------------------- 5 files changed, 5 insertions(+), 26 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 157c77b2..a5648989 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,6 +1,6 @@ setuptools <=75.1.0 pip -pylint <2.15.10 +pylint <3.2.8 pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 diff --git a/fire/core.py b/fire/core.py index c61a8b57..bce9b641 100644 --- a/fire/core.py +++ b/fire/core.py @@ -872,6 +872,7 @@ def _ParseKeywordArgs(args, fn_spec): key, value = stripped_argument.split('=', 1) else: key = stripped_argument + value = None # value will be set later on. key = key.replace('-', '_') is_bool_syntax = (not contains_equals and diff --git a/fire/test_components.py b/fire/test_components.py index 540a9e16..eb3a9e24 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -388,8 +388,7 @@ def example_generator(n): [0, 1, 2, 3] """ - for i in range(n): - yield i + yield from range(n) def simple_set(): diff --git a/fire/testutils.py b/fire/testutils.py index 816551b5..eca37f43 100644 --- a/fire/testutils.py +++ b/fire/testutils.py @@ -67,9 +67,6 @@ def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True): raise AssertionError('%s: Expected %r to match %r' % (name, value, regexp)) - def assertRaisesRegex(self, *args, **kwargs): # pylint: disable=arguments-differ - return super(BaseTestCase, self).assertRaisesRegex(*args, **kwargs) # pylint: disable=no-member - @contextlib.contextmanager def assertRaisesFireExit(self, code, regexp='.*'): """Asserts that a FireExit error is raised in the context. diff --git a/pylintrc b/pylintrc index 558d3ba2..8896bb5b 100644 --- a/pylintrc +++ b/pylintrc @@ -7,9 +7,6 @@ # pygtk.require(). #init-hook= -# Profiled execution. -profile=no - # Add to the black list. It should be a base name, not a # path. You may set this option multiple times. ignore= @@ -41,14 +38,6 @@ disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-d # (visual studio) and html output-format=text -# Include message's id in output -include-ids=no - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - # Tells whether to display a full report or only the messages reports=yes @@ -59,10 +48,6 @@ reports=yes # (R0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (R0004). -comment=no - [VARIABLES] @@ -79,9 +64,6 @@ additional-builtins= [BASIC] -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,apply,input,reduce - # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ @@ -114,7 +96,7 @@ inlinevar-rgx=^[a-z][a-z0-9_]*$ good-names=i,j,k,ex,main,Run,_ # Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata +bad-names=map,filter,apply,input,reduce,foo,bar,baz,toto,tutu,tata # Regular expression which should only match functions or classes name which do # not require a docstring @@ -186,7 +168,7 @@ max-locals=15 max-returns=6 # Maximum number of branch for function / method body -max-branchs=12 +max-branches=12 # Maximum number of statements in function / method body max-statements=50 From c5f5f9008303a661558339ea3c298d247248fdbe Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 22:18:32 -0400 Subject: [PATCH 60/86] Run github action on pull_request (#550) * Run github action on pull_request --- .github/workflows/build.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f5225c5..a6649201 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,12 @@ name: Python Fire -on: [push] +on: + push: + branches: + - master + pull_request: + branches: + - master jobs: build: From ca4e80b9072397ec1c03bdf83a0bd62524a601aa Mon Sep 17 00:00:00 2001 From: Kai Chen Date: Fri, 20 Sep 2024 10:22:06 +0800 Subject: [PATCH 61/86] Add current system MSYS check (#278) --- fire/console/platforms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fire/console/platforms.py b/fire/console/platforms.py index 018eb89e..13fd8204 100644 --- a/fire/console/platforms.py +++ b/fire/console/platforms.py @@ -153,6 +153,8 @@ def Current(): return OperatingSystem.MACOSX elif 'cygwin' in sys.platform: return OperatingSystem.CYGWIN + elif 'msys' in sys.platform: + return OperatingSystem.MSYS return None @staticmethod From 4efd44dbb14ba2bf044f2fae701f787da0bfbe1e Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 23:06:02 -0400 Subject: [PATCH 62/86] Remove .format in favor of f-strings (#551) * Remove .format in favor of f-strings --- docs/guide.md | 10 ++--- examples/widget/widget.py | 2 +- fire/completion.py | 7 +-- fire/completion_test.py | 3 +- fire/core.py | 32 +++++++------- fire/helptext.py | 92 +++++++++++++++++---------------------- fire/interact.py | 11 ++--- fire/trace.py | 13 +++--- 8 files changed, 75 insertions(+), 95 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index 44d8a46d..cdc3b2d0 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -30,7 +30,7 @@ the program to the command line. import fire def hello(name): - return 'Hello {name}!'.format(name=name) + return f'Hello {name}!' if __name__ == '__main__': fire.Fire() @@ -52,7 +52,7 @@ command line. import fire def hello(name): - return 'Hello {name}!'.format(name=name) + return f'Hello {name}!' if __name__ == '__main__': fire.Fire(hello) @@ -76,7 +76,7 @@ We can alternatively write this program like this: import fire def hello(name): - return 'Hello {name}!'.format(name=name) + return f'Hello {name}!' def main(): fire.Fire(hello) @@ -93,7 +93,7 @@ then simply this: import fire def hello(name): - return 'Hello {name}!'.format(name=name) + return f'Hello {name}!' def main(): fire.Fire(hello) @@ -105,7 +105,7 @@ If you have a file `example.py` that doesn't even import fire: ```python def hello(name): - return 'Hello {name}!'.format(name=name) + return f'Hello {name}!' ``` Then you can use it with Fire like this: diff --git a/examples/widget/widget.py b/examples/widget/widget.py index bf1cbeb2..9092ad75 100644 --- a/examples/widget/widget.py +++ b/examples/widget/widget.py @@ -25,7 +25,7 @@ def whack(self, n=1): def bang(self, noise='bang'): """Makes a loud noise.""" - return '{noise} bang!'.format(noise=noise) + return f'{noise} bang!' def main(): diff --git a/fire/completion.py b/fire/completion.py index 3aa8ab11..625e9d86 100644 --- a/fire/completion.py +++ b/fire/completion.py @@ -277,10 +277,7 @@ def _FishScript(name, commands, default_options=None): ) return fish_source.format( - global_options=' '.join( - '"{option}"'.format(option=option) - for option in global_options - ) + global_options=' '.join(f'"{option}"' for option in global_options) ) @@ -385,7 +382,7 @@ def _CompletionsFromArgs(fn_args): completions = [] for arg in fn_args: arg = arg.replace('_', '-') - completions.append('--{arg}'.format(arg=arg)) + completions.append(f'--{arg}') return completions diff --git a/fire/completion_test.py b/fire/completion_test.py index 5bafc279..c0d5d24f 100644 --- a/fire/completion_test.py +++ b/fire/completion_test.py @@ -33,9 +33,8 @@ def testCompletionBashScript(self): self.assertIn('command', script) self.assertIn('halt', script) - assert_template = '{command})' for last_command in ['command', 'halt']: - self.assertIn(assert_template.format(command=last_command), script) + self.assertIn(f'{last_command})', script) def testCompletionFishScript(self): # A sanity check test to make sure the fish completion script satisfies diff --git a/fire/core.py b/fire/core.py index bce9b641..e4156760 100644 --- a/fire/core.py +++ b/fire/core.py @@ -139,7 +139,7 @@ def Fire(component=None, command=None, name=None, serialize=None): _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)] + output = [f'Fire trace:\n{component_trace}\n'] result = component_trace.GetResult() help_text = helptext.HelpText( result, trace=component_trace, verbose=component_trace.verbose) @@ -147,7 +147,7 @@ def Fire(component=None, command=None, name=None, serialize=None): Display(output, out=sys.stderr) raise FireExit(0, component_trace) if component_trace.show_trace: - output = ['Fire trace:\n{trace}'.format(trace=component_trace)] + output = [f'Fire trace:\n{component_trace}'] Display(output, out=sys.stderr) raise FireExit(0, component_trace) if component_trace.show_help: @@ -231,9 +231,9 @@ def _IsHelpShortcut(component_trace, remaining_args): 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=shlex.quote(command)), file=sys.stderr) + command = f'{component_trace.GetCommand()} -- --help' + print(f'INFO: Showing help with the command {shlex.quote(command)}.\n', + file=sys.stderr) return show_help @@ -287,9 +287,9 @@ def _DisplayError(component_trace): show_help = True if show_help: - command = '{cmd} -- --help'.format(cmd=component_trace.GetCommand()) - print('INFO: Showing help with the command {cmd}.\n'.format( - cmd=shlex.quote(command)), file=sys.stderr) + command = f'{component_trace.GetCommand()} -- --help' + print(f'INFO: Showing help with the command {shlex.quote(command)}.\n', + file=sys.stderr) help_text = helptext.HelpText(result, trace=component_trace, verbose=component_trace.verbose) output.append(help_text) @@ -327,14 +327,13 @@ def _DictAsString(result, verbose=False): return '{}' longest_key = max(len(str(key)) for key in result_visible.keys()) - format_string = '{{key:{padding}s}} {{value}}'.format(padding=longest_key + 1) + format_string = f'{{key:{longest_key + 1}s}} {{value}}' lines = [] for key, value in result.items(): if completion.MemberVisible(result, key, value, class_attrs=class_attrs, verbose=verbose): - line = format_string.format(key=str(key) + ':', - value=_OneLineResult(value)) + line = format_string.format(key=f'{key}:', value=_OneLineResult(value)) lines.append(line) return '\n'.join(lines) @@ -348,10 +347,10 @@ def _OneLineResult(result): # TODO(dbieber): Show a small amount of usage information about the function # or module if it fits cleanly on the line. if inspect.isfunction(result): - return ''.format(name=result.__name__) + return f'' if inspect.ismodule(result): - return ''.format(name=result.__name__) + return f'' try: # Don't force conversion to ascii. @@ -890,9 +889,10 @@ def _ParseKeywordArgs(args, fn_spec): if len(matching_fn_args) == 1: keyword = matching_fn_args[0] elif len(matching_fn_args) > 1: - raise FireError("The argument '{}' is ambiguous as it could " - "refer to any of the following arguments: {}".format( - argument, matching_fn_args)) + raise FireError( + f"The argument '{argument}' is ambiguous as it could " + f"refer to any of the following arguments: {matching_fn_args}" + ) # Determine the value. if not keyword: diff --git a/fire/helptext.py b/fire/helptext.py index 1c0cb626..e57eb7d8 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -106,7 +106,7 @@ def _NameSection(component, info, trace=None, verbose=False): LINE_LENGTH) if summary: - text = current_command + ' - ' + summary + text = f'{current_command} - {summary}' else: text = current_command return ('NAME', text) @@ -132,11 +132,7 @@ def _SynopsisSection(component, actions_grouped_by_kind, spec, metadata, continuations.append(trace.separator) continuation = ' | '.join(continuations) - synopsis_template = '{current_command} {continuation}' - text = synopsis_template.format( - current_command=current_command, - continuation=continuation) - + text = f'{current_command} {continuation}' return ('SYNOPSIS', text) @@ -243,8 +239,6 @@ def _ArgsAndFlagsSections(info, spec, metadata): if spec.varkw: # Include kwargs documented via :key param: documented_kwargs = [] - flag_string = '--{name}' - short_flag_string = '-{short_name}, --{name}' # add short flags if possible flags = docstring_info.args or [] @@ -253,11 +247,10 @@ def _ArgsAndFlagsSections(info, spec, metadata): for flag in flags: if isinstance(flag, docstrings.KwargInfo): if flag.name[0] in unique_short_flags: - flag_string = short_flag_string.format( - name=flag.name, short_name=flag.name[0] - ) + short_name = flag.name[0] + flag_string = f'-{short_name}, --{flag.name}' else: - flag_string = flag_string.format(name=flag.name) + flag_string = f'--{flag.name}' flag_item = _CreateFlagItem( flag.name, docstring_info, spec, @@ -347,9 +340,9 @@ def _GetArgsAndFlagsString(spec, metadata): for arg in args_with_no_defaults] else: arg_strings = [ - '--{arg}={arg_upper}'.format( - arg=arg, arg_upper=formatting.Underline(arg.upper())) - for arg in args_with_no_defaults] + f'--{arg}={formatting.Underline(arg.upper())}' + for arg in args_with_no_defaults + ] arg_and_flag_strings.extend(arg_strings) # If there are any arguments that are treated as flags: @@ -357,8 +350,8 @@ def _GetArgsAndFlagsString(spec, metadata): arg_and_flag_strings.append('') if spec.varargs: - varargs_string = '[{varargs}]...'.format( - varargs=formatting.Underline(spec.varargs.upper())) + varargs_underlined = formatting.Underline(spec.varargs.upper()) + varargs_string = f'[{varargs_underlined}]...' arg_and_flag_strings.append(varargs_string) return ' '.join(arg_and_flag_strings) @@ -401,7 +394,7 @@ def _GetActionsGroupedByKind(component, verbose=False): if component_len < 10: indexes.Add(name=', '.join(str(x) for x in range(component_len))) else: - indexes.Add(name='0..{max}'.format(max=component_len-1)) + indexes.Add(name=f'0..{component_len-1}') return [groups, commands, values, indexes] @@ -416,10 +409,8 @@ def _GetCurrentCommand(trace=None, include_separators=True): def _CreateOutputSection(name, content): - return """{name} -{content}""".format( - name=formatting.Bold(name), - content=formatting.Indent(content, SECTION_INDENTATION)) + return f"""{formatting.Bold(name)} +{formatting.Indent(content, SECTION_INDENTATION)}""" def _CreateArgItem(arg, docstring_info, spec): @@ -430,7 +421,7 @@ def _CreateArgItem(arg, docstring_info, spec): docstring_info: A docstrings.DocstringInfo namedtuple with information about the containing function's docstring. spec: An instance of fire.inspectutils.FullArgSpec, containing type and - default information about the arguments to a callable. + default information about the arguments to a callable. Returns: A string to be used in constructing the help screen for the function. @@ -445,7 +436,7 @@ def _CreateArgItem(arg, docstring_info, spec): arg_string = formatting.BoldUnderline(arg.upper()) arg_type = _GetArgType(arg, spec) - arg_type = 'Type: {}'.format(arg_type) if arg_type else '' + arg_type = f'Type: {arg_type}' if arg_type else '' available_space = max_str_length - len(arg_type) arg_type = ( formatting.EllipsisTruncate(arg_type, available_space, max_str_length)) @@ -484,14 +475,13 @@ def _CreateFlagItem(flag, docstring_info, spec, required=False, description = _GetArgDescription(flag, docstring_info) if not flag_string: - flag_string_template = '--{flag_name}={flag_name_upper}' - flag_string = flag_string_template.format( - flag_name=flag, - flag_name_upper=formatting.Underline(flag.upper())) + flag_name_upper=formatting.Underline(flag.upper()) + flag_string = f'--{flag}={flag_name_upper}' if required: flag_string += ' (required)' if short_arg: - flag_string = '-{short_flag}, '.format(short_flag=flag[0]) + flag_string + short_flag = flag[0] + flag_string = f'-{short_flag}, {flag_string}' arg_type = _GetArgType(flag, spec) arg_default = _GetArgDefault(flag, spec) @@ -499,14 +489,14 @@ def _CreateFlagItem(flag, docstring_info, spec, required=False, # We need to handle the case where there is a default of None, but otherwise # the argument has another type. if arg_default == 'None': - arg_type = 'Optional[{}]'.format(arg_type) + arg_type = f'Optional[{arg_type}]' - arg_type = 'Type: {}'.format(arg_type) if arg_type else '' + arg_type = f'Type: {arg_type}' if arg_type else '' available_space = max_str_length - len(arg_type) arg_type = ( formatting.EllipsisTruncate(arg_type, available_space, max_str_length)) - arg_default = 'Default: {}'.format(arg_default) if arg_default else '' + arg_default = f'Default: {arg_default}' if arg_default else '' available_space = max_str_length - len(arg_default) arg_default = ( formatting.EllipsisTruncate(arg_default, available_space, max_str_length)) @@ -567,15 +557,15 @@ def _GetArgDefault(flag, spec): def _CreateItem(name, description, indent=2): if not description: return name - return """{name} -{description}""".format(name=name, - description=formatting.Indent(description, indent)) + description = formatting.Indent(description, indent) + return f"""{name} +{description}""" def _GetArgDescription(name, docstring_info): if docstring_info.args: for arg_in_docstring in docstring_info.args: - if arg_in_docstring.name in (name, '*' + name, '**' + name): + if arg_in_docstring.name in (name, f'*{name}', f'**{name}'): return arg_in_docstring.description return None @@ -621,9 +611,9 @@ def _ValuesUsageDetailsSection(component, values): def _NewChoicesSection(name, choices): + name_formatted = formatting.Bold(formatting.Underline(name)) return _CreateItem( - '{name} is one of the following:'.format( - name=formatting.Bold(formatting.Underline(name))), + f'{name_formatted} is one of the following:', '\n' + '\n\n'.join(choices), indent=1) @@ -639,11 +629,6 @@ def UsageText(component, trace=None, verbose=False): 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() @@ -687,15 +672,16 @@ def UsageText(component, trace=None, verbose=False): + '--help' ) - return output_template.format( - continued_command=continued_command, - availability_lines=''.join(availability_lines), - help_command=help_command) + return f"""Usage: {continued_command} +{''.join(availability_lines)} +For detailed information on this command, run: + {help_command}""" def _GetPossibleActionsUsageString(possible_actions): if possible_actions: - return '<{actions}>'.format(actions='|'.join(possible_actions)) + actions_str = '|'.join(possible_actions) + return f'<{actions_str}>' return None @@ -704,7 +690,7 @@ def _UsageAvailabilityLines(actions_grouped_by_kind): for action_group in actions_grouped_by_kind: if action_group.members: availability_line = _CreateAvailabilityLine( - header='available {plural}:'.format(plural=action_group.plural), + header=f'available {action_group.plural}:', items=action_group.names ) availability_lines.append(availability_line) @@ -720,7 +706,7 @@ def _GetCallableUsageItems(spec, metadata): accepts_positional_args = metadata.get(decorators.ACCEPTS_POSITIONAL_ARGS) if not accepts_positional_args: - items = ['--{arg}={upper}'.format(arg=arg, upper=arg.upper()) + items = [f'--{arg}={arg.upper()}' for arg in args_with_no_defaults] else: items = [arg.upper() for arg in args_with_no_defaults] @@ -730,7 +716,7 @@ def _GetCallableUsageItems(spec, metadata): items.append('') if spec.varargs: - items.append('[{varargs}]...'.format(varargs=spec.varargs.upper())) + items.append(f'[{spec.varargs.upper()}]...') return items @@ -745,10 +731,10 @@ def _GetCallableAvailabilityLines(spec): args_with_defaults = spec.args[len(spec.args) - len(spec.defaults):] # TODO(dbieber): Handle args_with_no_defaults if not accepts_positional_args. - optional_flags = [('--' + flag) for flag in itertools.chain( + optional_flags = [f'--{flag}' for flag in itertools.chain( args_with_defaults, _KeywordOnlyArguments(spec, required=False))] required_flags = [ - ('--' + flag) for flag in _KeywordOnlyArguments(spec, required=True) + f'--{flag}' for flag in _KeywordOnlyArguments(spec, required=True) ] # Flags section: diff --git a/fire/interact.py b/fire/interact.py index 7bdeb9a7..eccd3990 100644 --- a/fire/interact.py +++ b/fire/interact.py @@ -65,16 +65,17 @@ def _AvailableString(variables, verbose=False): lists = [ ('Modules', modules), ('Objects', other)] - liststrs = [] + list_strs = [] for name, varlist in lists: if varlist: - liststrs.append( - '{name}: {items}'.format(name=name, items=', '.join(sorted(varlist)))) + items_str = ', '.join(sorted(varlist)) + list_strs.append(f'{name}: {items_str}') + lists_str = '\n'.join(list_strs) return ( 'Fire is starting a Python REPL with the following objects:\n' - '{liststrs}\n' - ).format(liststrs='\n'.join(liststrs)) + f'{lists_str}\n' + ) def _EmbedIPython(variables, argv=None): diff --git a/fire/trace.py b/fire/trace.py index 2145186e..68b48ce5 100644 --- a/fire/trace.py +++ b/fire/trace.py @@ -212,10 +212,7 @@ def NeedsSeparator(self): def __str__(self): lines = [] for index, element in enumerate(self.elements): - line = '{index}. {trace_string}'.format( - index=index + 1, - trace_string=element, - ) + line = f'{index + 1}. {element}' lines.append(line) return '\n'.join(lines) @@ -261,7 +258,7 @@ def __init__(self, Args: component: The result of this element of the trace. - action: The type of action (eg instantiating a class) taking place. + action: The type of action (e.g. instantiating a class) taking place. target: (string) The name of the component being acted upon. args: The args consumed by the represented action. filename: The file in which the action is defined, or None if N/A. @@ -301,11 +298,11 @@ def __str__(self): # Format is: {action} "{target}" ({filename}:{lineno}) string = self._action if self._target is not None: - string += ' "{target}"'.format(target=self._target) + string += f' "{self._target}"' if self._filename is not None: path = self._filename if self._lineno is not None: - path += ':{lineno}'.format(lineno=self._lineno) + path += f':{self._lineno}' - string += ' ({path})'.format(path=path) + string += f' ({path})' return string From 93b0e3243b522ae9ab6ebbdc6dcf9a5bb68cc30d Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 23:24:46 -0400 Subject: [PATCH 63/86] Remove six from console, eliminates six entirely (#552) --- fire/console/console_attr.py | 18 ++++++++---------- fire/console/encoding.py | 31 ++++++------------------------- fire/console/files.py | 4 +--- setup.py | 1 - 4 files changed, 15 insertions(+), 39 deletions(-) diff --git a/fire/console/console_attr.py b/fire/console/console_attr.py index 815e16b8..c0a3d784 100644 --- a/fire/console/console_attr.py +++ b/fire/console/console_attr.py @@ -100,8 +100,6 @@ from fire.console import encoding as encoding_util from fire.console import text -import six - # TODO: Unify this logic with console.style.mappings class BoxLineCharacters(object): @@ -355,9 +353,9 @@ def ConvertOutputToUnicode(self, buf): Returns: The console output string buf converted to unicode. """ - if isinstance(buf, six.text_type): + if isinstance(buf, str): buf = buf.encode(self._encoding) - return six.text_type(buf, self._encoding, 'replace') + return str(buf, self._encoding, 'replace') def GetBoxLineCharacters(self): """Returns the box/line drawing characters object. @@ -480,7 +478,7 @@ def DisplayWidth(self, buf): Returns: The display width of buf, handling unicode and ANSI controls. """ - if not isinstance(buf, six.string_types): + if not isinstance(buf, str): # Handle non-string objects like Colorizer(). return len(buf) @@ -595,16 +593,16 @@ def __init__(self, string, color, justify=None): self._justify = justify def __eq__(self, other): - return self._string == six.text_type(other) + return self._string == str(other) def __ne__(self, other): return not self == other def __gt__(self, other): - return self._string > six.text_type(other) + return self._string > str(other) def __lt__(self, other): - return self._string < six.text_type(other) + return self._string < str(other) def __ge__(self, other): return not self < other @@ -692,7 +690,7 @@ def GetCharacterDisplayWidth(char): Returns: The monospaced terminal display width of char: either 0, 1, or 2. """ - if not isinstance(char, six.text_type): + if not isinstance(char, str): # Non-unicode chars have width 1. Don't use this function on control chars. return 1 @@ -779,7 +777,7 @@ def EncodeToBytes(data): return data # Coerce to text that will be converted to bytes. - s = six.text_type(data) + s = str(data) try: # Assume the text can be directly converted to bytes (8-bit ascii). diff --git a/fire/console/encoding.py b/fire/console/encoding.py index 41bda634..0a7fedfc 100644 --- a/fire/console/encoding.py +++ b/fire/console/encoding.py @@ -22,8 +22,6 @@ import sys -import six - def Encode(string, encoding=None): """Encode the text string to a byte string. @@ -35,18 +33,7 @@ def Encode(string, encoding=None): Returns: str, The binary string. """ - if string is None: - return None - if not six.PY2: - # In Python 3, the environment sets and gets accept and return text strings - # only, and it handles the encoding itself so this is not necessary. - return string - if isinstance(string, six.binary_type): - # Already an encoded byte string, we are done - return string - - encoding = encoding or _GetEncoding() - return string.encode(encoding) + return string def Decode(data, encoding=None): @@ -67,20 +54,13 @@ def Decode(data, encoding=None): return None # First we are going to get the data object to be a text string. - # Don't use six.string_types here because on Python 3 bytes is not considered - # a string type and we want to include that. - if isinstance(data, six.text_type) or isinstance(data, six.binary_type): + if isinstance(data, str) or isinstance(data, bytes): string = data else: # Some non-string type of object. - try: - string = six.text_type(data) - except (TypeError, UnicodeError): - # The string cannot be converted to unicode -- default to str() which will - # catch objects with special __str__ methods. - string = str(data) + string = str(data) - if isinstance(string, six.text_type): + if isinstance(string, str): # Our work is done here. return string @@ -199,7 +179,8 @@ def EncodeEnv(env, encoding=None): encoding = encoding or _GetEncoding() return { Encode(k, encoding=encoding): Encode(v, encoding=encoding) - for k, v in six.iteritems(env)} + for k, v in env.items() + } def _GetEncoding(): diff --git a/fire/console/files.py b/fire/console/files.py index 69970f43..97222c3d 100644 --- a/fire/console/files.py +++ b/fire/console/files.py @@ -24,8 +24,6 @@ from fire.console import encoding as encoding_util from fire.console import platforms -import six - def _GetSystemPath(): """Returns properly encoded system PATH variable string.""" @@ -48,7 +46,7 @@ def _FindExecutableOnPath(executable, path, pathext): ValueError: invalid input. """ - if isinstance(pathext, six.string_types): + if isinstance(pathext, str): raise ValueError('_FindExecutableOnPath(..., pathext=\'{0}\') failed ' 'because pathext must be an iterable of strings, but got ' 'a string.'.format(pathext)) diff --git a/setup.py b/setup.py index 53f3381a..82073be4 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,6 @@ A library for automatically generating command line interfaces.""".strip() DEPENDENCIES = [ - 'six', 'termcolor', ] From 5b2dadd7f3912bf8f05e7f1c381631ef5c14cada Mon Sep 17 00:00:00 2001 From: David Bieber Date: Thu, 19 Sep 2024 23:47:19 -0400 Subject: [PATCH 64/86] Move asyncio imports and update docs (#553) --- docs/guide.md | 19 +++++++++++++++++++ fire/core.py | 3 +-- fire/inspectutils.py | 3 +-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index cdc3b2d0..444a76ff 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -589,6 +589,25 @@ default values that you don't want to specify. It is also important to remember to change the separator if you want to pass `-` as an argument. +##### Async Functions + +Fire supports calling async functions too. Here's a simple example. + +```python +import asyncio + +async def count_to_ten(): + for i in range(1, 11): + await asyncio.sleep(1) + print(i) + +if __name__ == '__main__': + fire.Fire(count_to_ten) +``` + +Whenever fire encounters a coroutine function, it runs it, blocking until it completes. + + ### Argument Parsing The types of the arguments are determined by their values, rather than by the diff --git a/fire/core.py b/fire/core.py index e4156760..6cd1907e 100644 --- a/fire/core.py +++ b/fire/core.py @@ -49,6 +49,7 @@ def main(argv): --trace: Get the Fire Trace for the command. """ +import asyncio import inspect import json import os @@ -68,8 +69,6 @@ def main(argv): from fire import value_types from fire.console import console_io -import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error - def Fire(component=None, command=None, name=None, serialize=None): """This function, Fire, is the main entrypoint for Python Fire. diff --git a/fire/inspectutils.py b/fire/inspectutils.py index 0d0b048d..a3ae7c27 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -14,14 +14,13 @@ """Inspection utility functions for Python Fire.""" +import asyncio import inspect import sys import types from fire import docstrings -import asyncio # pylint: disable=import-error,g-import-not-at-top # pytype: disable=import-error - class FullArgSpec(object): """The arguments of a function, as in Python 3's inspect.FullArgSpec.""" From d3204373c4bba38a09db92f910d048222b8d6f0f Mon Sep 17 00:00:00 2001 From: David Bieber Date: Fri, 20 Sep 2024 07:20:04 -0700 Subject: [PATCH 65/86] Include Python 3.13 in github actions (#554) * Include Python 3.13 in github actions list * Include version in supported versions list --- .github/workflows/build.yml | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6649201..63c87edf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13.0-rc.2"] steps: # Checkout the repo. diff --git a/setup.py b/setup.py index 82073be4..beb367cf 100644 --- a/setup.py +++ b/setup.py @@ -67,6 +67,7 @@ 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Operating System :: OS Independent', 'Operating System :: POSIX', From 36a56c0a777d874f30e39412b2877ab171118d54 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 21 Sep 2024 08:04:39 -0700 Subject: [PATCH 66/86] Continue upgrade of codebase to Python 3 (#556) Obtained with pyupgrade, reverting any changes that remove a module we still depend on. `uv run pyupgrade **/**.py --py3-plus` --- fire/__main__.py | 6 ++-- fire/core.py | 2 +- fire/decorators_test.py | 12 +++---- fire/helptext.py | 2 +- fire/helptext_test.py | 2 +- fire/inspectutils.py | 6 ++-- fire/main_test.py | 2 +- fire/parser_fuzz_test.py | 2 +- fire/test_components.py | 66 ++++++++++++++++++------------------- fire/test_components_py3.py | 10 +++--- fire/trace.py | 4 +-- 11 files changed, 57 insertions(+), 57 deletions(-) diff --git a/fire/__main__.py b/fire/__main__.py index 11fb1b42..140b4a76 100644 --- a/fire/__main__.py +++ b/fire/__main__.py @@ -54,14 +54,14 @@ def import_from_file_path(path): """ if not os.path.exists(path): - raise IOError('Given file path does not exist.') + raise OSError('Given file path does not exist.') module_name = os.path.basename(path) spec = util.spec_from_file_location(module_name, path) if spec is None: - raise IOError('Unable to load module from specified path.') + raise OSError('Unable to load module from specified path.') module = util.module_from_spec(spec) # pylint: disable=no-member spec.loader.exec_module(module) # pytype: disable=attribute-error @@ -104,7 +104,7 @@ def import_module(module_or_filename): return import_from_file_path(module_or_filename) if os.path.sep in module_or_filename: # Use / to detect if it was a filename. - raise IOError('Fire was passed a filename which could not be found.') + raise OSError('Fire was passed a filename which could not be found.') return import_from_module_name(module_or_filename) # Assume it's a module. diff --git a/fire/core.py b/fire/core.py index 6cd1907e..26a25753 100644 --- a/fire/core.py +++ b/fire/core.py @@ -199,7 +199,7 @@ def __init__(self, code, component_trace): code: (int) Exit code for the Fire CLI. component_trace: (FireTrace) The trace for the Fire command. """ - super(FireExit, self).__init__(code) + super().__init__(code) self.trace = component_trace diff --git a/fire/decorators_test.py b/fire/decorators_test.py index a316b79f..9988743c 100644 --- a/fire/decorators_test.py +++ b/fire/decorators_test.py @@ -19,7 +19,7 @@ from fire import testutils -class NoDefaults(object): +class NoDefaults: """A class for testing decorated functions without default values.""" @decorators.SetParseFns(count=int) @@ -40,7 +40,7 @@ def double(count): return 2 * count -class WithDefaults(object): +class WithDefaults: @decorators.SetParseFns(float) def example1(self, arg1=10): @@ -51,14 +51,14 @@ def example2(self, arg1=10): return arg1, type(arg1) -class MixedArguments(object): +class MixedArguments: @decorators.SetParseFns(float, arg2=str) def example3(self, arg1, arg2): return arg1, arg2 -class PartialParseFn(object): +class PartialParseFn: @decorators.SetParseFns(arg1=str) def example4(self, arg1, arg2): @@ -69,7 +69,7 @@ def example5(self, arg1, arg2): return arg1, arg2 -class WithKwargs(object): +class WithKwargs: @decorators.SetParseFns(mode=str, count=int) def example6(self, **kwargs): @@ -79,7 +79,7 @@ def example6(self, **kwargs): ) -class WithVarArgs(object): +class WithVarArgs: @decorators.SetParseFn(str) def example7(self, arg1, arg2=None, *varargs, **kwargs): # pylint: disable=keyword-arg-before-vararg diff --git a/fire/helptext.py b/fire/helptext.py index e57eb7d8..9b578fac 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -767,7 +767,7 @@ def _CreateAvailabilityLine(header, items, return indented_header + indented_items_text[len(indented_header):] + '\n' -class ActionGroup(object): +class ActionGroup: """A group of actions of the same kind.""" def __init__(self, name, plural): diff --git a/fire/helptext_test.py b/fire/helptext_test.py index 4d35dc0a..d1a3f368 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -27,7 +27,7 @@ class HelpTest(testutils.BaseTestCase): def setUp(self): - super(HelpTest, self).setUp() + super().setUp() os.environ['ANSI_COLORS_DISABLED'] = '1' def testHelpTextNoDefaults(self): diff --git a/fire/inspectutils.py b/fire/inspectutils.py index a3ae7c27..d1438972 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -22,7 +22,7 @@ from fire import docstrings -class FullArgSpec(object): +class FullArgSpec: """The arguments of a function, as in Python 3's inspect.FullArgSpec.""" def __init__(self, args=None, varargs=None, varkw=None, defaults=None, @@ -229,7 +229,7 @@ def GetFileAndLine(component): try: unused_code, lineindex = inspect.findsource(component) lineno = lineindex + 1 - except (IOError, IndexError): + except (OSError, IndexError): lineno = None return filename, lineno @@ -268,7 +268,7 @@ def Info(component): try: unused_code, lineindex = inspect.findsource(component) info['line'] = lineindex + 1 - except (TypeError, IOError): + except (TypeError, OSError): info['line'] = None if 'docstring' in info: diff --git a/fire/main_test.py b/fire/main_test.py index a0184620..a2723347 100644 --- a/fire/main_test.py +++ b/fire/main_test.py @@ -43,7 +43,7 @@ class MainModuleFileTest(testutils.BaseTestCase): """Tests to verify correct import behavior for file executables.""" def setUp(self): - super(MainModuleFileTest, self).setUp() + super().setUp() self.file = tempfile.NamedTemporaryFile(suffix='.py') # pylint: disable=consider-using-with self.file.write(b'class Foo:\n def double(self, n):\n return 2 * n\n') self.file.flush() diff --git a/fire/parser_fuzz_test.py b/fire/parser_fuzz_test.py index 9739ec4e..10f497cf 100644 --- a/fire/parser_fuzz_test.py +++ b/fire/parser_fuzz_test.py @@ -53,7 +53,7 @@ def testDefaultParseValueFuzz(self, value): result = parser.DefaultParseValue(value) except TypeError: # It's OK to get a TypeError if the string has the null character. - if u'\x00' in value: + if '\x00' in value: return raise except MemoryError: diff --git a/fire/test_components.py b/fire/test_components.py index eb3a9e24..2dc4e0cc 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -43,7 +43,7 @@ def function_with_help(help=True): # pylint: disable=redefined-builtin return help -class Empty(object): +class Empty: pass @@ -51,20 +51,20 @@ class OldStyleEmpty: # pylint: disable=old-style-class,no-init pass -class WithInit(object): +class WithInit: def __init__(self): pass -class ErrorInConstructor(object): +class ErrorInConstructor: def __init__(self, value='value'): self.value = value raise ValueError('Error in constructor') -class WithHelpArg(object): +class WithHelpArg: """Test class for testing when class has a help= arg.""" def __init__(self, help=True): # pylint: disable=redefined-builtin @@ -72,7 +72,7 @@ def __init__(self, help=True): # pylint: disable=redefined-builtin self.dictionary = {'__help': 'help in a dict'} -class NoDefaults(object): +class NoDefaults: def double(self, count): return 2 * count @@ -81,7 +81,7 @@ def triple(self, count): return 3 * count -class WithDefaults(object): +class WithDefaults: """Class with functions that have default arguments.""" def double(self, count=0): @@ -115,7 +115,7 @@ def triple(self, count=0): return 3 * count -class MixedDefaults(object): +class MixedDefaults: def ten(self): return 10 @@ -127,7 +127,7 @@ def identity(self, alpha, beta='0'): return alpha, beta -class SimilarArgNames(object): +class SimilarArgNames: def identity(self, bool_one=False, bool_two=False): return bool_one, bool_two @@ -136,13 +136,13 @@ def identity2(self, a=None, alpha=None): return a, alpha -class CapitalizedArgNames(object): +class CapitalizedArgNames: def sum(self, Delta=1.0, Gamma=2.0): # pylint: disable=invalid-name return Delta + Gamma -class Annotations(object): +class Annotations: def double(self, count=0): return 2 * count @@ -154,7 +154,7 @@ def triple(self, count=0): triple.__annotations__ = {'count': float} -class TypedProperties(object): +class TypedProperties: """Test class for testing Python Fire with properties of various types.""" def __init__(self): @@ -173,7 +173,7 @@ def __init__(self): self.gamma = 'myexcitingstring' -class VarArgs(object): +class VarArgs: """Test class for testing Python Fire with a property with varargs.""" def cumsums(self, *items): @@ -191,7 +191,7 @@ def varchars(self, alpha=0, beta=0, *chars): # pylint: disable=keyword-arg-befo return alpha, beta, ''.join(chars) -class Underscores(object): +class Underscores: def __init__(self): self.underscore_example = 'fish fingers' @@ -200,20 +200,20 @@ def underscore_function(self, underscore_arg): return underscore_arg -class BoolConverter(object): +class BoolConverter: def as_bool(self, arg=False): return bool(arg) -class ReturnsObj(object): +class ReturnsObj: def get_obj(self, *items): del items # Unused return BoolConverter() -class NumberDefaults(object): +class NumberDefaults: def reciprocal(self, divisor=10.0): return 1.0 / divisor @@ -222,7 +222,7 @@ def integer_reciprocal(self, divisor=10): return 1.0 / divisor -class InstanceVars(object): +class InstanceVars: def __init__(self, arg1, arg2): self.arg1 = arg1 @@ -232,7 +232,7 @@ def run(self, arg1, arg2): return (self.arg1, self.arg2, arg1, arg2) -class Kwargs(object): +class Kwargs: def props(self, **kwargs): return kwargs @@ -244,13 +244,13 @@ def run(self, positional, named=None, **kwargs): return (positional, named, kwargs) -class ErrorRaiser(object): +class ErrorRaiser: def fail(self): raise ValueError('This error is part of a test.') -class NonComparable(object): +class NonComparable: def __eq__(self, other): raise ValueError('Instances of this class cannot be compared.') @@ -259,7 +259,7 @@ def __ne__(self, other): raise ValueError('Instances of this class cannot be compared.') -class EmptyDictOutput(object): +class EmptyDictOutput: def totally_empty(self): return {} @@ -268,7 +268,7 @@ def nothing_printable(self): return {'__do_not_print_me': 1} -class CircularReference(object): +class CircularReference: def create(self): x = {} @@ -276,7 +276,7 @@ def create(self): return x -class OrderedDictionary(object): +class OrderedDictionary: def empty(self): return collections.OrderedDict() @@ -288,7 +288,7 @@ def non_empty(self): return ordered_dict -class NamedTuple(object): +class NamedTuple: """Functions returning named tuples used for testing.""" def point(self): @@ -304,7 +304,7 @@ def matching_names(self): return Point(x='x', y='y') -class CallableWithPositionalArgs(object): +class CallableWithPositionalArgs: """Test class for supporting callable.""" TEST = 1 @@ -326,12 +326,12 @@ def coordinate_sum(self): return self.x + self.y -class CallableWithKeywordArgument(object): +class CallableWithKeywordArgument: """Test class for supporting callable.""" def __call__(self, **kwargs): for key, value in kwargs.items(): - print('%s: %s' % (key, value)) + print('{}: {}'.format(key, value)) def print_msg(self, msg): print(msg) @@ -340,7 +340,7 @@ def print_msg(self, msg): CALLABLE_WITH_KEYWORD_ARGUMENT = CallableWithKeywordArgument() -class ClassWithDocstring(object): +class ClassWithDocstring: """Test class for testing help text output. This is some detail description of this test class. @@ -363,7 +363,7 @@ def print_msg(self, msg=None): print(msg) -class ClassWithMultilineDocstring(object): +class ClassWithMultilineDocstring: """Test class for testing help text output with multiline docstring. This is a test class that has a long docstring description that spans across @@ -413,7 +413,7 @@ class Color(enum.Enum): BLUE = 3 -class HasStaticAndClassMethods(object): +class HasStaticAndClassMethods: """A class with a static method and a class method.""" CLASS_STATE = 1 @@ -467,7 +467,7 @@ def fn_with_code_in_docstring(): return True -class BinaryCanvas(object): +class BinaryCanvas: """A canvas with which to make binary art, one bit at a time.""" def __init__(self, size=10): @@ -500,7 +500,7 @@ def set(self, value): return self -class DefaultMethod(object): +class DefaultMethod: def double(self, number): return 2 * number @@ -511,7 +511,7 @@ def _missing(): return _missing -class InvalidProperty(object): +class InvalidProperty: def double(self, number): return 2 * number diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index 17fb932c..192302d3 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -31,7 +31,7 @@ def identity(self, *, alpha, beta='0'): return alpha, beta -class KeywordOnly(object): +class KeywordOnly: def double(self, *, count): return count * 2 @@ -43,7 +43,7 @@ def with_default(self, *, x="x"): print("x: " + x) -class LruCacheDecoratedMethod(object): +class LruCacheDecoratedMethod: @functools.lru_cache() def lru_cache_in_class(self, arg1): @@ -55,13 +55,13 @@ def lru_cache_decorated(arg1): return arg1 -class WithAsyncio(object): +class WithAsyncio: async def double(self, count=0): return 2 * count -class WithTypes(object): +class WithTypes: """Class with functions that have default arguments and types.""" def double(self, count: float) -> float: @@ -83,7 +83,7 @@ def long_type( return long_obj -class WithDefaultsAndTypes(object): +class WithDefaultsAndTypes: """Class with functions that have default arguments and types.""" def double(self, count: float = 0) -> float: diff --git a/fire/trace.py b/fire/trace.py index 68b48ce5..3a75cc9c 100644 --- a/fire/trace.py +++ b/fire/trace.py @@ -38,7 +38,7 @@ INTERACTIVE_MODE = 'Entered interactive mode' -class FireTrace(object): +class FireTrace: """A FireTrace represents the steps taken during a single Fire execution. A FireTrace consists of a sequence of FireTraceElement objects. Each element @@ -238,7 +238,7 @@ def NeedsSeparatingHyphenHyphen(self, flag='help'): or flag in spec.kwonlyargs) -class FireTraceElement(object): +class FireTraceElement: """A FireTraceElement represents a single step taken by a Fire execution. Examples of a FireTraceElement are the instantiation of a class or the From 8227364f113fcaf8661290fa3bb0c79741ff3be7 Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Sat, 21 Sep 2024 17:09:24 +0200 Subject: [PATCH 67/86] Update required Python 3.7 in `setup.py` (#555) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index beb367cf..8d4a381b 100644 --- a/setup.py +++ b/setup.py @@ -77,6 +77,7 @@ keywords='command line interface cli python fire interactive bash tool', + requires_python='>=3.7', packages=['fire', 'fire.console'], install_requires=DEPENDENCIES, From 1c43c36174feb7020e7c5a5c53f3a47bc8e368c8 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 21 Sep 2024 08:12:09 -0700 Subject: [PATCH 68/86] Bump version number in __init__ to setup.py --- fire/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/__init__.py b/fire/__init__.py index 742b03ac..9ff696d3 100644 --- a/fire/__init__.py +++ b/fire/__init__.py @@ -17,4 +17,4 @@ from fire.core import Fire __all__ = ['Fire'] -__version__ = '0.6.0' +__version__ = '0.7.0' From efcf60f7f8202d9887b9da16e4ff81a554b9d023 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 21 Sep 2024 08:45:04 -0700 Subject: [PATCH 69/86] Lint improvements and type safety (#558) * Clean up of lint errors * Always return an element when requested --- fire/console/encoding.py | 1 + fire/decorators.py | 2 +- fire/formatting_windows.py | 2 +- fire/helptext.py | 2 +- fire/helptext_test.py | 1 - fire/test_components.py | 3 ++- fire/trace.py | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fire/console/encoding.py b/fire/console/encoding.py index 0a7fedfc..3ce30cb5 100644 --- a/fire/console/encoding.py +++ b/fire/console/encoding.py @@ -33,6 +33,7 @@ def Encode(string, encoding=None): Returns: str, The binary string. """ + del encoding # Unused. return string diff --git a/fire/decorators.py b/fire/decorators.py index eb5b0d20..2758b0aa 100644 --- a/fire/decorators.py +++ b/fire/decorators.py @@ -107,5 +107,5 @@ def GetMetadata(fn): def GetParseFns(fn): # type: (...) -> dict metadata = GetMetadata(fn) - default = {"default": None, "positional": [], "named": {}} + default = {'default': None, 'positional': [], 'named': {}} return metadata.get(FIRE_PARSE_FNS, default) diff --git a/fire/formatting_windows.py b/fire/formatting_windows.py index f8241eaa..cee6f393 100644 --- a/fire/formatting_windows.py +++ b/fire/formatting_windows.py @@ -31,7 +31,7 @@ def initialize_or_disable(): """Enables ANSI processing on Windows or disables it as needed.""" if HAS_COLORAMA: wrap = True - if (hasattr(sys.stdout, "isatty") + if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() and platform.release() == '10'): # Enables native ANSI sequences in console. diff --git a/fire/helptext.py b/fire/helptext.py index 9b578fac..318d6276 100644 --- a/fire/helptext.py +++ b/fire/helptext.py @@ -475,7 +475,7 @@ def _CreateFlagItem(flag, docstring_info, spec, required=False, description = _GetArgDescription(flag, docstring_info) if not flag_string: - flag_name_upper=formatting.Underline(flag.upper()) + flag_name_upper = formatting.Underline(flag.upper()) flag_string = f'--{flag}={flag_name_upper}' if required: flag_string += ' (required)' diff --git a/fire/helptext_test.py b/fire/helptext_test.py index d1a3f368..aeff5240 100644 --- a/fire/helptext_test.py +++ b/fire/helptext_test.py @@ -428,7 +428,6 @@ def testHelpTextMultipleKeywoardArgumentsWithShortArgs(self): self.assertIn('\n --late', help_screen) - class UsageTest(testutils.BaseTestCase): def testUsageOutput(self): diff --git a/fire/test_components.py b/fire/test_components.py index 2dc4e0cc..887a0dc6 100644 --- a/fire/test_components.py +++ b/fire/test_components.py @@ -554,7 +554,7 @@ def fn_with_kwarg_and_defaults(arg1, arg2, opt=True, **kwargs): """ del arg1, arg2, opt return kwargs.get('arg3') -# pylint: enable=g-doc-args,g-doc-return-or-yield + def fn_with_multiple_defaults(first='first', last='last', late='late'): """Function with kwarg and defaults. @@ -565,3 +565,4 @@ def fn_with_multiple_defaults(first='first', last='last', late='late'): """ del last, late return first +# pylint: enable=g-doc-args,g-doc-return-or-yield diff --git a/fire/trace.py b/fire/trace.py index 3a75cc9c..4a6d4776 100644 --- a/fire/trace.py +++ b/fire/trace.py @@ -77,7 +77,7 @@ def GetLastHealthyElement(self): for element in reversed(self.elements): if not element.HasError(): return element - return None + return self.elements[0] # The initial element is always healthy. def HasError(self): """Returns whether the Fire execution encountered a Fire usage error.""" From a0cb1ca3c2697ea7f5f1f7314353f1c7e920088f Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Sun, 22 Sep 2024 18:00:15 +0200 Subject: [PATCH 70/86] Expand build matrix to include mac (#490) * Expand build matrix to include mac (#490) --------- Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: David Bieber --- .github/workflows/build.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 63c87edf..59b0a4ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,18 +2,23 @@ name: Python Fire on: push: - branches: - - master + branches: ["master"] pull_request: - branches: - - master + branches: ["master"] + +defaults: + run: + shell: bash jobs: build: - runs-on: ubuntu-20.04 + runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13.0-rc.2"] + os: ["macos-latest", "ubuntu-latest"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13.0-rc.2"] + include: + - {os: "ubuntu-20.04", python-version: "3.7"} steps: # Checkout the repo. @@ -28,7 +33,6 @@ jobs: # Build Python Fire using the build.sh script. - name: Run build script - shell: bash run: ./.github/scripts/build.sh env: PYTHON_VERSION: ${{ matrix.python-version }} From 90b7f824f2e760e6363b0d10c52b1940346a0fa6 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sun, 22 Sep 2024 09:14:50 -0700 Subject: [PATCH 71/86] Replace Python 2 type hints with real type annotations (#559) * Replace Python 2 type hints with real type annotations --- CONTRIBUTING.md | 3 --- fire/decorators.py | 7 +++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index baae1a6e..b5d67c96 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,12 +40,9 @@ In addition, the project follows a convention of: - Maximum line length: 80 characters - Indentation: 2 spaces (4 for line continuation) - PascalCase for function and method names. -- No type hints, as described in [PEP 484], to maintain compatibility with -Python versions < 3.5. - Single quotes around strings, three double quotes around docstrings. [Google Python Style Guide]: http://google.github.io/styleguide/pyguide.html -[PEP 484]: https://www.python.org/dev/peps/pep-0484 ## Testing diff --git a/fire/decorators.py b/fire/decorators.py index 2758b0aa..914b1de6 100644 --- a/fire/decorators.py +++ b/fire/decorators.py @@ -18,6 +18,7 @@ command line arguments to client code. """ +from typing import Any, Dict import inspect FIRE_METADATA = 'FIRE_METADATA' @@ -80,8 +81,7 @@ def _SetMetadata(fn, attribute, value): setattr(fn, FIRE_METADATA, metadata) -def GetMetadata(fn): - # type: (...) -> dict +def GetMetadata(fn) -> Dict[str, Any]: """Gets metadata attached to the function `fn` as an attribute. Args: @@ -104,8 +104,7 @@ def GetMetadata(fn): return default -def GetParseFns(fn): - # type: (...) -> dict +def GetParseFns(fn) -> Dict[str, Any]: metadata = GetMetadata(fn) default = {'default': None, 'positional': [], 'named': {}} return metadata.get(FIRE_PARSE_FNS, default) From 8feb04a5936ba7b94e96430cc04f6f4b9ba8170c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:34:19 -0400 Subject: [PATCH 72/86] Update pylint requirement from <3.2.8 to <3.3.2 in /.github/scripts (#562) Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - [Release notes](https://github.com/pylint-dev/pylint/releases) - [Commits](https://github.com/pylint-dev/pylint/compare/pylint-version-0.18.1...v3.3.1) --- updated-dependencies: - dependency-name: pylint dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index a5648989..0b32ac05 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,6 +1,6 @@ setuptools <=75.1.0 pip -pylint <3.2.8 +pylint <3.3.2 pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 From 0aff6b9452080a1fe53bf8537b5e71bd04986c24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 13:56:00 -0400 Subject: [PATCH 73/86] Update hypothesis requirement in /.github/scripts (#566) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.116.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 0b32ac05..5c947b3e 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,5 +5,5 @@ pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.5.0 -hypothesis <6.113.0 +hypothesis <6.117.0 levenshtein <=0.26.0 From dfa1071b7a9aee0ca1538dc4e08236c0c5dedda4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 14:09:07 -0400 Subject: [PATCH 74/86] Update termcolor requirement from <2.5.0 to <2.6.0 in /.github/scripts (#569) Updates the requirements on [termcolor](https://github.com/termcolor/termcolor) to permit the latest version. - [Release notes](https://github.com/termcolor/termcolor/releases) - [Changelog](https://github.com/termcolor/termcolor/blob/main/CHANGES.md) - [Commits](https://github.com/termcolor/termcolor/compare/0.1...2.5.0) --- updated-dependencies: - dependency-name: termcolor dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 5c947b3e..6147fcbb 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -4,6 +4,6 @@ pylint <3.3.2 pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 -termcolor <2.5.0 +termcolor <2.6.0 hypothesis <6.117.0 levenshtein <=0.26.0 From 98d7fbce9c93a6b0c3b209a8ed1144cd233decc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 14:14:29 -0400 Subject: [PATCH 75/86] Update setuptools requirement in /.github/scripts (#567) Updates the requirements on [setuptools](https://github.com/pypa/setuptools) to permit the latest version. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/0.6...v75.3.0) --- updated-dependencies: - dependency-name: setuptools dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 6147fcbb..6df54e28 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,4 +1,4 @@ -setuptools <=75.1.0 +setuptools <=75.3.0 pip pylint <3.3.2 pytest <=8.3.3 From c3b4474ea42c2f5330ee28fea7a9fc31e4c59451 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 18:49:46 -0400 Subject: [PATCH 76/86] Update levenshtein requirement in /.github/scripts (#568) Updates the requirements on [levenshtein](https://github.com/rapidfuzz/Levenshtein) to permit the latest version. - [Release notes](https://github.com/rapidfuzz/Levenshtein/releases) - [Changelog](https://github.com/rapidfuzz/Levenshtein/blob/main/HISTORY.md) - [Commits](https://github.com/rapidfuzz/Levenshtein/compare/v0.13.0...v0.26.1) --- updated-dependencies: - dependency-name: levenshtein dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 6df54e28..cf8a3420 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -6,4 +6,4 @@ pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.6.0 hypothesis <6.117.0 -levenshtein <=0.26.0 +levenshtein <=0.26.1 From deb25efee883191f9dac1cec579d3f96f1e32226 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:52:02 -0500 Subject: [PATCH 77/86] Update setuptools requirement in /.github/scripts (#573) Updates the requirements on [setuptools](https://github.com/pypa/setuptools) to permit the latest version. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/0.6...v75.6.0) --- updated-dependencies: - dependency-name: setuptools dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index cf8a3420..0480a001 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,4 +1,4 @@ -setuptools <=75.3.0 +setuptools <=75.6.0 pip pylint <3.3.2 pytest <=8.3.3 From 6cf45c663075c96b20dd0dfa733c2374545a4ad6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:53:58 -0500 Subject: [PATCH 78/86] Update hypothesis requirement in /.github/scripts (#574) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.122.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 0480a001..958c6248 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,5 +5,5 @@ pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.6.0 -hypothesis <6.117.0 +hypothesis <6.123.0 levenshtein <=0.26.1 From 2e0867d3371db9db6e95fad7f82d58ccb894d94c Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sun, 23 Mar 2025 14:43:44 -0400 Subject: [PATCH 79/86] Use Neutral theme for Inspector (#588) * Use Neutral theme for Inspector * Catch when theme_name not available --- fire/inspectutils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fire/inspectutils.py b/fire/inspectutils.py index d1438972..06c30ef1 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -256,7 +256,10 @@ def Info(component): """ try: from IPython.core import oinspect # pylint: disable=import-outside-toplevel,g-import-not-at-top - inspector = oinspect.Inspector() + try: + inspector = oinspect.Inspector(theme_name="Neutral") + except TypeError: # Only recent versions of IPython support theme_name. + inspector = oinspect.Inspector() info = inspector.info(component) # IPython's oinspect.Inspector.info may return '' From 45152e18255e5c5803f3805604eb738c50befeff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 19:34:56 -0400 Subject: [PATCH 80/86] Update pylint requirement from <3.3.2 to <3.3.5 in /.github/scripts (#581) Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - [Release notes](https://github.com/pylint-dev/pylint/releases) - [Commits](https://github.com/pylint-dev/pylint/compare/pylint-version-0.18.1...v3.3.4) --- updated-dependencies: - dependency-name: pylint dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 958c6248..5810abf5 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,6 +1,6 @@ setuptools <=75.6.0 pip -pylint <3.3.2 +pylint <3.3.5 pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 From 525708c3d7bcfc36a71e23694f09d0b587a7bf72 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Mon, 14 Apr 2025 14:40:30 -0400 Subject: [PATCH 81/86] Use lowercase neutral instead of upper (#596) --- fire/inspectutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fire/inspectutils.py b/fire/inspectutils.py index 06c30ef1..d9c62ca7 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -257,7 +257,7 @@ def Info(component): try: from IPython.core import oinspect # pylint: disable=import-outside-toplevel,g-import-not-at-top try: - inspector = oinspect.Inspector(theme_name="Neutral") + inspector = oinspect.Inspector(theme_name="neutral") except TypeError: # Only recent versions of IPython support theme_name. inspector = oinspect.Inspector() info = inspector.info(component) From c5ab602240a160902986e48db8980d59338be944 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 14:40:45 -0400 Subject: [PATCH 82/86] Update hypothesis requirement in /.github/scripts (#594) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.130.6) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.130.6 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 5810abf5..b922f04a 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,5 +5,5 @@ pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.6.0 -hypothesis <6.123.0 +hypothesis <6.131.0 levenshtein <=0.26.1 From 8527235d18835223dad5055e29d50664ab5bfb2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 14:41:02 -0400 Subject: [PATCH 83/86] Update setuptools requirement in /.github/scripts (#593) Updates the requirements on [setuptools](https://github.com/pypa/setuptools) to permit the latest version. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/0.6...v78.1.0) --- updated-dependencies: - dependency-name: setuptools dependency-version: 78.1.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index b922f04a..8db34c71 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,4 +1,4 @@ -setuptools <=75.6.0 +setuptools <=78.1.0 pip pylint <3.3.5 pytest <=8.3.3 From fb01c7c619eda3107c7e32c42370573f6f63f33c Mon Sep 17 00:00:00 2001 From: David Bieber Date: Wed, 21 May 2025 12:23:08 -0700 Subject: [PATCH 84/86] Call inspectutils.GetClassAttrsDict on component, not None (#606) * inspectutils.GetClassAttrsDict on component, not None * Remove ubuntu-20.04 in favor of ubuntu-22.04 for Python 3.7 --- .github/workflows/build.yml | 2 +- fire/completion.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 59b0a4ba..75a687f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: os: ["macos-latest", "ubuntu-latest"] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13.0-rc.2"] include: - - {os: "ubuntu-20.04", python-version: "3.7"} + - {os: "ubuntu-22.04", python-version: "3.7"} steps: # Checkout the repo. diff --git a/fire/completion.py b/fire/completion.py index 625e9d86..1597d464 100644 --- a/fire/completion.py +++ b/fire/completion.py @@ -321,7 +321,7 @@ def MemberVisible(component, name, member, class_attrs=None, verbose=False): if inspect.isclass(component): # If class_attrs has not been provided, compute it. if class_attrs is None: - class_attrs = inspectutils.GetClassAttrsDict(class_attrs) or {} + class_attrs = inspectutils.GetClassAttrsDict(component) or {} class_attr = class_attrs.get(name) if class_attr: # Methods and properties should only be accessible on instantiated From 51974c67bf72ac649ed28015d960884712bcbc0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:23:37 -0700 Subject: [PATCH 85/86] Update pylint requirement from <3.3.5 to <3.3.7 in /.github/scripts (#591) Updates the requirements on [pylint](https://github.com/pylint-dev/pylint) to permit the latest version. - [Release notes](https://github.com/pylint-dev/pylint/releases) - [Commits](https://github.com/pylint-dev/pylint/compare/pylint-version-0.18.1...v3.3.6) --- updated-dependencies: - dependency-name: pylint dependency-version: 3.3.6 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 8db34c71..82b1be4a 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,6 +1,6 @@ setuptools <=78.1.0 pip -pylint <3.3.5 +pylint <3.3.7 pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 From dba7e1d0da014e555d174225fdf5ab4c4574b18b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 10:55:56 -0400 Subject: [PATCH 86/86] Update hypothesis requirement in /.github/scripts (#608) Updates the requirements on [hypothesis](https://github.com/HypothesisWorks/hypothesis) to permit the latest version. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-ruby-0.0.1...hypothesis-python-6.132.0) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.132.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 82b1be4a..613c4da0 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,5 +5,5 @@ pytest <=8.3.3 pytest-pylint <=1.1.2 pytest-runner <7.0.0 termcolor <2.6.0 -hypothesis <6.131.0 +hypothesis <6.133.0 levenshtein <=0.26.1