From ed8b824f4ba109da85a23501b93d6450eef97112 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 11:43:24 -0500 Subject: [PATCH 01/16] Add Python 3.11 and Python 3.12 to build workflow --- .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 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. From 55d1237b2f1aa10863a12ed2793f2885e63d5857 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 11:59:45 -0500 Subject: [PATCH 02/16] Use different versions of levenshtein for different Python versions --- .github/scripts/requirements.txt | 5 +++-- fire/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 9e48e20d..578455e4 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -6,5 +6,6 @@ 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/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/setup.py b/setup.py index 8e95f414..3e5cc3b7 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( From 5a46a976e51673d8a953e6a225145c1b6df2577c Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:01:54 -0500 Subject: [PATCH 03/16] Vary setuptools version by Python version --- .github/scripts/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 578455e4..d80030ec 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,4 +1,5 @@ -setuptools <65.7.0 +setuptools <65.7.0 ; python_version == '2.7' +setuptools <=69.1.1 ; python_version >= '3.8' pip <23.0 pylint <2.15.10 pytest <=7.2.1 From 90cdb7b440b2a58b44471d72a524f4897d1280df Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:06:09 -0500 Subject: [PATCH 04/16] Vary pip version by Python version --- .github/scripts/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index d80030ec..de15c3aa 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,6 +1,7 @@ setuptools <65.7.0 ; python_version == '2.7' setuptools <=69.1.1 ; python_version >= '3.8' -pip <23.0 +pip <23.0 ; python_version == '2.7' +pip ; python_version >= '3.7' pylint <2.15.10 pytest <=7.2.1 pytest-pylint <=1.1.2 From 4d72c43dc8571bb6a3f66becff0bc801f6f050a1 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:13:15 -0500 Subject: [PATCH 05/16] Line length in formatting_windows.py --- .github/scripts/requirements.txt | 2 +- fire/formatting_windows.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index de15c3aa..13880c9c 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -1,7 +1,7 @@ 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.7' +pip ; python_version >= '3.5' pylint <2.15.10 pytest <=7.2.1 pytest-pylint <=1.1.2 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. From 350c583061cea092931fe29e5f4637c67b619100 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:17:14 -0500 Subject: [PATCH 06/16] Ignore linter errors --- fire/__main__.py | 2 +- pylintrc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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] From 1b2f85a5f27b4b18ddd7ffed5f884558a464db5d Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:20:00 -0500 Subject: [PATCH 07/16] Remove IsCoroutineFunction --- fire/core.py | 6 +----- fire/inspectutils.py | 7 ------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/fire/core.py b/fire/core.py index 6367262d..89fcf7f9 100644 --- a/fire/core.py +++ b/fire/core.py @@ -686,11 +686,7 @@ def _CallAndUpdateTrace(component, args, component_trace, treatment='class', (varargs, kwargs), consumed_args, remaining_args, capacity = parse(args) # Call the function. - if inspectutils.IsCoroutineFunction(fn): - loop = asyncio.get_event_loop() - component = loop.run_until_complete(fn(*varargs, **kwargs)) - else: - component = fn(*varargs, **kwargs) + component = fn(*varargs, **kwargs) if treatment == 'class': action = trace.INSTANTIATED_CLASS diff --git a/fire/inspectutils.py b/fire/inspectutils.py index 0fa8e7d3..84bc2650 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -363,10 +363,3 @@ def GetClassAttrsDict(component): class_attr.name: class_attr for class_attr in class_attrs_list } - - -def IsCoroutineFunction(fn): - try: - return six.PY34 and asyncio.iscoroutinefunction(fn) - except: # pylint: disable=bare-except - return False From 612cedb7ac7e01ca27630b2abe17e4019ee64381 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:25:30 -0500 Subject: [PATCH 08/16] Disable async test temporarily --- fire/fire_test.py | 7 ++++--- fire/test_components_py3.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fire/fire_test.py b/fire/fire_test.py index 8b904c29..2184db12 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -721,9 +721,10 @@ 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, + @testutils.skip("Temporarily disabling this test.") + @testutils.skipIf(six.PY2, 'async not available in Python 2.') + def testFireAsync(self): + self.assertEqual(fire.Fire(tc.py3.WithAsync, command=['double', '--count', '10']), 20) diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index 17fb932c..8f4bc618 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -55,7 +55,7 @@ def lru_cache_decorated(arg1): return arg1 -class WithAsyncio(object): +class WithAsync(object): async def double(self, count=0): return 2 * count From f0672f2e478ff1317a24d9a3f2c7547def45d820 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:30:05 -0500 Subject: [PATCH 09/16] Undo asyncio changes --- fire/core.py | 6 +++++- fire/fire_test.py | 5 ++--- fire/inspectutils.py | 7 +++++++ fire/test_components_py3.py | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/fire/core.py b/fire/core.py index 89fcf7f9..6367262d 100644 --- a/fire/core.py +++ b/fire/core.py @@ -686,7 +686,11 @@ def _CallAndUpdateTrace(component, args, component_trace, treatment='class', (varargs, kwargs), consumed_args, remaining_args, capacity = parse(args) # Call the function. - component = fn(*varargs, **kwargs) + if inspectutils.IsCoroutineFunction(fn): + loop = asyncio.get_event_loop() + component = loop.run_until_complete(fn(*varargs, **kwargs)) + else: + component = fn(*varargs, **kwargs) if treatment == 'class': action = trace.INSTANTIATED_CLASS diff --git a/fire/fire_test.py b/fire/fire_test.py index 2184db12..c41c31f0 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -721,10 +721,9 @@ def testHelpKwargsDecorator(self): with self.assertRaisesFireExit(0): fire.Fire(tc.decorated_method, command=['--help']) - @testutils.skip("Temporarily disabling this test.") - @testutils.skipIf(six.PY2, 'async not available in Python 2.') + @testutils.skipIf(six.PY2, 'Asyncio not available in Python 2.') def testFireAsync(self): - self.assertEqual(fire.Fire(tc.py3.WithAsync, + self.assertEqual(fire.Fire(tc.py3.WithAsyncio, command=['double', '--count', '10']), 20) diff --git a/fire/inspectutils.py b/fire/inspectutils.py index 84bc2650..0fa8e7d3 100644 --- a/fire/inspectutils.py +++ b/fire/inspectutils.py @@ -363,3 +363,10 @@ def GetClassAttrsDict(component): class_attr.name: class_attr for class_attr in class_attrs_list } + + +def IsCoroutineFunction(fn): + try: + return six.PY34 and asyncio.iscoroutinefunction(fn) + except: # pylint: disable=bare-except + return False diff --git a/fire/test_components_py3.py b/fire/test_components_py3.py index 8f4bc618..17fb932c 100644 --- a/fire/test_components_py3.py +++ b/fire/test_components_py3.py @@ -55,7 +55,7 @@ def lru_cache_decorated(arg1): return arg1 -class WithAsync(object): +class WithAsyncio(object): async def double(self, count=0): return 2 * count From c737a96bfb715e0f870354695975925e8d364dec Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:32:09 -0500 Subject: [PATCH 10/16] Disable no-member for assertRaisesRegexp already guarded by version check --- fire/fire_test.py | 2 +- fire/testutils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fire/fire_test.py b/fire/fire_test.py index c41c31f0..8b904c29 100644 --- a/fire/fire_test.py +++ b/fire/fire_test.py @@ -722,7 +722,7 @@ def testHelpKwargsDecorator(self): fire.Fire(tc.decorated_method, command=['--help']) @testutils.skipIf(six.PY2, 'Asyncio not available in Python 2.') - def testFireAsync(self): + def testFireAsyncio(self): self.assertEqual(fire.Fire(tc.py3.WithAsyncio, command=['double', '--count', '10']), 20) 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 From 8201c52c434359277a208945ba0b07fdc643172a Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:33:04 -0500 Subject: [PATCH 11/16] Disable no-member for getargspec already guarded by version check --- fire/inspectutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 9f08bba6b42b92e1766987cfb108a37fedbcac2c Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:45:12 -0500 Subject: [PATCH 12/16] Attempt to restore testing of Python 2.7 --- .github/workflows/build.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb510f03..0b64d50a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,18 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: ["3.5", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + include: + - python-version: "3.5" + - python-version: "3.7" + - python-version: "3.8" + - python-version: "3.9" + - python-version: "3.10" + - python-version: "3.11" + - python-version: "3.12" + - python-version: "2.7" + container: python:2.7.18-buster + + container: ${{ matrix.container }} steps: # Checkout the repo. From 4b83232a03702df66ad1cb3ae4a87f5745d92012 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:50:59 -0500 Subject: [PATCH 13/16] Set image for 2.7 --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b64d50a..51dd2496 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,9 @@ jobs: strategy: matrix: include: + - python-version: "2.7" + container: + image: python:2.7.18-buster - python-version: "3.5" - python-version: "3.7" - python-version: "3.8" @@ -15,8 +18,6 @@ jobs: - python-version: "3.10" - python-version: "3.11" - python-version: "3.12" - - python-version: "2.7" - container: python:2.7.18-buster container: ${{ matrix.container }} From 37b2174bb58c481e2f532860420537f83705089f Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:53:43 -0500 Subject: [PATCH 14/16] Set image for 2.7 --- .github/workflows/build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51dd2496..35dc6412 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,8 +19,6 @@ jobs: - python-version: "3.11" - python-version: "3.12" - container: ${{ matrix.container }} - steps: # Checkout the repo. - name: Checkout Python Fire repository @@ -31,6 +29,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + container: ${{ matrix.container }} # Build Python Fire using the build.sh script. - name: Run build script From e4d8fb13bf17d6f358e5a1810f0dc332f7ea2d91 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 12:58:12 -0500 Subject: [PATCH 15/16] Remove 2.7 again --- .github/workflows/build.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 35dc6412..eb510f03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,17 +7,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - include: - - python-version: "2.7" - container: - image: python:2.7.18-buster - - python-version: "3.5" - - python-version: "3.7" - - python-version: "3.8" - - python-version: "3.9" - - python-version: "3.10" - - python-version: "3.11" - - python-version: "3.12" + python-version: ["3.5", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: # Checkout the repo. @@ -29,7 +19,6 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - container: ${{ matrix.container }} # Build Python Fire using the build.sh script. - name: Run build script From c74e17cf6299b106ffbf684f9048d55d833cabe2 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Sat, 24 Feb 2024 13:01:46 -0500 Subject: [PATCH 16/16] Add Python 3.11 and Python 3.12 to setup.py; disable=attribute-error --- fire/console/encoding.py | 12 ++++++------ setup.py | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) 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/setup.py b/setup.py index 3e5cc3b7..24e0e325 100644 --- a/setup.py +++ b/setup.py @@ -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',