Skip to content

Commit eb64b65

Browse files
Strict typing (#103)
1 parent d44bb30 commit eb64b65

18 files changed

+147
-190
lines changed

.codecov.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
codecov:
44
notify:
5-
after_n_builds: 23 # The number of test matrix+lint jobs uploading coverage
5+
after_n_builds: 20 # The number of test matrix+lint jobs uploading coverage
66
wait_for_ci: false
77

88
require_ci_to_pass: false

.github/workflows/reusable-linters.yml

+1-4
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,7 @@ jobs:
7171
with:
7272
token: ${{ secrets.codecov-token }}
7373
files: >-
74-
.tox/.tmp/.mypy/python-3.13/cobertura.xml,
75-
.tox/.tmp/.mypy/python-3.12/cobertura.xml,
76-
.tox/.tmp/.mypy/python-3.11/cobertura.xml,
77-
.tox/.tmp/.mypy/python-3.9/cobertura.xml
74+
.tox/.tmp/.mypy/python-3.11/cobertura.xml
7875
flags: >-
7976
CI-GHA,
8077
MyPy

.mypy.ini

+27-45
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,28 @@
11
[mypy]
2-
python_version = 3.9
3-
color_output = true
4-
error_summary = true
5-
files =
6-
packaging/,
7-
tests/,
8-
src/propcache/
9-
10-
# check_untyped_defs = true
11-
12-
# disallow_untyped_calls = true
13-
# disallow_untyped_defs = true
14-
# disallow_any_generics = true
15-
16-
enable_error_code =
17-
ignore-without-code
18-
19-
follow_imports = normal
20-
21-
ignore_missing_imports = false
22-
23-
pretty = true
24-
25-
show_column_numbers = true
26-
show_error_codes = true
27-
strict_optional = true
28-
29-
warn_no_return = true
30-
warn_redundant_casts = true
31-
warn_unused_ignores = true
32-
33-
[mypy-Cython.*]
34-
ignore_missing_imports = true
35-
36-
[mypy-distutils.*]
37-
ignore_missing_imports = true
38-
39-
[mypy-expandvars]
40-
ignore_missing_imports = true
41-
42-
[mypy-pytest]
43-
ignore_missing_imports = true
44-
45-
[mypy-tomllib]
46-
ignore_missing_imports = true
2+
files = packaging, src, tests
3+
check_untyped_defs = True
4+
follow_imports_for_stubs = True
5+
disallow_any_decorated = True
6+
disallow_any_generics = True
7+
disallow_any_unimported = True
8+
disallow_incomplete_defs = True
9+
disallow_subclassing_any = True
10+
disallow_untyped_calls = True
11+
disallow_untyped_decorators = True
12+
disallow_untyped_defs = True
13+
# TODO(PY312): explicit-override
14+
enable_error_code = deprecated, ignore-without-code, possibly-undefined, redundant-expr, redundant-self, truthy-bool, truthy-iterable, unused-awaitable
15+
extra_checks = True
16+
follow_untyped_imports = True
17+
implicit_reexport = False
18+
no_implicit_optional = True
19+
pretty = True
20+
show_column_numbers = True
21+
show_error_codes = True
22+
show_error_code_links = True
23+
strict_equality = True
24+
warn_incomplete_stub = True
25+
warn_redundant_casts = True
26+
warn_return_any = True
27+
warn_unreachable = True
28+
warn_unused_ignores = True

.pre-commit-config.yaml

+2-47
Original file line numberDiff line numberDiff line change
@@ -109,40 +109,12 @@ repos:
109109
- repo: https://github.com/pre-commit/mirrors-mypy.git
110110
rev: v1.14.1
111111
hooks:
112-
- id: mypy
113-
alias: mypy-py313
114-
name: MyPy, for Python 3.13
115-
additional_dependencies:
116-
- lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report`
117-
- pytest
118-
- pytest_codspeed==3.0.0
119-
- tomli # requirement of packaging/pep517_backend/
120-
- types-setuptools # requirement of packaging/pep517_backend/
121-
args:
122-
- --python-version=3.13
123-
- --txt-report=.tox/.tmp/.mypy/python-3.13
124-
- --cobertura-xml-report=.tox/.tmp/.mypy/python-3.13
125-
- --html-report=.tox/.tmp/.mypy/python-3.13
126-
pass_filenames: false
127-
- id: mypy
128-
alias: mypy-py312
129-
name: MyPy, for Python 3.12
130-
additional_dependencies:
131-
- lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report`
132-
- pytest
133-
- pytest_codspeed==3.0.0
134-
- tomli # requirement of packaging/pep517_backend/
135-
- types-setuptools # requirement of packaging/pep517_backend/
136-
args:
137-
- --python-version=3.12
138-
- --txt-report=.tox/.tmp/.mypy/python-3.12
139-
- --cobertura-xml-report=.tox/.tmp/.mypy/python-3.12
140-
- --html-report=.tox/.tmp/.mypy/python-3.12
141-
pass_filenames: false
142112
- id: mypy
143113
alias: mypy-py311
144114
name: MyPy, for Python 3.11
145115
additional_dependencies:
116+
- Cython
117+
- expandvars
146118
- lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report`
147119
- pytest
148120
- pytest_codspeed==3.0.0
@@ -156,23 +128,6 @@ repos:
156128
- --cobertura-xml-report=.tox/.tmp/.mypy/python-3.11
157129
- --html-report=.tox/.tmp/.mypy/python-3.11
158130
pass_filenames: false
159-
- id: mypy
160-
alias: mypy-py39
161-
name: MyPy, for Python 3.9
162-
additional_dependencies:
163-
- lxml # dep of `--txt-report`, `--cobertura-xml-report` & `--html-report`
164-
- pytest
165-
- pytest_codspeed==3.0.0
166-
- tomli # requirement of packaging/pep517_backend/
167-
- types-setuptools # requirement of packaging/pep517_backend/
168-
- types-Pygments
169-
- types-colorama
170-
args:
171-
- --python-version=3.9
172-
- --txt-report=.tox/.tmp/.mypy/python-3.9
173-
- --cobertura-xml-report=.tox/.tmp/.mypy/python-3.9
174-
- --html-report=.tox/.tmp/.mypy/python-3.9
175-
pass_filenames: false
176131

177132
- repo: https://github.com/rhysd/actionlint.git
178133
rev: v1.7.6

CHANGES/103.bugfix.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improved typing annotations, fixing some type errors under correct usage
2+
and improving typing robustness generally -- by :user:`Dreamsorcerer`.

packaging/pep517_backend/_backend.py

+18-16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import sysconfig
88
import typing as t
9+
from collections.abc import Iterator
910
from contextlib import contextmanager, nullcontext, suppress
1011
from functools import partial
1112
from pathlib import Path
@@ -56,7 +57,7 @@
5657
'get_requires_for_build_wheel',
5758
'prepare_metadata_for_build_wheel',
5859
*(
59-
() if _setuptools_build_editable is None
60+
() if _setuptools_build_editable is None # type: ignore[redundant-expr]
6061
else (
6162
'build_editable',
6263
'get_requires_for_build_editable',
@@ -87,7 +88,7 @@
8788
"""A fallback for ``pure-python`` is not set."""
8889

8990

90-
def _is_truthy_setting_value(setting_value) -> bool:
91+
def _is_truthy_setting_value(setting_value: str) -> bool:
9192
truthy_values = {'', None, 'true', '1', 'on'}
9293
return setting_value.lower() in truthy_values
9394

@@ -108,7 +109,7 @@ def _get_setting_value(
108109
continue
109110

110111
with suppress(lookup_errors): # type: ignore[arg-type]
111-
return _is_truthy_setting_value(src_mapping[src_key]) # type: ignore[index]
112+
return _is_truthy_setting_value(src_mapping[src_key]) # type: ignore[arg-type,index]
112113

113114
return default
114115

@@ -125,7 +126,7 @@ def _make_pure_python(config_settings: _ConfigDict | None = None) -> bool:
125126
def _include_cython_line_tracing(
126127
config_settings: _ConfigDict | None = None,
127128
*,
128-
default=False,
129+
default: bool = False,
129130
) -> bool:
130131
return _get_setting_value(
131132
config_settings,
@@ -136,60 +137,61 @@ def _include_cython_line_tracing(
136137

137138

138139
@contextmanager
139-
def patched_distutils_cmd_install():
140+
def patched_distutils_cmd_install() -> Iterator[None]:
140141
"""Make `install_lib` of `install` cmd always use `platlib`.
141142
142143
:yields: None
143144
"""
144145
# Without this, build_lib puts stuff under `*.data/purelib/` folder
145146
orig_finalize = _distutils_install_cmd.finalize_options
146147

147-
def new_finalize_options(self): # noqa: WPS430
148+
def new_finalize_options(self: _distutils_install_cmd) -> None:
148149
self.install_lib = self.install_platlib
149150
orig_finalize(self)
150151

151-
_distutils_install_cmd.finalize_options = new_finalize_options
152+
_distutils_install_cmd.finalize_options = new_finalize_options # type: ignore[method-assign]
152153
try:
153154
yield
154155
finally:
155-
_distutils_install_cmd.finalize_options = orig_finalize
156+
_distutils_install_cmd.finalize_options = orig_finalize # type: ignore[method-assign]
156157

157158

158159
@contextmanager
159-
def patched_dist_has_ext_modules():
160+
def patched_dist_has_ext_modules() -> Iterator[None]:
160161
"""Make `has_ext_modules` of `Distribution` always return `True`.
161162
162163
:yields: None
163164
"""
164165
# Without this, build_lib puts stuff under `*.data/platlib/` folder
165166
orig_func = _DistutilsDistribution.has_ext_modules
166167

167-
_DistutilsDistribution.has_ext_modules = lambda *args, **kwargs: True
168+
_DistutilsDistribution.has_ext_modules = lambda *args, **kwargs: True # type: ignore[method-assign]
168169
try:
169170
yield
170171
finally:
171-
_DistutilsDistribution.has_ext_modules = orig_func
172+
_DistutilsDistribution.has_ext_modules = orig_func # type: ignore[method-assign]
172173

173174

174175
@contextmanager
175-
def patched_dist_get_long_description():
176+
def patched_dist_get_long_description() -> Iterator[None]:
176177
"""Make `has_ext_modules` of `Distribution` always return `True`.
177178
178179
:yields: None
179180
"""
180181
# Without this, build_lib puts stuff under `*.data/platlib/` folder
181182
_orig_func = _DistutilsDistributionMetadata.get_long_description
182183

183-
def _get_sanitized_long_description(self):
184+
def _get_sanitized_long_description(self: _DistutilsDistributionMetadata) -> str:
185+
assert self.long_description is not None
184186
return sanitize_rst_roles(self.long_description)
185187

186-
_DistutilsDistributionMetadata.get_long_description = (
188+
_DistutilsDistributionMetadata.get_long_description = ( # type: ignore[method-assign]
187189
_get_sanitized_long_description
188190
)
189191
try:
190192
yield
191193
finally:
192-
_DistutilsDistributionMetadata.get_long_description = _orig_func
194+
_DistutilsDistributionMetadata.get_long_description = _orig_func # type: ignore[method-assign]
193195

194196

195197
def _exclude_dir_path(
@@ -293,7 +295,7 @@ def maybe_prebuild_c_extensions(
293295

294296
cythonize_args = _make_cythonize_cli_args_from_config(config)
295297
with _patched_cython_env(config['env'], cython_line_tracing_requested):
296-
_cythonize_cli_cmd(cythonize_args)
298+
_cythonize_cli_cmd(cythonize_args) # type: ignore[no-untyped-call]
297299
with patched_distutils_cmd_install():
298300
with patched_dist_has_ext_modules():
299301
yield

packaging/pep517_backend/_compat.py

+9-14
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
"""Cross-python stdlib shims."""
22

33
import os
4-
import typing as t
4+
import sys
5+
from collections.abc import Iterator
56
from contextlib import contextmanager
67
from pathlib import Path
78

89
# isort: off
9-
try:
10-
from contextlib import chdir as chdir_cm # type: ignore[attr-defined, unused-ignore] # noqa: E501
11-
except ImportError:
10+
if sys.version_info >= (3, 11):
11+
from contextlib import chdir as chdir_cm
12+
from tomllib import loads as load_toml_from_string
13+
else:
14+
from tomli import loads as load_toml_from_string
1215

13-
@contextmanager # type: ignore[no-redef, unused-ignore]
14-
def chdir_cm(path: os.PathLike) -> t.Iterator[None]:
16+
@contextmanager
17+
def chdir_cm(path: os.PathLike) -> Iterator[None]:
1518
"""Temporarily change the current directory, recovering on exit."""
1619
original_wd = Path.cwd()
1720
os.chdir(path)
@@ -22,12 +25,4 @@ def chdir_cm(path: os.PathLike) -> t.Iterator[None]:
2225

2326

2427
# isort: on
25-
26-
27-
try:
28-
from tomllib import loads as load_toml_from_string
29-
except ImportError:
30-
from tomli import loads as load_toml_from_string
31-
32-
3328
__all__ = ("chdir_cm", "load_toml_from_string") # noqa: WPS410

packaging/pep517_backend/_cython_configuration.py

+14-5
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,26 @@
33
from __future__ import annotations
44

55
import os
6+
from collections.abc import Iterator
67
from contextlib import contextmanager
78
from pathlib import Path
89
from sys import version_info as _python_version_tuple
10+
from typing import TypedDict
911

1012
from expandvars import expandvars
1113

1214
from ._compat import load_toml_from_string
1315
from ._transformers import get_cli_kwargs_from_config, get_enabled_cli_flags_from_config
1416

1517

16-
def get_local_cython_config() -> dict:
18+
class Config(TypedDict):
19+
env: dict[str, str]
20+
flags: dict[str, bool]
21+
kwargs: dict[str, str]
22+
src: list[str]
23+
24+
25+
def get_local_cython_config() -> Config:
1726
"""Grab optional build dependencies from pyproject.toml config.
1827
1928
:returns: config section from ``pyproject.toml``
@@ -67,10 +76,10 @@ def get_local_cython_config() -> dict:
6776
"""
6877
config_toml_txt = (Path.cwd().resolve() / 'pyproject.toml').read_text()
6978
config_mapping = load_toml_from_string(config_toml_txt)
70-
return config_mapping['tool']['local']['cythonize']
79+
return config_mapping['tool']['local']['cythonize'] # type: ignore[no-any-return]
7180

7281

73-
def make_cythonize_cli_args_from_config(config) -> list[str]:
82+
def make_cythonize_cli_args_from_config(config: Config) -> list[str]:
7483
py_ver_arg = f'-{_python_version_tuple.major!s}'
7584

7685
cli_flags = get_enabled_cli_flags_from_config(config['flags'])
@@ -80,7 +89,7 @@ def make_cythonize_cli_args_from_config(config) -> list[str]:
8089

8190

8291
@contextmanager
83-
def patched_env(env: dict[str, str], cython_line_tracing_requested: bool):
92+
def patched_env(env: dict[str, str], cython_line_tracing_requested: bool) -> Iterator[None]:
8493
"""Temporary set given env vars.
8594
8695
:param env: tmp env vars to set
@@ -89,7 +98,7 @@ def patched_env(env: dict[str, str], cython_line_tracing_requested: bool):
8998
:yields: None
9099
"""
91100
orig_env = os.environ.copy()
92-
expanded_env = {name: expandvars(var_val) for name, var_val in env.items()}
101+
expanded_env = {name: expandvars(var_val) for name, var_val in env.items()} # type: ignore[no-untyped-call]
93102
os.environ.update(expanded_env)
94103

95104
if cython_line_tracing_requested:

0 commit comments

Comments
 (0)