##// END OF EJS Templates
Drop Python 3.10 (#14589)
M Bussonnier -
r28984:f32e1b2a merge
parent child Browse files
Show More
@@ -19,10 +19,10 jobs:
19 strategy:
19 strategy:
20 matrix:
20 matrix:
21 os: [ubuntu-latest]
21 os: [ubuntu-latest]
22 python-version: ["3.10"]
22 python-version: ["3.13"]
23 include:
23 include:
24 - os: macos-13
24 - os: macos-13
25 python-version: "3.10"
25 python-version: "3.13"
26
26
27 steps:
27 steps:
28 - uses: actions/checkout@v4
28 - uses: actions/checkout@v4
@@ -17,7 +17,7 jobs:
17 - name: Set up Python
17 - name: Set up Python
18 uses: actions/setup-python@v5
18 uses: actions/setup-python@v5
19 with:
19 with:
20 python-version: "3.10"
20 python-version: "3.13"
21 cache: pip
21 cache: pip
22 cache-dependency-path: |
22 cache-dependency-path: |
23 pyproject.toml
23 pyproject.toml
@@ -21,14 +21,11 jobs:
21 fail-fast: false
21 fail-fast: false
22 matrix:
22 matrix:
23 os: [ubuntu-latest, windows-latest]
23 os: [ubuntu-latest, windows-latest]
24 python-version: ["3.10", "3.11", "3.12","3.13"]
24 python-version: ["3.11", "3.12","3.13"]
25 deps: [test_extra]
25 deps: [test_extra]
26 # Test all on ubuntu, test ends on macos
26 # Test all on ubuntu, test ends on macos
27 include:
27 include:
28 - os: macos-latest
28 - os: macos-latest
29 python-version: "3.10"
30 deps: test_extra
31 - os: macos-latest
32 python-version: "3.11"
29 python-version: "3.11"
33 deps: test_extra
30 deps: test_extra
34 # Tests minimal dependencies set
31 # Tests minimal dependencies set
@@ -40,15 +37,15 jobs:
40 python-version: "3.13"
37 python-version: "3.13"
41 deps: test
38 deps: test
42 # Installing optional dependencies stuff takes ages on PyPy
39 # Installing optional dependencies stuff takes ages on PyPy
43 - os: ubuntu-latest
40 # - os: ubuntu-latest
44 python-version: "pypy-3.10"
41 # python-version: "pypy-3.11"
45 deps: test
42 # deps: test
46 - os: windows-latest
43 # - os: windows-latest
47 python-version: "pypy-3.10"
44 # python-version: "pypy-3.11"
48 deps: test
45 # deps: test
49 - os: macos-latest
46 # - os: macos-latest
50 python-version: "pypy-3.10"
47 # python-version: "pypy-3.11"
51 deps: test
48 # deps: test
52 # Temporary CI run to use entry point compatible code in matplotlib-inline.
49 # Temporary CI run to use entry point compatible code in matplotlib-inline.
53 - os: ubuntu-latest
50 - os: ubuntu-latest
54 python-version: "3.12"
51 python-version: "3.12"
@@ -88,7 +85,7 jobs:
88 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
85 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
89 run: check-manifest
86 run: check-manifest
90
87
91 - name: Install entry point compatible code (TEMPORARY)
88 - name: Install entry point compatible code (TEMPORARY, April 2024)
92 if: matrix.want-latest-entry-point-code
89 if: matrix.want-latest-entry-point-code
93 run: |
90 run: |
94 python -m pip list
91 python -m pip list
@@ -26,9 +26,10 import sys
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 # Don't forget to also update setup.py when this changes!
28 # Don't forget to also update setup.py when this changes!
29 if sys.version_info < (3, 10):
29 if sys.version_info < (3, 11):
30 raise ImportError(
30 raise ImportError(
31 """
31 """
32 IPython 8.31+ supports Python 3.11 and above, following SPEC0
32 IPython 8.19+ supports Python 3.10 and above, following SPEC0.
33 IPython 8.19+ supports Python 3.10 and above, following SPEC0.
33 IPython 8.13+ supports Python 3.9 and above, following NEP 29.
34 IPython 8.13+ supports Python 3.9 and above, following NEP 29.
34 IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
35 IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
@@ -243,6 +243,14 from traitlets.config.configurable import Configurable
243
243
244 import __main__
244 import __main__
245
245
246 from typing import cast
247
248 if sys.version_info < (3, 12):
249 from typing_extensions import TypedDict, NotRequired, Protocol, TypeAlias, TypeGuard
250 else:
251 from typing import TypedDict, NotRequired, Protocol, TypeAlias, TypeGuard
252
253
246 # skip module docstests
254 # skip module docstests
247 __skip_doctest__ = True
255 __skip_doctest__ = True
248
256
@@ -257,25 +265,6 except ImportError:
257 JEDI_INSTALLED = False
265 JEDI_INSTALLED = False
258
266
259
267
260 if TYPE_CHECKING or GENERATING_DOCUMENTATION and sys.version_info >= (3, 11):
261 from typing import cast
262 from typing_extensions import TypedDict, NotRequired, Protocol, TypeAlias, TypeGuard
263 else:
264 from typing import Generic
265
266 def cast(type_, obj):
267 """Workaround for `TypeError: MatcherAPIv2() takes no arguments`"""
268 return obj
269
270 # do not require on runtime
271 NotRequired = Tuple # requires Python >=3.11
272 TypedDict = Dict # by extension of `NotRequired` requires 3.11 too
273 Protocol = object # requires Python >=3.8
274 TypeAlias = Any # requires Python >=3.10
275 TypeGuard = Generic # requires Python >=3.10
276 if GENERATING_DOCUMENTATION:
277 from typing import TypedDict
278
279 # -----------------------------------------------------------------------------
268 # -----------------------------------------------------------------------------
280 # Globals
269 # Globals
281 #-----------------------------------------------------------------------------
270 #-----------------------------------------------------------------------------
@@ -31,9 +31,6 from types import MethodDescriptorType, ModuleType
31 from IPython.utils.decorators import undoc
31 from IPython.utils.decorators import undoc
32
32
33
33
34 if sys.version_info < (3, 11):
35 from typing_extensions import Self, LiteralString
36 else:
37 from typing import Self, LiteralString
34 from typing import Self, LiteralString
38
35
39 if sys.version_info < (3, 12):
36 if sys.version_info < (3, 12):
@@ -149,8 +149,6 try:
149 except ImportError:
149 except ImportError:
150 sphinxify = None
150 sphinxify = None
151
151
152 if sys.version_info[:2] < (3, 11):
153 from exceptiongroup import BaseExceptionGroup
154
152
155 class ProvisionalWarning(DeprecationWarning):
153 class ProvisionalWarning(DeprecationWarning):
156 """
154 """
@@ -13,7 +13,6 def _exceptiongroup_common(
13 native: bool,
13 native: bool,
14 ) -> None:
14 ) -> None:
15 pre_raise = "exceptiongroup." if not native else ""
15 pre_raise = "exceptiongroup." if not native else ""
16 pre_catch = pre_raise if sys.version_info < (3, 11) else ""
17 filestr = f"""
16 filestr = f"""
18 {"import exceptiongroup" if not native else ""}
17 {"import exceptiongroup" if not native else ""}
19 import pytest
18 import pytest
@@ -42,7 +41,7 def _exceptiongroup_common(
42 def outer(outer_chain, inner_chain):
41 def outer(outer_chain, inner_chain):
43 try:
42 try:
44 inner(inner_chain)
43 inner(inner_chain)
45 except {pre_catch}BaseExceptionGroup as e:
44 except BaseExceptionGroup as e:
46 if outer_chain == "none":
45 if outer_chain == "none":
47 raise
46 raise
48 if outer_chain == "from":
47 if outer_chain == "from":
@@ -68,7 +67,7 def _exceptiongroup_common(
68
67
69 match_lines += [
68 match_lines += [
70 " + Exception Group Traceback (most recent call last):",
69 " + Exception Group Traceback (most recent call last):",
71 f" | {pre_catch}BaseExceptionGroup: Oops (2 sub-exceptions)",
70 " | BaseExceptionGroup: Oops (2 sub-exceptions)",
72 " | ValueError: From f()",
71 " | ValueError: From f()",
73 " | BaseException: From g()",
72 " | BaseException: From g()",
74 ]
73 ]
@@ -96,9 +95,6 def _exceptiongroup_common(
96 assert False, f"{expected} not found in cap.stderr"
95 assert False, f"{expected} not found in cap.stderr"
97
96
98
97
99 @pytest.mark.skipif(
100 sys.version_info < (3, 11), reason="Native ExceptionGroup not implemented"
101 )
102 @pytest.mark.parametrize("outer_chain", ["none", "from", "another"])
98 @pytest.mark.parametrize("outer_chain", ["none", "from", "another"])
103 @pytest.mark.parametrize("inner_chain", ["none", "from", "another"])
99 @pytest.mark.parametrize("inner_chain", ["none", "from", "another"])
104 def test_native_exceptiongroup(outer_chain, inner_chain) -> None:
100 def test_native_exceptiongroup(outer_chain, inner_chain) -> None:
@@ -23,9 +23,6 from IPython.testing import decorators as dec
23 import pytest
23 import pytest
24
24
25
25
26 if sys.version_info < (3, 11):
27 from typing_extensions import Self, LiteralString
28 else:
29 from typing import Self, LiteralString
26 from typing import Self, LiteralString
30
27
31 if sys.version_info < (3, 12):
28 if sys.version_info < (3, 12):
@@ -320,12 +320,6 class InputSplitterTestCase(unittest.TestCase):
320 self.isp.push(u'\xc3\xa9')
320 self.isp.push(u'\xc3\xa9')
321 self.isp.push(u"u'\xc3\xa9'")
321 self.isp.push(u"u'\xc3\xa9'")
322
322
323 @pytest.mark.xfail(
324 reason="Bug in python 3.9.8 – bpo 45738",
325 condition=sys.version_info in [(3, 11, 0, "alpha", 2)],
326 raises=SystemError,
327 strict=True,
328 )
329 def test_line_continuation(self):
323 def test_line_continuation(self):
330 """ Test issue #2108."""
324 """ Test issue #2108."""
331 isp = self.isp
325 isp = self.isp
@@ -314,17 +314,7 examples = [
314 pytest.param("\\\r\n", "incomplete", 0),
314 pytest.param("\\\r\n", "incomplete", 0),
315 pytest.param("a = '''\n hi", "incomplete", 3),
315 pytest.param("a = '''\n hi", "incomplete", 3),
316 pytest.param("def a():\n x=1\n global x", "invalid", None),
316 pytest.param("def a():\n x=1\n global x", "invalid", None),
317 pytest.param(
317 pytest.param("a \\ ", "invalid", None), # Nothing allowed after backslash,
318 "a \\ ",
319 "invalid",
320 None,
321 marks=pytest.mark.xfail(
322 reason="Bug in python 3.9.8 – bpo 45738",
323 condition=sys.version_info in [(3, 11, 0, "alpha", 2)],
324 raises=SystemError,
325 strict=True,
326 ),
327 ), # Nothing allowed after backslash,
328 pytest.param("1\\\n+2", "complete", None),
318 pytest.param("1\\\n+2", "complete", None),
329 ]
319 ]
330
320
@@ -336,12 +326,6 def test_check_complete_param(code, expected, number):
336
326
337
327
338 @pytest.mark.xfail(platform.python_implementation() == "PyPy", reason="fail on pypy")
328 @pytest.mark.xfail(platform.python_implementation() == "PyPy", reason="fail on pypy")
339 @pytest.mark.xfail(
340 reason="Bug in python 3.9.8 – bpo 45738",
341 condition=sys.version_info in [(3, 11, 0, "alpha", 2)],
342 raises=SystemError,
343 strict=True,
344 )
345 def test_check_complete():
329 def test_check_complete():
346 cc = ipt2.TransformerManager().check_complete
330 cc = ipt2.TransformerManager().check_complete
347
331
@@ -76,14 +76,9 def foo(self, args):
76
76
77
77
78 def test_magic_arguments():
78 def test_magic_arguments():
79 # “optional arguments” was replaced with “options” in argparse help
80 # https://docs.python.org/3/whatsnew/3.10.html#argparse
81 # https://bugs.python.org/issue9694
82 options = "optional arguments" if sys.version_info < (3, 10) else "options"
83
84 assert (
79 assert (
85 magic_foo1.__doc__
80 magic_foo1.__doc__
86 == f"::\n\n %foo1 [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
81 == f"::\n\n %foo1 [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\noptions:\n -f FOO, --foo FOO an argument\n"
87 )
82 )
88 assert getattr(magic_foo1, "argcmd_name", None) == None
83 assert getattr(magic_foo1, "argcmd_name", None) == None
89 assert real_name(magic_foo1) == "foo1"
84 assert real_name(magic_foo1) == "foo1"
@@ -98,7 +93,7 def test_magic_arguments():
98
93
99 assert (
94 assert (
100 magic_foo3.__doc__
95 magic_foo3.__doc__
101 == f"::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n{LEADING_SPACE}A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n"
96 == f"::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n{LEADING_SPACE}A docstring.\n\noptions:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n"
102 )
97 )
103 assert getattr(magic_foo3, "argcmd_name", None) == None
98 assert getattr(magic_foo3, "argcmd_name", None) == None
104 assert real_name(magic_foo3) == "foo3"
99 assert real_name(magic_foo3) == "foo3"
@@ -107,7 +102,7 def test_magic_arguments():
107
102
108 assert (
103 assert (
109 magic_foo4.__doc__
104 magic_foo4.__doc__
110 == f"::\n\n %foo4 [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
105 == f"::\n\n %foo4 [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\noptions:\n -f FOO, --foo FOO an argument\n"
111 )
106 )
112 assert getattr(magic_foo4, "argcmd_name", None) == None
107 assert getattr(magic_foo4, "argcmd_name", None) == None
113 assert real_name(magic_foo4) == "foo4"
108 assert real_name(magic_foo4) == "foo4"
@@ -116,7 +111,7 def test_magic_arguments():
116
111
117 assert (
112 assert (
118 magic_foo5.__doc__
113 magic_foo5.__doc__
119 == f"::\n\n %frobnicate [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
114 == f"::\n\n %frobnicate [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\noptions:\n -f FOO, --foo FOO an argument\n"
120 )
115 )
121 assert getattr(magic_foo5, "argcmd_name", None) == "frobnicate"
116 assert getattr(magic_foo5, "argcmd_name", None) == "frobnicate"
122 assert real_name(magic_foo5) == "frobnicate"
117 assert real_name(magic_foo5) == "frobnicate"
@@ -125,7 +120,7 def test_magic_arguments():
125
120
126 assert (
121 assert (
127 magic_magic_foo.__doc__
122 magic_magic_foo.__doc__
128 == f"::\n\n %magic_foo [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
123 == f"::\n\n %magic_foo [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\noptions:\n -f FOO, --foo FOO an argument\n"
129 )
124 )
130 assert getattr(magic_magic_foo, "argcmd_name", None) == None
125 assert getattr(magic_magic_foo, "argcmd_name", None) == None
131 assert real_name(magic_magic_foo) == "magic_foo"
126 assert real_name(magic_magic_foo) == "magic_foo"
@@ -134,7 +129,7 def test_magic_arguments():
134
129
135 assert (
130 assert (
136 foo.__doc__
131 foo.__doc__
137 == f"::\n\n %foo [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
132 == f"::\n\n %foo [-f FOO]\n\n{LEADING_SPACE}A docstring.\n\noptions:\n -f FOO, --foo FOO an argument\n"
138 )
133 )
139 assert getattr(foo, "argcmd_name", None) == None
134 assert getattr(foo, "argcmd_name", None) == None
140 assert real_name(foo) == "foo"
135 assert real_name(foo) == "foo"
@@ -141,9 +141,7 def test_pprint_heap_allocated_type():
141 Test that pprint works for heap allocated types.
141 Test that pprint works for heap allocated types.
142 """
142 """
143 module_name = "xxlimited_35"
143 module_name = "xxlimited_35"
144 expected_output = (
144 expected_output = "xxlimited_35.Null"
145 "xxlimited.Null" if sys.version_info < (3, 10, 6) else "xxlimited_35.Null"
146 )
147 xxlimited = pytest.importorskip(module_name)
145 xxlimited = pytest.importorskip(module_name)
148 output = pretty.pretty(xxlimited.Null)
146 output = pretty.pretty(xxlimited.Null)
149 assert output == expected_output
147 assert output == expected_output
@@ -19,10 +19,7
19 import sys, os
19 import sys, os
20 from pathlib import Path
20 from pathlib import Path
21
21
22 if sys.version_info > (3, 11):
23 import tomllib
22 import tomllib
24 else:
25 import tomli as tomllib
26
23
27 with open("./sphinx.toml", "rb") as f:
24 with open("./sphinx.toml", "rb") as f:
28 config = tomllib.load(f)
25 config = tomllib.load(f)
@@ -20,11 +20,10 classifiers = [
20 "Programming Language :: Python :: 3 :: Only",
20 "Programming Language :: Python :: 3 :: Only",
21 "Topic :: System :: Shells",
21 "Topic :: System :: Shells",
22 ]
22 ]
23 requires-python = ">=3.10"
23 requires-python = ">=3.11"
24 dependencies = [
24 dependencies = [
25 'colorama; sys_platform == "win32"',
25 'colorama; sys_platform == "win32"',
26 "decorator",
26 "decorator",
27 "exceptiongroup; python_version<'3.11'",
28 "jedi>=0.16",
27 "jedi>=0.16",
29 "matplotlib-inline",
28 "matplotlib-inline",
30 'pexpect>4.3; sys_platform != "win32" and sys_platform != "emscripten"',
29 'pexpect>4.3; sys_platform != "win32" and sys_platform != "emscripten"',
@@ -71,8 +70,6 doc = [
71 "sphinx-rtd-theme",
70 "sphinx-rtd-theme",
72 "sphinx>=1.3",
71 "sphinx>=1.3",
73 "sphinxcontrib-jquery",
72 "sphinxcontrib-jquery",
74 "tomli ; python_version<'3.11'",
75 "typing_extensions",
76 ]
73 ]
77 kernel = [
74 kernel = [
78 "ipykernel",
75 "ipykernel",
@@ -23,7 +23,7 import sys
23 #
23 #
24 # This check is also made in IPython/__init__, don't forget to update both when
24 # This check is also made in IPython/__init__, don't forget to update both when
25 # changing Python version requirements.
25 # changing Python version requirements.
26 if sys.version_info < (3, 10):
26 if sys.version_info < (3, 11):
27 pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.'
27 pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.'
28 try:
28 try:
29 import pip
29 import pip
@@ -39,18 +39,10 if sys.version_info < (3, 10):
39
39
40
40
41 error = """
41 error = """
42 (information not available for more recent version of IPython)
42 IPython 8.19+ supports Python 3.10 and above, following SPEC0
43 IPython 8.19+ supports Python 3.10 and above, following SPEC0
43 IPython 8.13+ supports Python 3.9 and above, following NEP 29.
44 IPython 8.13+ supports Python 3.9 and above, following NEP 29.
44 IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
45 IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
45 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
46 Python 3.3 and 3.4 were supported up to IPython 6.x.
47 Python 3.5 was supported with IPython 7.0 to 7.9.
48 Python 3.6 was supported with IPython up to 7.16.
49 Python 3.7 was still supported with the 7.x branch.
50
51 See IPython `README.rst` file for more information:
52
53 https://github.com/ipython/ipython/blob/main/README.rst
54
46
55 Python {py} detected.
47 Python {py} detected.
56 {pip}
48 {pip}
General Comments 0
You need to be logged in to leave comments. Login now