diff options
| author | robot-piglet <[email protected]> | 2025-12-09 22:20:39 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2025-12-09 22:32:08 +0300 |
| commit | 3169aa98e7da898818e5f4c1d24a70765789d095 (patch) | |
| tree | 1776d83954726415d454c9a357cf08e2bfd90a82 /contrib/python/pytest-localserver | |
| parent | 5c27d943a052eb87cd1a621030fbac24ffd93390 (diff) | |
Intermediate changes
commit_hash:2d8a15822847c98cadfd5135ea9535a5dfa9f3c2
Diffstat (limited to 'contrib/python/pytest-localserver')
9 files changed, 256 insertions, 178 deletions
diff --git a/contrib/python/pytest-localserver/py3/.dist-info/METADATA b/contrib/python/pytest-localserver/py3/.dist-info/METADATA index 56fa7bf975d..dd27e8a3a84 100644 --- a/contrib/python/pytest-localserver/py3/.dist-info/METADATA +++ b/contrib/python/pytest-localserver/py3/.dist-info/METADATA @@ -1,22 +1,20 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: pytest-localserver -Version: 0.9.0.post0 +Version: 0.10.0 Summary: pytest plugin to test server connections locally. Home-page: https://github.com/pytest-dev/pytest-localserver Author: Sebastian Rahlf Author-email: [email protected] Maintainer: David Zaslavsky Maintainer-email: [email protected] -License: MIT License +License-Expression: MIT Keywords: pytest server localhost http smtp Classifier: Framework :: Pytest Classifier: Operating System :: OS Independent Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 @@ -24,13 +22,27 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 Classifier: Topic :: Software Development :: Testing -Requires-Python: >=3.6 +Requires-Python: >=3.7 License-File: LICENSE -License-File: AUTHORS -Requires-Dist: werkzeug >=0.10 +Requires-Dist: werkzeug>=0.10 Provides-Extra: smtp -Requires-Dist: aiosmtpd ; extra == 'smtp' +Requires-Dist: aiosmtpd; extra == "smtp" +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: keywords +Dynamic: license-file +Dynamic: license-expression +Dynamic: maintainer +Dynamic: maintainer-email +Dynamic: provides-extra +Dynamic: requires-dist +Dynamic: requires-python +Dynamic: summary .. image:: https://img.shields.io/pypi/v/pytest-localserver.svg?style=flat :alt: PyPI Version @@ -63,15 +75,48 @@ no further! Quickstart ========== +`myproject.py` + +.. code:: python + + import requests + + + def make_request(url): + """A function that makes a web request.""" + rsp = requests.get(url) + return rsp.text + +`test_myproject.py` + +.. code:: python + + from myproject import request + + + def test_make_request(httpserver): + httpserver.serve_content( + content="success", + code=200, + ) + + assert make_request(httpserver.url) == "success" + +How-To +====== + Let's say you have a function to scrape HTML which only required to be pointed -at a URL :: +at a URL : + +.. code:: python import requests + def scrape(url): - html = requests.get(url).text - # some parsing happens here - # ... - return result + html = requests.get(url).text + # some parsing happens here + # ... + return result You want to test this function in its entirety without having to rely on a remote server whose content you cannot control, neither do you want to waste @@ -79,30 +124,40 @@ time setting up a complex mechanism to mock or patch the underlying Python modules dealing with the actual HTTP request (of which there are more than one BTW). So what do you do? -You simply use pytest's `funcargs feature`_ and simulate an entire server -locally! :: +You simply use pytest's `fixture feature`_ and simulate an entire server +locally! + +.. code:: python def test_retrieve_some_content(httpserver): - httpserver.serve_content(open('cached-content.html').read()) - assert scrape(httpserver.url) == 'Found it!' + httpserver.serve_content(open("cached-content.html").read()) + assert scrape(httpserver.url) == "Found it!" What happened here is that for the duration of your tests an HTTP server is started on a random port on localhost which will serve the content you tell it to and behaves just like the real thing. The added bonus is that you can test whether your code behaves gracefully if -there is a network problem:: +there is a network problem: + +.. code:: python - def test_content_retrieval_fails_graciously(httpserver): - httpserver.serve_content('File not found!', 404) - pytest.raises(ContentNotFoundException, scrape, httpserver.url) + def test_content_retrieval_fails_graciously(httpserver): + httpserver.serve_content("File not found!", 404) + pytest.raises(ContentNotFoundException, scrape, httpserver.url) -The same thing works for SMTP servers, too:: +The same thing works for SMTP servers, too: + +.. code:: python def test_sending_some_message(smtpserver): mailer = MyMailer(host=smtpserver.addr[0], port=smtpserver.addr[1]) - mailer.send(to='[email protected]', from_='[email protected]', - subject='MyMailer v1.0', body='Check out my mailer!') + mailer.send( + to="[email protected]", + from_="[email protected]", + subject="MyMailer v1.0", + body="Check out my mailer!" + ) assert len(smtpserver.outbox)==1 Here an SMTP server is started which accepts e-mails being sent to it. The @@ -111,11 +166,12 @@ and what was sent by looking into the smtpserver's ``outbox``. It is really that easy! -Available funcargs -================== +Fixtures +======== -Here is a short overview of the available funcargs. For more details I suggest -poking around in the code itself. +Here is a short overview of the available pytest fixtures and their usage. This +information is also available via `pytest --fixtures`. For more details I +suggest poking around in the code itself. ``httpserver`` provides a threaded HTTP server instance running on localhost. It has the @@ -129,9 +185,17 @@ poking around in the code itself. Once these attributes are set, all subsequent requests will be answered with these values until they are changed or the server is stopped. A more - convenient way to change these is :: + convenient way to change these is : + + .. code:: python - httpserver.serve_content(content=None, code=200, headers=None, chunked=pytest_localserver.http.Chunked.NO, store_request_data=True) + httpserver.serve_content( + content=None, + code=200, + headers=None, + chunked=pytest_localserver.http.Chunked.NO, + store_request_data=True + ) The ``chunked`` attribute or parameter can be set to @@ -183,27 +247,37 @@ Using your a WSGI application as test server ============================================ As of version 0.3 you can now use a `WSGI application`_ to run on the test -server :: +server : + +.. code:: python + + import pytest + from pytest_localserver.http import WSGIServer + + from myproject import make_request + + + def simple_app(environ, start_response): + """Respond with success.""" + status = "200 OK" + response_headers = [("Content-type", "text/plain")] + start_response(status, response_headers) + return ["success".encode("utf-8")] + - from pytest_localserver.http import WSGIServer + @pytest.fixture + def testserver(): + """Server for simple_app.""" + server = WSGIServer(application=simple_app) + server.start() + yield server + server.stop() - def simple_app(environ, start_response): - """Simplest possible WSGI application""" - status = '200 OK' - response_headers = [('Content-type', 'text/plain')] - start_response(status, response_headers) - return ['Hello world!\n'] - @pytest.fixture - def testserver(request): - """Defines the testserver funcarg""" - server = WSGIServer(application=simple_app) - server.start() - request.addfinalizer(server.stop) - return server + def test_make_request(testserver): + """make_request() should return "success".""" + assert make_request(testserver.url) == "success" - def test_retrieve_some_content(testserver): - assert scrape(testserver.url) == 'Hello world!\n' Have a look at the following page for more information on WSGI: http://wsgi.readthedocs.org/en/latest/learn.html @@ -287,9 +361,9 @@ For package maintainers, here is how we release a new version: Having unsuccessfully tried to mock a server, I stumbled across `linkchecker`_ which uses a the same idea to test its internals. -.. _monkeypatching: http://pytest.org/latest/monkeypatch.html +.. _monkeypatching: https://docs.pytest.org/en/stable/how-to/monkeypatch.html .. _pytest: http://pytest.org/ -.. _funcargs feature: http://pytest.org/latest/funcargs.html +.. _fixture feature: https://pytest.org/en/stable/explanation/fixtures.html .. _linkchecker: http://linkchecker.sourceforge.net/ .. _WSGI application: http://www.python.org/dev/peps/pep-0333/ .. _PyPI: http://pypi.python.org/pypi/pytest-localserver/ diff --git a/contrib/python/pytest-localserver/py3/AUTHORS b/contrib/python/pytest-localserver/py3/AUTHORS index ae651ae25e1..0ca48bb7b11 100644 --- a/contrib/python/pytest-localserver/py3/AUTHORS +++ b/contrib/python/pytest-localserver/py3/AUTHORS @@ -17,3 +17,6 @@ Theodore Ni Nicola Coretti <[email protected]> Alissa Gerhard <[email protected]> Raphael Boidol <[email protected]> +Pierre Sassoulas <[email protected]> +Alissa Huskey <[email protected]> +Hugo van Kemenade <[email protected]> diff --git a/contrib/python/pytest-localserver/py3/README.rst b/contrib/python/pytest-localserver/py3/README.rst index 41fd5c32579..7a4e5574b1a 100644 --- a/contrib/python/pytest-localserver/py3/README.rst +++ b/contrib/python/pytest-localserver/py3/README.rst @@ -29,15 +29,48 @@ no further! Quickstart ========== +`myproject.py` + +.. code:: python + + import requests + + + def make_request(url): + """A function that makes a web request.""" + rsp = requests.get(url) + return rsp.text + +`test_myproject.py` + +.. code:: python + + from myproject import request + + + def test_make_request(httpserver): + httpserver.serve_content( + content="success", + code=200, + ) + + assert make_request(httpserver.url) == "success" + +How-To +====== + Let's say you have a function to scrape HTML which only required to be pointed -at a URL :: +at a URL : + +.. code:: python import requests + def scrape(url): - html = requests.get(url).text - # some parsing happens here - # ... - return result + html = requests.get(url).text + # some parsing happens here + # ... + return result You want to test this function in its entirety without having to rely on a remote server whose content you cannot control, neither do you want to waste @@ -45,30 +78,40 @@ time setting up a complex mechanism to mock or patch the underlying Python modules dealing with the actual HTTP request (of which there are more than one BTW). So what do you do? -You simply use pytest's `funcargs feature`_ and simulate an entire server -locally! :: +You simply use pytest's `fixture feature`_ and simulate an entire server +locally! + +.. code:: python def test_retrieve_some_content(httpserver): - httpserver.serve_content(open('cached-content.html').read()) - assert scrape(httpserver.url) == 'Found it!' + httpserver.serve_content(open("cached-content.html").read()) + assert scrape(httpserver.url) == "Found it!" What happened here is that for the duration of your tests an HTTP server is started on a random port on localhost which will serve the content you tell it to and behaves just like the real thing. The added bonus is that you can test whether your code behaves gracefully if -there is a network problem:: +there is a network problem: + +.. code:: python - def test_content_retrieval_fails_graciously(httpserver): - httpserver.serve_content('File not found!', 404) - pytest.raises(ContentNotFoundException, scrape, httpserver.url) + def test_content_retrieval_fails_graciously(httpserver): + httpserver.serve_content("File not found!", 404) + pytest.raises(ContentNotFoundException, scrape, httpserver.url) -The same thing works for SMTP servers, too:: +The same thing works for SMTP servers, too: + +.. code:: python def test_sending_some_message(smtpserver): mailer = MyMailer(host=smtpserver.addr[0], port=smtpserver.addr[1]) - mailer.send(to='[email protected]', from_='[email protected]', - subject='MyMailer v1.0', body='Check out my mailer!') + mailer.send( + to="[email protected]", + from_="[email protected]", + subject="MyMailer v1.0", + body="Check out my mailer!" + ) assert len(smtpserver.outbox)==1 Here an SMTP server is started which accepts e-mails being sent to it. The @@ -77,11 +120,12 @@ and what was sent by looking into the smtpserver's ``outbox``. It is really that easy! -Available funcargs -================== +Fixtures +======== -Here is a short overview of the available funcargs. For more details I suggest -poking around in the code itself. +Here is a short overview of the available pytest fixtures and their usage. This +information is also available via `pytest --fixtures`. For more details I +suggest poking around in the code itself. ``httpserver`` provides a threaded HTTP server instance running on localhost. It has the @@ -95,9 +139,17 @@ poking around in the code itself. Once these attributes are set, all subsequent requests will be answered with these values until they are changed or the server is stopped. A more - convenient way to change these is :: + convenient way to change these is : + + .. code:: python - httpserver.serve_content(content=None, code=200, headers=None, chunked=pytest_localserver.http.Chunked.NO, store_request_data=True) + httpserver.serve_content( + content=None, + code=200, + headers=None, + chunked=pytest_localserver.http.Chunked.NO, + store_request_data=True + ) The ``chunked`` attribute or parameter can be set to @@ -149,27 +201,37 @@ Using your a WSGI application as test server ============================================ As of version 0.3 you can now use a `WSGI application`_ to run on the test -server :: +server : + +.. code:: python + + import pytest + from pytest_localserver.http import WSGIServer + + from myproject import make_request + + + def simple_app(environ, start_response): + """Respond with success.""" + status = "200 OK" + response_headers = [("Content-type", "text/plain")] + start_response(status, response_headers) + return ["success".encode("utf-8")] + - from pytest_localserver.http import WSGIServer + @pytest.fixture + def testserver(): + """Server for simple_app.""" + server = WSGIServer(application=simple_app) + server.start() + yield server + server.stop() - def simple_app(environ, start_response): - """Simplest possible WSGI application""" - status = '200 OK' - response_headers = [('Content-type', 'text/plain')] - start_response(status, response_headers) - return ['Hello world!\n'] - @pytest.fixture - def testserver(request): - """Defines the testserver funcarg""" - server = WSGIServer(application=simple_app) - server.start() - request.addfinalizer(server.stop) - return server + def test_make_request(testserver): + """make_request() should return "success".""" + assert make_request(testserver.url) == "success" - def test_retrieve_some_content(testserver): - assert scrape(testserver.url) == 'Hello world!\n' Have a look at the following page for more information on WSGI: http://wsgi.readthedocs.org/en/latest/learn.html @@ -253,9 +315,9 @@ For package maintainers, here is how we release a new version: Having unsuccessfully tried to mock a server, I stumbled across `linkchecker`_ which uses a the same idea to test its internals. -.. _monkeypatching: http://pytest.org/latest/monkeypatch.html +.. _monkeypatching: https://docs.pytest.org/en/stable/how-to/monkeypatch.html .. _pytest: http://pytest.org/ -.. _funcargs feature: http://pytest.org/latest/funcargs.html +.. _fixture feature: https://pytest.org/en/stable/explanation/fixtures.html .. _linkchecker: http://linkchecker.sourceforge.net/ .. _WSGI application: http://www.python.org/dev/peps/pep-0333/ .. _PyPI: http://pypi.python.org/pypi/pytest-localserver/ diff --git a/contrib/python/pytest-localserver/py3/pytest_localserver/_version.py b/contrib/python/pytest-localserver/py3/pytest_localserver/_version.py index 372502bdbf9..68d2c98c427 100644 --- a/contrib/python/pytest-localserver/py3/pytest_localserver/_version.py +++ b/contrib/python/pytest-localserver/py3/pytest_localserver/_version.py @@ -1,16 +1,34 @@ -# file generated by setuptools_scm +# file generated by setuptools-scm # don't change, don't track in version control + +__all__ = [ + "__version__", + "__version_tuple__", + "version", + "version_tuple", + "__commit_id__", + "commit_id", +] + TYPE_CHECKING = False if TYPE_CHECKING: - from typing import Tuple, Union + from typing import Tuple + from typing import Union + VERSION_TUPLE = Tuple[Union[int, str], ...] + COMMIT_ID = Union[str, None] else: VERSION_TUPLE = object + COMMIT_ID = object version: str __version__: str __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE +commit_id: COMMIT_ID +__commit_id__: COMMIT_ID + +__version__ = version = '0.10.0' +__version_tuple__ = version_tuple = (0, 10, 0) -__version__ = version = '0.9.0.post0' -__version_tuple__ = version_tuple = (0, 9, 0) +__commit_id__ = commit_id = None diff --git a/contrib/python/pytest-localserver/py3/pytest_localserver/http.py b/contrib/python/pytest-localserver/py3/pytest_localserver/http.py index a4c3bef2236..270ec6ff31a 100644 --- a/contrib/python/pytest-localserver/py3/pytest_localserver/http.py +++ b/contrib/python/pytest-localserver/py3/pytest_localserver/http.py @@ -5,7 +5,6 @@ import enum import itertools import json -import sys import threading from werkzeug.datastructures import Headers @@ -56,7 +55,7 @@ class Chunked(enum.Enum): def _encode_chunk(chunk, charset): if isinstance(chunk, str): chunk = chunk.encode(charset) - return "{:x}".format(len(chunk)).encode(charset) + b"\r\n" + chunk + b"\r\n" + return f"{len(chunk):x}".encode(charset) + b"\r\n" + chunk + b"\r\n" class ContentServer(WSGIServer): @@ -161,29 +160,3 @@ class ContentServer(WSGIServer): self.store_request_data = store_request_data if headers: self.headers = Headers(headers) - - -if __name__ == "__main__": # pragma: no cover - import os.path - import time - - app = ContentServer() - server = WSGIServer(application=app) - server.start() - - print("HTTP server is running at %s" % server.url) - print("Type <Ctrl-C> to stop") - - try: - path = sys.argv[1] - except IndexError: - path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "README.rst") - - app.serve_content(open(path).read(), 302) - - try: - while True: - time.sleep(1) - except KeyboardInterrupt: - print("\rstopping...") - server.stop() diff --git a/contrib/python/pytest-localserver/py3/pytest_localserver/https.py b/contrib/python/pytest-localserver/py3/pytest_localserver/https.py index 73392114974..621f3caac8b 100644 --- a/contrib/python/pytest-localserver/py3/pytest_localserver/https.py +++ b/contrib/python/pytest-localserver/py3/pytest_localserver/https.py @@ -133,32 +133,3 @@ class SecureContentServer(ContentServer): certificate path across different versions or test runs. """ return self._cert - - -if __name__ == "__main__": # pragma: no cover - - import sys - import time - - print("Using certificate %s." % DEFAULT_CERTIFICATE) - - server = SecureContentServer() - server.start() - server.logging = True - - print("HTTPS server is running at %s" % server.url) - print("Type <Ctrl-C> to stop") - - try: - path = sys.argv[1] - except IndexError: - path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "README.rst") - - server.serve_content(open(path).read(), 302) - - try: - while True: - time.sleep(1) - except KeyboardInterrupt: - print("\rstopping...") - server.stop() diff --git a/contrib/python/pytest-localserver/py3/pytest_localserver/smtp.py b/contrib/python/pytest-localserver/py3/pytest_localserver/smtp.py index 0b285eb10ab..dc59b43a7b7 100644 --- a/contrib/python/pytest-localserver/py3/pytest_localserver/smtp.py +++ b/contrib/python/pytest-localserver/py3/pytest_localserver/smtp.py @@ -142,26 +142,3 @@ class Server(aiosmtpd.controller.Controller): def __repr__(self): # pragma: no cover return "<smtp.Server %s:%s>" % self.addr - - -def main(): - import time - - server = Server() - server.start() - - print("SMTP server is running on %s:%i" % server.addr) - print("Type <Ctrl-C> to stop") - - try: - while True: - time.sleep(1) - except KeyboardInterrupt: - pass - finally: - print("\rstopping...") - server.stop() - - -if __name__ == "__main__": # pragma: no cover - main() diff --git a/contrib/python/pytest-localserver/py3/tests/test_http.py b/contrib/python/pytest-localserver/py3/tests/test_http.py index 904e6aea5ed..11902fd01d9 100644 --- a/contrib/python/pytest-localserver/py3/tests/test_http.py +++ b/contrib/python/pytest-localserver/py3/tests/test_http.py @@ -241,7 +241,7 @@ def _format_chunk(chunk): if len(r) <= 40: return r else: - return r[:13] + "..." + r[-14:] + " (length {})".format(len(chunk)) + return r[:13] + "..." + r[-14:] + f" (length {len(chunk)})" def _compare_chunks(expected, actual): @@ -252,7 +252,7 @@ def _compare_chunks(expected, actual): for i, (e, a) in enumerate(itertools.zip_longest(expected, actual, fillvalue="<end>")): if e != a: message += [ - " Chunks differ at index {}:".format(i), + f" Chunks differ at index {i}:", " Expected: " + (repr(expected[i : i + 5]) + "..." if e != "<end>" else "<end>"), " Found: " + (repr(actual[i : i + 5]) + "..." if a != "<end>" else "<end>"), ] diff --git a/contrib/python/pytest-localserver/py3/ya.make b/contrib/python/pytest-localserver/py3/ya.make index f066c6f5f1a..1048113ad71 100644 --- a/contrib/python/pytest-localserver/py3/ya.make +++ b/contrib/python/pytest-localserver/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(0.9.0.post0) +VERSION(0.10.0) LICENSE(MIT) |
