pytest_httpserver 1.1.1__tar.gz → 1.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/CHANGES.rst +14 -0
  2. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/PKG-INFO +2 -3
  3. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/conf.py +1 -1
  4. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pyproject.toml +3 -3
  5. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pytest_httpserver/blocking_httpserver.py +2 -2
  6. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pytest_httpserver/httpserver.py +57 -40
  7. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_release.py +4 -1
  8. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_threaded.py +1 -1
  9. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/CONTRIBUTION.md +0 -0
  10. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/LICENSE +0 -0
  11. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/README.md +0 -0
  12. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/Makefile +0 -0
  13. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/_static/.placeholder +0 -0
  14. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/api.rst +0 -0
  15. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/background.rst +0 -0
  16. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/changes.rst +0 -0
  17. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/fixtures.rst +0 -0
  18. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/guide.rst +0 -0
  19. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/howto.rst +0 -0
  20. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/index.rst +0 -0
  21. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/patch.py +0 -0
  22. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/tutorial.rst +0 -0
  23. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/doc/upgrade.rst +0 -0
  24. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/example.py +0 -0
  25. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/example_pytest.py +0 -0
  26. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pytest_httpserver/__init__.py +0 -0
  27. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pytest_httpserver/hooks.py +0 -0
  28. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pytest_httpserver/py.typed +0 -0
  29. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/pytest_httpserver/pytest_plugin.py +0 -0
  30. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/Makefile +0 -0
  31. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/README +0 -0
  32. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/rootCA.cnf +0 -0
  33. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/rootCA.crt +0 -0
  34. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/rootCA.key +0 -0
  35. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/rootCA.srl +0 -0
  36. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/server.cnf +0 -0
  37. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/server.crt +0 -0
  38. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/server.csr +0 -0
  39. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/server.key +0 -0
  40. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/assets/v3.ext +0 -0
  41. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/conftest.py +0 -0
  42. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_example_blocking_httpserver.py +0 -0
  43. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_example_query_params1.py +0 -0
  44. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_example_query_params2.py +0 -0
  45. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_authorization_headers.py +0 -0
  46. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_case_insensitive_matcher.py +0 -0
  47. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_check.py +0 -0
  48. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_check_handler_errors.py +0 -0
  49. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_custom_handler.py +0 -0
  50. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_custom_hooks.py +0 -0
  51. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_custom_request_matcher.py +0 -0
  52. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_header_value_matcher.py +0 -0
  53. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_hooks.py +0 -0
  54. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_json_matcher.py +0 -0
  55. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_log_querying.py +0 -0
  56. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_query_params_dict.py +0 -0
  57. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_query_params_never_do_this.py +0 -0
  58. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_query_params_proper_use.py +0 -0
  59. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_regexp.py +0 -0
  60. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_timeout_requests.py +0 -0
  61. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_url_matcher.py +0 -0
  62. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/examples/test_howto_wait_success.py +0 -0
  63. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_blocking_httpserver.py +0 -0
  64. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_handler_errors.py +0 -0
  65. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_headers.py +0 -0
  66. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_hooks.py +0 -0
  67. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_ip_protocols.py +0 -0
  68. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_json_matcher.py +0 -0
  69. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_log_leak.py +0 -0
  70. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_log_querying.py +0 -0
  71. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_matcher.py +0 -0
  72. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_mixed.py +0 -0
  73. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_oneshot.py +0 -0
  74. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_ordered.py +0 -0
  75. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_parse_qs.py +0 -0
  76. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_permanent.py +0 -0
  77. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_port_changing.py +0 -0
  78. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_querymatcher.py +0 -0
  79. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_querystring.py +0 -0
  80. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_ssl.py +0 -0
  81. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_urimatch.py +0 -0
  82. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_wait.py +0 -0
  83. {pytest_httpserver-1.1.1 → pytest_httpserver-1.1.2}/tests/test_with_statement.py +0 -0
@@ -2,6 +2,20 @@
2
2
  Release Notes
3
3
  =============
4
4
 
5
+ .. _Release Notes_1.1.2:
6
+
7
+ 1.1.2
8
+ =====
9
+
10
+ .. _Release Notes_1.1.2_Deprecation Notes:
11
+
12
+ Deprecation Notes
13
+ -----------------
14
+
15
+ - Python versions earlier than 3.9 have been deprecated in order to make the
16
+ code more type safe. Python 3.8 has reached EOL on 2024-10-07.
17
+
18
+
5
19
  .. _Release Notes_1.1.1:
6
20
 
7
21
  1.1.1
@@ -1,19 +1,18 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytest_httpserver
3
- Version: 1.1.1
3
+ Version: 1.1.2
4
4
  Summary: pytest-httpserver is a httpserver for pytest
5
5
  Home-page: https://github.com/csernazs/pytest-httpserver
6
6
  License: MIT
7
7
  Author: Zsolt Cserna
8
8
  Author-email: cserna.zsolt@gmail.com
9
- Requires-Python: >=3.8
9
+ Requires-Python: >=3.9
10
10
  Classifier: Development Status :: 3 - Alpha
11
11
  Classifier: Framework :: Pytest
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.8
17
16
  Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
@@ -68,7 +68,7 @@ author = "Zsolt Cserna"
68
68
  # built documents.
69
69
  #
70
70
  # The short X.Y version.
71
- version = "1.1.1"
71
+ version = "1.1.2"
72
72
  # The full version, including alpha/beta/rc tags.
73
73
  release = version
74
74
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pytest_httpserver"
3
- version = "1.1.1"
3
+ version = "1.1.2"
4
4
  description = "pytest-httpserver is a httpserver for pytest"
5
5
  authors = ["Zsolt Cserna <cserna.zsolt@gmail.com>"]
6
6
  license = "MIT"
@@ -24,7 +24,7 @@ include = [
24
24
  ]
25
25
 
26
26
  [tool.poetry.dependencies]
27
- python = ">=3.8"
27
+ python = ">=3.9"
28
28
  Werkzeug = ">= 2.0.0"
29
29
 
30
30
 
@@ -137,5 +137,5 @@ lint.ignore = [
137
137
  "UP032",
138
138
  ]
139
139
  line-length = 120
140
- target-version = "py38"
140
+ target-version = "py39"
141
141
  exclude = ["doc", "example*.py", "tests/examples/*.py"]
@@ -4,8 +4,6 @@ from queue import Empty
4
4
  from queue import Queue
5
5
  from typing import TYPE_CHECKING
6
6
  from typing import Any
7
- from typing import Mapping
8
- from typing import Pattern
9
7
 
10
8
  from pytest_httpserver.httpserver import METHOD_ALL
11
9
  from pytest_httpserver.httpserver import UNDEFINED
@@ -16,6 +14,8 @@ from pytest_httpserver.httpserver import RequestHandlerBase
16
14
  from pytest_httpserver.httpserver import URIPattern
17
15
 
18
16
  if TYPE_CHECKING:
17
+ from collections.abc import Mapping
18
+ from re import Pattern
19
19
  from ssl import SSLContext
20
20
 
21
21
  from werkzeug import Request
@@ -9,20 +9,19 @@ import threading
9
9
  import time
10
10
  import urllib.parse
11
11
  from collections import defaultdict
12
+ from collections.abc import Iterable
13
+ from collections.abc import Mapping
14
+ from collections.abc import MutableMapping
12
15
  from contextlib import contextmanager
13
16
  from contextlib import suppress
14
17
  from copy import copy
15
18
  from enum import Enum
19
+ from re import Pattern
16
20
  from typing import TYPE_CHECKING
17
21
  from typing import Any
18
22
  from typing import Callable
19
23
  from typing import ClassVar
20
- from typing import Iterable
21
- from typing import Mapping
22
- from typing import MutableMapping
23
24
  from typing import Optional
24
- from typing import Pattern
25
- from typing import Tuple
26
25
  from typing import Union
27
26
 
28
27
  import werkzeug.http
@@ -34,13 +33,16 @@ from werkzeug.serving import make_server
34
33
 
35
34
  if TYPE_CHECKING:
36
35
  from ssl import SSLContext
36
+ from types import TracebackType
37
+
38
+ from werkzeug.serving import BaseWSGIServer
37
39
 
38
40
  URI_DEFAULT = ""
39
41
  METHOD_ALL = "__ALL"
40
42
 
41
43
  HEADERS_T = Union[
42
44
  Mapping[str, Union[str, Iterable[str]]],
43
- Iterable[Tuple[str, str]],
45
+ Iterable[tuple[str, str]],
44
46
  ]
45
47
 
46
48
  HVMATCHER_T = Callable[[str, Optional[str], str], bool]
@@ -113,11 +115,13 @@ class Waiting:
113
115
 
114
116
  @property
115
117
  def result(self) -> bool:
116
- return self._result
118
+ return bool(self._result)
117
119
 
118
120
  @property
119
121
  def elapsed_time(self) -> float:
120
122
  """Elapsed time in seconds"""
123
+ if self._stop is None:
124
+ raise TypeError("unsupported operand type(s) for -: 'NoneType' and 'float'")
121
125
  return self._stop - self._start
122
126
 
123
127
 
@@ -139,7 +143,7 @@ class HeaderValueMatcher:
139
143
  func = getattr(Authorization, "from_header", None)
140
144
  if func is None: # Werkzeug < 2.3.0
141
145
  func = werkzeug.http.parse_authorization_header # type: ignore[attr-defined]
142
- return func(actual) == func(expected)
146
+ return func(actual) == func(expected) # type: ignore
143
147
 
144
148
  @staticmethod
145
149
  def default_header_value_matcher(actual: str | None, expected: str) -> bool:
@@ -174,7 +178,7 @@ class QueryMatcher(abc.ABC):
174
178
  return values[0] == values[1]
175
179
 
176
180
  @abc.abstractmethod
177
- def get_comparing_values(self, request_query_string: bytes) -> tuple:
181
+ def get_comparing_values(self, request_query_string: bytes) -> tuple[Any, Any]:
178
182
  pass
179
183
 
180
184
 
@@ -195,10 +199,10 @@ class StringQueryMatcher(QueryMatcher):
195
199
 
196
200
  self.query_string = query_string
197
201
 
198
- def get_comparing_values(self, request_query_string: bytes) -> tuple:
202
+ def get_comparing_values(self, request_query_string: bytes) -> tuple[bytes, bytes]:
199
203
  if isinstance(self.query_string, str):
200
204
  query_string = self.query_string.encode()
201
- elif isinstance(self.query_string, bytes):
205
+ elif isinstance(self.query_string, bytes): # type: ignore
202
206
  query_string = self.query_string
203
207
  else:
204
208
  raise TypeError("query_string must be a string, or a bytes-like object")
@@ -211,7 +215,7 @@ class MappingQueryMatcher(QueryMatcher):
211
215
  Matches a query string to a dictionary or MultiDict specified
212
216
  """
213
217
 
214
- def __init__(self, query_dict: Mapping | MultiDict):
218
+ def __init__(self, query_dict: Mapping[str, str] | MultiDict[str, str]):
215
219
  """
216
220
  :param query_dict: if dictionary (Mapping) is specified, it will be used as a
217
221
  key-value mapping where both key and value should be string. If there are multiple
@@ -221,7 +225,7 @@ class MappingQueryMatcher(QueryMatcher):
221
225
  """
222
226
  self.query_dict = query_dict
223
227
 
224
- def get_comparing_values(self, request_query_string: bytes) -> tuple:
228
+ def get_comparing_values(self, request_query_string: bytes) -> tuple[Mapping[str, str], Mapping[str, str]]:
225
229
  query = MultiDict(urllib.parse.parse_qsl(request_query_string.decode("utf-8")))
226
230
  if isinstance(self.query_dict, MultiDict):
227
231
  return (query, self.query_dict)
@@ -241,14 +245,14 @@ class BooleanQueryMatcher(QueryMatcher):
241
245
  """
242
246
  self.result = result
243
247
 
244
- def get_comparing_values(self, request_query_string): # noqa: ARG002
248
+ def get_comparing_values(self, request_query_string: bytes): # noqa: ARG002
245
249
  if self.result:
246
250
  return (True, True)
247
251
  else:
248
252
  return (True, False)
249
253
 
250
254
 
251
- def _create_query_matcher(query_string: None | QueryMatcher | str | bytes | Mapping) -> QueryMatcher:
255
+ def _create_query_matcher(query_string: None | QueryMatcher | str | bytes | Mapping[str, str]) -> QueryMatcher:
252
256
  if isinstance(query_string, QueryMatcher):
253
257
  return query_string
254
258
 
@@ -312,7 +316,7 @@ class RequestMatcher:
312
316
  data: str | bytes | None = None,
313
317
  data_encoding: str = "utf-8",
314
318
  headers: Mapping[str, str] | None = None,
315
- query_string: None | QueryMatcher | str | bytes | Mapping = None,
319
+ query_string: None | QueryMatcher | str | bytes | Mapping[str, str] = None,
316
320
  header_value_matcher: HVMATCHER_T | None = None,
317
321
  json: Any = UNDEFINED,
318
322
  ):
@@ -410,7 +414,7 @@ class RequestMatcher:
410
414
 
411
415
  return json_received == self.json
412
416
 
413
- def difference(self, request: Request) -> list[tuple]:
417
+ def difference(self, request: Request) -> list[tuple[str, str, str | URIPattern]]:
414
418
  """
415
419
  Calculates the difference between the matcher and the request.
416
420
 
@@ -422,7 +426,7 @@ class RequestMatcher:
422
426
  matches the fields set in the matcher object.
423
427
  """
424
428
 
425
- retval: list[tuple] = []
429
+ retval: list[tuple[str, Any, Any]] = []
426
430
 
427
431
  if not self.match_uri(request):
428
432
  retval.append(("uri", request.path, self.uri))
@@ -433,8 +437,8 @@ class RequestMatcher:
433
437
  if not self.query_matcher.match(request.query_string):
434
438
  retval.append(("query_string", request.query_string, self.query_string))
435
439
 
436
- request_headers = {}
437
- expected_headers = {}
440
+ request_headers: dict[str, str | None] = {}
441
+ expected_headers: dict[str, str] = {}
438
442
  for key, value in self.headers.items():
439
443
  if not self.header_value_matcher(key, request.headers.get(key), value):
440
444
  request_headers[key] = request.headers.get(key)
@@ -467,7 +471,7 @@ class RequestHandlerBase(abc.ABC):
467
471
 
468
472
  def respond_with_json(
469
473
  self,
470
- response_json,
474
+ response_json: Any,
471
475
  status: int = 200,
472
476
  headers: Mapping[str, str] | None = None,
473
477
  content_type: str = "application/json",
@@ -578,7 +582,7 @@ class RequestHandler(RequestHandlerBase):
578
582
  return retval
579
583
 
580
584
 
581
- class RequestHandlerList(list):
585
+ class RequestHandlerList(list[RequestHandler]):
582
586
  """
583
587
  Represents a list of :py:class:`RequestHandler` objects.
584
588
 
@@ -638,9 +642,9 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
638
642
  """
639
643
  self.host = host
640
644
  self.port = port
641
- self.server = None
642
- self.server_thread = None
643
- self.assertions: list[str] = []
645
+ self.server: BaseWSGIServer | None = None
646
+ self.server_thread: threading.Thread | None = None
647
+ self.assertions: list[str | AssertionError] = []
644
648
  self.handler_errors: list[Exception] = []
645
649
  self.log: list[tuple[Request, Response]] = []
646
650
  self.ssl_context = ssl_context
@@ -727,7 +731,7 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
727
731
 
728
732
  This should not be called directly, but can be overridden to tailor it to your needs.
729
733
  """
730
-
734
+ assert self.server is not None
731
735
  self.server.serve_forever()
732
736
 
733
737
  def is_running(self) -> bool:
@@ -736,7 +740,7 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
736
740
  """
737
741
  return bool(self.server)
738
742
 
739
- def start(self):
743
+ def start(self) -> None:
740
744
  """
741
745
  Start the server in a thread.
742
746
 
@@ -755,9 +759,16 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
755
759
  if self.is_running():
756
760
  raise HTTPServerError("Server is already running")
757
761
 
762
+ app = Request.application(self.application)
763
+
758
764
  self.server = make_server(
759
- self.host, self.port, self.application, ssl_context=self.ssl_context, threaded=self.threaded
765
+ self.host,
766
+ self.port,
767
+ app,
768
+ ssl_context=self.ssl_context,
769
+ threaded=self.threaded,
760
770
  )
771
+
761
772
  self.port = self.server.port # Update port (needed if `port` was set to 0)
762
773
  self.server_thread = threading.Thread(target=self.thread_target)
763
774
  self.server_thread.start()
@@ -772,6 +783,8 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
772
783
  Only a running server can be stopped. If the sever is not running, :py:class`HTTPServerError`
773
784
  will be raised.
774
785
  """
786
+ assert self.server is not None
787
+ assert self.server_thread is not None
775
788
  if not self.is_running():
776
789
  raise HTTPServerError("Server is not running")
777
790
  self.server.shutdown()
@@ -779,7 +792,7 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
779
792
  self.server = None
780
793
  self.server_thread = None
781
794
 
782
- def add_assertion(self, obj):
795
+ def add_assertion(self, obj: str | AssertionError):
783
796
  """
784
797
  Add a new assertion
785
798
 
@@ -848,8 +861,7 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
848
861
  :return: the response object what the handler responded, or a response which contains the error
849
862
  """
850
863
 
851
- @Request.application # type: ignore
852
- def application(self, request: Request):
864
+ def application(self, request: Request) -> Response:
853
865
  """
854
866
  Entry point of werkzeug.
855
867
 
@@ -875,7 +887,12 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
875
887
  self.start()
876
888
  return self
877
889
 
878
- def __exit__(self, *args, **kwargs):
890
+ def __exit__(
891
+ self,
892
+ exc_type: type[BaseException] | None,
893
+ exc_value: BaseException | None,
894
+ traceback: TracebackType | None,
895
+ ):
879
896
  """
880
897
  Provide the context API
881
898
 
@@ -886,7 +903,7 @@ class HTTPServerBase(abc.ABC): # pylint: disable=too-many-instance-attributes
886
903
  self.stop()
887
904
 
888
905
  @staticmethod
889
- def format_host(host):
906
+ def format_host(host: str):
890
907
  """
891
908
  Formats a hostname so it can be used in a URL.
892
909
  Notably, this adds brackets around IPV6 addresses when
@@ -929,8 +946,8 @@ class HTTPServer(HTTPServerBase): # pylint: disable=too-many-instance-attribute
929
946
 
930
947
  def __init__(
931
948
  self,
932
- host=DEFAULT_LISTEN_HOST,
933
- port=DEFAULT_LISTEN_PORT,
949
+ host: str = DEFAULT_LISTEN_HOST,
950
+ port: int = DEFAULT_LISTEN_PORT,
934
951
  ssl_context: SSLContext | None = None,
935
952
  default_waiting_settings: WaitingSettings | None = None,
936
953
  *,
@@ -995,7 +1012,7 @@ class HTTPServer(HTTPServerBase): # pylint: disable=too-many-instance-attribute
995
1012
  data: str | bytes | None = None,
996
1013
  data_encoding: str = "utf-8",
997
1014
  headers: Mapping[str, str] | None = None,
998
- query_string: None | QueryMatcher | str | bytes | Mapping = None,
1015
+ query_string: None | QueryMatcher | str | bytes | Mapping[str, str] = None,
999
1016
  header_value_matcher: HVMATCHER_T | None = None,
1000
1017
  handler_type: HandlerType = HandlerType.PERMANENT,
1001
1018
  json: Any = UNDEFINED,
@@ -1078,7 +1095,7 @@ class HTTPServer(HTTPServerBase): # pylint: disable=too-many-instance-attribute
1078
1095
  data: str | bytes | None = None,
1079
1096
  data_encoding: str = "utf-8",
1080
1097
  headers: Mapping[str, str] | None = None,
1081
- query_string: None | QueryMatcher | str | bytes | Mapping = None,
1098
+ query_string: None | QueryMatcher | str | bytes | Mapping[str, str] = None,
1082
1099
  header_value_matcher: HVMATCHER_T | None = None,
1083
1100
  json: Any = UNDEFINED,
1084
1101
  ) -> RequestHandler:
@@ -1133,7 +1150,7 @@ class HTTPServer(HTTPServerBase): # pylint: disable=too-many-instance-attribute
1133
1150
  data: str | bytes | None = None,
1134
1151
  data_encoding: str = "utf-8",
1135
1152
  headers: Mapping[str, str] | None = None,
1136
- query_string: None | QueryMatcher | str | bytes | Mapping = None,
1153
+ query_string: None | QueryMatcher | str | bytes | Mapping[str, str] = None,
1137
1154
  header_value_matcher: HVMATCHER_T | None = None,
1138
1155
  json: Any = UNDEFINED,
1139
1156
  ) -> RequestHandler:
@@ -1191,13 +1208,13 @@ class HTTPServer(HTTPServerBase): # pylint: disable=too-many-instance-attribute
1191
1208
  This method is primarily used when reporting errors.
1192
1209
  """
1193
1210
 
1194
- def format_handlers(handlers):
1211
+ def format_handlers(handlers: list[RequestHandler]):
1195
1212
  if handlers:
1196
1213
  return [" {!r}".format(handler.matcher) for handler in handlers]
1197
1214
  else:
1198
1215
  return [" none"]
1199
1216
 
1200
- lines = []
1217
+ lines: list[str] = []
1201
1218
  lines.append("Ordered matchers:")
1202
1219
  lines.extend(format_handlers(self.ordered_handlers))
1203
1220
  lines.append("")
@@ -8,10 +8,13 @@ import tarfile
8
8
  import zipfile
9
9
  from dataclasses import dataclass
10
10
  from pathlib import Path
11
- from typing import Iterable
11
+ from typing import TYPE_CHECKING
12
12
 
13
13
  import pytest
14
14
 
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Iterable
17
+
15
18
  try:
16
19
  import tomllib
17
20
  except ImportError:
@@ -1,7 +1,7 @@
1
1
  import http.client
2
2
  import threading
3
3
  import time
4
- from typing import Iterable
4
+ from collections.abc import Iterable
5
5
 
6
6
  import pytest
7
7
  from werkzeug import Request