Convert make_test_environ_builder into class (fixes #3207)

This commit is contained in:
Daniel Pope 2019-05-31 15:49:23 +01:00
parent 91e53da054
commit 976dfedaa9
4 changed files with 99 additions and 48 deletions

View file

@ -2359,9 +2359,9 @@ class Flask(_PackageBoundObject):
:param kwargs: other keyword arguments passed to :param kwargs: other keyword arguments passed to
:class:`~werkzeug.test.EnvironBuilder`. :class:`~werkzeug.test.EnvironBuilder`.
""" """
from flask.testing import make_test_environ_builder from flask.testing import EnvironBuilder
builder = make_test_environ_builder(self, *args, **kwargs) builder = EnvironBuilder(self, *args, **kwargs)
try: try:
return self.request_context(builder.get_environ()) return self.request_context(builder.get_environ())

View file

@ -9,8 +9,9 @@
:copyright: © 2010 by the Pallets team. :copyright: © 2010 by the Pallets team.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import warnings
import werkzeug import werkzeug
import werkzeug.test
from contextlib import contextmanager from contextlib import contextmanager
from click.testing import CliRunner from click.testing import CliRunner
@ -21,11 +22,9 @@ from flask.json import dumps as json_dumps
from werkzeug.urls import url_parse from werkzeug.urls import url_parse
def make_test_environ_builder( class EnvironBuilder(werkzeug.test.EnvironBuilder):
app, path="/", base_url=None, subdomain=None, url_scheme=None, *args, **kwargs """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the
): application.
"""Create a :class:`~werkzeug.test.EnvironBuilder`, taking some
defaults from the application.
:param app: The Flask application to configure the environment from. :param app: The Flask application to configure the environment from.
:param path: URL path being requested. :param path: URL path being requested.
@ -45,41 +44,72 @@ def make_test_environ_builder(
:class:`~werkzeug.test.EnvironBuilder`. :class:`~werkzeug.test.EnvironBuilder`.
""" """
assert not (base_url or subdomain or url_scheme) or (base_url is not None) != bool( def __init__(
subdomain or url_scheme self,
), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' app,
path="/",
base_url=None,
subdomain=None,
url_scheme=None,
*args,
**kwargs
):
assert not (base_url or subdomain or url_scheme) or (
base_url is not None
) != bool(
subdomain or url_scheme
), 'Cannot pass "subdomain" or "url_scheme" with "base_url".'
if base_url is None: if base_url is None:
http_host = app.config.get("SERVER_NAME") or "localhost" http_host = app.config.get("SERVER_NAME") or "localhost"
app_root = app.config["APPLICATION_ROOT"] app_root = app.config["APPLICATION_ROOT"]
if subdomain: if subdomain:
http_host = "{0}.{1}".format(subdomain, http_host) http_host = "{0}.{1}".format(subdomain, http_host)
if url_scheme is None: if url_scheme is None:
url_scheme = app.config["PREFERRED_URL_SCHEME"] url_scheme = app.config["PREFERRED_URL_SCHEME"]
url = url_parse(path) url = url_parse(path)
base_url = "{scheme}://{netloc}/{path}".format( base_url = "{scheme}://{netloc}/{path}".format(
scheme=url.scheme or url_scheme, scheme=url.scheme or url_scheme,
netloc=url.netloc or http_host, netloc=url.netloc or http_host,
path=app_root.lstrip("/"), path=app_root.lstrip("/"),
)
path = url.path
if url.query:
sep = b"?" if isinstance(url.query, bytes) else "?"
path += sep + url.query
if "json" in kwargs:
assert "data" not in kwargs, "Client cannot provide both 'json' and 'data'."
kwargs["data"] = self.json_dumps(kwargs.pop("json"), app=app)
if "content_type" not in kwargs:
kwargs["content_type"] = "application/json"
super(EnvironBuilder, self).__init__(path, base_url, *args, **kwargs)
self.app = app
json_dumps = staticmethod(json_dumps)
def make_test_environ_builder(*args, **kwargs):
"""Create a :class:`flask.testing.EnvironBuilder`.
.. deprecated: 1.1
Will be removed in 1.2. Construct ``flask.testing.EnvironBuilder``
directly instead.
"""
warnings.warn(
DeprecationWarning(
'"make_test_environ_builder()" is deprecated and will be removed '
'in 1.2. Construct "flask.testing.EnvironBuilder" directly '
"instead."
) )
path = url.path )
return EnvironBuilder(*args, **kwargs)
if url.query:
sep = b"?" if isinstance(url.query, bytes) else "?"
path += sep + url.query
# TODO use EnvironBuilder.json_dumps once we require Werkzeug 0.15
if "json" in kwargs:
assert "data" not in kwargs, "Client cannot provide both 'json' and 'data'."
kwargs["data"] = json_dumps(kwargs.pop("json"), app=app)
if "content_type" not in kwargs:
kwargs["content_type"] = "application/json"
return EnvironBuilder(path, base_url, *args, **kwargs)
class FlaskClient(Client): class FlaskClient(Client):
@ -167,11 +197,11 @@ class FlaskClient(Client):
if ( if (
not kwargs not kwargs
and len(args) == 1 and len(args) == 1
and isinstance(args[0], (EnvironBuilder, dict)) and isinstance(args[0], (werkzeug.test.EnvironBuilder, dict))
): ):
environ = self.environ_base.copy() environ = self.environ_base.copy()
if isinstance(args[0], EnvironBuilder): if isinstance(args[0], werkzeug.test.EnvironBuilder):
environ.update(args[0].get_environ()) environ.update(args[0].get_environ())
else: else:
environ.update(args[0]) environ.update(args[0])
@ -182,7 +212,7 @@ class FlaskClient(Client):
"flask._preserve_context" "flask._preserve_context"
] = self.preserve_context ] = self.preserve_context
kwargs.setdefault("environ_base", self.environ_base) kwargs.setdefault("environ_base", self.environ_base)
builder = make_test_environ_builder(self.application, *args, **kwargs) builder = EnvironBuilder(self.application, *args, **kwargs)
try: try:
environ = builder.get_environ() environ = builder.get_environ()

View file

@ -243,9 +243,9 @@ def test_bad_environ_raises_bad_request():
# because werkzeug enforces latin1 on Python 2. # because werkzeug enforces latin1 on Python 2.
# However it works when actually passed to the server. # However it works when actually passed to the server.
from flask.testing import make_test_environ_builder from flask.testing import EnvironBuilder
builder = make_test_environ_builder(app) builder = EnvironBuilder(app)
environ = builder.get_environ() environ = builder.get_environ()
# use a non-printable character in the Host - this is key to this test # use a non-printable character in the Host - this is key to this test
@ -267,9 +267,9 @@ def test_environ_for_valid_idna_completes():
# because werkzeug enforces latin1 on Python 2. # because werkzeug enforces latin1 on Python 2.
# However it works when actually passed to the server. # However it works when actually passed to the server.
from flask.testing import make_test_environ_builder from flask.testing import EnvironBuilder
builder = make_test_environ_builder(app) builder = EnvironBuilder(app)
environ = builder.get_environ() environ = builder.get_environ()
# these characters are all IDNA-compatible # these characters are all IDNA-compatible

View file

@ -18,7 +18,7 @@ from flask import appcontext_popped
from flask._compat import text_type from flask._compat import text_type
from flask.cli import ScriptInfo from flask.cli import ScriptInfo
from flask.json import jsonify from flask.json import jsonify
from flask.testing import make_test_environ_builder, FlaskCliRunner from flask.testing import make_test_environ_builder, FlaskCliRunner, EnvironBuilder
try: try:
import blinker import blinker
@ -88,7 +88,7 @@ def test_client_open_environ(app, client, request):
def index(): def index():
return flask.request.remote_addr return flask.request.remote_addr
builder = make_test_environ_builder(app, path="/index", method="GET") builder = EnvironBuilder(app, path="/index", method="GET")
request.addfinalizer(builder.close) request.addfinalizer(builder.close)
rv = client.open(builder) rv = client.open(builder)
@ -113,13 +113,34 @@ def test_specify_url_scheme(app, client):
def test_path_is_url(app): def test_path_is_url(app):
eb = make_test_environ_builder(app, "https://example.com/") eb = EnvironBuilder(app, "https://example.com/")
assert eb.url_scheme == "https" assert eb.url_scheme == "https"
assert eb.host == "example.com" assert eb.host == "example.com"
assert eb.script_root == "" assert eb.script_root == ""
assert eb.path == "/" assert eb.path == "/"
def test_make_test_environ_builder(app):
with pytest.deprecated_call():
eb = make_test_environ_builder(app, "https://example.com/")
assert eb.url_scheme == "https"
assert eb.host == "example.com"
assert eb.script_root == ""
assert eb.path == "/"
def test_environbuilder_json_dumps(app):
"""EnvironBuilder.json_dumps() takes settings from the app."""
app.config["JSON_AS_ASCII"] = False
eb = EnvironBuilder(app, json=u"\u20ac")
assert eb.input_stream.read().decode("utf8") == u'"\u20ac"'
def test_environbuilder_json_dumps_static():
"""EnvironBuilder.json_dumps() can be called as a static method."""
assert EnvironBuilder.json_dumps(u"\u20ac") == u'"\\u20ac"'
def test_blueprint_with_subdomain(): def test_blueprint_with_subdomain():
app = flask.Flask(__name__, subdomain_matching=True) app = flask.Flask(__name__, subdomain_matching=True)
app.config["SERVER_NAME"] = "example.com:1234" app.config["SERVER_NAME"] = "example.com:1234"