pytest_httpserver 1.1.3__tar.gz → 1.1.5__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.
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/CHANGES.rst +42 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/PKG-INFO +8 -8
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/api.rst +12 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/conf.py +1 -1
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/howto.rst +61 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/tutorial.rst +73 -10
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pyproject.toml +32 -23
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/__init__.py +4 -0
- pytest_httpserver-1.1.5/pytest_httpserver/bake.py +105 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/blocking_httpserver.py +7 -7
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/hooks.py +5 -5
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/httpserver.py +144 -63
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/pytest_plugin.py +29 -16
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/assets/Makefile +1 -1
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/assets/rootCA.cnf +4 -0
- pytest_httpserver-1.1.5/tests/assets/rootCA.crt +24 -0
- pytest_httpserver-1.1.5/tests/assets/rootCA.key +28 -0
- pytest_httpserver-1.1.5/tests/assets/rootCA.srl +1 -0
- pytest_httpserver-1.1.5/tests/assets/server.crt +25 -0
- pytest_httpserver-1.1.5/tests/assets/server.csr +18 -0
- pytest_httpserver-1.1.5/tests/assets/server.key +28 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/assets/v3.ext +1 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_example_blocking_httpserver.py +1 -1
- pytest_httpserver-1.1.5/tests/examples/test_howto_bake.py +25 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_check.py +1 -1
- pytest_httpserver-1.1.5/tests/examples/test_howto_readiness.py +30 -0
- pytest_httpserver-1.1.5/tests/test_bake.py +162 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_hooks.py +4 -4
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_log_querying.py +2 -2
- pytest_httpserver-1.1.5/tests/test_readiness.py +124 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_release.py +11 -7
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_urimatch.py +1 -1
- pytest_httpserver-1.1.3/tests/assets/rootCA.crt +0 -22
- pytest_httpserver-1.1.3/tests/assets/rootCA.key +0 -27
- pytest_httpserver-1.1.3/tests/assets/rootCA.srl +0 -1
- pytest_httpserver-1.1.3/tests/assets/server.crt +0 -28
- pytest_httpserver-1.1.3/tests/assets/server.csr +0 -18
- pytest_httpserver-1.1.3/tests/assets/server.key +0 -28
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/CONTRIBUTION.md +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/LICENSE +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/README.md +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/Makefile +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/_static/.placeholder +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/background.rst +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/changes.rst +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/fixtures.rst +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/guide.rst +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/index.rst +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/patch.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/doc/upgrade.rst +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/example.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/example_pytest.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/py.typed +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/assets/README +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/assets/server.cnf +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/conftest.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_example_query_params1.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_example_query_params2.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_authorization_headers.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_case_insensitive_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_check_handler_errors.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_custom_handler.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_custom_hooks.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_custom_request_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_header_value_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_hooks.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_json_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_log_querying.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_query_params_dict.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_query_params_never_do_this.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_query_params_proper_use.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_regexp.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_timeout_requests.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_url_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/examples/test_howto_wait_success.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_blocking_httpserver.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_handler_errors.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_headers.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_ip_protocols.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_json_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_log_leak.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_matcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_mixed.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_oneshot.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_ordered.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_parse_qs.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_permanent.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_port_changing.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_querymatcher.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_querystring.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_ssl.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_thread_type.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_threaded.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_wait.py +0 -0
- {pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/tests/test_with_statement.py +0 -0
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
Release Notes
|
|
3
3
|
=============
|
|
4
4
|
|
|
5
|
+
.. _Release Notes_1.1.5:
|
|
6
|
+
|
|
7
|
+
1.1.5
|
|
8
|
+
=====
|
|
9
|
+
|
|
10
|
+
.. _Release Notes_1.1.5_New Features:
|
|
11
|
+
|
|
12
|
+
New Features
|
|
13
|
+
------------
|
|
14
|
+
|
|
15
|
+
- Add ``bake()`` method to ``HTTPServer`` for creating pre-configured
|
|
16
|
+
request expectation proxies (``BakedHTTPServer``). This allows sharing
|
|
17
|
+
common keyword arguments (e.g. ``method``, ``headers``) across multiple
|
|
18
|
+
``expect_request()`` calls with last-wins merging semantics.
|
|
19
|
+
`#470 <https://github.com/csernazs/pytest-httpserver/pull/470>`_
|
|
20
|
+
Contributed by `@HayaoSuzuki <https://github.com/HayaoSuzuki>`_
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
.. _Release Notes_1.1.4:
|
|
24
|
+
|
|
25
|
+
1.1.4
|
|
26
|
+
=====
|
|
27
|
+
|
|
28
|
+
.. _Release Notes_1.1.4_New Features:
|
|
29
|
+
|
|
30
|
+
New Features
|
|
31
|
+
------------
|
|
32
|
+
|
|
33
|
+
- More robust server startup by checking server readiness (disabled by
|
|
34
|
+
default).
|
|
35
|
+
`#462 <https://github.com/csernazs/pytest-httpserver/pull/462>`_
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
.. _Release Notes_1.1.4_Deprecation Notes:
|
|
39
|
+
|
|
40
|
+
Deprecation Notes
|
|
41
|
+
-----------------
|
|
42
|
+
|
|
43
|
+
- Python 3.9 has been deprecated as it reached EOL 2025-10-31. While the code
|
|
44
|
+
may work on this version, there will be no CI tests running on it.
|
|
45
|
+
|
|
46
|
+
|
|
5
47
|
.. _Release Notes_1.1.3:
|
|
6
48
|
|
|
7
49
|
1.1.3
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest_httpserver
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.5
|
|
4
4
|
Summary: pytest-httpserver is a httpserver for pytest
|
|
5
|
-
|
|
6
|
-
License:
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
7
|
Author: Zsolt Cserna
|
|
8
8
|
Author-email: cserna.zsolt@gmail.com
|
|
9
|
-
Requires-Python: >=3.
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
10
|
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: Framework :: Pytest
|
|
12
11
|
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
12
|
Classifier: Operating System :: OS Independent
|
|
15
13
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Framework :: Pytest
|
|
22
21
|
Requires-Dist: Werkzeug (>=2.0.0)
|
|
23
22
|
Project-URL: Bug Tracker, https://github.com/csernazs/pytest-httpserver/issues
|
|
24
23
|
Project-URL: Documentation, https://pytest-httpserver.readthedocs.io/en/latest/
|
|
24
|
+
Project-URL: Homepage, https://github.com/csernazs/pytest-httpserver
|
|
25
25
|
Project-URL: Repository, https://github.com/csernazs/pytest-httpserver
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
|
|
@@ -24,6 +24,12 @@ RequestHandler
|
|
|
24
24
|
:inherited-members:
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
RequestMatcherKwargs
|
|
28
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
29
|
+
|
|
30
|
+
.. autoclass:: RequestMatcherKwargs
|
|
31
|
+
:members:
|
|
32
|
+
|
|
27
33
|
RequestMatcher
|
|
28
34
|
~~~~~~~~~~~~~~
|
|
29
35
|
|
|
@@ -31,6 +37,12 @@ RequestMatcher
|
|
|
31
37
|
:members:
|
|
32
38
|
|
|
33
39
|
|
|
40
|
+
BakedHTTPServer
|
|
41
|
+
~~~~~~~~~~~~~~~~
|
|
42
|
+
|
|
43
|
+
.. autoclass:: BakedHTTPServer
|
|
44
|
+
:members:
|
|
45
|
+
|
|
34
46
|
BlockingHTTPServer
|
|
35
47
|
~~~~~~~~~~~~~~~~~~
|
|
36
48
|
|
|
@@ -299,6 +299,41 @@ the ``httpserver`` fixture).
|
|
|
299
299
|
return ("127.0.0.1", 8000)
|
|
300
300
|
|
|
301
301
|
|
|
302
|
+
Waiting for server to be ready
|
|
303
|
+
------------------------------
|
|
304
|
+
|
|
305
|
+
By default, the ``httpserver`` fixture ensures that the server is bound to the
|
|
306
|
+
configured address and listening for incoming connections. While this is
|
|
307
|
+
sufficient for most use cases, you can optionally wait for the server to be
|
|
308
|
+
fully ready to serve HTTP requests before proceeding with your tests. This is
|
|
309
|
+
particularly useful when your client has strict timeout requirements or when the
|
|
310
|
+
HTTP server has a slow startup time.
|
|
311
|
+
|
|
312
|
+
To enable this check, *pytest-httpserver* issues an HTTP probe request to the
|
|
313
|
+
server before your test starts to ensure the server is ready to serve requests.
|
|
314
|
+
You can configure the timeout for this probe request as needed.
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
.. warning::
|
|
318
|
+
|
|
319
|
+
This check is not supported in SSL mode, as the probe request is not
|
|
320
|
+
configured to accept the self-signed certificate used by the server. To
|
|
321
|
+
enable this feature with SSL, override the ``wait_for_server_ready()``
|
|
322
|
+
method with your implementation.
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
To enable this feature, set the ``startup_timeout`` keyword argument when
|
|
326
|
+
initializing ``HTTPServer``. This parameter specifies the maximum time to wait
|
|
327
|
+
for the server to become ready to serve HTTP requests.
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
.. literalinclude :: ../tests/examples/test_howto_readiness.py
|
|
331
|
+
:language: python
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
In the case the server times out, the test will fail.
|
|
335
|
+
|
|
336
|
+
|
|
302
337
|
Multi-threading support
|
|
303
338
|
-----------------------
|
|
304
339
|
|
|
@@ -669,3 +704,29 @@ Example:
|
|
|
669
704
|
will register the hooks, and hooks will be called sequentially, one by one. Each
|
|
670
705
|
hook will receive the response what the previous hook returned, and the last
|
|
671
706
|
hook called will return the final response which will be sent back to the client.
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
Reducing repetition with bake
|
|
710
|
+
-----------------------------
|
|
711
|
+
|
|
712
|
+
When multiple expectations share common parameters (such as headers or method),
|
|
713
|
+
the ``bake()`` method creates a proxy with pre-configured defaults. Keyword
|
|
714
|
+
arguments passed to ``bake()`` become defaults that are merged with arguments
|
|
715
|
+
provided at call time using last-wins semantics: if the same keyword appears in
|
|
716
|
+
both, the call-time value is used.
|
|
717
|
+
|
|
718
|
+
.. literalinclude :: ../tests/examples/test_howto_bake.py
|
|
719
|
+
:language: python
|
|
720
|
+
|
|
721
|
+
The ``bake()`` method can be chained to layer additional defaults:
|
|
722
|
+
|
|
723
|
+
.. code-block:: python
|
|
724
|
+
|
|
725
|
+
json_post = httpserver.bake(method="POST").bake(
|
|
726
|
+
headers={"Content-Type": "application/json"}
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
All ``expect_request``, ``expect_oneshot_request``, and
|
|
730
|
+
``expect_ordered_request`` methods are available on the baked object. Other
|
|
731
|
+
attributes such as ``url_for()`` and ``check_assertions()`` are delegated to
|
|
732
|
+
the underlying server transparently.
|
|
@@ -419,7 +419,7 @@ unhandled and in the end the test will be failed.
|
|
|
419
419
|
|
|
420
420
|
In some cases, however, you want to make sure that everything is ok so far,
|
|
421
421
|
and raise AssertionError when something is not good. Call the
|
|
422
|
-
``
|
|
422
|
+
``check()`` method of the httpserver object, and this will look at
|
|
423
423
|
the server's internal state (which is running in the other thread) and if
|
|
424
424
|
there's something not right (such as the order of the requests not matching,
|
|
425
425
|
or there was a non-matching request), it will raise an AssertionError and
|
|
@@ -434,8 +434,71 @@ your test will properly fail:
|
|
|
434
434
|
requests.get(httpserver.url_for("/foobaz"))
|
|
435
435
|
requests.get(httpserver.url_for("/foobar")) # gets 500
|
|
436
436
|
|
|
437
|
-
httpserver.
|
|
437
|
+
httpserver.check() # this will raise AssertionError and make the test failing
|
|
438
438
|
|
|
439
|
+
This will also produce a (hopefully) helpful description about what went wrong::
|
|
440
|
+
|
|
441
|
+
> raise AssertionError(assertion)
|
|
442
|
+
E AssertionError: No handler found for request <Request 'http://localhost:41085/foobaz' [GET]> with data b''.Ordered matchers:
|
|
443
|
+
E <RequestMatcher uri='/foobar' method='__ALL' query_string=None headers={} data=None json=<UNDEFINED>>
|
|
444
|
+
E <RequestMatcher uri='/foobaz' method='__ALL' query_string=None headers={} data=None json=<UNDEFINED>>
|
|
445
|
+
E
|
|
446
|
+
E Oneshot matchers:
|
|
447
|
+
E none
|
|
448
|
+
E
|
|
449
|
+
E Persistent matchers:
|
|
450
|
+
E none
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
Calling ``check()`` for all tests
|
|
454
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
455
|
+
|
|
456
|
+
Sometimes you want to see the informative message made by ``check()`` if
|
|
457
|
+
your test failed.
|
|
458
|
+
|
|
459
|
+
In such case you can implement a new fixture or override the behavior:
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
.. code:: python
|
|
463
|
+
|
|
464
|
+
from collections.abc import Iterable
|
|
465
|
+
from pytest_httpserver import HTTPServer
|
|
466
|
+
import requests
|
|
467
|
+
|
|
468
|
+
import pytest
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
@pytest.fixture
|
|
472
|
+
def httpserver(httpserver: HTTPServer) -> Iterable[HTTPServer]:
|
|
473
|
+
yield httpserver
|
|
474
|
+
httpserver.check() # this will raise AssertionError and make the test failing
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def test_client(httpserver: HTTPServer):
|
|
478
|
+
httpserver.expect_request("/foo").respond_with_data("foo")
|
|
479
|
+
httpserver.expect_request("/bar").respond_with_data("bar")
|
|
480
|
+
|
|
481
|
+
resp = requests.get(httpserver.url_for("/foobar")) # gets 500
|
|
482
|
+
resp.raise_for_status() # raises error
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
When the tests are run with ``-vv`` then it will show both errors::
|
|
486
|
+
|
|
487
|
+
FAILED example2.py::test_client - requests.exceptions.HTTPError: 500 Server Error: INTERNAL SERVER ERROR for url: http://localhost:37425/foobar
|
|
488
|
+
ERROR example2.py::test_client - AssertionError: No handler found for request <Request 'http://localhost:37425/foobar' [GET]> with data b''.
|
|
489
|
+
Ordered matchers:
|
|
490
|
+
none
|
|
491
|
+
|
|
492
|
+
Oneshot matchers:
|
|
493
|
+
none
|
|
494
|
+
|
|
495
|
+
Persistent matchers:
|
|
496
|
+
<RequestMatcher uri='/foo' method='__ALL' query_string=None headers={} data=None json=<UNDEFINED>>
|
|
497
|
+
<RequestMatcher uri='/bar' method='__ALL' query_string=None headers={} data=None json=<UNDEFINED>>
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
Logs
|
|
501
|
+
~~~~
|
|
439
502
|
|
|
440
503
|
The server writes a log about the requests and responses which were
|
|
441
504
|
processed. This can be accessed in the `log` attribute of the http server.
|
|
@@ -457,7 +520,7 @@ Debugging
|
|
|
457
520
|
~~~~~~~~~
|
|
458
521
|
|
|
459
522
|
If you having multiple requests for the server, adding the call to
|
|
460
|
-
``
|
|
523
|
+
``check()`` may help to debug as it will make the test failed as
|
|
461
524
|
soon as possible.
|
|
462
525
|
|
|
463
526
|
.. code:: python
|
|
@@ -471,20 +534,20 @@ soon as possible.
|
|
|
471
534
|
requests.get(httpserver.url_for("/bar"))
|
|
472
535
|
requests.get(httpserver.url_for("/foobar"))
|
|
473
536
|
|
|
474
|
-
httpserver.
|
|
537
|
+
httpserver.check()
|
|
475
538
|
|
|
476
539
|
In the above code, the first request (to **/foo**) is not successful (it gets
|
|
477
540
|
http status 500), but as the response status is not checked (or any of the
|
|
478
|
-
response), and there's no call to ``
|
|
541
|
+
response), and there's no call to ``check()``, the test continues the
|
|
479
542
|
running. It gets through the **/bar** request, which is also not successful
|
|
480
543
|
(and gets http status 500 also like the first one), then goes the last request
|
|
481
544
|
which is successful (as there's a handler defined for it)
|
|
482
545
|
|
|
483
|
-
In the end, when checking the
|
|
546
|
+
In the end, when checking the check() raise the error for the first
|
|
484
547
|
request, but it is a bit late: figuring out the request which caused the problem
|
|
485
548
|
could be troublesome. Also, it will report the problem for the first request only.
|
|
486
549
|
|
|
487
|
-
Adding more call of ``
|
|
550
|
+
Adding more call of ``check()`` will help.
|
|
488
551
|
|
|
489
552
|
|
|
490
553
|
.. code:: python
|
|
@@ -495,13 +558,13 @@ Adding more call of ``check_assertions()`` will help.
|
|
|
495
558
|
def test_json_client(httpserver: HTTPServer):
|
|
496
559
|
httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"})
|
|
497
560
|
requests.get(httpserver.url_for("/foo"))
|
|
498
|
-
httpserver.
|
|
561
|
+
httpserver.check()
|
|
499
562
|
|
|
500
563
|
requests.get(httpserver.url_for("/bar"))
|
|
501
|
-
httpserver.
|
|
564
|
+
httpserver.check()
|
|
502
565
|
|
|
503
566
|
requests.get(httpserver.url_for("/foobar"))
|
|
504
|
-
httpserver.
|
|
567
|
+
httpserver.check()
|
|
505
568
|
|
|
506
569
|
|
|
507
570
|
In the above code, the test will fail after the first request.
|
|
@@ -1,20 +1,40 @@
|
|
|
1
|
-
[
|
|
1
|
+
[project]
|
|
2
2
|
name = "pytest_httpserver"
|
|
3
|
-
version = "1.1.
|
|
3
|
+
version = "1.1.5"
|
|
4
4
|
description = "pytest-httpserver is a httpserver for pytest"
|
|
5
|
-
authors = ["Zsolt Cserna <cserna.zsolt@gmail.com>"]
|
|
6
|
-
license = "MIT"
|
|
7
5
|
readme = "README.md"
|
|
8
|
-
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Zsolt Cserna", email = "cserna.zsolt@gmail.com" }
|
|
9
|
+
]
|
|
9
10
|
classifiers = [
|
|
10
11
|
"Development Status :: 3 - Alpha",
|
|
11
12
|
"Intended Audience :: Developers",
|
|
12
13
|
"Operating System :: OS Independent",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
13
20
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
14
21
|
"Framework :: Pytest",
|
|
15
22
|
]
|
|
16
|
-
|
|
23
|
+
requires-python = ">=3.10"
|
|
24
|
+
dependencies = [
|
|
25
|
+
"Werkzeug >= 2.0.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/csernazs/pytest-httpserver"
|
|
30
|
+
Documentation = "https://pytest-httpserver.readthedocs.io/en/latest/"
|
|
31
|
+
Repository = "https://github.com/csernazs/pytest-httpserver"
|
|
32
|
+
"Bug Tracker" = "https://github.com/csernazs/pytest-httpserver/issues"
|
|
33
|
+
|
|
34
|
+
[project.entry-points.pytest11]
|
|
35
|
+
pytest_httpserver = "pytest_httpserver.pytest_plugin"
|
|
17
36
|
|
|
37
|
+
[tool.poetry]
|
|
18
38
|
include = [
|
|
19
39
|
{ path = "tests", format = "sdist" },
|
|
20
40
|
{ path = "CHANGES.rst", format = "sdist" },
|
|
@@ -23,29 +43,19 @@ include = [
|
|
|
23
43
|
{ path = "doc", format = "sdist" },
|
|
24
44
|
]
|
|
25
45
|
|
|
26
|
-
[tool.poetry.dependencies]
|
|
27
|
-
python = ">=3.9"
|
|
28
|
-
Werkzeug = ">= 2.0.0"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
[tool.poetry.plugins.pytest11]
|
|
32
|
-
pytest_httpserver = "pytest_httpserver.pytest_plugin"
|
|
33
|
-
|
|
34
|
-
[tool.poetry.urls]
|
|
35
|
-
"Bug Tracker" = "https://github.com/csernazs/pytest-httpserver/issues"
|
|
36
|
-
|
|
37
46
|
[tool.poetry.group.develop]
|
|
38
47
|
optional = true
|
|
39
48
|
|
|
40
49
|
[tool.poetry.group.develop.dependencies]
|
|
41
50
|
pre-commit = ">=2.20,<5.0"
|
|
42
51
|
requests = "*"
|
|
43
|
-
|
|
52
|
+
typing_extensions = { version = ">=4.0", markers = "python_version < '3.11'" }
|
|
53
|
+
Sphinx = ">=5.1.1,<9.0.0"
|
|
44
54
|
sphinx-rtd-theme = ">=1,<4"
|
|
45
55
|
reno = "*"
|
|
46
56
|
types-requests = "*"
|
|
47
|
-
pytest = ">=7.1.3,<
|
|
48
|
-
pytest-cov = ">=3,<
|
|
57
|
+
pytest = ">=7.1.3,<10.0.0"
|
|
58
|
+
pytest-cov = ">=3,<8"
|
|
49
59
|
coverage = ">=6.4.4,<8.0.0"
|
|
50
60
|
tomli = { version = "*", markers = "python_version < '3.11'"}
|
|
51
61
|
black = "*"
|
|
@@ -57,7 +67,7 @@ mypy = "*"
|
|
|
57
67
|
optional = true
|
|
58
68
|
|
|
59
69
|
[tool.poetry.group.doc.dependencies]
|
|
60
|
-
Sphinx = ">=5.1.1,<
|
|
70
|
+
Sphinx = ">=5.1.1,<9.0.0"
|
|
61
71
|
sphinx-rtd-theme = ">=1,<4"
|
|
62
72
|
|
|
63
73
|
|
|
@@ -116,7 +126,6 @@ lint.ignore = [
|
|
|
116
126
|
"PLR0913",
|
|
117
127
|
"PLR2004",
|
|
118
128
|
"PLW2901",
|
|
119
|
-
"PT004",
|
|
120
129
|
"PT012",
|
|
121
130
|
"PT013",
|
|
122
131
|
"PTH118",
|
|
@@ -137,5 +146,5 @@ lint.ignore = [
|
|
|
137
146
|
"UP032",
|
|
138
147
|
]
|
|
139
148
|
line-length = 120
|
|
140
|
-
target-version = "
|
|
149
|
+
target-version = "py310"
|
|
141
150
|
exclude = ["doc", "example*.py", "tests/examples/*.py"]
|
|
@@ -6,6 +6,7 @@ This is package provides the main API for the pytest_httpserver package.
|
|
|
6
6
|
__all__ = [
|
|
7
7
|
"METHOD_ALL",
|
|
8
8
|
"URI_DEFAULT",
|
|
9
|
+
"BakedHTTPServer",
|
|
9
10
|
"BlockingHTTPServer",
|
|
10
11
|
"BlockingRequestHandler",
|
|
11
12
|
"Error",
|
|
@@ -15,10 +16,12 @@ __all__ = [
|
|
|
15
16
|
"NoHandlerError",
|
|
16
17
|
"RequestHandler",
|
|
17
18
|
"RequestMatcher",
|
|
19
|
+
"RequestMatcherKwargs",
|
|
18
20
|
"URIPattern",
|
|
19
21
|
"WaitingSettings",
|
|
20
22
|
]
|
|
21
23
|
|
|
24
|
+
from .bake import BakedHTTPServer
|
|
22
25
|
from .blocking_httpserver import BlockingHTTPServer
|
|
23
26
|
from .blocking_httpserver import BlockingRequestHandler
|
|
24
27
|
from .httpserver import METHOD_ALL
|
|
@@ -30,5 +33,6 @@ from .httpserver import HTTPServerError
|
|
|
30
33
|
from .httpserver import NoHandlerError
|
|
31
34
|
from .httpserver import RequestHandler
|
|
32
35
|
from .httpserver import RequestMatcher
|
|
36
|
+
from .httpserver import RequestMatcherKwargs
|
|
33
37
|
from .httpserver import URIPattern
|
|
34
38
|
from .httpserver import WaitingSettings
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
import sys
|
|
8
|
+
from re import Pattern
|
|
9
|
+
from types import TracebackType
|
|
10
|
+
|
|
11
|
+
if sys.version_info >= (3, 11):
|
|
12
|
+
from typing import Self
|
|
13
|
+
else:
|
|
14
|
+
from typing_extensions import Self
|
|
15
|
+
|
|
16
|
+
if sys.version_info >= (3, 12):
|
|
17
|
+
from typing import Unpack
|
|
18
|
+
else:
|
|
19
|
+
from typing_extensions import Unpack
|
|
20
|
+
|
|
21
|
+
from .httpserver import HTTPServer
|
|
22
|
+
from .httpserver import RequestHandler
|
|
23
|
+
from .httpserver import RequestMatcherKwargs
|
|
24
|
+
from .httpserver import URIPattern
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class BakedHTTPServer:
|
|
28
|
+
"""
|
|
29
|
+
A proxy for :py:class:`HTTPServer` with pre-configured defaults for
|
|
30
|
+
``expect_request()`` and related methods.
|
|
31
|
+
|
|
32
|
+
Created via :py:meth:`HTTPServer.bake`. Keyword arguments stored at bake
|
|
33
|
+
time are merged with arguments provided at call time using last-wins
|
|
34
|
+
semantics: if the same keyword appears in both, the call-time value is
|
|
35
|
+
used.
|
|
36
|
+
|
|
37
|
+
Any attribute not explicitly defined here is delegated to the wrapped
|
|
38
|
+
:py:class:`HTTPServer`, so ``url_for()``, ``check_assertions()``, etc.
|
|
39
|
+
work transparently.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, server: HTTPServer, **kwargs: Unpack[RequestMatcherKwargs]) -> None:
|
|
43
|
+
self._server = server
|
|
44
|
+
self._defaults = kwargs
|
|
45
|
+
self._context_depth: int = 0
|
|
46
|
+
self._started_server: bool = False
|
|
47
|
+
|
|
48
|
+
def __enter__(self) -> Self:
|
|
49
|
+
if self._context_depth == 0:
|
|
50
|
+
self._started_server = not self._server.is_running()
|
|
51
|
+
self._server.__enter__()
|
|
52
|
+
self._context_depth += 1
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def __exit__(
|
|
56
|
+
self,
|
|
57
|
+
exc_type: type[BaseException] | None,
|
|
58
|
+
exc_value: BaseException | None,
|
|
59
|
+
traceback: TracebackType | None,
|
|
60
|
+
) -> None:
|
|
61
|
+
self._context_depth -= 1
|
|
62
|
+
if self._started_server and self._context_depth == 0:
|
|
63
|
+
self._server.__exit__(exc_type, exc_value, traceback)
|
|
64
|
+
self._started_server = False
|
|
65
|
+
|
|
66
|
+
def __getattr__(self, name: str) -> Any:
|
|
67
|
+
return getattr(self._server, name)
|
|
68
|
+
|
|
69
|
+
def __repr__(self) -> str:
|
|
70
|
+
return f"<{self.__class__.__name__} defaults={self._defaults!r} server={self._server!r}>"
|
|
71
|
+
|
|
72
|
+
def _merge_kwargs(self, kwargs: RequestMatcherKwargs) -> RequestMatcherKwargs:
|
|
73
|
+
return self._defaults | kwargs
|
|
74
|
+
|
|
75
|
+
def bake(self, **kwargs: Unpack[RequestMatcherKwargs]) -> Self:
|
|
76
|
+
"""
|
|
77
|
+
Create a new :py:class:`BakedHTTPServer` by further layering defaults.
|
|
78
|
+
|
|
79
|
+
The new proxy merges the current defaults with the new ``kwargs``.
|
|
80
|
+
"""
|
|
81
|
+
return self.__class__(self._server, **self._merge_kwargs(kwargs))
|
|
82
|
+
|
|
83
|
+
def expect_request(
|
|
84
|
+
self,
|
|
85
|
+
uri: str | URIPattern | Pattern[str],
|
|
86
|
+
**kwargs: Unpack[RequestMatcherKwargs],
|
|
87
|
+
) -> RequestHandler:
|
|
88
|
+
"""Create and register a request handler, using baked defaults."""
|
|
89
|
+
return self._server.expect_request(uri, **self._merge_kwargs(kwargs))
|
|
90
|
+
|
|
91
|
+
def expect_oneshot_request(
|
|
92
|
+
self,
|
|
93
|
+
uri: str | URIPattern | Pattern[str],
|
|
94
|
+
**kwargs: Unpack[RequestMatcherKwargs],
|
|
95
|
+
) -> RequestHandler:
|
|
96
|
+
"""Create and register a oneshot request handler, using baked defaults."""
|
|
97
|
+
return self._server.expect_oneshot_request(uri, **self._merge_kwargs(kwargs))
|
|
98
|
+
|
|
99
|
+
def expect_ordered_request(
|
|
100
|
+
self,
|
|
101
|
+
uri: str | URIPattern | Pattern[str],
|
|
102
|
+
**kwargs: Unpack[RequestMatcherKwargs],
|
|
103
|
+
) -> RequestHandler:
|
|
104
|
+
"""Create and register an ordered request handler, using baked defaults."""
|
|
105
|
+
return self._server.expect_ordered_request(uri, **self._merge_kwargs(kwargs))
|
{pytest_httpserver-1.1.3 → pytest_httpserver-1.1.5}/pytest_httpserver/blocking_httpserver.py
RENAMED
|
@@ -29,10 +29,10 @@ class BlockingRequestHandler(RequestHandlerBase):
|
|
|
29
29
|
This class should only be instantiated inside the implementation of the :py:class:`BlockingHTTPServer`.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
def __init__(self):
|
|
33
|
-
self.response_queue = Queue()
|
|
32
|
+
def __init__(self) -> None:
|
|
33
|
+
self.response_queue: Queue[Response] = Queue()
|
|
34
34
|
|
|
35
|
-
def respond_with_response(self, response: Response):
|
|
35
|
+
def respond_with_response(self, response: Response) -> None:
|
|
36
36
|
self.response_queue.put_nowait(response)
|
|
37
37
|
|
|
38
38
|
|
|
@@ -59,11 +59,11 @@ class BlockingHTTPServer(HTTPServerBase):
|
|
|
59
59
|
|
|
60
60
|
def __init__(
|
|
61
61
|
self,
|
|
62
|
-
host=DEFAULT_LISTEN_HOST,
|
|
63
|
-
port=DEFAULT_LISTEN_PORT,
|
|
62
|
+
host: str = DEFAULT_LISTEN_HOST,
|
|
63
|
+
port: int = DEFAULT_LISTEN_PORT,
|
|
64
64
|
ssl_context: SSLContext | None = None,
|
|
65
65
|
timeout: int = 30,
|
|
66
|
-
):
|
|
66
|
+
) -> None:
|
|
67
67
|
super().__init__(host, port, ssl_context)
|
|
68
68
|
self.timeout = timeout
|
|
69
69
|
self.request_queue: Queue[Request] = Queue()
|
|
@@ -76,7 +76,7 @@ class BlockingHTTPServer(HTTPServerBase):
|
|
|
76
76
|
data: str | bytes | None = None,
|
|
77
77
|
data_encoding: str = "utf-8",
|
|
78
78
|
headers: Mapping[str, str] | None = None,
|
|
79
|
-
query_string: None | QueryMatcher | str | bytes | Mapping = None,
|
|
79
|
+
query_string: None | QueryMatcher | str | bytes | Mapping[str, str] = None,
|
|
80
80
|
header_value_matcher: HeaderValueMatcher | None = None,
|
|
81
81
|
json: Any = UNDEFINED,
|
|
82
82
|
timeout: int = 30,
|
|
@@ -4,7 +4,7 @@ Hooks for pytest-httpserver
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import time
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Callable
|
|
8
8
|
|
|
9
9
|
from werkzeug import Request
|
|
10
10
|
from werkzeug import Response
|
|
@@ -20,7 +20,7 @@ class Chain:
|
|
|
20
20
|
similar to reduce.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
def __init__(self, *args: Callable[[Request, Response], Response]):
|
|
23
|
+
def __init__(self, *args: Callable[[Request, Response], Response]) -> None:
|
|
24
24
|
"""
|
|
25
25
|
:param *args: callable objects specified in the same order they should
|
|
26
26
|
be called.
|
|
@@ -43,13 +43,13 @@ class Delay:
|
|
|
43
43
|
Delays returning the response
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
|
-
def __init__(self, seconds: float):
|
|
46
|
+
def __init__(self, seconds: float) -> None:
|
|
47
47
|
"""
|
|
48
48
|
:param seconds: seconds to sleep before returning the response
|
|
49
49
|
"""
|
|
50
50
|
self._seconds = seconds
|
|
51
51
|
|
|
52
|
-
def _sleep(self):
|
|
52
|
+
def _sleep(self) -> None:
|
|
53
53
|
"""
|
|
54
54
|
Sleeps for the seconds specified in the constructor
|
|
55
55
|
"""
|
|
@@ -65,7 +65,7 @@ class Delay:
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
class Garbage:
|
|
68
|
-
def __init__(self, prefix_size: int = 0, suffix_size: int = 0):
|
|
68
|
+
def __init__(self, prefix_size: int = 0, suffix_size: int = 0) -> None:
|
|
69
69
|
"""
|
|
70
70
|
Adds random bytes to the beginning or to the end of the response data.
|
|
71
71
|
|