From ca8532b9c0ea2111c5b4ce1d30e5711bfef5d9c7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 30 Apr 2023 22:30:27 +0200 Subject: [PATCH 01/15] Slightly annotate cpp.py --- Tools/clinic/cpp.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 77f5f9696a6d84..8c467ec6731107 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,7 +1,11 @@ import re import sys +from typing import NoReturn, Callable -def negate(condition): +TokenAndCondition = tuple[str, str] +TokenStack = list[TokenAndCondition] + +def negate(condition: str) -> str: """ Returns a CPP conditional that is the opposite of the conditional passed in. """ @@ -22,17 +26,17 @@ class Monitor: Anyway this implementation seems to work well enough for the CPython sources. """ - is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match + is_a_simple_defined: Callable = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match - def __init__(self, filename=None, *, verbose=False): - self.stack = [] + def __init__(self, filename=None, *, verbose: bool = False): + self.stack: TokenStack = [] self.in_comment = False - self.continuation = None + self.continuation: str | None = None self.line_number = 0 self.filename = filename self.verbose = verbose - def __repr__(self): + def __repr__(self) -> str: return ''.join(( '")) - def status(self): + def status(self) -> str: return str(self.line_number).rjust(4) + ": " + self.condition() - def condition(self): + def condition(self) -> str: """ Returns the current preprocessor state, as a single #if condition. """ @@ -62,15 +66,15 @@ def close(self): if self.stack: self.fail("Ended file while still in a preprocessor conditional block!") - def write(self, s): + def write(self, s: str): for line in s.split("\n"): self.writeline(line) - def writeline(self, line): + def writeline(self, line: str): self.line_number += 1 line = line.strip() - def pop_stack(): + def pop_stack() -> TokenAndCondition | NoReturn: if not self.stack: self.fail("#" + token + " without matching #if / #ifdef / #ifndef!") return self.stack.pop() From d2ec2ef36d0a387aa13429ddf493c3538ada7ef6 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 1 May 2023 10:05:06 +0200 Subject: [PATCH 02/15] Slightly annotate clinic.py --- Tools/clinic/clinic.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index b8b2b75c749152..92ec4033880b86 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -27,6 +27,7 @@ import types from types import * +from typing import TypeVar, Callable # TODO: # @@ -68,7 +69,7 @@ def __repr__(self): sig_end_marker = '--' -_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output") +_text_accumulator_nt = collections.namedtuple("_text_accumulator_nt", "text append output") def _text_accumulator(): text = [] @@ -79,7 +80,7 @@ def output(): return _text_accumulator_nt(text, text.append, output) -text_accumulator_nt = collections.namedtuple("text_accumulator", "text append") +text_accumulator_nt = collections.namedtuple("text_accumulator_nt", "text append") def text_accumulator(): """ @@ -1915,8 +1916,11 @@ def dump(self): # maps strings to Language objects. # "languages" maps the name of the language ("C", "Python"). # "extensions" maps the file extension ("c", "py"). +L = TypeVar('L', bound=Language) +LangDict = dict[str, L] + languages = { 'C': CLanguage, 'Python': PythonLanguage } -extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } +extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } extensions['py'] = PythonLanguage @@ -2550,6 +2554,8 @@ def __init__(cls, name, bases, classdict): add_c_converter(cls) add_default_legacy_c_converter(cls) +from typing import Type + class CConverter(metaclass=CConverterAutoRegister): """ For the init function, self, name, function, and default @@ -2558,15 +2564,15 @@ class CConverter(metaclass=CConverterAutoRegister): """ # The C name to use for this variable. - name = None + name: str | None = None # The Python name to use for this variable. - py_name = None + py_name: str | None = None # The C type to use for this variable. # 'type' should be a Python string specifying the type, e.g. "int". # If this is a pointer type, the type string should end with ' *'. - type = None + type: str | None = None # The Python default value for this parameter, as a Python value. # Or the magic value "unspecified" if there is no default. @@ -2577,15 +2583,15 @@ class CConverter(metaclass=CConverterAutoRegister): # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) - default_type = None + default_type: Type | tuple[Type, ...] | None = None # "default" converted into a C value, as a string. # Or None if there is no default. - c_default = None + c_default: str | None = None # "default" converted into a Python value, as a string. # Or None if there is no default. - py_default = None + py_default: str | None = None # The default value used to initialize the C variable when # there is no default, but not specifying a default may @@ -2597,11 +2603,11 @@ class CConverter(metaclass=CConverterAutoRegister): # # This value is specified as a string. # Every non-abstract subclass should supply a valid value. - c_ignored_default = 'NULL' + c_ignored_default: str = 'NULL' # The C converter *function* to be used, if any. # (If this is not None, format_unit must be 'O&'.) - converter = None + converter: str | None = None # Should Argument Clinic add a '&' before the name of # the variable when passing it into the _impl function? @@ -3414,7 +3420,7 @@ class robuffer: pass def str_converter_key(types, encoding, zeroes): return (frozenset(types), bool(encoding), bool(zeroes)) -str_converter_argument_map = {} +str_converter_argument_map: dict[str, str] = {} class str_converter(CConverter): type = 'const char *' From 801af38ba0d4613f9bf2c7fbcc23703661d4fa5f Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 1 May 2023 19:32:58 +0200 Subject: [PATCH 03/15] Address review - ditch no-return - use callable from collections.abc - use namedtuple from typing --- Tools/clinic/clinic.py | 20 +++++++++++++------- Tools/clinic/cpp.py | 6 ++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 92ec4033880b86..d776dd3f01dd5f 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -26,8 +26,9 @@ import traceback import types +from collections.abc import Callable from types import * -from typing import TypeVar, Callable +from typing import NamedTuple, TypeVar, Type # TODO: # @@ -68,8 +69,13 @@ def __repr__(self): sig_end_marker = '--' +Appender = Callable[[str], None] +Outputter = Callable[[None], str] -_text_accumulator_nt = collections.namedtuple("_text_accumulator_nt", "text append output") +class _TextAccumulator(NamedTuple): + text: list[str] + append: Appender + output: Outputter def _text_accumulator(): text = [] @@ -77,10 +83,12 @@ def output(): s = ''.join(text) text.clear() return s - return _text_accumulator_nt(text, text.append, output) + return _TextAccumulator(text, text.append, output) -text_accumulator_nt = collections.namedtuple("text_accumulator_nt", "text append") +class TextAccumulator(NamedTuple): + text: list[str] + append: Appender def text_accumulator(): """ @@ -94,7 +102,7 @@ def text_accumulator(): empties the accumulator. """ text, append, output = _text_accumulator() - return text_accumulator_nt(append, output) + return TextAccumulator(append, output) def warn_or_fail(fail=False, *args, filename=None, line_number=None): @@ -2554,8 +2562,6 @@ def __init__(cls, name, bases, classdict): add_c_converter(cls) add_default_legacy_c_converter(cls) -from typing import Type - class CConverter(metaclass=CConverterAutoRegister): """ For the init function, self, name, function, and default diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 8c467ec6731107..24968753ebc4ec 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,6 +1,8 @@ import re import sys -from typing import NoReturn, Callable +from typing import NewType +from collections.abc import Callable + TokenAndCondition = tuple[str, str] TokenStack = list[TokenAndCondition] @@ -74,7 +76,7 @@ def writeline(self, line: str): self.line_number += 1 line = line.strip() - def pop_stack() -> TokenAndCondition | NoReturn: + def pop_stack() -> TokenAndCondition: if not self.stack: self.fail("#" + token + " without matching #if / #ifdef / #ifndef!") return self.stack.pop() From 00183ff17574307e4ceac7cf0b31c1866c1e70f8 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Fri, 12 May 2023 13:27:21 +0100 Subject: [PATCH 04/15] Add basic mypy workflow to CI --- .github/workflows/mypy-clinic.yml | 31 +++++++++++++++++++++++++++++++ Tools/clinic/mypy.ini | 9 +++++++++ 2 files changed, 40 insertions(+) create mode 100644 .github/workflows/mypy-clinic.yml create mode 100644 Tools/clinic/mypy.ini diff --git a/.github/workflows/mypy-clinic.yml b/.github/workflows/mypy-clinic.yml new file mode 100644 index 00000000000000..47a6589a097ccd --- /dev/null +++ b/.github/workflows/mypy-clinic.yml @@ -0,0 +1,31 @@ +name: Run mypy on Tools/clinic + +on: + push: + branches: + - main + pull_request: + paths: + - "Tools/clinic/**/*" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + mypy: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.11" + cache: pip + cache-dependency-path: .github/workflows/mypy-clinic.yml + - run: pip install mypy==1.3.0 + - run: mypy --config-file Tools/clinic/mypy.ini diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini new file mode 100644 index 00000000000000..9d1689e04a925d --- /dev/null +++ b/Tools/clinic/mypy.ini @@ -0,0 +1,9 @@ +[mypy] +pretty = True +enable_error_code = ignore-without-code +disallow_any_generics = True +strict_concatenate = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_unused_configs = True +files = Tools/clinic/ From 4bdd409fc64f3a584128e0828fad1108f8aa43b4 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Fri, 12 May 2023 13:34:50 +0100 Subject: [PATCH 05/15] Make the type check pass --- Tools/clinic/clinic.py | 7 +++---- Tools/clinic/cpp.py | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d776dd3f01dd5f..e978551d8bdeb8 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -28,7 +28,7 @@ from collections.abc import Callable from types import * -from typing import NamedTuple, TypeVar, Type +from typing import Any, NamedTuple, Type # TODO: # @@ -1924,8 +1924,7 @@ def dump(self): # maps strings to Language objects. # "languages" maps the name of the language ("C", "Python"). # "extensions" maps the file extension ("c", "py"). -L = TypeVar('L', bound=Language) -LangDict = dict[str, L] +LangDict = dict[str, Callable[[str], Language]] languages = { 'C': CLanguage, 'Python': PythonLanguage } extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } @@ -2589,7 +2588,7 @@ class CConverter(metaclass=CConverterAutoRegister): # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) - default_type: Type | tuple[Type, ...] | None = None + default_type: Type[Any] | tuple[Type[Any], ...] | None = None # "default" converted into a C value, as a string. # Or None if there is no default. diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 24968753ebc4ec..49462b7f4f2dc3 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -28,7 +28,8 @@ class Monitor: Anyway this implementation seems to work well enough for the CPython sources. """ - is_a_simple_defined: Callable = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match + is_a_simple_defined: Callable[[str], re.Match[str] | None] + is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match def __init__(self, filename=None, *, verbose: bool = False): self.stack: TokenStack = [] From 632843b308f66b16875455958f3ae3ed59045724 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Fri, 12 May 2023 13:38:09 +0100 Subject: [PATCH 06/15] Tweak workflow file --- .github/workflows/mypy-clinic.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mypy-clinic.yml b/.github/workflows/mypy-clinic.yml index 47a6589a097ccd..0623eee2fcb53b 100644 --- a/.github/workflows/mypy-clinic.yml +++ b/.github/workflows/mypy-clinic.yml @@ -7,6 +7,7 @@ on: pull_request: paths: - "Tools/clinic/**/*" + - ".github/workflows/mypy-clinic.yml" workflow_dispatch: permissions: From f7e7a2556720e96f6c338a27f42b13114366353d Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 12 May 2023 13:53:48 +0100 Subject: [PATCH 07/15] improve workflow file --- .github/workflows/mypy-clinic.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/mypy-clinic.yml b/.github/workflows/mypy-clinic.yml index 0623eee2fcb53b..c42946f445edfa 100644 --- a/.github/workflows/mypy-clinic.yml +++ b/.github/workflows/mypy-clinic.yml @@ -13,6 +13,11 @@ on: permissions: contents: read +env: + PIP_DISABLE_PIP_VERSION_CHECK: 1 + FORCE_COLOR: 1 + TERM: xterm-256color # needed for FORCE_COLOR to work on mypy on Ubuntu, see https://github.com/python/mypy/issues/13817 + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true From 510e08bd90f5d8c3566a5d1d0b3b38494e8bc23f Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 12 May 2023 14:18:10 +0100 Subject: [PATCH 08/15] Add some more return annotations Co-authored-by: Nikita Sobolev --- Tools/clinic/cpp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 49462b7f4f2dc3..895944f30d2385 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -69,11 +69,11 @@ def close(self): if self.stack: self.fail("Ended file while still in a preprocessor conditional block!") - def write(self, s: str): + def write(self, s: str) -> None: for line in s.split("\n"): self.writeline(line) - def writeline(self, line: str): + def writeline(self, line: str) -> None: self.line_number += 1 line = line.strip() From 773c2bad32e881a614c6fa3043c34cecb3069def Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 12 May 2023 14:21:39 +0100 Subject: [PATCH 09/15] simpler glob Co-authored-by: Hugo van Kemenade --- .github/workflows/mypy-clinic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mypy-clinic.yml b/.github/workflows/mypy-clinic.yml index c42946f445edfa..e67e561d374fad 100644 --- a/.github/workflows/mypy-clinic.yml +++ b/.github/workflows/mypy-clinic.yml @@ -6,7 +6,7 @@ on: - main pull_request: paths: - - "Tools/clinic/**/*" + - "Tools/clinic/**" - ".github/workflows/mypy-clinic.yml" workflow_dispatch: From 6c7ecb9d8ac77e1a013a53ebed0422e603f17e61 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Fri, 12 May 2023 14:35:28 +0100 Subject: [PATCH 10/15] Address various reviews! --- .github/dependabot.yml | 7 +++++++ .github/workflows/{mypy-clinic.yml => mypy.yml} | 8 +++++--- Tools/clinic/clinic.py | 5 +++-- Tools/clinic/mypy.ini | 1 + Tools/clinic/requirements-dev.txt | 2 ++ 5 files changed, 18 insertions(+), 5 deletions(-) rename .github/workflows/{mypy-clinic.yml => mypy.yml} (79%) create mode 100644 Tools/clinic/requirements-dev.txt diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 555e246e402bf9..f026b0f5f9454a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,3 +12,10 @@ updates: update-types: - "version-update:semver-minor" - "version-update:semver-patch" + - package-ecosystem: "pip" + directory: "/Tools/clinic/" + schedule: + interval: "monthly" + labels: + - "skip issue" + - "skip news" diff --git a/.github/workflows/mypy-clinic.yml b/.github/workflows/mypy.yml similarity index 79% rename from .github/workflows/mypy-clinic.yml rename to .github/workflows/mypy.yml index e67e561d374fad..9994b1bf1b3777 100644 --- a/.github/workflows/mypy-clinic.yml +++ b/.github/workflows/mypy.yml @@ -1,4 +1,5 @@ -name: Run mypy on Tools/clinic +# Workflow to run mypy on select parts of the CPython repo +name: mypy on: push: @@ -7,7 +8,7 @@ on: pull_request: paths: - "Tools/clinic/**" - - ".github/workflows/mypy-clinic.yml" + - ".github/workflows/mypy.yml" workflow_dispatch: permissions: @@ -24,6 +25,7 @@ concurrency: jobs: mypy: + name: Run mypy on Tools/clinic/ runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -33,5 +35,5 @@ jobs: python-version: "3.11" cache: pip cache-dependency-path: .github/workflows/mypy-clinic.yml - - run: pip install mypy==1.3.0 + - run: pip install -r Tools/clinic/requirements-dev.txt - run: mypy --config-file Tools/clinic/mypy.ini diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index e978551d8bdeb8..dd6407a945dd13 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -7,6 +7,7 @@ import abc import ast +import builtins as bltns import collections import contextlib import copy @@ -28,7 +29,7 @@ from collections.abc import Callable from types import * -from typing import Any, NamedTuple, Type +from typing import Any, NamedTuple # TODO: # @@ -2588,7 +2589,7 @@ class CConverter(metaclass=CConverterAutoRegister): # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) - default_type: Type[Any] | tuple[Type[Any], ...] | None = None + default_type: bltns.type[Any] | tuple[bltns.type[Any], ...] | None = None # "default" converted into a C value, as a string. # Or None if there is no default. diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini index 9d1689e04a925d..39ed16b7d6ea9f 100644 --- a/Tools/clinic/mypy.ini +++ b/Tools/clinic/mypy.ini @@ -1,4 +1,5 @@ [mypy] +python_version = 3.10 # make sure clinic can still be run on Python 3.10 pretty = True enable_error_code = ignore-without-code disallow_any_generics = True diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt new file mode 100644 index 00000000000000..154934003c31c4 --- /dev/null +++ b/Tools/clinic/requirements-dev.txt @@ -0,0 +1,2 @@ +# Requirements file for external linters and checks we run on Tools/clinic/ in CI +mypy==1.3.0 From 717ee47bc76eb3f39fc0d1c3d81207d628c884a9 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 12 May 2023 15:12:10 +0100 Subject: [PATCH 11/15] more from Hugo Co-authored-by: Hugo van Kemenade --- .github/workflows/mypy.yml | 4 ++-- Tools/clinic/requirements-dev.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 9994b1bf1b3777..1315bb5a966f01 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -32,8 +32,8 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.x" cache: pip - cache-dependency-path: .github/workflows/mypy-clinic.yml + cache-dependency-path: Tools/clinic/requirements-dev.txt - run: pip install -r Tools/clinic/requirements-dev.txt - run: mypy --config-file Tools/clinic/mypy.ini diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt index 154934003c31c4..7e0aa37a46d7bc 100644 --- a/Tools/clinic/requirements-dev.txt +++ b/Tools/clinic/requirements-dev.txt @@ -1,2 +1,2 @@ # Requirements file for external linters and checks we run on Tools/clinic/ in CI -mypy==1.3.0 +mypy==1.2.0 From 62669d1ee421551c48715d859e73485d8c948b3f Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Fri, 12 May 2023 15:15:34 +0100 Subject: [PATCH 12/15] Fix ini syntax --- Tools/clinic/mypy.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini index 39ed16b7d6ea9f..3c5643e789be37 100644 --- a/Tools/clinic/mypy.ini +++ b/Tools/clinic/mypy.ini @@ -1,5 +1,6 @@ [mypy] -python_version = 3.10 # make sure clinic can still be run on Python 3.10 +# make sure clinic can still be run on Python 3.10 +python_version = 3.10 pretty = True enable_error_code = ignore-without-code disallow_any_generics = True From ddd0843e9d3b75b30b63827187223dfd786b0876 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 12 May 2023 16:17:01 +0100 Subject: [PATCH 13/15] Unused import --- Tools/clinic/cpp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 895944f30d2385..bc2cc713aac394 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,6 +1,5 @@ import re import sys -from typing import NewType from collections.abc import Callable From 9fcd87fd09247c5926cfcde18cabc1c35dc90356 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Sat, 13 May 2023 12:19:02 +0100 Subject: [PATCH 14/15] Restore compatibility with Python 3.8 --- Tools/clinic/clinic.py | 14 +++++++++++--- Tools/clinic/cpp.py | 8 +++++--- Tools/clinic/mypy.ini | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 4270fb3cc56613..0b3c517e7e91c1 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5,6 +5,8 @@ # Licensed to the PSF under a contributor agreement. # +from __future__ import annotations + import abc import ast import builtins as bltns @@ -27,9 +29,15 @@ import traceback import types -from collections.abc import Callable from types import * -from typing import Any, NamedTuple +from typing import Any, Callable, Dict, NamedTuple, TYPE_CHECKING + +# types.NoneType only exists on Python 3.10+ +# type(None) isn't understood by type-checkers on <3.10 :( +if TYPE_CHECKING: + from _typeshed import NoneType +else: + NoneType = type(None) # TODO: # @@ -1935,7 +1943,7 @@ def dump(self): # maps strings to Language objects. # "languages" maps the name of the language ("C", "Python"). # "extensions" maps the file extension ("c", "py"). -LangDict = dict[str, Callable[[str], Language]] +LangDict = Dict[str, Callable[[str], Language]] languages = { 'C': CLanguage, 'Python': PythonLanguage } extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index bc2cc713aac394..49036d2558d49c 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,10 +1,12 @@ +from __future__ import annotations + import re import sys -from collections.abc import Callable +from typing import Callable, List, Tuple -TokenAndCondition = tuple[str, str] -TokenStack = list[TokenAndCondition] +TokenAndCondition = Tuple[str, str] +TokenStack = List[TokenAndCondition] def negate(condition: str) -> str: """ diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini index 3c5643e789be37..40e93e4622fcfb 100644 --- a/Tools/clinic/mypy.ini +++ b/Tools/clinic/mypy.ini @@ -1,6 +1,6 @@ [mypy] -# make sure clinic can still be run on Python 3.10 -python_version = 3.10 +# make sure clinic can still be run on Python 3.8 +python_version = 3.8 pretty = True enable_error_code = ignore-without-code disallow_any_generics = True From 010f0dd313f36d34f2a0e52659e20a44e117efc8 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Mon, 15 May 2023 09:20:18 +0100 Subject: [PATCH 15/15] Revert "Restore compatibility with Python 3.8" This reverts commit 9fcd87fd09247c5926cfcde18cabc1c35dc90356. --- Tools/clinic/clinic.py | 14 +++----------- Tools/clinic/cpp.py | 8 +++----- Tools/clinic/mypy.ini | 4 ++-- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 0b3c517e7e91c1..4270fb3cc56613 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5,8 +5,6 @@ # Licensed to the PSF under a contributor agreement. # -from __future__ import annotations - import abc import ast import builtins as bltns @@ -29,15 +27,9 @@ import traceback import types +from collections.abc import Callable from types import * -from typing import Any, Callable, Dict, NamedTuple, TYPE_CHECKING - -# types.NoneType only exists on Python 3.10+ -# type(None) isn't understood by type-checkers on <3.10 :( -if TYPE_CHECKING: - from _typeshed import NoneType -else: - NoneType = type(None) +from typing import Any, NamedTuple # TODO: # @@ -1943,7 +1935,7 @@ def dump(self): # maps strings to Language objects. # "languages" maps the name of the language ("C", "Python"). # "extensions" maps the file extension ("c", "py"). -LangDict = Dict[str, Callable[[str], Language]] +LangDict = dict[str, Callable[[str], Language]] languages = { 'C': CLanguage, 'Python': PythonLanguage } extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 49036d2558d49c..bc2cc713aac394 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,12 +1,10 @@ -from __future__ import annotations - import re import sys -from typing import Callable, List, Tuple +from collections.abc import Callable -TokenAndCondition = Tuple[str, str] -TokenStack = List[TokenAndCondition] +TokenAndCondition = tuple[str, str] +TokenStack = list[TokenAndCondition] def negate(condition: str) -> str: """ diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini index 40e93e4622fcfb..3c5643e789be37 100644 --- a/Tools/clinic/mypy.ini +++ b/Tools/clinic/mypy.ini @@ -1,6 +1,6 @@ [mypy] -# make sure clinic can still be run on Python 3.8 -python_version = 3.8 +# make sure clinic can still be run on Python 3.10 +python_version = 3.10 pretty = True enable_error_code = ignore-without-code disallow_any_generics = True