From 05f6a6e884c1fb235012694f415d45af6511855c 2023-04-18 13:30:11 From: Matthias Bussonnier Date: 2023-04-18 13:30:11 Subject: [PATCH] MAINT: remove support and testing on Python 3.8 According to NEP 29 it is now time to remove support for Python 3.8 This commit removes support for Python 3.8 from the codebase, as well as removing the tests for Python 3.8 from the CI workflow. It also updates the `pyproject.toml` file to reflect the removal of Python 3.8 support. --- diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 82a1535..2708082 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,12 +19,12 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11"] deps: [test_extra] # Test all on ubuntu, test ends on macos include: - os: macos-latest - python-version: "3.8" + python-version: "3.9" deps: test_extra - os: macos-latest python-version: "3.11" @@ -39,13 +39,13 @@ jobs: deps: test # Installing optional dependencies stuff takes ages on PyPy - os: ubuntu-latest - python-version: "pypy-3.8" + python-version: "pypy-3.9" deps: test - os: windows-latest - python-version: "pypy-3.8" + python-version: "pypy-3.9" deps: test - os: macos-latest - python-version: "pypy-3.8" + python-version: "pypy-3.9" deps: test steps: diff --git a/IPython/__init__.py b/IPython/__init__.py index e930dfc..3322562 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -26,10 +26,11 @@ import sys #----------------------------------------------------------------------------- # Don't forget to also update setup.py when this changes! -if sys.version_info < (3, 8): +if sys.version_info < (3, 9): raise ImportError( """ -IPython 8+ supports Python 3.8 and above, following NEP 29. +IPython 8.13+ supports Python 3.9 and above, following NEP 29. +IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29. When using Python 2.7, please install IPython 5.x LTS Long Term Support version. Python 3.3 and 3.4 were supported up to IPython 6.x. Python 3.5 was supported with IPython 7.0 to 7.9. diff --git a/IPython/core/guarded_eval.py b/IPython/core/guarded_eval.py index 3c95213..66d598b 100644 --- a/IPython/core/guarded_eval.py +++ b/IPython/core/guarded_eval.py @@ -508,9 +508,6 @@ def eval_node(node: Union[ast.AST, None], context: EvaluationContext): return all_true if isinstance(node, ast.Constant): return node.value - if isinstance(node, ast.Index): - # deprecated since Python 3.9 - return eval_node(node.value, context) # pragma: no cover if isinstance(node, ast.Tuple): return tuple(eval_node(e, context) for e in node.elts) if isinstance(node, ast.List): @@ -530,9 +527,6 @@ def eval_node(node: Union[ast.AST, None], context: EvaluationContext): eval_node(node.upper, context), eval_node(node.step, context), ) - if isinstance(node, ast.ExtSlice): - # deprecated since Python 3.9 - return tuple([eval_node(dim, context) for dim in node.dims]) # pragma: no cover if isinstance(node, ast.UnaryOp): value = eval_node(node.operand, context) dunders = _find_dunder(node.op, UNARY_OP_DUNDERS) diff --git a/IPython/core/tests/test_async_helpers.py b/IPython/core/tests/test_async_helpers.py index 40a840c..a326c98 100644 --- a/IPython/core/tests/test_async_helpers.py +++ b/IPython/core/tests/test_async_helpers.py @@ -276,12 +276,12 @@ class AsyncTest(TestCase): """ ) - if sys.version_info < (3, 9) and platform.python_implementation() != "PyPy": - # new pgen parser in 3.9 does not raise MemoryError on too many nested - # parens anymore - def test_memory_error(self): - with self.assertRaises(MemoryError): - iprc("(" * 200 + ")" * 200) + def test_memory_error(self): + """ + The pgen parser in 3.8 or before use to raise MemoryError on too many + nested parens anymore""" + + iprc("(" * 200 + ")" * 200) @skip_without('curio') def test_autoawait_curio(self): diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index b55062d..c99044e 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -713,12 +713,10 @@ class TestModules(tt.TempFileMixin): class Negator(ast.NodeTransformer): """Negates all number literals in an AST.""" - # for python 3.7 and earlier def visit_Num(self, node): node.n = -node.n return node - # for python 3.8+ def visit_Constant(self, node): if isinstance(node.value, int): return self.visit_Num(node) @@ -900,7 +898,6 @@ class StringRejector(ast.NodeTransformer): not be executed by throwing an InputRejected. """ - # 3.8 only def visit_Constant(self, node): if isinstance(node.value, str): raise InputRejected("test") diff --git a/IPython/core/tests/test_iplib.py b/IPython/core/tests/test_iplib.py index c5e0650..a5e51fb 100644 --- a/IPython/core/tests/test_iplib.py +++ b/IPython/core/tests/test_iplib.py @@ -166,93 +166,48 @@ def doctest_tb_sysexit(): """ -if sys.version_info >= (3, 9): - if SV_VERSION < (0, 6): - - def doctest_tb_sysexit_verbose_stack_data_05(): - """ - In [18]: %run simpleerr.py exit - An exception has occurred, use %tb to see the full traceback. - SystemExit: (1, 'Mode = exit') - - In [19]: %run simpleerr.py exit 2 - An exception has occurred, use %tb to see the full traceback. - SystemExit: (2, 'Mode = exit') - - In [23]: %xmode verbose - Exception reporting mode: Verbose - - In [24]: %tb - --------------------------------------------------------------------------- - SystemExit Traceback (most recent call last) - - ... - 30 except IndexError: - 31 mode = 'div' - ---> 33 bar(mode) - mode = 'exit' - - ... in bar(mode='exit') - ... except: - ... stat = 1 - ---> ... sysexit(stat, mode) - mode = 'exit' - stat = 2 - ... else: - ... raise ValueError('Unknown mode') - - ... in sysexit(stat=2, mode='exit') - 10 def sysexit(stat, mode): - ---> 11 raise SystemExit(stat, f"Mode = {mode}") - stat = 2 - - SystemExit: (2, 'Mode = exit') - """ - - else: - # currently the only difference is - # + mode = 'exit' - - def doctest_tb_sysexit_verbose_stack_data_06(): - """ - In [18]: %run simpleerr.py exit - An exception has occurred, use %tb to see the full traceback. - SystemExit: (1, 'Mode = exit') - - In [19]: %run simpleerr.py exit 2 - An exception has occurred, use %tb to see the full traceback. - SystemExit: (2, 'Mode = exit') - - In [23]: %xmode verbose - Exception reporting mode: Verbose - - In [24]: %tb - --------------------------------------------------------------------------- - SystemExit Traceback (most recent call last) - - ... - 30 except IndexError: - 31 mode = 'div' - ---> 33 bar(mode) - mode = 'exit' - - ... in bar(mode='exit') - ... except: - ... stat = 1 - ---> ... sysexit(stat, mode) - mode = 'exit' - stat = 2 - ... else: - ... raise ValueError('Unknown mode') - - ... in sysexit(stat=2, mode='exit') - 10 def sysexit(stat, mode): - ---> 11 raise SystemExit(stat, f"Mode = {mode}") - stat = 2 - mode = 'exit' - - SystemExit: (2, 'Mode = exit') - """ +if SV_VERSION < (0, 6): + + def doctest_tb_sysexit_verbose_stack_data_05(): + """ + In [18]: %run simpleerr.py exit + An exception has occurred, use %tb to see the full traceback. + SystemExit: (1, 'Mode = exit') + + In [19]: %run simpleerr.py exit 2 + An exception has occurred, use %tb to see the full traceback. + SystemExit: (2, 'Mode = exit') + + In [23]: %xmode verbose + Exception reporting mode: Verbose + + In [24]: %tb + --------------------------------------------------------------------------- + SystemExit Traceback (most recent call last) + + ... + 30 except IndexError: + 31 mode = 'div' + ---> 33 bar(mode) + mode = 'exit' + + ... in bar(mode='exit') + ... except: + ... stat = 1 + ---> ... sysexit(stat, mode) + mode = 'exit' + stat = 2 + ... else: + ... raise ValueError('Unknown mode') + + ... in sysexit(stat=2, mode='exit') + 10 def sysexit(stat, mode): + ---> 11 raise SystemExit(stat, f"Mode = {mode}") + stat = 2 + + SystemExit: (2, 'Mode = exit') + """ + def test_run_cell(): import textwrap diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index fd325c5..fa0c694 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -568,20 +568,12 @@ def test_render_signature_long(): signature(long_function), long_function.__name__, ) - if sys.version_info >= (3, 9): - expected = """\ + expected = """\ long_function( a_really_long_parameter: int, and_another_long_one: bool = False, let_us_make_sure_this_is_looong: Optional[str] = None, ) -> bool\ """ - else: - expected = """\ -long_function( - a_really_long_parameter: int, - and_another_long_one: bool = False, - let_us_make_sure_this_is_looong: Union[str, NoneType] = None, -) -> bool\ -""" + assert sig == expected diff --git a/IPython/core/tests/test_ultratb.py b/IPython/core/tests/test_ultratb.py index 349d2ac..d8c969a 100644 --- a/IPython/core/tests/test_ultratb.py +++ b/IPython/core/tests/test_ultratb.py @@ -244,15 +244,14 @@ bar() import sys -if sys.version_info < (3, 9) and platform.python_implementation() != "PyPy": +if platform.python_implementation() != "PyPy": """ New 3.9 Pgen Parser does not raise Memory error, except on failed malloc. """ class MemoryErrorTest(unittest.TestCase): def test_memoryerror(self): memoryerror_code = "(" * 200 + ")" * 200 - with tt.AssertPrints("MemoryError"): - ip.run_cell(memoryerror_code) + ip.run_cell(memoryerror_code) class Python3ChainedExceptionsTest(unittest.TestCase): diff --git a/appveyor.yml b/appveyor.yml index 7637841..ec18b4b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,8 +8,8 @@ environment: COLUMNS: 120 # Appveyor web viewer window width is 130 chars matrix: - - PYTHON: "C:\\Python38" - PYTHON_VERSION: "3.8.x" + - PYTHON: "C:\\Python39" + PYTHON_VERSION: "3.9.x" PYTHON_ARCH: "32" init: diff --git a/pyproject.toml b/pyproject.toml index 8d4e4a6..f7287d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ requires = ["setuptools >= 51.0.0"] build-backend = "setuptools.build_meta" [tool.mypy] -python_version = 3.8 +python_version = 3.9 ignore_missing_imports = true follow_imports = 'silent' exclude = [ diff --git a/setup.py b/setup.py index 3f7cd6d..2b3359f 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ import sys # # This check is also made in IPython/__init__, don't forget to update both when # changing Python version requirements. -if sys.version_info < (3, 8): +if sys.version_info < (3, 9): pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.' try: import pip @@ -39,7 +39,8 @@ if sys.version_info < (3, 8): error = """ -IPython 8+ supports Python 3.8 and above, following NEP 29. +IPython 8.13+ supports Python 3.8 and above, following NEP 29. +IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29. When using Python 2.7, please install IPython 5.x LTS Long Term Support version. Python 3.3 and 3.4 were supported up to IPython 6.x. Python 3.5 was supported with IPython 7.0 to 7.9.