chore: automatic commit 2025-04-30 12:48

This commit is contained in:
2025-04-30 12:48:06 +02:00
parent f69356473b
commit e4ab1e1bb5
5284 changed files with 868438 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
#!/usr/bin/env python
from ._version import version as __version__

View File

@@ -0,0 +1,35 @@
import functools
import warnings
def deprecated(reason):
"""Decorator which can be used to mark function or method as deprecated.
It will result a warning being emmitted when the function is called."""
def decorator(func):
@functools.wraps(func)
def deprecated_call(*args, **kwargs):
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(reason, DeprecationWarning, stacklevel=2)
warnings.simplefilter("default", DeprecationWarning)
return func(*args, **kwargs)
return deprecated_call
return decorator
def _rewrite_server_name(server_name, new_port):
"""Rewrite server port in ``server_name`` with ``new_port`` value."""
sep = ":"
if sep in server_name:
server_name, _ = server_name.split(sep, 1)
return sep.join((server_name, new_port))
def _determine_scope(*, fixture_name, config):
return config.getini("live_server_scope")
def _make_accept_header(mimetype):
return [("Accept", mimetype)]

View File

@@ -0,0 +1,5 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
version = '1.2.0'
version_tuple = (1, 2, 0)

View File

@@ -0,0 +1,135 @@
#!/usr/bin/env python
import socket
import warnings
import pytest
from flask import _request_ctx_stack
from ._internal import _determine_scope
from ._internal import _make_accept_header
from ._internal import _rewrite_server_name
from ._internal import deprecated
from .live_server import LiveServer
@pytest.fixture
def client(app):
"""A Flask test client. An instance of :class:`flask.testing.TestClient`
by default.
"""
with app.test_client() as client:
yield client
@pytest.fixture
def client_class(request, client):
"""Uses to set a ``client`` class attribute to current Flask test client::
@pytest.mark.usefixtures('client_class')
class TestView:
def login(self, email, password):
credentials = {'email': email, 'password': password}
return self.client.post(url_for('login'), data=credentials)
def test_login(self):
assert self.login('foo@example.com', 'pass').status_code == 200
"""
if request.cls is not None:
request.cls.client = client
@pytest.fixture(scope=_determine_scope)
def live_server(request, app, pytestconfig):
"""Run application in a separate process.
When the ``live_server`` fixture is applied, the ``url_for`` function
works as expected::
def test_server_is_up_and_running(live_server):
index_url = url_for('index', _external=True)
assert index_url == 'http://localhost:5000/'
res = urllib2.urlopen(index_url)
assert res.code == 200
"""
# Set or get a port
port = app.config.get("LIVESERVER_PORT", None)
if not port:
port = pytestconfig.getvalue("live_server_port")
if port == 0:
# Bind to an open port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 0))
port = s.getsockname()[1]
s.close()
host = pytestconfig.getvalue("live_server_host")
# Explicitly set application ``SERVER_NAME`` for test suite
original_server_name = app.config["SERVER_NAME"] or "localhost"
final_server_name = _rewrite_server_name(original_server_name, str(port))
app.config["SERVER_NAME"] = final_server_name
wait = request.config.getvalue("live_server_wait")
clean_stop = request.config.getvalue("live_server_clean_stop")
server = LiveServer(app, host, port, wait, clean_stop)
if request.config.getvalue("start_live_server"):
server.start()
request.addfinalizer(server.stop)
yield server
if original_server_name is not None:
app.config["SERVER_NAME"] = original_server_name
@pytest.fixture
def config(app):
"""An application config."""
return app.config
@pytest.fixture
def request_ctx(app):
"""The request context which contains all request relevant information,
e.g. `session`, `g`, `flashes`, etc.
"""
warnings.warn(
"In Werzeug 2.0.0, the Client request methods "
"(client.get, client.post) always return an instance of TestResponse. This "
"class provides a reference to the request object through 'response.request' "
"The fixture 'request_ctx' is deprecated and will be removed in the future, using TestResponse.request "
"is the prefered way.",
DeprecationWarning,
stacklevel=2,
)
return _request_ctx_stack.top
@pytest.fixture(params=["application/json", "text/html"])
def mimetype(request):
return request.param
@pytest.fixture
def accept_mimetype(mimetype):
return _make_accept_header(mimetype)
@pytest.fixture
def accept_json(request):
return _make_accept_header("application/json")
@pytest.fixture
def accept_jsonp():
return _make_accept_header("application/json-p")
@pytest.fixture(params=["*", "*/*"])
def accept_any(request):
return _make_accept_header(request.param)

View File

@@ -0,0 +1,92 @@
import logging
import multiprocessing
import os
import signal
import socket
import time
import pytest
from ._internal import deprecated
class LiveServer:
"""The helper class used to manage a live server. Handles creation and
stopping application in a separate process.
:param app: The application to run.
:param host: The host where to listen (default localhost).
:param port: The port to run application.
:param wait: The timeout after which test case is aborted if
application is not started.
"""
def __init__(self, app, host, port, wait, clean_stop=False):
self.app = app
self.port = port
self.host = host
self.wait = wait
self.clean_stop = clean_stop
self._process = None
def start(self):
"""Start application in a separate process."""
def worker(app, host, port):
app.run(host=host, port=port, use_reloader=False, threaded=True)
self._process = multiprocessing.Process(
target=worker, args=(self.app, self.host, self.port)
)
self._process.daemon = True
self._process.start()
keep_trying = True
start_time = time.time()
while keep_trying:
elapsed_time = time.time() - start_time
if elapsed_time > self.wait:
pytest.fail(
"Failed to start the server after {!s} "
"seconds.".format(self.wait)
)
if self._is_ready():
keep_trying = False
def _is_ready(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((self.host, self.port))
except socket.error:
ret = False
else:
ret = True
finally:
sock.close()
return ret
def stop(self):
"""Stop application process."""
if self._process:
if self.clean_stop and self._stop_cleanly():
return
if self._process.is_alive():
# If it's still alive, kill it
self._process.terminate()
def _stop_cleanly(self, timeout=5):
"""Attempts to stop the server cleanly by sending a SIGINT signal and waiting for
``timeout`` seconds.
:return: True if the server was cleanly stopped, False otherwise.
"""
try:
os.kill(self._process.pid, signal.SIGINT)
self._process.join(timeout)
return True
except Exception as ex:
logging.error("Failed to join the live server process: %r", ex)
return False
def __repr__(self):
return "<LiveServer listening at %s>" % self.url()

View File

@@ -0,0 +1,198 @@
#!/usr/bin/env python
"""
A py.test plugin which helps testing Flask applications.
:copyright: (c) by Vital Kudzelka
:license: MIT
"""
import sys
import pytest
from flask import json
from werkzeug.utils import cached_property
from .fixtures import accept_any
from .fixtures import accept_json
from .fixtures import accept_jsonp
from .fixtures import accept_mimetype
from .fixtures import client
from .fixtures import client_class
from .fixtures import config
from .fixtures import live_server
from .fixtures import request_ctx
from .pytest_compat import getfixturevalue
class JSONResponse:
"""Mixin with testing helper methods for JSON responses."""
def __eq__(self, other):
if isinstance(other, int):
return self.status_code == other
return super().__eq__(other)
def __ne__(self, other):
return not self == other
def pytest_assertrepr_compare(op, left, right):
if isinstance(left, JSONResponse) and op == "==" and isinstance(right, int):
return [
"Mismatch in status code for response: {} != {}".format(
left.status_code,
right,
),
"Response status: {}".format(left.status),
]
return None
def _make_test_response_class(response_class):
"""Extends the response class with special attribute to test JSON
responses. Don't override user-defined `json` attribute if any.
:param response_class: An original response class.
"""
if "json" in response_class.__dict__:
return response_class
return type(str(JSONResponse), (response_class, JSONResponse), {})
@pytest.fixture(autouse=True)
def _monkeypatch_response_class(request, monkeypatch):
"""Set custom response class before test suite and restore the original
after. Custom response has `json` property to easily test JSON responses::
@app.route('/ping')
def ping():
return jsonify(ping='pong')
def test_json(client):
res = client.get(url_for('ping'))
assert res.json == {'ping': 'pong'}
"""
if "app" not in request.fixturenames:
return
app = getfixturevalue(request, "app")
monkeypatch.setattr(
app, "response_class", _make_test_response_class(app.response_class)
)
@pytest.fixture(autouse=True)
def _push_request_context(request):
"""During tests execution request context has been pushed, e.g. `url_for`,
`session`, etc. can be used in tests as is::
def test_app(app, client):
assert client.get(url_for('myview')).status_code == 200
"""
if "app" not in request.fixturenames:
return
app = getfixturevalue(request, "app")
# Get application bound to the live server if ``live_server`` fixture
# is applied. Live server application has an explicit ``SERVER_NAME``,
# so ``url_for`` function generates a complete URL for endpoint which
# includes application port as well.
if "live_server" in request.fixturenames:
app = getfixturevalue(request, "live_server").app
ctx = app.test_request_context()
ctx.push()
def teardown():
ctx.pop()
request.addfinalizer(teardown)
@pytest.fixture(autouse=True)
def _configure_application(request, monkeypatch):
"""Use `pytest.mark.options` decorator to pass options to your application
factory::
@pytest.mark.options(debug=False)
def test_something(app):
assert not app.debug, 'the application works not in debug mode!'
"""
if "app" not in request.fixturenames:
return
app = getfixturevalue(request, "app")
for options in request.node.iter_markers("options"):
for key, value in options.kwargs.items():
monkeypatch.setitem(app.config, key.upper(), value)
def pytest_addoption(parser):
group = parser.getgroup("flask")
group.addoption(
"--start-live-server",
action="store_true",
dest="start_live_server",
default=True,
help="start server automatically when live_server "
"fixture is applied (enabled by default).",
)
group.addoption(
"--no-start-live-server",
action="store_false",
dest="start_live_server",
help="don't start server automatically when live_server " "fixture is applied.",
)
group.addoption(
"--live-server-wait",
action="store",
dest="live_server_wait",
default=5,
type=float,
help="the timeout after which test case is aborted if live server is "
" not started.",
)
group.addoption(
"--live-server-clean-stop",
action="store_true",
dest="live_server_clean_stop",
default=True,
help="attempt to kill the live server cleanly.",
)
group.addoption(
"--no-live-server-clean-stop",
action="store_false",
dest="live_server_clean_stop",
help="terminate the server forcefully after stop.",
)
group.addoption(
"--live-server-host",
action="store",
default="localhost",
type=str,
help="use a host where to listen (default localhost).",
)
group.addoption(
"--live-server-port",
action="store",
default=0,
type=int,
help="use a fixed port for the live_server fixture.",
)
parser.addini(
"live_server_scope",
"modify the scope of the live_server fixture.",
default="session",
)
def pytest_configure(config):
config.addinivalue_line(
"markers", "app(options): pass options to your application factory"
)
config.addinivalue_line("markers", "options: app config manipulation")

View File

@@ -0,0 +1,5 @@
def getfixturevalue(request, value):
if hasattr(request, "getfixturevalue"):
return request.getfixturevalue(value)
return request.getfuncargvalue(value) # pragma: no cover