Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-pytest-httpserver for
openSUSE:Factory checked in at 2024-03-01 23:35:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest-httpserver (Old)
and /work/SRC/openSUSE:Factory/.python-pytest-httpserver.new.1770 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pytest-httpserver"
Fri Mar 1 23:35:49 2024 rev:13 rq:1153853 version:1.0.10
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-pytest-httpserver/python-pytest-httpserver.changes
2023-06-03 00:06:42.461806124 +0200
+++
/work/SRC/openSUSE:Factory/.python-pytest-httpserver.new.1770/python-pytest-httpserver.changes
2024-03-01 23:35:57.554226607 +0100
@@ -1,0 +2,14 @@
+Fri Mar 1 10:19:34 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 1.0.10:
+ * When there's no handler for the request, add more details to
+ the response sent by the server about the request to help
+ debugging.
+ * Use ruff for linting. It includes some source code changes
+ which should not introduce functional changes, or API
+ changes.
+ * Add __repr__ to RequestHandler object so when it is compared
+ (eg. with the log attribute of the server) it will show the
+ matcher parameters.
+
+-------------------------------------------------------------------
Old:
----
pytest_httpserver-1.0.8.tar.gz
New:
----
pytest_httpserver-1.0.10.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pytest-httpserver.spec ++++++
--- /var/tmp/diff_new_pack.IFelks/_old 2024-03-01 23:35:58.046244401 +0100
+++ /var/tmp/diff_new_pack.IFelks/_new 2024-03-01 23:35:58.050244545 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pytest-httpserver
#
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-pytest-httpserver
-Version: 1.0.8
+Version: 1.0.10
Release: 0
Summary: A HTTP server for pytest
License: MIT
++++++ pytest_httpserver-1.0.8.tar.gz -> pytest_httpserver-1.0.10.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/CHANGES.rst
new/pytest_httpserver-1.0.10/CHANGES.rst
--- old/pytest_httpserver-1.0.8/CHANGES.rst 2023-05-22 20:35:22.853064500
+0200
+++ new/pytest_httpserver-1.0.10/CHANGES.rst 2024-02-24 20:44:27.227664200
+0100
@@ -2,6 +2,43 @@
Release Notes
=============
+.. _Release Notes_1.0.10:
+
+1.0.10
+======
+
+.. _Release Notes_1.0.10_New Features:
+
+New Features
+------------
+
+- When there's no handler for the request, add more details to the response
+ sent by the server about the request to help debugging.
+
+
+.. _Release Notes_1.0.10_Other Notes:
+
+Other Notes
+-----------
+
+- Use ruff for linting. It includes some source code changes which should not
+ introduce functional changes, or API changes.
+
+
+.. _Release Notes_1.0.9:
+
+1.0.9
+=====
+
+.. _Release Notes_1.0.9_New Features:
+
+New Features
+------------
+
+- Add ``__repr__`` to ``RequestHandler`` object so when it is compared (eg.
with
+ the ``log`` attribute of the server) it will show the matcher parameters.
+
+
.. _Release Notes_1.0.8:
1.0.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/PKG-INFO
new/pytest_httpserver-1.0.10/PKG-INFO
--- old/pytest_httpserver-1.0.8/PKG-INFO 1970-01-01 01:00:00.000000000
+0100
+++ new/pytest_httpserver-1.0.10/PKG-INFO 1970-01-01 01:00:00.000000000
+0100
@@ -1,12 +1,12 @@
Metadata-Version: 2.1
-Name: pytest-httpserver
-Version: 1.0.8
+Name: pytest_httpserver
+Version: 1.0.10
Summary: pytest-httpserver is a httpserver for pytest
Home-page: https://github.com/csernazs/pytest-httpserver
License: MIT
Author: Zsolt Cserna
Author-email: [email protected]
-Requires-Python: >=3.8,<4.0
+Requires-Python: >=3.8
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Pytest
Classifier: Intended Audience :: Developers
@@ -17,6 +17,7 @@
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Dist: Werkzeug (>=2.0.0)
Project-URL: Bug Tracker, https://github.com/csernazs/pytest-httpserver/issues
@@ -26,10 +27,12 @@
[](https://github.com/csernazs/pytest-httpserver/actions?query=workflow%3Abuild+branch%3Amaster)
[](https://pytest-httpserver.readthedocs.io/en/latest/?badge=latest)
- [](https://opensource.org/licenses/MIT)
-[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=K6PU3AGBZW4QC&item_name=pytest-httpserver¤cy_code=EUR&source=url)
+[](https://opensource.org/licenses/MIT)
[](https://codecov.io/gh/csernazs/pytest-httpserver)
[](https://github.com/psf/black)
+[](https://github.com/astral-sh/ruff)
+[](https://pepy.tech/project/pytest-httpserver)
+[](https://github.com/pre-commit/pre-commit)
## pytest_httpserver
@@ -143,12 +146,16 @@
### Donation
-If you want to donate to this project, you can find the donate button at the
top
-of the README.
+Currently, this project is based heavily on werkzeug and pytest.
-Currently, this project is based heavily on werkzeug. Werkzeug does all the
heavy lifting
-behind the scenes, parsing HTTP request and defining Request and Response
objects, which
-are currently transparent in the API.
+Werkzeug does all the heavy lifting behind the scenes, parsing HTTP request and
+defining Request and Response objects, which are currently transparent in the
+API.
-If you wish to donate, please consider donating to them:
https://palletsprojects.com/donate
+If you wish to donate to werkzeug: https://palletsprojects.com/donate
+
+
+Pytest is the de-facto test library for python.
+
+If you wish to donate to pytest: https://opencollective.com/pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/README.md
new/pytest_httpserver-1.0.10/README.md
--- old/pytest_httpserver-1.0.8/README.md 2023-01-18 23:01:30.858852400
+0100
+++ new/pytest_httpserver-1.0.10/README.md 2024-02-24 20:33:46.159088900
+0100
@@ -1,9 +1,11 @@
[](https://github.com/csernazs/pytest-httpserver/actions?query=workflow%3Abuild+branch%3Amaster)
[](https://pytest-httpserver.readthedocs.io/en/latest/?badge=latest)
- [](https://opensource.org/licenses/MIT)
-[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=K6PU3AGBZW4QC&item_name=pytest-httpserver¤cy_code=EUR&source=url)
+[](https://opensource.org/licenses/MIT)
[](https://codecov.io/gh/csernazs/pytest-httpserver)
[](https://github.com/psf/black)
+[](https://github.com/astral-sh/ruff)
+[](https://pepy.tech/project/pytest-httpserver)
+[](https://github.com/pre-commit/pre-commit)
## pytest_httpserver
@@ -117,11 +119,15 @@
### Donation
-If you want to donate to this project, you can find the donate button at the
top
-of the README.
+Currently, this project is based heavily on werkzeug and pytest.
-Currently, this project is based heavily on werkzeug. Werkzeug does all the
heavy lifting
-behind the scenes, parsing HTTP request and defining Request and Response
objects, which
-are currently transparent in the API.
+Werkzeug does all the heavy lifting behind the scenes, parsing HTTP request and
+defining Request and Response objects, which are currently transparent in the
+API.
-If you wish to donate, please consider donating to them:
https://palletsprojects.com/donate
+If you wish to donate to werkzeug: https://palletsprojects.com/donate
+
+
+Pytest is the de-facto test library for python.
+
+If you wish to donate to pytest: https://opencollective.com/pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/doc/conf.py
new/pytest_httpserver-1.0.10/doc/conf.py
--- old/pytest_httpserver-1.0.8/doc/conf.py 2023-05-22 20:35:22.853064500
+0200
+++ new/pytest_httpserver-1.0.10/doc/conf.py 2024-02-24 20:44:27.227664200
+0100
@@ -66,7 +66,7 @@
# built documents.
#
# The short X.Y version.
-version = "1.0.8"
+version = "1.0.10"
# The full version, including alpha/beta/rc tags.
release = version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/doc/tutorial.rst
new/pytest_httpserver-1.0.10/doc/tutorial.rst
--- old/pytest_httpserver-1.0.8/doc/tutorial.rst 2023-05-16
20:58:37.763110000 +0200
+++ new/pytest_httpserver-1.0.10/doc/tutorial.rst 2024-02-17
17:55:07.351395600 +0100
@@ -39,6 +39,12 @@
it must respond with the provided json. The library accepts here any python
object which is json serializable. Here, a dict is provided.
+.. note::
+
+ It is important to specify what response to be sent back to the client
+ otherwise *pytest-httpserver* will error with ``Matching request handler
+ found but no response defined`` message on an incoming request.
+
In the next line, an http request is sent with the *requests* library:
.. code:: python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/pyproject.toml
new/pytest_httpserver-1.0.10/pyproject.toml
--- old/pytest_httpserver-1.0.8/pyproject.toml 2023-05-22 20:35:22.853064500
+0200
+++ new/pytest_httpserver-1.0.10/pyproject.toml 2024-02-24 20:44:27.227664200
+0100
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pytest_httpserver"
-version = "1.0.8"
+version = "1.0.10"
description = "pytest-httpserver is a httpserver for pytest"
authors = ["Zsolt Cserna <[email protected]>"]
license = "MIT"
@@ -24,7 +24,7 @@
]
[tool.poetry.dependencies]
-python = ">=3.8,<4.0"
+python = ">=3.8"
Werkzeug = ">= 2.0.0"
@@ -51,6 +51,7 @@
types-toml = "^0.10.8"
toml = "^0.10.2"
black = "^23.1.0"
+ruff = "^0.2.1"
[tool.poetry.group.doc]
@@ -88,3 +89,55 @@
[tool.mypy]
files = ["pytest_httpserver", "scripts", "tests", "doc"]
implicit_reexport = false
+
+
+[tool.black]
+line-length = 120
+safe = true
+
+[tool.ruff]
+lint.select = ["ALL"]
+lint.ignore = [
+ "I",
+ "D",
+
+ "ANN",
+ "ARG005",
+ "B011",
+ "B904",
+ "C408",
+ "C901",
+ "COM812",
+ "EM101",
+ "EM103",
+ "FBT002",
+ "FIX002",
+ "INP001",
+ "PGH003",
+ "PLR0912",
+ "PLR0913",
+ "PLR2004",
+ "PLW2901",
+ "PT004",
+ "PT012",
+ "PT013",
+ "PTH118",
+ "PTH120",
+ "RET504",
+ "RET505",
+ "RET506",
+ "RUF005",
+ "S101",
+ "S113",
+ "S603",
+ "S607",
+ "SIM108",
+ "T201",
+ "TD002",
+ "TD003",
+ "TRY003",
+ "UP032",
+]
+line-length = 120
+target-version = "py38"
+exclude = ["doc", "example*.py", "tests/examples/*.py"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_httpserver-1.0.8/pytest_httpserver/blocking_httpserver.py
new/pytest_httpserver-1.0.10/pytest_httpserver/blocking_httpserver.py
--- old/pytest_httpserver-1.0.8/pytest_httpserver/blocking_httpserver.py
2023-02-03 08:55:52.829130600 +0100
+++ new/pytest_httpserver-1.0.10/pytest_httpserver/blocking_httpserver.py
2024-02-17 17:55:07.352395800 +0100
@@ -1,15 +1,11 @@
+from __future__ import annotations
+
from queue import Empty
from queue import Queue
-from ssl import SSLContext
+from typing import TYPE_CHECKING
from typing import Any
-from typing import Dict
from typing import Mapping
-from typing import Optional
from typing import Pattern
-from typing import Union
-
-from werkzeug.wrappers import Request
-from werkzeug.wrappers import Response
from pytest_httpserver.httpserver import METHOD_ALL
from pytest_httpserver.httpserver import UNDEFINED
@@ -19,6 +15,12 @@
from pytest_httpserver.httpserver import RequestHandlerBase
from pytest_httpserver.httpserver import URIPattern
+if TYPE_CHECKING:
+ from ssl import SSLContext
+
+ from werkzeug.wrappers import Request
+ from werkzeug.wrappers import Response
+
class BlockingRequestHandler(RequestHandlerBase):
"""
@@ -59,23 +61,23 @@
self,
host=DEFAULT_LISTEN_HOST,
port=DEFAULT_LISTEN_PORT,
- ssl_context: Optional[SSLContext] = None,
+ ssl_context: SSLContext | None = None,
timeout: int = 30,
):
super().__init__(host, port, ssl_context)
self.timeout = timeout
self.request_queue: Queue[Request] = Queue()
- self.request_handlers: Dict[Request, Queue[BlockingRequestHandler]] =
{}
+ self.request_handlers: dict[Request, Queue[BlockingRequestHandler]] =
{}
def assert_request(
self,
- uri: Union[str, URIPattern, Pattern[str]],
+ uri: str | URIPattern | Pattern[str],
method: str = METHOD_ALL,
- data: Union[str, bytes, None] = None,
+ data: str | bytes | None = None,
data_encoding: str = "utf-8",
- headers: Optional[Mapping[str, str]] = None,
- query_string: Union[None, QueryMatcher, str, bytes, Mapping] = None,
- header_value_matcher: Optional[HeaderValueMatcher] = None,
+ headers: Mapping[str, str] | None = None,
+ query_string: None | QueryMatcher | str | bytes | Mapping = None,
+ header_value_matcher: HeaderValueMatcher | None = None,
json: Any = UNDEFINED,
timeout: int = 30,
) -> BlockingRequestHandler:
@@ -127,7 +129,7 @@
try:
request = self.request_queue.get(timeout=timeout)
except Empty:
- raise AssertionError(f"Waiting for request {matcher} timed out")
+ raise AssertionError(f"Waiting for request {matcher} timed out")
# noqa: EM102
diff = matcher.difference(request)
@@ -137,7 +139,7 @@
if diff:
request_handler.respond_with_response(self.respond_nohandler(request))
- raise AssertionError(f"Request {matcher} does not match: {diff}")
+ raise AssertionError(f"Request {matcher} does not match: {diff}")
# noqa: EM102
return request_handler
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_httpserver-1.0.8/pytest_httpserver/httpserver.py
new/pytest_httpserver-1.0.10/pytest_httpserver/httpserver.py
--- old/pytest_httpserver-1.0.8/pytest_httpserver/httpserver.py 2023-05-16
20:58:37.764109800 +0200
+++ new/pytest_httpserver-1.0.10/pytest_httpserver/httpserver.py
2024-02-20 08:59:32.854914200 +0100
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import abc
import ipaddress
import json
@@ -11,11 +13,11 @@
from contextlib import suppress
from copy import copy
from enum import Enum
-from ssl import SSLContext
+from typing import TYPE_CHECKING
from typing import Any
from typing import Callable
+from typing import ClassVar
from typing import Iterable
-from typing import List
from typing import Mapping
from typing import MutableMapping
from typing import Optional
@@ -30,6 +32,9 @@
from werkzeug.wrappers import Request
from werkzeug.wrappers import Response
+if TYPE_CHECKING:
+ from ssl import SSLContext
+
URI_DEFAULT = ""
METHOD_ALL = "__ALL"
@@ -54,32 +59,24 @@
Base class for all exception defined in this package.
"""
- pass
-
class NoHandlerError(Error):
"""
Raised when a :py:class:`RequestHandler` has no registered method to serve
the request.
"""
- pass
-
class HTTPServerError(Error):
"""
Raised when there's a problem with HTTP server.
"""
- pass
-
class NoMethodFoundForMatchingHeaderValueError(Error):
"""
Raised when a :py:class:`HeaderValueMatcher` has no registered method to
match the header value.
"""
- pass
-
class WaitingSettings:
"""Class for providing default settings and storing them in HTTPServer
@@ -89,7 +86,12 @@
:param timeout: time (in seconds) until time is out
"""
- def __init__(self, raise_assertions: bool = True, stop_on_nohandler: bool
= True, timeout: float = 5):
+ def __init__(
+ self,
+ raise_assertions: bool = True, # noqa: FBT001
+ stop_on_nohandler: bool = True, # noqa: FBT001
+ timeout: float = 5,
+ ):
self.raise_assertions = raise_assertions
self.stop_on_nohandler = stop_on_nohandler
self.timeout = timeout
@@ -105,7 +107,7 @@
self._start = time.monotonic()
self._stop = None
- def complete(self, result: bool):
+ def complete(self, result: bool): # noqa: FBT001
self._result = result
self._stop = time.monotonic()
@@ -127,23 +129,23 @@
and return whether they are equal as bool.
"""
- DEFAULT_MATCHERS: MutableMapping[str, Callable[[Optional[str], str],
bool]] = {}
+ DEFAULT_MATCHERS: ClassVar[MutableMapping[str, Callable[[str | None, str],
bool]]] = {}
- def __init__(self, matchers: Optional[Mapping[str,
Callable[[Optional[str], str], bool]]] = None):
+ def __init__(self, matchers: Mapping[str, Callable[[str | None, str],
bool]] | None = None):
self.matchers = self.DEFAULT_MATCHERS if matchers is None else matchers
@staticmethod
- def authorization_header_value_matcher(actual: Optional[str], expected:
str) -> bool:
- callable = getattr(Authorization, "from_header", None)
- if callable is None: # Werkzeug < 2.3.0
- callable = werkzeug.http.parse_authorization_header
- return callable(actual) == callable(expected)
+ def authorization_header_value_matcher(actual: str | None, expected: str)
-> bool:
+ func = getattr(Authorization, "from_header", None)
+ if func is None: # Werkzeug < 2.3.0
+ func = werkzeug.http.parse_authorization_header # type:
ignore[attr-defined]
+ return func(actual) == func(expected)
@staticmethod
- def default_header_value_matcher(actual: Optional[str], expected: str) ->
bool:
+ def default_header_value_matcher(actual: str | None, expected: str) ->
bool:
return actual == expected
- def __call__(self, header_name: str, actual: Optional[str], expected: str)
-> bool:
+ def __call__(self, header_name: str, actual: str | None, expected: str) ->
bool:
try:
matcher = self.matchers[header_name]
except KeyError:
@@ -181,7 +183,7 @@
Matches a query for a string or bytes specified
"""
- def __init__(self, query_string: Union[bytes, str]):
+ def __init__(self, query_string: bytes | str):
"""
:param query_string: the query string will be compared to this string
or bytes.
If string is specified, it will be encoded by the encode() method.
@@ -209,7 +211,7 @@
Matches a query string to a dictionary or MultiDict specified
"""
- def __init__(self, query_dict: Union[Mapping, MultiDict]):
+ def __init__(self, query_dict: Mapping | MultiDict):
"""
:param query_dict: if dictionary (Mapping) is specified, it will be
used as a
key-value mapping where both key and value should be string. If
there are multiple
@@ -232,26 +234,26 @@
Matches the query depending on the boolean value
"""
- def __init__(self, result: bool):
+ def __init__(self, result: bool): # noqa: FBT001
"""
:param result: if this parameter is true, the query match will be
always
successful. Otherwise, no query match will be successful.
"""
self.result = result
- def get_comparing_values(self, request_query_string):
+ def get_comparing_values(self, request_query_string): # noqa: ARG002
if self.result:
return (True, True)
else:
return (True, False)
-def _create_query_matcher(query_string: Union[None, QueryMatcher, str, bytes,
Mapping]) -> QueryMatcher:
+def _create_query_matcher(query_string: None | QueryMatcher | str | bytes |
Mapping) -> QueryMatcher:
if isinstance(query_string, QueryMatcher):
return query_string
if query_string is None:
- return BooleanQueryMatcher(True)
+ return BooleanQueryMatcher(result=True)
if isinstance(query_string, (str, bytes)):
return StringQueryMatcher(query_string)
@@ -272,7 +274,6 @@
with "/" and does not contain the query part.
:return: True if there's a match, False otherwise
"""
- pass
class RequestMatcher:
@@ -306,13 +307,13 @@
def __init__(
self,
- uri: Union[str, URIPattern, Pattern[str]],
+ uri: str | URIPattern | Pattern[str],
method: str = METHOD_ALL,
- data: Union[str, bytes, None] = None,
+ data: str | bytes | None = None,
data_encoding: str = "utf-8",
- headers: Optional[Mapping[str, str]] = None,
- query_string: Union[None, QueryMatcher, str, bytes, Mapping] = None,
- header_value_matcher: Optional[HVMATCHER_T] = None,
+ headers: Mapping[str, str] | None = None,
+ query_string: None | QueryMatcher | str | bytes | Mapping = None,
+ header_value_matcher: HVMATCHER_T | None = None,
json: Any = UNDEFINED,
):
if json is not UNDEFINED and data is not None:
@@ -383,7 +384,7 @@
#
# also, python will raise TypeError when self.uri is a conflicting
type
- return self.uri == URI_DEFAULT or path == self.uri
+ return self.uri in (URI_DEFAULT, path)
def match_json(self, request: Request) -> bool:
"""
@@ -409,7 +410,7 @@
return json_received == self.json
- def difference(self, request: Request) -> List[Tuple]:
+ def difference(self, request: Request) -> list[tuple]:
"""
Calculates the difference between the matcher and the request.
@@ -421,12 +422,12 @@
matches the fields set in the matcher object.
"""
- retval: List[Tuple] = []
+ retval: list[tuple] = []
if not self.match_uri(request):
retval.append(("uri", request.path, self.uri))
- if self.method != METHOD_ALL and self.method != request.method:
+ if self.method not in (METHOD_ALL, request.method):
retval.append(("method", request.method, self.method))
if not self.query_matcher.match(request.query_string):
@@ -468,7 +469,7 @@
self,
response_json,
status: int = 200,
- headers: Optional[Mapping[str, str]] = None,
+ headers: Mapping[str, str] | None = None,
content_type: str = "application/json",
):
"""
@@ -485,11 +486,11 @@
def respond_with_data(
self,
- response_data: Union[str, bytes] = "",
+ response_data: str | bytes = "",
status: int = 200,
- headers: Optional[HEADERS_T] = None,
- mimetype: Optional[str] = None,
- content_type: Optional[str] = None,
+ headers: HEADERS_T | None = None,
+ mimetype: str | None = None,
+ content_type: str | None = None,
):
"""
Prepares a response with raw data.
@@ -514,8 +515,6 @@
:param response: the response object which will be responded
"""
- pass
-
class RequestHandler(RequestHandlerBase):
"""
@@ -529,7 +528,7 @@
def __init__(self, matcher: RequestMatcher):
self.matcher = matcher
- self.request_handler: Optional[Callable[[Request], Response]] = None
+ self.request_handler: Callable[[Request], Response] | None = None
def respond(self, request: Request) -> Response:
"""
@@ -560,6 +559,15 @@
def respond_with_response(self, response: Response):
self.request_handler = lambda request: response
+ def __repr__(self) -> str:
+ class_name = self.__class__.__name__
+ retval = (
+ f"<{class_name} uri={self.matcher.uri!r}
method={self.matcher.method!r} "
+ f"query_string={self.matcher.query_string!r}
headers={self.matcher.headers!r} data={self.matcher.data!r} "
+ f"json={self.matcher.json!r}>"
+ )
+ return retval
+
class RequestHandlerList(list):
"""
@@ -567,7 +575,7 @@
"""
- def match(self, request: Request) -> Optional[RequestHandler]:
+ def match(self, request: Request) -> RequestHandler | None:
"""
Returns the first request handler which matches the specified request.
Otherwise, it returns `None`.
"""
@@ -610,7 +618,7 @@
self,
host: str,
port: int,
- ssl_context: Optional[SSLContext] = None,
+ ssl_context: SSLContext | None = None,
):
"""
Initializes the instance.
@@ -620,9 +628,9 @@
self.port = port
self.server = None
self.server_thread = None
- self.assertions: List[str] = []
- self.handler_errors: List[Exception] = []
- self.log: List[Tuple[Request, Response]] = []
+ self.assertions: list[str] = []
+ self.handler_errors: list[Exception] = []
+ self.log: list[tuple[Request, Response]] = []
self.ssl_context = ssl_context
self.no_handler_status_code = 500
@@ -812,9 +820,9 @@
As the result, there's an assertion added (which can be raised by
:py:meth:`check_assertions`).
"""
- text = "No handler found for request {!r}.\n".format(request)
+ text = "No handler found for request {!r} with data
{!r}.".format(request, request.data)
self.add_assertion(text + extra_message)
- return Response("No handler found for this request",
self.no_handler_status_code)
+ return Response(text + extra_message, self.no_handler_status_code)
@abc.abstractmethod
def dispatch(self, request: Request) -> Response:
@@ -824,7 +832,6 @@
:param request: the request object from the werkzeug library
:return: the response object what the handler responded, or a response
which contains the error
"""
- pass
@Request.application # type: ignore
def application(self, request: Request):
@@ -907,15 +914,15 @@
self,
host=DEFAULT_LISTEN_HOST,
port=DEFAULT_LISTEN_PORT,
- ssl_context: Optional[SSLContext] = None,
- default_waiting_settings: Optional[WaitingSettings] = None,
+ ssl_context: SSLContext | None = None,
+ default_waiting_settings: WaitingSettings | None = None,
):
"""
Initializes the instance.
"""
super().__init__(host, port, ssl_context)
- self.ordered_handlers: List[RequestHandler] = []
+ self.ordered_handlers: list[RequestHandler] = []
self.oneshot_handlers = RequestHandlerList()
self.handlers = RequestHandlerList()
self.permanently_failed = False
@@ -948,13 +955,13 @@
def expect_request(
self,
- uri: Union[str, URIPattern, Pattern[str]],
+ uri: str | URIPattern | Pattern[str],
method: str = METHOD_ALL,
- data: Union[str, bytes, None] = None,
+ data: str | bytes | None = None,
data_encoding: str = "utf-8",
- headers: Optional[Mapping[str, str]] = None,
- query_string: Union[None, QueryMatcher, str, bytes, Mapping] = None,
- header_value_matcher: Optional[HVMATCHER_T] = None,
+ headers: Mapping[str, str] | None = None,
+ query_string: None | QueryMatcher | str | bytes | Mapping = None,
+ header_value_matcher: HVMATCHER_T | None = None,
handler_type: HandlerType = HandlerType.PERMANENT,
json: Any = UNDEFINED,
) -> RequestHandler:
@@ -971,7 +978,15 @@
If `handler_type` is `HandlerType.ORDERED` an ordered request handler
is created. Comparing to oneshot handler,
ordered handler also determines the order of the requests to be
served. For example if there are two ordered
handlers registered, the first request must hit the first handler, and
the second request must hit the second
- one, and not vice versa. If one or more ordered handler defined, those
must be exhausted first.
+ one, and not vice versa. If one or more ordered handler defined, those
+ must be exhausted first.
+
+ .. note::
+
+ Once this method is called, the response should also be specified
by
+ calling one of the respond methods of the returned
+ :py:class:`RequestHandler` object, otherwise
+ :py:class:`NoHandlerError` will be raised on an incoming request.
:param uri: URI of the request. This must be an absolute path starting
with ``/``, a
@@ -1023,13 +1038,13 @@
def expect_oneshot_request(
self,
- uri: Union[str, URIPattern, Pattern[str]],
+ uri: str | URIPattern | Pattern[str],
method: str = METHOD_ALL,
- data: Union[str, bytes, None] = None,
+ data: str | bytes | None = None,
data_encoding: str = "utf-8",
- headers: Optional[Mapping[str, str]] = None,
- query_string: Union[None, QueryMatcher, str, bytes, Mapping] = None,
- header_value_matcher: Optional[HVMATCHER_T] = None,
+ headers: Mapping[str, str] | None = None,
+ query_string: None | QueryMatcher | str | bytes | Mapping = None,
+ header_value_matcher: HVMATCHER_T | None = None,
json: Any = UNDEFINED,
) -> RequestHandler:
"""
@@ -1078,13 +1093,13 @@
def expect_ordered_request(
self,
- uri: Union[str, URIPattern, Pattern[str]],
+ uri: str | URIPattern | Pattern[str],
method: str = METHOD_ALL,
- data: Union[str, bytes, None] = None,
+ data: str | bytes | None = None,
data_encoding: str = "utf-8",
- headers: Optional[Mapping[str, str]] = None,
- query_string: Union[None, QueryMatcher, str, bytes, Mapping] = None,
- header_value_matcher: Optional[HVMATCHER_T] = None,
+ headers: Mapping[str, str] | None = None,
+ query_string: None | QueryMatcher | str | bytes | Mapping = None,
+ header_value_matcher: HVMATCHER_T | None = None,
json: Any = UNDEFINED,
) -> RequestHandler:
"""
@@ -1168,7 +1183,7 @@
"""
if self._waiting_settings.stop_on_nohandler:
- self._set_waiting_result(False)
+ self._set_waiting_result(value=False)
return super().respond_nohandler(request, self.format_matchers() +
extra_message)
@@ -1246,7 +1261,7 @@
return response
- def _set_waiting_result(self, value: bool) -> None:
+ def _set_waiting_result(self, value: bool) -> None: # noqa: FBT001
"""Set waiting_result
Setting is implemented as putting value to queue without waiting. If
queue is full we simply ignore the
@@ -1257,14 +1272,14 @@
def _update_waiting_result(self) -> None:
if not self.oneshot_handlers and not self.ordered_handlers:
- self._set_waiting_result(True)
+ self._set_waiting_result(value=True)
@contextmanager
def wait(
self,
- raise_assertions: Optional[bool] = None,
- stop_on_nohandler: Optional[bool] = None,
- timeout: Optional[float] = None,
+ raise_assertions: bool | None = None,
+ stop_on_nohandler: bool | None = None,
+ timeout: float | None = None,
):
"""Context manager to wait until the first of following event occurs:
all ordered and oneshot handlers were
executed, unexpected request was received (if `stop_on_nohandler` is
set to `True`), or time was out
@@ -1314,7 +1329,7 @@
waiting.complete(result=False)
if self._waiting_settings.raise_assertions:
raise AssertionError(
- "Wait timeout occurred, but some handlers left:\n"
"{}".format(self.format_matchers())
+ "Wait timeout occurred, but some handlers
left:\n{}".format(self.format_matchers())
)
if self._waiting_settings.raise_assertions and not waiting.result:
self.check_assertions()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_httpserver-1.0.8/pytest_httpserver/pytest_plugin.py
new/pytest_httpserver-1.0.10/pytest_httpserver/pytest_plugin.py
--- old/pytest_httpserver-1.0.8/pytest_httpserver/pytest_plugin.py
2023-05-16 20:58:37.764109800 +0200
+++ new/pytest_httpserver-1.0.10/pytest_httpserver/pytest_plugin.py
2024-02-17 17:55:07.352395800 +0100
@@ -54,14 +54,14 @@
server.stop()
-def pytest_sessionfinish(session, exitstatus): # pylint:
disable=unused-argument
+def pytest_sessionfinish(session, exitstatus): # noqa: ARG001
if Plugin.SERVER is not None:
Plugin.SERVER.clear()
if Plugin.SERVER.is_running():
Plugin.SERVER.stop()
[email protected]
[email protected]()
def httpserver(make_httpserver):
server = make_httpserver
yield server
@@ -78,7 +78,7 @@
server.stop()
[email protected]
[email protected]()
def httpserver_ipv4(make_httpserver_ipv4):
server = make_httpserver_ipv4
yield server
@@ -95,7 +95,7 @@
server.stop()
[email protected]
[email protected]()
def httpserver_ipv6(make_httpserver_ipv6):
server = make_httpserver_ipv6
yield server
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/setup.py
new/pytest_httpserver-1.0.10/setup.py
--- old/pytest_httpserver-1.0.8/setup.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pytest_httpserver-1.0.10/setup.py 1970-01-01 01:00:00.000000000
+0100
@@ -1,34 +0,0 @@
-# -*- coding: utf-8 -*-
-from setuptools import setup
-
-packages = \
-['pytest_httpserver']
-
-package_data = \
-{'': ['*']}
-
-install_requires = \
-['Werkzeug>=2.0.0']
-
-entry_points = \
-{'pytest11': ['pytest_httpserver = pytest_httpserver.pytest_plugin']}
-
-setup_kwargs = {
- 'name': 'pytest-httpserver',
- 'version': '1.0.8',
- 'description': 'pytest-httpserver is a httpserver for pytest',
- 'long_description': '[](https://github.com/csernazs/pytest-httpserver/actions?query=workflow%3Abuild+branch%3Amaster)\n[](https://pytest-httpserver.readthedocs.io/en/latest/?badge=latest)\n
[](https://opensource.org/licenses/MIT)\n[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=K6PU3AGBZW4QC&item_name=pytest-httpserver¤cy_code=EUR&source=url)\n[](https://codecov.io/gh/csernazs/pytest-httpserver)\n[](https://github.com/psf/black)\n\n##
pytest_httpserve
r\n\nHTTP server for pytest\n\n\n### Nutshell\n\nThis library is designed to
help to test http clients without contacting the real http server.\nIn other
words, it is a fake http server which is accessible via localhost can be
started with\nthe pre-defined expected http requests and their
responses.\n\n### Example\n\n#### Handling a simple GET request\n```python\ndef
test_my_client(\n httpserver,\n): # httpserver is a pytest fixture which
starts the server\n # set up the server to serve /foobar with the json\n
httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"})\n #
check that the request is served\n assert
requests.get(httpserver.url_for("/foobar")).json() == {"foo":
"bar"}\n```\n\n#### Handing a POST request with an expected json
body\n```python\ndef test_json_request(\n httpserver,\n): # httpserver is a
pytest fixture which starts the server\n # set up the server to serve
/foobar with the json\n httpserver.expect_request(\n "/foo
bar", method="POST", json={"id": 12, "name": "foo"}\n
).respond_with_json({"foo": "bar"})\n # check that the request is served\n
assert requests.post(\n httpserver.url_for("/foobar"), json={"id": 12,
"name": "foo"}\n ).json() == {"foo": "bar"}\n```\n\n\nYou can also use the
library without pytest. There\'s a with statement to ensure that the server is
stopped.\n\n\n```python\nwith HTTPServer() as httpserver:\n # set up the
server to serve /foobar with the json\n
httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"})\n #
check that the request is served\n
print(requests.get(httpserver.url_for("/foobar")).json())\n```\n\n###
Documentation\n\nPlease find the API documentation at
https://pytest-httpserver.readthedocs.io/en/latest/.\n\n### Features\n\nYou can
set up a dozen of expectations for the requests, and also what response should
be sent by the server to the client.\n\n\n#### Requests\n\nThere are three
different types:\n\n- **permane
nt**: this will be always served when there\'s match for this request, you can
make as many HTTP requests as you want\n- **oneshot**: this will be served only
once when there\'s a match for this request, you can only make 1 HTTP
request\n- **ordered**: same as oneshot but the order must be strictly matched
to the order of setting up\n\nYou can also fine-tune the expected request. The
following can be specified:\n\n- URI (this is a must)\n- HTTP method\n-
headers\n- query string\n- data (HTTP body of the request)\n- JSON (HTTP body
loaded as JSON)\n\n\n#### Responses\n\nOnce you have the expectations for the
request set up, you should also define the response you want to send back.\nThe
following is supported currently:\n\n- respond arbitrary data (string or
bytearray)\n- respond a json (a python dict converted in-place to json)\n-
respond a Response object of werkzeug\n- use your own function\n\nSimilar to
requests, you can fine-tune what response you want to send:\n\n- HTTP status\
n- headers\n- data\n\n\n#### Behave support\n\nUsing the `BlockingHTTPServer`
class, the assertion for a request and the\nresponse can be performed in real
order. For more info, see the\n[test](tests/test_blocking_httpserver.py),
the\n[howto](https://pytest-httpserver.readthedocs.io/en/latest/howto.html#running-httpserver-in-blocking-mode)\nand
the
[API\ndocumentation](https://pytest-httpserver.readthedocs.io/en/latest/api.html#blockinghttpserver).\n\n\n###
Missing features\n* HTTP/2\n* Keepalive\n* ~~TLS~~\n\n### Donation\n\nIf you
want to donate to this project, you can find the donate button at the top\nof
the README.\n\nCurrently, this project is based heavily on werkzeug. Werkzeug
does all the heavy lifting\nbehind the scenes, parsing HTTP request and
defining Request and Response objects, which\nare currently transparent in the
API.\n\nIf you wish to donate, please consider donating to them:
https://palletsprojects.com/donate\n',
- 'author': 'Zsolt Cserna',
- 'author_email': '[email protected]',
- 'maintainer': 'None',
- 'maintainer_email': 'None',
- 'url': 'https://github.com/csernazs/pytest-httpserver',
- 'packages': packages,
- 'package_data': package_data,
- 'install_requires': install_requires,
- 'entry_points': entry_points,
- 'python_requires': '>=3.8,<4.0',
-}
-
-
-setup(**setup_kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_httpserver-1.0.8/tests/examples/test_example_blocking_httpserver.py
new/pytest_httpserver-1.0.10/tests/examples/test_example_blocking_httpserver.py
---
old/pytest_httpserver-1.0.8/tests/examples/test_example_blocking_httpserver.py
2023-05-16 20:58:37.764109800 +0200
+++
new/pytest_httpserver-1.0.10/tests/examples/test_example_blocking_httpserver.py
2024-02-17 17:55:07.352395800 +0100
@@ -16,7 +16,6 @@
yield server
- server.clear()
if server.is_running():
server.stop()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_httpserver-1.0.8/tests/test_blocking_httpserver.py
new/pytest_httpserver-1.0.10/tests/test_blocking_httpserver.py
--- old/pytest_httpserver-1.0.8/tests/test_blocking_httpserver.py
2023-05-16 20:58:37.765109800 +0200
+++ new/pytest_httpserver-1.0.10/tests/test_blocking_httpserver.py
2024-02-17 17:55:07.352395800 +0100
@@ -40,7 +40,7 @@
assert server_connection.get(timeout=9).json() == response
[email protected]
[email protected]()
def httpserver():
server = BlockingHTTPServer(timeout=1)
server.start()
@@ -97,7 +97,10 @@
)
with when_a_request_is_being_sent_to_the_server(request) as
server_connection:
- assert server_connection.get(timeout=9).text == "No handler found for
this request"
+ assert (
+ server_connection.get(timeout=9).text == "No handler found for
request "
+ f"<Request 'http://localhost:{httpserver.port}/my/path' [GET]>
with data b''."
+ )
def test_raises_assertion_error_when_request_was_not_responded(httpserver:
BlockingHTTPServer):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_handler_errors.py
new/pytest_httpserver-1.0.10/tests/test_handler_errors.py
--- old/pytest_httpserver-1.0.8/tests/test_handler_errors.py 2021-11-09
10:15:44.000000000 +0100
+++ new/pytest_httpserver-1.0.10/tests/test_handler_errors.py 2024-02-17
17:55:07.352395800 +0100
@@ -7,7 +7,7 @@
def test_check_assertions_raises_handler_assertions(httpserver: HTTPServer):
def handler(_):
- assert 1 == 2
+ assert False # noqa: PT015
httpserver.expect_request("/foobar").respond_with_handler(handler)
@@ -29,7 +29,7 @@
httpserver.check_assertions()
- with pytest.raises(ValueError):
+ with pytest.raises(ValueError): # noqa: PT011
httpserver.check_handler_errors()
@@ -48,10 +48,10 @@
httpserver.check_assertions()
- with pytest.raises(ValueError):
+ with pytest.raises(ValueError): # noqa: PT011
httpserver.check_handler_errors()
- with pytest.raises(OSError):
+ with pytest.raises(OSError): # noqa: PT011
httpserver.check_handler_errors()
httpserver.check_handler_errors()
@@ -69,7 +69,7 @@
def test_check_raises_errors_in_order(httpserver):
def handler1(_):
- assert 1 == 2
+ assert False # noqa: PT015
def handler2(_):
pass # does nothing
@@ -88,5 +88,5 @@
with pytest.raises(AssertionError):
httpserver.check()
- with pytest.raises(ValueError):
+ with pytest.raises(ValueError): # noqa: PT011
httpserver.check()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_json_matcher.py
new/pytest_httpserver-1.0.10/tests/test_json_matcher.py
--- old/pytest_httpserver-1.0.8/tests/test_json_matcher.py 2023-02-03
08:56:47.174314300 +0100
+++ new/pytest_httpserver-1.0.10/tests/test_json_matcher.py 2024-02-17
17:55:07.352395800 +0100
@@ -36,5 +36,5 @@
def test_data_and_json_mutually_exclusive(httpserver: HTTPServer):
- with pytest.raises(ValueError):
+ with pytest.raises(ValueError): # noqa: PT011
httpserver.expect_request("/foo", json={}, data="foo")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_parse_qs.py
new/pytest_httpserver-1.0.10/tests/test_parse_qs.py
--- old/pytest_httpserver-1.0.8/tests/test_parse_qs.py 2023-05-16
20:58:37.765109800 +0200
+++ new/pytest_httpserver-1.0.10/tests/test_parse_qs.py 2024-02-17
17:55:07.352395800 +0100
@@ -1,10 +1,8 @@
+from __future__ import annotations
+
import urllib.parse
-from typing import List
-from typing import Tuple
import pytest
-import werkzeug.urls
-from werkzeug.datastructures import MultiDict
parse_qsl_semicolon_cases = [
("&", []),
@@ -19,12 +17,6 @@
]
[email protected]("qs,expected", parse_qsl_semicolon_cases)
-def test_qsl(qs: str, expected: List[Tuple[bytes, bytes]]):
[email protected](("qs", "expected"), parse_qsl_semicolon_cases)
+def test_qsl(qs: str, expected: list[tuple[bytes, bytes]]):
assert urllib.parse.parse_qsl(qs, keep_blank_values=True) == expected
-
-
[email protected](reason="skipped to avoid werkzeug warnings")
[email protected]("qs,expected", parse_qsl_semicolon_cases)
-def test_qsl_werkzeug(qs: str, expected: List[Tuple[bytes, bytes]]):
- assert werkzeug.urls.url_decode(qs) == MultiDict(expected)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_permanent.py
new/pytest_httpserver-1.0.10/tests/test_permanent.py
--- old/pytest_httpserver-1.0.8/tests/test_permanent.py 2023-05-16
20:58:37.765109800 +0200
+++ new/pytest_httpserver-1.0.10/tests/test_permanent.py 2024-02-17
17:55:07.352395800 +0100
@@ -106,3 +106,17 @@
response = requests.get(httpserver.url_for("/foobar"))
assert response.json() == {"foo": "bar"}
assert response.status_code == 200
+
+
+def test_request_handler_repr(httpserver: HTTPServer):
+ handler = httpserver.expect_request("/foo", method="POST")
+ assert (
+ repr(handler)
+ == "<RequestHandler uri='/foo' method='POST' query_string=None
headers={} data=None json=<UNDEFINED>>"
+ )
+
+ handler = httpserver.expect_request("/query", query_string={"a": "123"})
+ assert (
+ repr(handler) == "<RequestHandler uri='/query' method='__ALL'
query_string={'a': '123'} "
+ "headers={} data=None json=<UNDEFINED>>"
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_port_changing.py
new/pytest_httpserver-1.0.10/tests/test_port_changing.py
--- old/pytest_httpserver-1.0.8/tests/test_port_changing.py 2023-02-03
08:56:47.174314300 +0100
+++ new/pytest_httpserver-1.0.10/tests/test_port_changing.py 2024-02-17
17:55:07.353395700 +0100
@@ -9,7 +9,7 @@
HOST_KEY = "PYTEST_HTTPSERVER_HOST"
[email protected]
[email protected]()
def tmpenv():
old_vars = {}
for key in (HOST_KEY, PORT_KEY):
@@ -37,7 +37,7 @@
assert httpserver.port == int(os.environ[PORT_KEY])
-def test_get_httpserver_listen_address_with_env(tmpenv):
+def test_get_httpserver_listen_address_with_env(tmpenv): # noqa: ARG001
address = get_httpserver_listen_address()
assert address[0] == "5.5.5.5"
assert address[1] == 12345
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_querymatcher.py
new/pytest_httpserver-1.0.10/tests/test_querymatcher.py
--- old/pytest_httpserver-1.0.8/tests/test_querymatcher.py 2023-01-18
23:01:30.866852500 +0100
+++ new/pytest_httpserver-1.0.10/tests/test_querymatcher.py 2024-02-17
17:55:07.353395700 +0100
@@ -28,7 +28,7 @@
def test_qm_boolean():
- qm = BooleanQueryMatcher(True)
+ qm = BooleanQueryMatcher(result=True)
assert_match(qm, b"k1=v1")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_httpserver-1.0.8/tests/test_release.py
new/pytest_httpserver-1.0.10/tests/test_release.py
--- old/pytest_httpserver-1.0.8/tests/test_release.py 2023-05-16
20:58:37.765109800 +0200
+++ new/pytest_httpserver-1.0.10/tests/test_release.py 2024-02-17
17:55:07.353395700 +0100
@@ -1,5 +1,4 @@
-# TODO: skip if poetry is not available or add mark to test it explicitly
-
+from __future__ import annotations
import email
import re
@@ -10,15 +9,18 @@
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable
-from typing import Tuple
import pytest
import toml
+# TODO: skip if poetry is not available or add mark to test it explicitly
+
+
pytestmark = pytest.mark.release
NAME = "pytest-httpserver"
NAME_UNDERSCORE = NAME.replace("-", "_")
+PY_MAX_VERSION = (3, 12)
@pytest.fixture(scope="session")
@@ -44,7 +46,7 @@
def extract(self):
with zipfile.ZipFile(self.path) as zf:
- zf.extractall(self.wheel_out_dir)
+ zf.extractall(self.wheel_out_dir) # noqa: S202
def get_meta(self, version: str, name: str = NAME_UNDERSCORE) ->
email.message.Message:
metadata_path =
self.wheel_out_dir.joinpath(f"{name}-{version}.dist-info", "METADATA")
@@ -64,7 +66,7 @@
def extract(self):
with tarfile.open(self.path, mode="r:gz") as tf:
- tf.extractall(self.sdist_out_dir)
+ tf.extractall(self.sdist_out_dir) # noqa: S202
@dataclass
@@ -103,7 +105,7 @@
return pyproject["tool"]["poetry"]["version"]
-def version_to_tuple(version: str) -> Tuple:
+def version_to_tuple(version: str) -> tuple:
return tuple([int(x) for x in version.split(".")])
@@ -120,20 +122,20 @@
pyproject_meta = pyproject["tool"]["poetry"]
wheel_meta = build.wheel.get_meta(version=pyproject_meta["version"])
python_dependency = pyproject_meta["dependencies"]["python"]
- m = re.match(r">=(\d+\.\d+),<(\d+\.\d+)", python_dependency)
+ m = re.match(r">=(\d+\.\d+)", python_dependency)
if m:
- min_version, max_version = m.groups()
+ min_version, *_ = m.groups()
else:
raise ValueError(python_dependency)
min_version_tuple = version_to_tuple(min_version)
- max_version_tuple = version_to_tuple(max_version)
for classifier in wheel_meta.get_all("Classifier"):
if classifier.startswith("Programming Language :: Python ::"):
version_tuple =
version_to_tuple(classifier.split("::")[-1].strip())
if len(version_tuple) > 1:
- assert version_tuple >= min_version_tuple and version_tuple <
max_version_tuple
+ assert version_tuple >= min_version_tuple
+ assert version_tuple <= PY_MAX_VERSION
def test_wheel_no_extra_contents(build: Build, version: str):
@@ -168,7 +170,6 @@
"pyproject.toml",
"pytest_httpserver",
"README.md",
- "setup.py",
"tests",
},
"doc": {