Skip to content

Commit 505278d

Browse files
authored
chore: statically type the tests (#982)
* chore: add -> to tests Signed-off-by: Henry Schreiner <[email protected]> * chore: add some fixture types Signed-off-by: Henry Schreiner <[email protected]> * chore: work through remaining types Signed-off-by: Henry Schreiner <[email protected]> --------- Signed-off-by: Henry Schreiner <[email protected]>
1 parent f451a9f commit 505278d

14 files changed

+699
-458
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ repos:
2626
rev: v1.18.1
2727
hooks:
2828
- id: mypy
29-
exclude: '^(docs|tasks|tests)|setup\.py'
29+
exclude: '^(docs|tasks)'
3030
args: []
31-
additional_dependencies: [pyparsing, nox, orjson]
31+
additional_dependencies: [pyparsing, nox, orjson, 'pytest<9', tomli, tomli_w]
3232

3333
- repo: https://github.com/codespell-project/codespell
3434
rev: "v2.4.1"

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ strict = true
8080
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
8181
warn_unused_ignores = true
8282
python_version = "3.8"
83+
files = ["src", "tests", "noxfile.py"]
8384

8485
[[tool.mypy.overrides]]
85-
module = ["_manylinux"]
86+
module = ["_manylinux", "pretend"]
8687
ignore_missing_imports = true
8788

8889
[tool.ruff]

src/packaging/markers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import os
99
import platform
1010
import sys
11-
from typing import AbstractSet, Any, Callable, Literal, TypedDict, Union, cast
11+
from typing import AbstractSet, Any, Callable, Literal, Mapping, TypedDict, Union, cast
1212

1313
from ._parser import MarkerAtom, MarkerList, Op, Value, Variable
1414
from ._parser import parse_marker as _parse_marker
@@ -314,7 +314,7 @@ def __eq__(self, other: object) -> bool:
314314

315315
def evaluate(
316316
self,
317-
environment: dict[str, str] | None = None,
317+
environment: Mapping[str, str | AbstractSet[str]] | None = None,
318318
context: EvaluateContext = "metadata",
319319
) -> bool:
320320
"""Evaluate a marker.

tests/test_elffile.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
("s390x-s390x", EIClass.C64, EIData.Msb, EMachine.S390),
2323
],
2424
)
25-
def test_elffile_glibc(name, capacity, encoding, machine):
25+
def test_elffile_glibc(
26+
name: str, capacity: EIClass, encoding: EIData, machine: EMachine
27+
) -> None:
2628
path = DIR_MANYLINUX.joinpath(f"hello-world-{name}")
2729
with path.open("rb") as f:
2830
ef = ELFFile(f)
@@ -46,7 +48,9 @@ def test_elffile_glibc(name, capacity, encoding, machine):
4648
("x86_64", EIClass.C64, EIData.Lsb, EMachine.X8664, "x86_64"),
4749
],
4850
)
49-
def test_elffile_musl(name, capacity, encoding, machine, interpreter):
51+
def test_elffile_musl(
52+
name: str, capacity: EIClass, encoding: EIData, machine: EMachine, interpreter: str
53+
) -> None:
5054
path = DIR_MUSLLINUX.joinpath(f"musl-{name}")
5155
with path.open("rb") as f:
5256
ef = ELFFile(f)
@@ -68,25 +72,25 @@ def test_elffile_musl(name, capacity, encoding, machine, interpreter):
6872
],
6973
ids=["no-magic", "wrong-magic", "unknown-format"],
7074
)
71-
def test_elffile_bad_ident(data):
75+
def test_elffile_bad_ident(data: bytes) -> None:
7276
with pytest.raises(ELFInvalid):
7377
ELFFile(io.BytesIO(data))
7478

7579

76-
def test_elffile_no_section():
80+
def test_elffile_no_section() -> None:
7781
"""Enough for magic, but not the section definitions."""
7882
data = BIN_MUSL_X86_64[:25]
7983
with pytest.raises(ELFInvalid):
8084
ELFFile(io.BytesIO(data))
8185

8286

83-
def test_elffile_invalid_section():
87+
def test_elffile_invalid_section() -> None:
8488
"""Enough for section definitions, but not the actual sections."""
8589
data = BIN_MUSL_X86_64[:58]
8690
assert ELFFile(io.BytesIO(data)).interpreter is None
8791

8892

89-
def test_elffle_no_interpreter_section():
93+
def test_elffle_no_interpreter_section() -> None:
9094
ef = ELFFile(io.BytesIO(BIN_MUSL_X86_64))
9195

9296
# Change all sections to *not* PT_INTERP.

tests/test_licenses.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from packaging.licenses._spdx import EXCEPTIONS, LICENSES
22

33

4-
def test_licenses():
4+
def test_licenses() -> None:
55
for license_id in LICENSES:
66
assert license_id == license_id.lower()
77

88

9-
def test_exceptions():
9+
def test_exceptions() -> None:
1010
for exception_id in EXCEPTIONS:
1111
assert exception_id == exception_id.lower()

tests/test_manylinux.py

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
from __future__ import annotations
2+
13
try:
24
import ctypes
35
except ImportError:
4-
ctypes = None
6+
ctypes = None # type: ignore[assignment]
57
import os
68
import pathlib
79
import platform
810
import re
911
import sys
1012
import types
13+
import typing
14+
15+
if typing.TYPE_CHECKING:
16+
from collections.abc import Generator
1117

1218
import pretend
1319
import pytest
@@ -18,20 +24,21 @@
1824
_glibc_version_string,
1925
_glibc_version_string_confstr,
2026
_glibc_version_string_ctypes,
27+
_GLibCVersion,
2128
_is_compatible,
2229
_parse_elf,
2330
_parse_glibc_version,
2431
)
2532

2633

2734
@pytest.fixture(autouse=True)
28-
def clear_lru_cache():
35+
def clear_lru_cache() -> Generator[None, None, None]:
2936
yield
3037
_get_glibc_version.cache_clear()
3138

3239

3340
@pytest.fixture
34-
def manylinux_module(monkeypatch):
41+
def manylinux_module(monkeypatch: pytest.MonkeyPatch) -> types.ModuleType:
3542
monkeypatch.setattr(_manylinux, "_get_glibc_version", lambda *args: (2, 20))
3643
module_name = "_manylinux"
3744
module = types.ModuleType(module_name)
@@ -43,41 +50,55 @@ def manylinux_module(monkeypatch):
4350
@pytest.mark.parametrize(
4451
("attribute", "glibc"), [("1", (2, 5)), ("2010", (2, 12)), ("2014", (2, 17))]
4552
)
46-
def test_module_declaration(monkeypatch, manylinux_module, attribute, glibc, tf):
53+
def test_module_declaration(
54+
monkeypatch: pytest.MonkeyPatch,
55+
manylinux_module: types.ModuleType,
56+
attribute: str,
57+
glibc: tuple[int, int],
58+
tf: bool,
59+
) -> None:
4760
manylinux = f"manylinux{attribute}_compatible"
4861
monkeypatch.setattr(manylinux_module, manylinux, tf, raising=False)
49-
res = _is_compatible("x86_64", glibc)
62+
glibc_version = _GLibCVersion(glibc[0], glibc[1])
63+
res = _is_compatible("x86_64", glibc_version)
5064
assert tf is res
5165

5266

5367
@pytest.mark.parametrize(
5468
("attribute", "glibc"), [("1", (2, 5)), ("2010", (2, 12)), ("2014", (2, 17))]
5569
)
5670
def test_module_declaration_missing_attribute(
57-
monkeypatch, manylinux_module, attribute, glibc
58-
):
71+
monkeypatch: pytest.MonkeyPatch,
72+
manylinux_module: types.ModuleType,
73+
attribute: str,
74+
glibc: tuple[int, int],
75+
) -> None:
5976
manylinux = f"manylinux{attribute}_compatible"
6077
monkeypatch.delattr(manylinux_module, manylinux, raising=False)
61-
assert _is_compatible("x86_64", glibc)
78+
glibc_version = _GLibCVersion(glibc[0], glibc[1])
79+
assert _is_compatible("x86_64", glibc_version)
6280

6381

6482
@pytest.mark.parametrize(
6583
("version", "compatible"), [((2, 0), True), ((2, 5), True), ((2, 10), False)]
6684
)
67-
def test_is_manylinux_compatible_glibc_support(version, compatible, monkeypatch):
85+
def test_is_manylinux_compatible_glibc_support(
86+
version: tuple[int, int], compatible: bool, monkeypatch: pytest.MonkeyPatch
87+
) -> None:
6888
monkeypatch.setitem(sys.modules, "_manylinux", None)
6989
monkeypatch.setattr(_manylinux, "_get_glibc_version", lambda: (2, 5))
70-
assert bool(_is_compatible("any", version)) == compatible
90+
glibc_version = _GLibCVersion(version[0], version[1])
91+
assert bool(_is_compatible("any", glibc_version)) == compatible
7192

7293

7394
@pytest.mark.parametrize("version_str", ["glibc-2.4.5", "2"])
74-
def test_check_glibc_version_warning(version_str):
95+
def test_check_glibc_version_warning(version_str: str) -> None:
7596
msg = f"Expected glibc version with 2 components major.minor, got: {version_str}"
7697
with pytest.warns(RuntimeWarning, match=re.escape(msg)):
7798
_parse_glibc_version(version_str)
7899

79100

80-
@pytest.mark.skipif(not ctypes, reason="requires ctypes")
101+
@pytest.mark.skipif(not ctypes, reason="requires ctypes") # type: ignore[truthy-bool]
81102
@pytest.mark.parametrize(
82103
("version_str", "expected"),
83104
[
@@ -86,16 +107,18 @@ def test_check_glibc_version_warning(version_str):
86107
("2.4", "2.4"),
87108
],
88109
)
89-
def test_glibc_version_string(version_str, expected, monkeypatch):
110+
def test_glibc_version_string(
111+
version_str: str | bytes, expected: str, monkeypatch: pytest.MonkeyPatch
112+
) -> None:
90113
class LibcVersion:
91-
def __init__(self, version_str):
114+
def __init__(self, version_str: str | bytes) -> None:
92115
self.version_str = version_str
93116

94-
def __call__(self):
95-
return version_str
117+
def __call__(self) -> str | bytes:
118+
return self.version_str
96119

97120
class ProcessNamespace:
98-
def __init__(self, libc_version):
121+
def __init__(self, libc_version: LibcVersion) -> None:
99122
self.gnu_get_libc_version = libc_version
100123

101124
process_namespace = ProcessNamespace(LibcVersion(version_str))
@@ -108,12 +131,12 @@ def __init__(self, libc_version):
108131
assert _glibc_version_string() is None
109132

110133

111-
def test_glibc_version_string_confstr(monkeypatch):
134+
def test_glibc_version_string_confstr(monkeypatch: pytest.MonkeyPatch) -> None:
112135
monkeypatch.setattr(os, "confstr", lambda _: "glibc 2.20", raising=False)
113136
assert _glibc_version_string_confstr() == "2.20"
114137

115138

116-
def test_glibc_version_string_fail(monkeypatch):
139+
def test_glibc_version_string_fail(monkeypatch: pytest.MonkeyPatch) -> None:
117140
monkeypatch.setattr(os, "confstr", lambda _: None, raising=False)
118141
monkeypatch.setitem(sys.modules, "ctypes", None)
119142
assert _glibc_version_string() is None
@@ -124,55 +147,61 @@ def test_glibc_version_string_fail(monkeypatch):
124147
"failure",
125148
[pretend.raiser(ValueError), pretend.raiser(OSError), lambda _: "XXX"],
126149
)
127-
def test_glibc_version_string_confstr_fail(monkeypatch, failure):
150+
def test_glibc_version_string_confstr_fail(
151+
monkeypatch: pytest.MonkeyPatch, failure: typing.Callable[[int], str | None]
152+
) -> None:
128153
monkeypatch.setattr(os, "confstr", failure, raising=False)
129154
assert _glibc_version_string_confstr() is None
130155

131156

132-
def test_glibc_version_string_confstr_missing(monkeypatch):
157+
def test_glibc_version_string_confstr_missing(monkeypatch: pytest.MonkeyPatch) -> None:
133158
monkeypatch.delattr(os, "confstr", raising=False)
134159
assert _glibc_version_string_confstr() is None
135160

136161

137-
def test_glibc_version_string_ctypes_missing(monkeypatch):
162+
def test_glibc_version_string_ctypes_missing(monkeypatch: pytest.MonkeyPatch) -> None:
138163
monkeypatch.setitem(sys.modules, "ctypes", None)
139164
assert _glibc_version_string_ctypes() is None
140165

141166

142167
@pytest.mark.xfail(ctypes is None, reason="ctypes not available")
143-
def test_glibc_version_string_ctypes_raise_oserror(monkeypatch):
144-
def patched_cdll(_name):
168+
def test_glibc_version_string_ctypes_raise_oserror(
169+
monkeypatch: pytest.MonkeyPatch,
170+
) -> None:
171+
def patched_cdll(_name: str) -> None:
145172
raise OSError("Dynamic loading not supported")
146173

147174
monkeypatch.setattr(ctypes, "CDLL", patched_cdll)
148175
assert _glibc_version_string_ctypes() is None
149176

150177

151178
@pytest.mark.skipif(platform.system() != "Linux", reason="requires Linux")
152-
def test_is_manylinux_compatible_old():
179+
def test_is_manylinux_compatible_old() -> None:
153180
# Assuming no one is running this test with a version of glibc released in
154181
# 1997.
155-
assert _is_compatible("any", (2, 0))
182+
assert _is_compatible("any", _GLibCVersion(2, 0))
156183

157184

158-
def test_is_manylinux_compatible(monkeypatch):
185+
def test_is_manylinux_compatible(monkeypatch: pytest.MonkeyPatch) -> None:
159186
monkeypatch.setattr(_manylinux, "_glibc_version_string", lambda: "2.4")
160-
assert _is_compatible("any", (2, 4))
187+
assert _is_compatible("any", _GLibCVersion(2, 4))
161188

162189

163-
def test_glibc_version_string_none(monkeypatch):
190+
def test_glibc_version_string_none(monkeypatch: pytest.MonkeyPatch) -> None:
164191
monkeypatch.setattr(_manylinux, "_glibc_version_string", lambda: None)
165-
assert not _is_compatible("any", (2, 4))
192+
assert not _is_compatible("any", _GLibCVersion(2, 4))
166193

167194

168195
@pytest.mark.parametrize(
169196
"content", [None, "invalid-magic", "invalid-class", "invalid-data", "too-short"]
170197
)
171-
def test_parse_elf_bad_executable(content):
198+
def test_parse_elf_bad_executable(content: str | None) -> None:
199+
path_str: str | None
172200
if content:
173201
path = pathlib.Path(__file__).parent / "manylinux" / f"hello-world-{content}"
174-
path = os.fsdecode(path)
202+
path_str = os.fsdecode(path)
175203
else:
176-
path = None
177-
with _parse_elf(path) as ef:
204+
path_str = None
205+
# None is not supported in the type annotation, but it was tested before.
206+
with _parse_elf(path_str) as ef: # type: ignore[arg-type]
178207
assert ef is None

0 commit comments

Comments
 (0)