Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,18 @@ jobs:
include:
# Make sure to run mypyc compiled unit tests for both
# the oldest and newest supported Python versions
- name: Test suite with py39-ubuntu, mypyc-compiled
python: '3.9'
os: ubuntu-24.04-arm
toxenv: py
tox_extra_args: "-n 4"
test_mypyc: true
- name: Test suite with py310-ubuntu
- name: Test suite with py310-ubuntu, mypyc-compiled
python: '3.10'
os: ubuntu-24.04-arm
toxenv: py
tox_extra_args: "-n 4"
test_mypyc: true
- name: Test suite with py311-ubuntu
python: '3.11'
os: ubuntu-24.04-arm
toxenv: py
tox_extra_args: "-n 4"
- name: Test suite with py312-ubuntu, mypyc-compiled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be removed, is there a reason to do so?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far we've tested a subset of versions with mypyc-compiled and without. In particular

  • The oldest and latest supported versions with mypyc
  • Often the second and third oldest without => that's what I'm doing here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should also change the test_mypyc: true

- name: Test suite with py312-ubuntu
python: '3.12'
os: ubuntu-24.04-arm
toxenv: py
Expand Down Expand Up @@ -101,12 +96,12 @@ jobs:
# tox_extra_args: "-n 4 mypyc/test/test_run.py mypyc/test/test_external.py"
# debug_build: true

- name: Type check our own code (py39-ubuntu)
python: '3.9'
- name: Type check our own code (py310-ubuntu)
python: '3.10'
os: ubuntu-latest
toxenv: type
- name: Type check our own code (py39-windows-64)
python: '3.9'
- name: Type check our own code (py310-windows-64)
python: '3.10'
os: windows-latest
toxenv: type

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test_stubgenc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ jobs:
with:
persist-credentials: false

- name: Setup 🐍 3.9
- name: Setup 🐍 3.10
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: '3.10'

- name: Test stubgenc
run: misc/test-stubgenc.sh
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Next Release

### Drop Support for Python 3.9

Mypy no longer supports running with Python 3.9, which has reached end-of-life.
When running mypy with Python 3.10+, it is still possible to type check code
that needs to support Python 3.9 with the `--python-version 3.9` argument.
Support for this will be dropped in the first half of 2026!

Contributed by Marc Mueller (PR [20156](https://github.com/python/mypy/pull/20156)).
Comment on lines +5 to +12
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reused the changelog entry from dropping Python 3.8 here. Just adjusted the numbers :)


## Mypy 1.18.1

We’ve just uploaded mypy 1.18.1 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)).
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ hash -r # This resets shell PATH cache, not necessary on Windows
```

> **Note**
> You'll need Python 3.9 or higher to install all requirements listed in
> You'll need Python 3.10 or higher to install all requirements listed in
> test-requirements.txt

### Running tests
Expand Down
2 changes: 1 addition & 1 deletion docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ may not make much sense otherwise.
Installing and running mypy
***************************

Mypy requires Python 3.9 or later to run. You can install mypy using pip:
Mypy requires Python 3.10 or later to run. You can install mypy using pip:

.. code-block:: shell

Expand Down
2 changes: 1 addition & 1 deletion mypy/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Earliest fully supported Python 3.x version. Used as the default Python
# version in tests. Mypy wheels should be built starting with this version,
# and CI tests should be run on this version (and later versions).
PYTHON3_VERSION: Final = (3, 9)
PYTHON3_VERSION: Final = (3, 10)

# Earliest Python 3.x version supported via --python-version 3.x. To run
# mypy, at least version PYTHON3_VERSION is needed.
Expand Down
10 changes: 7 additions & 3 deletions mypy/test/meta/test_parse_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ def test_bad_ge_version_check(self) -> None:
"""
[case abc]
s: str
[out version>=3.9]
[out version>=3.10]
abc
"""
)

# Assert
assert "version>=3.9 always true since minimum runtime version is (3, 9)" in actual.stdout
assert (
"version>=3.10 always true since minimum runtime version is (3, 10)" in actual.stdout
)

def test_bad_eq_version_check(self) -> None:
# Act
Expand All @@ -70,4 +72,6 @@ def test_bad_eq_version_check(self) -> None:
)

# Assert
assert "version==3.7 always false since minimum runtime version is (3, 9)" in actual.stdout
assert (
"version==3.7 always false since minimum runtime version is (3, 10)" in actual.stdout
)
3 changes: 3 additions & 0 deletions mypy/test/testpythoneval.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
return
mypy_cmdline.extend(additional_flags)

if "--no-force-union-syntax" not in mypy_cmdline:
mypy_cmdline.append("--force-union-syntax")
Comment on lines +74 to +75
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this here temporarily. Without it the output of a lot of pythoneval test would change now that these are run with 3.10 by default.

I plan to update the test outputs to use the PEP 604 union syntax in separate PRs later.


# Write the program to a file.
program = "_" + testcase.name + ".py"
program_path = os.path.join(test_temp_dir, program)
Expand Down
6 changes: 3 additions & 3 deletions mypy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,10 @@ def get_unique_redefinition_name(name: str, existing: Container[str]) -> str:
def check_python_version(program: str) -> None:
"""Report issues with the Python used to run mypy, dmypy, or stubgen"""
# Check for known bad Python versions.
if sys.version_info[:2] < (3, 9): # noqa: UP036, RUF100
if sys.version_info[:2] < (3, 10): # noqa: UP036, RUF100
sys.exit(
"Running {name} with Python 3.8 or lower is not supported; "
"please upgrade to 3.9 or newer".format(name=program)
"Running {name} with Python 3.9 or lower is not supported; "
"please upgrade to 3.10 or newer".format(name=program)
)


Expand Down
2 changes: 1 addition & 1 deletion mypy_self_check.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ show_traceback = True
pretty = True
always_false = MYPYC
plugins = mypy.plugins.proper_plugin
python_version = 3.9
python_version = 3.10
exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/
enable_error_code = ignore-without-code,redundant-expr
enable_incomplete_feature = PreciseTupleTypes
Expand Down
2 changes: 1 addition & 1 deletion mypyc/doc/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Installation
------------

Mypyc is shipped as part of the mypy distribution. Install mypy like
this (you need Python 3.9 or later):
this (you need Python 3.10 or later):

.. code-block::

Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -47,7 +46,7 @@ classifiers = [
"Topic :: Software Development",
"Typing :: Typed",
]
requires-python = ">=3.9"
requires-python = ">=3.10"
dependencies = [
# When changing this, also update build-system.requires and mypy-requirements.txt
"typing_extensions>=4.6.0",
Expand Down Expand Up @@ -107,7 +106,7 @@ mypyc = [

[tool.black]
line-length = 99
target-version = ["py39", "py310", "py311", "py312", "py313", "py314"]
target-version = ["py310", "py311", "py312", "py313", "py314"]
skip-magic-trailing-comma = true
force-exclude = '''
^/mypy/typeshed|
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import sys
from typing import TYPE_CHECKING, Any

if sys.version_info < (3, 9, 0): # noqa: UP036, RUF100
sys.stderr.write("ERROR: You need Python 3.9 or later to use mypy.\n")
if sys.version_info < (3, 10, 0): # noqa: UP036, RUF100
sys.stderr.write("ERROR: You need Python 3.10 or later to use mypy.\n")
exit(1)

# we'll import stuff from the source tree, let's ensure is on the sys path
Expand Down
4 changes: 0 additions & 4 deletions test-data/unit/cmdline.test
Original file line number Diff line number Diff line change
Expand Up @@ -1038,10 +1038,6 @@ public static void main(String[] args)
[file pkg/y.py]
x: str = 0
[out]
pkg/x.py:1: error: Invalid syntax
Found 1 error in 1 file (errors prevented further checking)
== Return code: 2
[out version>=3.10]
pkg/x.py:1: error: Invalid syntax. Perhaps you forgot a comma?
Found 1 error in 1 file (errors prevented further checking)
== Return code: 2
Expand Down
31 changes: 0 additions & 31 deletions test-data/unit/fine-grained-blockers.test
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ def f(x: int) -> None: pass
def f() -> None: pass
[out]
==
a.py:1: error: Invalid syntax
==
main:2: error: Missing positional argument "x" in call to "f"
==
[out version>=3.10]
==
a.py:1: error: Expected ':'
==
main:2: error: Missing positional argument "x" in call to "f"
Expand All @@ -44,16 +38,6 @@ def f(x: int) -> None: pass
def f() -> None: pass
[out]
==
a.py:1: error: Invalid syntax [syntax]
def f(x: int) ->
^
==
main:3: error: Missing positional argument "x" in call to "f" [call-arg]
a.f()
^~~~~
==
[out version>=3.10]
==
a.py:1: error: Expected ':' [syntax]
def f(x: int) ->
^
Expand All @@ -77,13 +61,6 @@ def f(x: int
def f(x: int) -> None: pass
[out]
==
a.py:1: error: Invalid syntax
==
a.py:2: error: Invalid syntax
==
main:2: error: Missing positional argument "x" in call to "f"
[out version>=3.10]
==
a.py:1: error: Expected ':'
==
a.py:2: error: Expected ':'
Expand Down Expand Up @@ -124,14 +101,6 @@ def f() -> None: pass
main:3: error: Too many arguments for "f"
main:5: error: Too many arguments for "f"
==
a.py:1: error: Invalid syntax
==
main:3: error: Too many arguments for "f"
main:5: error: Too many arguments for "f"
[out version>=3.10]
main:3: error: Too many arguments for "f"
main:5: error: Too many arguments for "f"
==
a.py:1: error: Expected ':'
==
main:3: error: Too many arguments for "f"
Expand Down
5 changes: 0 additions & 5 deletions test-data/unit/fine-grained-suggest.test
Original file line number Diff line number Diff line change
Expand Up @@ -1117,11 +1117,6 @@ def foo():

(
[out]
foo.py:4: error: Unexpected EOF while parsing
Command 'suggest' is only valid after a 'check' command (that produces no parse errors)
==
foo.py:4: error: Unexpected EOF while parsing
[out version>=3.10]
foo.py:4: error: '(' was never closed
Command 'suggest' is only valid after a 'check' command (that produces no parse errors)
==
Expand Down
2 changes: 0 additions & 2 deletions test-data/unit/parse-errors.test
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ file:2: error: Syntax error in type comment "A B"
[case testMissingBracket]
def foo(
[out]
file:1: error: Unexpected EOF while parsing
[out version>=3.10]
file:1: error: '(' was never closed

[case testInvalidSignatureInComment1]
Expand Down
14 changes: 7 additions & 7 deletions test-data/unit/pythoneval.test
Original file line number Diff line number Diff line change
Expand Up @@ -1651,8 +1651,8 @@ def foo(x: T) -> T:
return x
[out]
_testTypeAliasWithNewStyleUnion.py:5: note: Revealed type is "typing._SpecialForm"
_testTypeAliasWithNewStyleUnion.py:25: note: Revealed type is "type[builtins.int] | builtins.str"
_testTypeAliasWithNewStyleUnion.py:28: note: Revealed type is "type[builtins.int] | builtins.str"
_testTypeAliasWithNewStyleUnion.py:25: note: Revealed type is "Union[type[builtins.int], builtins.str]"
_testTypeAliasWithNewStyleUnion.py:28: note: Revealed type is "Union[type[builtins.int], builtins.str]"

[case testTypeAliasWithNewStyleUnionInStub]
import m
Expand Down Expand Up @@ -1704,7 +1704,7 @@ CU3 = int | Callable[[str | bool], str]
CU4: TypeAlias = int | Callable[[str | bool], str]
[out]
m.pyi:5: note: Revealed type is "typing._SpecialForm"
m.pyi:22: note: Revealed type is "typing._SpecialForm"
m.pyi:22: note: Revealed type is "types.UnionType[type[builtins.int], builtins.str]"
_testTypeAliasWithNewStyleUnionInStub.py:3: note: Revealed type is "Union[type[builtins.int], builtins.str]"
_testTypeAliasWithNewStyleUnionInStub.py:5: note: Revealed type is "Union[type[builtins.int], builtins.str]"
_testTypeAliasWithNewStyleUnionInStub.py:7: note: Revealed type is "Union[type[builtins.int], builtins.str]"
Expand All @@ -1730,7 +1730,7 @@ reveal_type(e.foo)
reveal_type(E.Y.foo)
[out]
_testEnumNameWorkCorrectlyOn311.py:11: note: Revealed type is "builtins.str"
_testEnumNameWorkCorrectlyOn311.py:12: note: Revealed type is "Literal[1]? | Literal[2]?"
_testEnumNameWorkCorrectlyOn311.py:12: note: Revealed type is "Union[Literal[1]?, Literal[2]?]"
_testEnumNameWorkCorrectlyOn311.py:13: note: Revealed type is "Literal['X']?"
_testEnumNameWorkCorrectlyOn311.py:14: note: Revealed type is "builtins.int"
_testEnumNameWorkCorrectlyOn311.py:15: note: Revealed type is "builtins.int"
Expand Down Expand Up @@ -1799,9 +1799,9 @@ WrongEllipsis = tuple[float, float, ...] | str # Error

reveal_type(tuple[int, str]((1, "x")))
[out]
_testTupleWithDifferentArgsPy310.py:15: note: Revealed type is "builtins.str | tuple[builtins.float, builtins.float, builtins.str]"
_testTupleWithDifferentArgsPy310.py:16: note: Revealed type is "tuple[builtins.float] | builtins.str"
_testTupleWithDifferentArgsPy310.py:17: note: Revealed type is "builtins.tuple[builtins.float, ...] | builtins.str"
_testTupleWithDifferentArgsPy310.py:15: note: Revealed type is "Union[builtins.str, tuple[builtins.float, builtins.float, builtins.str]]"
_testTupleWithDifferentArgsPy310.py:16: note: Revealed type is "Union[tuple[builtins.float], builtins.str]"
_testTupleWithDifferentArgsPy310.py:17: note: Revealed type is "Union[builtins.tuple[builtins.float, ...], builtins.str]"
_testTupleWithDifferentArgsPy310.py:18: note: Revealed type is "tuple[builtins.float, builtins.str]"
_testTupleWithDifferentArgsPy310.py:19: note: Revealed type is "builtins.tuple[builtins.float, ...]"
_testTupleWithDifferentArgsPy310.py:20: note: Revealed type is "builtins.list[tuple[builtins.int, builtins.str]]"
Expand Down
Loading