Skip to content

Commit e4e334a

Browse files
authored
Merge pull request #10388 from jdufresne/mypy-tests
Run mypy on the tests directory
2 parents 3e640bc + 943af79 commit e4e334a

13 files changed

+78
-88
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ repos:
4242
rev: v0.910
4343
hooks:
4444
- id: mypy
45-
exclude: tests
45+
exclude: tests/data
4646
args: ["--pretty", "--show-error-codes"]
4747
additional_dependencies: [
4848
'keyring==23.0.1',
4949
'nox==2021.6.12',
5050
'types-docutils==0.1.8',
51+
'types-setuptools==57.0.2',
5152
'types-six==0.1.9',
5253
]
5354

news/f231bb92-a022-4b48-b7fd-c83edefb4353.trivial.rst

Whitespace-only changes.

setup.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ follow_imports = skip
5151
[mypy-pip._vendor.requests.*]
5252
follow_imports = skip
5353

54+
[mypy-tests.*]
55+
# TODO: The following option should be removed at some point in the future.
56+
allow_untyped_defs = True
57+
5458
[tool:pytest]
5559
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache -r aR --color=yes
5660
markers =

tests/conftest.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import sys
99
import time
1010
from contextlib import ExitStack, contextmanager
11-
from typing import Dict, Iterable
11+
from typing import TYPE_CHECKING, Dict, Iterable, List
1212
from unittest.mock import patch
1313

1414
import pytest
@@ -21,11 +21,14 @@
2121
from tests.lib.certs import make_tls_cert, serialize_cert, serialize_key
2222
from tests.lib.path import Path
2323
from tests.lib.server import MockServer as _MockServer
24-
from tests.lib.server import Responder, make_mock_server, server_running
24+
from tests.lib.server import make_mock_server, server_running
2525
from tests.lib.venv import VirtualEnvironment
2626

2727
from .lib.compat import nullcontext
2828

29+
if TYPE_CHECKING:
30+
from wsgi import WSGIApplication
31+
2932

3033
def pytest_addoption(parser):
3134
parser.addoption(
@@ -521,7 +524,7 @@ def port(self):
521524
def host(self):
522525
return self._server.host
523526

524-
def set_responses(self, responses: Iterable[Responder]) -> None:
527+
def set_responses(self, responses: Iterable["WSGIApplication"]) -> None:
525528
assert not self._running, "responses cannot be set on running server"
526529
self._server.mock.side_effect = responses
527530

@@ -542,7 +545,7 @@ def stop(self) -> None:
542545
assert self._running, "idle server cannot be stopped"
543546
self.context.close()
544547

545-
def get_requests(self) -> Dict[str, str]:
548+
def get_requests(self) -> List[Dict[str, str]]:
546549
"""Get environ for each received request."""
547550
assert not self._running, "cannot get mock from running server"
548551
# Legacy: replace call[0][0] with call.args[0]

tests/functional/test_pep517.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import pytest
2-
3-
# The vendored `tomli` package is not used here because it doesn't
4-
# have write capability
5-
import toml
2+
import tomli_w
63

74
from pip._internal.build_env import BuildEnvironment
85
from pip._internal.req import InstallRequirement
@@ -18,7 +15,7 @@ def make_project(tmpdir, requires=None, backend=None, backend_path=None):
1815
buildsys["build-backend"] = backend
1916
if backend_path:
2017
buildsys["backend-path"] = backend_path
21-
data = toml.dumps({"build-system": buildsys})
18+
data = tomli_w.dumps({"build-system": buildsys})
2219
project_dir.joinpath("pyproject.toml").write_text(data)
2320
return project_dir
2421

@@ -189,7 +186,7 @@ def make_pyproject_with_setup(tmpdir, build_system=True, set_backend=True):
189186
if set_backend:
190187
buildsys["build-backend"] = "setuptools.build_meta"
191188
expect_script_dir_on_path = False
192-
project_data = toml.dumps({"build-system": buildsys})
189+
project_data = tomli_w.dumps({"build-system": buildsys})
193190
else:
194191
project_data = ""
195192

tests/lib/local_repos.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def local_checkout(
5454
repo_url_path = os.path.join(repo_url_path, "trunk")
5555
else:
5656
vcs_backend = vcs.get_backend(vcs_name)
57+
assert vcs_backend is not None
5758
vcs_backend.obtain(repo_url_path, url=hide_url(remote_repo))
5859

5960
return "{}+{}".format(vcs_name, path_to_url(repo_url_path))

tests/lib/server.py

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,18 @@
55
from base64 import b64encode
66
from contextlib import contextmanager
77
from textwrap import dedent
8-
from types import TracebackType
9-
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type
8+
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator
109
from unittest.mock import Mock
1110

1211
from werkzeug.serving import BaseWSGIServer, WSGIRequestHandler
1312
from werkzeug.serving import make_server as _make_server
1413

1514
from .compat import nullcontext
1615

17-
Environ = Dict[str, str]
18-
Status = str
19-
Headers = Iterable[Tuple[str, str]]
20-
ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
21-
Write = Callable[[bytes], None]
22-
StartResponse = Callable[[Status, Headers, Optional[ExcInfo]], Write]
23-
Body = List[bytes]
24-
Responder = Callable[[Environ, StartResponse], Body]
16+
if TYPE_CHECKING:
17+
from wsgi import StartResponse, WSGIApplication, WSGIEnvironment
18+
19+
Body = Iterable[bytes]
2520

2621

2722
class MockServer(BaseWSGIServer):
@@ -78,13 +73,13 @@ def make_environ(self):
7873

7974

8075
def _mock_wsgi_adapter(
81-
mock: Callable[[Environ, StartResponse], Responder]
82-
) -> Responder:
76+
mock: Callable[["WSGIEnvironment", "StartResponse"], "WSGIApplication"]
77+
) -> "WSGIApplication":
8378
"""Uses a mock to record function arguments and provide
8479
the actual function that should respond.
8580
"""
8681

87-
def adapter(environ: Environ, start_response: StartResponse) -> Body:
82+
def adapter(environ: "WSGIEnvironment", start_response: "StartResponse") -> Body:
8883
try:
8984
responder = mock(environ, start_response)
9085
except StopIteration:
@@ -134,7 +129,7 @@ def make_mock_server(**kwargs: Any) -> MockServer:
134129

135130

136131
@contextmanager
137-
def server_running(server: BaseWSGIServer) -> None:
132+
def server_running(server: BaseWSGIServer) -> Iterator[None]:
138133
"""Context manager for running the provided server in a separate thread."""
139134
thread = threading.Thread(target=server.serve_forever)
140135
thread.daemon = True
@@ -150,8 +145,8 @@ def server_running(server: BaseWSGIServer) -> None:
150145
# Helper functions for making responses in a declarative way.
151146

152147

153-
def text_html_response(text: str) -> Responder:
154-
def responder(environ: Environ, start_response: StartResponse) -> Body:
148+
def text_html_response(text: str) -> "WSGIApplication":
149+
def responder(environ: "WSGIEnvironment", start_response: "StartResponse") -> Body:
155150
start_response(
156151
"200 OK",
157152
[
@@ -180,24 +175,24 @@ def html5_page(text: str) -> str:
180175
)
181176

182177

183-
def index_page(spec: Dict[str, str]) -> Responder:
178+
def index_page(spec: Dict[str, str]) -> "WSGIApplication":
184179
def link(name, value):
185180
return '<a href="{}">{}</a>'.format(value, name)
186181

187182
links = "".join(link(*kv) for kv in spec.items())
188183
return text_html_response(html5_page(links))
189184

190185

191-
def package_page(spec: Dict[str, str]) -> Responder:
186+
def package_page(spec: Dict[str, str]) -> "WSGIApplication":
192187
def link(name, value):
193188
return '<a href="{}">{}</a>'.format(value, name)
194189

195190
links = "".join(link(*kv) for kv in spec.items())
196191
return text_html_response(html5_page(links))
197192

198193

199-
def file_response(path: str) -> Responder:
200-
def responder(environ: Environ, start_response: StartResponse) -> Body:
194+
def file_response(path: str) -> "WSGIApplication":
195+
def responder(environ: "WSGIEnvironment", start_response: "StartResponse") -> Body:
201196
size = os.stat(path).st_size
202197
start_response(
203198
"200 OK",
@@ -213,10 +208,10 @@ def responder(environ: Environ, start_response: StartResponse) -> Body:
213208
return responder
214209

215210

216-
def authorization_response(path: str) -> Responder:
211+
def authorization_response(path: str) -> "WSGIApplication":
217212
correct_auth = "Basic " + b64encode(b"USERNAME:PASSWORD").decode("ascii")
218213

219-
def responder(environ: Environ, start_response: StartResponse) -> Body:
214+
def responder(environ: "WSGIEnvironment", start_response: "StartResponse") -> Body:
220215

221216
if environ.get("HTTP_AUTHORIZATION") == correct_auth:
222217
size = os.stat(path).st_size

tests/lib/wheel.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from io import BytesIO, StringIO
1313
from typing import (
1414
AnyStr,
15-
Callable,
1615
Dict,
1716
Iterable,
1817
List,
@@ -28,9 +27,6 @@
2827

2928
from tests.lib.path import Path
3029

31-
# path, digest, size
32-
RecordLike = Tuple[str, str, str]
33-
RecordCallback = Callable[[List["Record"]], Union[str, bytes, List[RecordLike]]]
3430
# As would be used in metadata
3531
HeaderValue = Union[str, List[str]]
3632

@@ -82,7 +78,7 @@ def make_metadata_file(
8278
value: Defaulted[Optional[AnyStr]],
8379
updates: Defaulted[Dict[str, HeaderValue]],
8480
body: Defaulted[AnyStr],
85-
) -> File:
81+
) -> Optional[File]:
8682
if value is None:
8783
return None
8884

@@ -199,9 +195,8 @@ def digest(contents: bytes) -> str:
199195
def record_file_maker_wrapper(
200196
name: str,
201197
version: str,
202-
files: List[File],
198+
files: Iterable[File],
203199
record: Defaulted[Optional[AnyStr]],
204-
record_callback: Defaulted[RecordCallback],
205200
) -> Iterable[File]:
206201
records: List[Record] = []
207202
for file in files:
@@ -221,19 +216,22 @@ def record_file_maker_wrapper(
221216

222217
records.append(Record(record_path, "", ""))
223218

224-
if record_callback is not _default:
225-
records = record_callback(records)
226-
227219
with StringIO(newline="") as buf:
228220
writer = csv.writer(buf)
229-
for record in records:
230-
writer.writerow(record)
221+
for r in records:
222+
writer.writerow(r)
231223
contents = buf.getvalue().encode("utf-8")
232224

233225
yield File(record_path, contents)
234226

235227

236-
def wheel_name(name: str, version: str, pythons: str, abis: str, platforms: str) -> str:
228+
def wheel_name(
229+
name: str,
230+
version: str,
231+
pythons: Iterable[str],
232+
abis: Iterable[str],
233+
platforms: Iterable[str],
234+
) -> str:
237235
stem = "-".join(
238236
[
239237
name,
@@ -249,7 +247,7 @@ def wheel_name(name: str, version: str, pythons: str, abis: str, platforms: str)
249247
class WheelBuilder:
250248
"""A wheel that can be saved or converted to several formats."""
251249

252-
def __init__(self, name: str, files: List[File]) -> None:
250+
def __init__(self, name: str, files: Iterable[File]) -> None:
253251
self._name = name
254252
self._files = files
255253

@@ -259,9 +257,9 @@ def save_to_dir(self, path: Union[Path, str]) -> str:
259257
260258
:returns the wheel file path
261259
"""
262-
path = Path(path) / self._name
263-
path.write_bytes(self.as_bytes())
264-
return str(path)
260+
p = Path(path) / self._name
261+
p.write_bytes(self.as_bytes())
262+
return str(p)
265263

266264
def save_to(self, path: Union[Path, str]) -> str:
267265
"""Generate wheel file, saving to the provided path. Any parent
@@ -298,7 +296,6 @@ def make_wheel(
298296
console_scripts: Defaulted[List[str]] = _default,
299297
entry_points: Defaulted[Dict[str, List[str]]] = _default,
300298
record: Defaulted[Optional[AnyStr]] = _default,
301-
record_callback: Defaulted[RecordCallback] = _default,
302299
) -> WheelBuilder:
303300
"""
304301
Helper function for generating test wheels which are compliant by default.
@@ -359,9 +356,6 @@ def make_wheel(
359356
:param entry_points:
360357
:param record: if provided and None, then no RECORD file is generated;
361358
else if a string then sets the content of the RECORD file
362-
:param record_callback: callback function that receives and can edit the
363-
records before they are written to RECORD, ignored if record is
364-
provided
365359
"""
366360
pythons = ["py2", "py3"]
367361
abis = ["none"]
@@ -388,7 +382,7 @@ def make_wheel(
388382
actual_files = filter(None, possible_files)
389383

390384
files_and_record_file = record_file_maker_wrapper(
391-
name, version, actual_files, record, record_callback
385+
name, version, actual_files, record
392386
)
393387
wheel_file_name = wheel_name(name, version, pythons, abis, platforms)
394388

tests/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ setuptools
1010
virtualenv < 20.0
1111
werkzeug
1212
wheel
13-
toml
13+
tomli-w

tests/unit/resolution_resolvelib/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)