Skip to content

Commit ee0b1f6

Browse files
committed
pytest_httpserver: add type checking with mypy
Add mypy to dev dependencies and wire it in to gitlab actions. Fix type annotations (currently without "--strict"). Fixes #65.
1 parent f86f16f commit ee0b1f6

File tree

5 files changed

+29
-20
lines changed

5 files changed

+29
-20
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
make dev
1818
- name: Lint
1919
run: |
20-
make cs
20+
make cs mypy
2121
2222
test:
2323
name: Test with python ${{ matrix.python-version }}

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ dev: venv
1616
cs: venv
1717
.venv/bin/flake8 pytest_httpserver tests
1818

19+
.PHONY: mypy
20+
mypy: venv
21+
.venv/bin/mypy pytest_httpserver
22+
1923
.PHONY: autoformat
2024
autoformat: dev
2125
.venv/bin/autopep8 --in-place --recursive pytest_httpserver tests

pytest_httpserver/httpserver.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from enum import Enum
99
from contextlib import suppress, contextmanager
1010
from copy import copy
11-
from typing import Any, Callable, Mapping, Optional, Union, Pattern
11+
from typing import Any, Callable, List, Mapping, Optional, Tuple, Union, Pattern
1212
from ssl import SSLContext
1313
import abc
1414

@@ -109,20 +109,20 @@ class HeaderValueMatcher:
109109
:param matchers: mapping from header name to comparator function that accepts actual and expected header values
110110
and return whether they are equal as bool.
111111
"""
112-
DEFAULT_MATCHERS = {}
112+
DEFAULT_MATCHERS: Mapping[str, Callable[[Optional[str], str], bool]] = {}
113113

114-
def __init__(self, matchers: Optional[Mapping[str, Callable[[str, str], bool]]] = None):
114+
def __init__(self, matchers: Optional[Mapping[str, Callable[[Optional[str], str], bool]]] = None):
115115
self.matchers = self.DEFAULT_MATCHERS if matchers is None else matchers
116116

117117
@staticmethod
118-
def authorization_header_value_matcher(actual: str, expected: str) -> bool:
118+
def authorization_header_value_matcher(actual: Optional[str], expected: str) -> bool:
119119
return parse_authorization_header(actual) == parse_authorization_header(expected)
120120

121121
@staticmethod
122-
def default_header_value_matcher(actual: str, expected: str) -> bool:
122+
def default_header_value_matcher(actual: Optional[str], expected: str) -> bool:
123123
return actual == expected
124124

125-
def __call__(self, header_name: str, actual: str, expected: str) -> bool:
125+
def __call__(self, header_name: str, actual: Optional[str], expected: str) -> bool:
126126
try:
127127
matcher = self.matchers[header_name]
128128
except KeyError:
@@ -295,9 +295,8 @@ def __init__(
295295
self.query_matcher = _create_query_matcher(self.query_string)
296296
self.json = json
297297

298-
if headers is None:
299-
self.headers = {}
300-
else:
298+
self.headers: Mapping[str, str] = {}
299+
if headers is not None:
301300
self.headers = headers
302301

303302
if isinstance(data, str):
@@ -376,7 +375,7 @@ def match_json(self, request: Request) -> bool:
376375

377376
return json_received == self.json
378377

379-
def difference(self, request: Request) -> list:
378+
def difference(self, request: Request) -> List[Tuple]:
380379
"""
381380
Calculates the difference between the matcher and the request.
382381
@@ -388,7 +387,7 @@ def difference(self, request: Request) -> list:
388387
matches the fields set in the matcher object.
389388
"""
390389

391-
retval = []
390+
retval: List[Tuple] = []
392391

393392
if not self.match_uri(request):
394393
retval.append(("uri", request.path, self.uri))
@@ -437,7 +436,7 @@ class RequestHandler:
437436

438437
def __init__(self, matcher: RequestMatcher):
439438
self.matcher = matcher
440-
self.request_handler = None
439+
self.request_handler: Optional[Callable[[Request], Response]] = None
441440

442441
def respond(self, request: Request) -> Response:
443442
"""
@@ -521,7 +520,7 @@ class RequestHandlerList(list):
521520
522521
"""
523522

524-
def match(self, request: Request) -> RequestHandler:
523+
def match(self, request: Request) -> Optional[RequestHandler]:
525524
"""
526525
Returns the first request handler which matches the specified request. Otherwise, it returns `None`.
527526
"""
@@ -575,10 +574,10 @@ def __init__(self, host=DEFAULT_LISTEN_HOST, port=DEFAULT_LISTEN_PORT, ssl_conte
575574
self.port = port
576575
self.server = None
577576
self.server_thread = None
578-
self.assertions = []
579-
self.handler_errors = []
580-
self.log = []
581-
self.ordered_handlers = []
577+
self.assertions: List[str] = []
578+
self.handler_errors: List[Exception] = []
579+
self.log: List[Tuple[Request, Response]] = []
580+
self.ordered_handlers: List[RequestHandler] = []
582581
self.oneshot_handlers = RequestHandlerList()
583582
self.handlers = RequestHandlerList()
584583
self.permanently_failed = False
@@ -588,7 +587,7 @@ def __init__(self, host=DEFAULT_LISTEN_HOST, port=DEFAULT_LISTEN_PORT, ssl_conte
588587
else:
589588
self.default_waiting_settings = WaitingSettings()
590589
self._waiting_settings = copy(self.default_waiting_settings)
591-
self._waiting_result = queue.LifoQueue(maxsize=1)
590+
self._waiting_result: queue.LifoQueue[bool] = queue.LifoQueue(maxsize=1)
592591
self.no_handler_status_code = 500
593592

594593
def clear(self):
@@ -1124,7 +1123,7 @@ def test_wait(httpserver):
11241123
if self._waiting_settings.raise_assertions and not waiting.result:
11251124
self.check_assertions()
11261125

1127-
@Request.application
1126+
@Request.application # type: ignore
11281127
def application(self, request: Request):
11291128
"""
11301129
Entry point of werkzeug.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
Type hints updated to conform to 'mypy' type checking tool.
5+
Also, py.typed file is added as package data according to PEP 561.

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"sphinx_rtd_theme",
3636
"reno",
3737
"autopep8",
38+
"mypy",
3839
],
3940
"test": [
4041
"pytest",

0 commit comments

Comments
 (0)