mirror of https://github.com/pallets/flask.git
838 lines
22 KiB
Python
838 lines
22 KiB
Python
import pytest
|
|
from jinja2 import TemplateNotFound
|
|
from werkzeug.http import parse_cache_control_header
|
|
|
|
import flask
|
|
|
|
|
|
def test_blueprint_specific_error_handling(app, client):
|
|
frontend = flask.Blueprint("frontend", __name__)
|
|
backend = flask.Blueprint("backend", __name__)
|
|
sideend = flask.Blueprint("sideend", __name__)
|
|
|
|
@frontend.errorhandler(403)
|
|
def frontend_forbidden(e):
|
|
return "frontend says no", 403
|
|
|
|
@frontend.route("/frontend-no")
|
|
def frontend_no():
|
|
flask.abort(403)
|
|
|
|
@backend.errorhandler(403)
|
|
def backend_forbidden(e):
|
|
return "backend says no", 403
|
|
|
|
@backend.route("/backend-no")
|
|
def backend_no():
|
|
flask.abort(403)
|
|
|
|
@sideend.route("/what-is-a-sideend")
|
|
def sideend_no():
|
|
flask.abort(403)
|
|
|
|
app.register_blueprint(frontend)
|
|
app.register_blueprint(backend)
|
|
app.register_blueprint(sideend)
|
|
|
|
@app.errorhandler(403)
|
|
def app_forbidden(e):
|
|
return "application itself says no", 403
|
|
|
|
assert client.get("/frontend-no").data == b"frontend says no"
|
|
assert client.get("/backend-no").data == b"backend says no"
|
|
assert client.get("/what-is-a-sideend").data == b"application itself says no"
|
|
|
|
|
|
def test_blueprint_specific_user_error_handling(app, client):
|
|
class MyDecoratorException(Exception):
|
|
pass
|
|
|
|
class MyFunctionException(Exception):
|
|
pass
|
|
|
|
blue = flask.Blueprint("blue", __name__)
|
|
|
|
@blue.errorhandler(MyDecoratorException)
|
|
def my_decorator_exception_handler(e):
|
|
assert isinstance(e, MyDecoratorException)
|
|
return "boom"
|
|
|
|
def my_function_exception_handler(e):
|
|
assert isinstance(e, MyFunctionException)
|
|
return "bam"
|
|
|
|
blue.register_error_handler(MyFunctionException, my_function_exception_handler)
|
|
|
|
@blue.route("/decorator")
|
|
def blue_deco_test():
|
|
raise MyDecoratorException()
|
|
|
|
@blue.route("/function")
|
|
def blue_func_test():
|
|
raise MyFunctionException()
|
|
|
|
app.register_blueprint(blue)
|
|
|
|
assert client.get("/decorator").data == b"boom"
|
|
assert client.get("/function").data == b"bam"
|
|
|
|
|
|
def test_blueprint_app_error_handling(app, client):
|
|
errors = flask.Blueprint("errors", __name__)
|
|
|
|
@errors.app_errorhandler(403)
|
|
def forbidden_handler(e):
|
|
return "you shall not pass", 403
|
|
|
|
@app.route("/forbidden")
|
|
def app_forbidden():
|
|
flask.abort(403)
|
|
|
|
forbidden_bp = flask.Blueprint("forbidden_bp", __name__)
|
|
|
|
@forbidden_bp.route("/nope")
|
|
def bp_forbidden():
|
|
flask.abort(403)
|
|
|
|
app.register_blueprint(errors)
|
|
app.register_blueprint(forbidden_bp)
|
|
|
|
assert client.get("/forbidden").data == b"you shall not pass"
|
|
assert client.get("/nope").data == b"you shall not pass"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("prefix", "rule", "url"),
|
|
(
|
|
("", "/", "/"),
|
|
("/", "", "/"),
|
|
("/", "/", "/"),
|
|
("/foo", "", "/foo"),
|
|
("/foo/", "", "/foo/"),
|
|
("", "/bar", "/bar"),
|
|
("/foo/", "/bar", "/foo/bar"),
|
|
("/foo/", "bar", "/foo/bar"),
|
|
("/foo", "/bar", "/foo/bar"),
|
|
("/foo/", "//bar", "/foo/bar"),
|
|
("/foo//", "/bar", "/foo/bar"),
|
|
),
|
|
)
|
|
def test_blueprint_prefix_slash(app, client, prefix, rule, url):
|
|
bp = flask.Blueprint("test", __name__, url_prefix=prefix)
|
|
|
|
@bp.route(rule)
|
|
def index():
|
|
return "", 204
|
|
|
|
app.register_blueprint(bp)
|
|
assert client.get(url).status_code == 204
|
|
|
|
|
|
def test_blueprint_url_defaults(app, client):
|
|
bp = flask.Blueprint("test", __name__)
|
|
|
|
@bp.route("/foo", defaults={"baz": 42})
|
|
def foo(bar, baz):
|
|
return f"{bar}/{baz:d}"
|
|
|
|
@bp.route("/bar")
|
|
def bar(bar):
|
|
return str(bar)
|
|
|
|
app.register_blueprint(bp, url_prefix="/1", url_defaults={"bar": 23})
|
|
app.register_blueprint(bp, url_prefix="/2", url_defaults={"bar": 19})
|
|
|
|
assert client.get("/1/foo").data == b"23/42"
|
|
assert client.get("/2/foo").data == b"19/42"
|
|
assert client.get("/1/bar").data == b"23"
|
|
assert client.get("/2/bar").data == b"19"
|
|
|
|
|
|
def test_blueprint_url_processors(app, client):
|
|
bp = flask.Blueprint("frontend", __name__, url_prefix="/<lang_code>")
|
|
|
|
@bp.url_defaults
|
|
def add_language_code(endpoint, values):
|
|
values.setdefault("lang_code", flask.g.lang_code)
|
|
|
|
@bp.url_value_preprocessor
|
|
def pull_lang_code(endpoint, values):
|
|
flask.g.lang_code = values.pop("lang_code")
|
|
|
|
@bp.route("/")
|
|
def index():
|
|
return flask.url_for(".about")
|
|
|
|
@bp.route("/about")
|
|
def about():
|
|
return flask.url_for(".index")
|
|
|
|
app.register_blueprint(bp)
|
|
|
|
assert client.get("/de/").data == b"/de/about"
|
|
assert client.get("/de/about").data == b"/de/"
|
|
|
|
|
|
def test_templates_and_static(test_apps):
|
|
from blueprintapp import app
|
|
|
|
client = app.test_client()
|
|
|
|
rv = client.get("/")
|
|
assert rv.data == b"Hello from the Frontend"
|
|
rv = client.get("/admin/")
|
|
assert rv.data == b"Hello from the Admin"
|
|
rv = client.get("/admin/index2")
|
|
assert rv.data == b"Hello from the Admin"
|
|
rv = client.get("/admin/static/test.txt")
|
|
assert rv.data.strip() == b"Admin File"
|
|
rv.close()
|
|
rv = client.get("/admin/static/css/test.css")
|
|
assert rv.data.strip() == b"/* nested file */"
|
|
rv.close()
|
|
|
|
# try/finally, in case other tests use this app for Blueprint tests.
|
|
max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"]
|
|
try:
|
|
expected_max_age = 3600
|
|
if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == expected_max_age:
|
|
expected_max_age = 7200
|
|
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = expected_max_age
|
|
rv = client.get("/admin/static/css/test.css")
|
|
cc = parse_cache_control_header(rv.headers["Cache-Control"])
|
|
assert cc.max_age == expected_max_age
|
|
rv.close()
|
|
finally:
|
|
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default
|
|
|
|
with app.test_request_context():
|
|
assert (
|
|
flask.url_for("admin.static", filename="test.txt")
|
|
== "/admin/static/test.txt"
|
|
)
|
|
|
|
with app.test_request_context():
|
|
with pytest.raises(TemplateNotFound) as e:
|
|
flask.render_template("missing.html")
|
|
assert e.value.name == "missing.html"
|
|
|
|
with flask.Flask(__name__).test_request_context():
|
|
assert flask.render_template("nested/nested.txt") == "I'm nested"
|
|
|
|
|
|
def test_default_static_max_age(app):
|
|
class MyBlueprint(flask.Blueprint):
|
|
def get_send_file_max_age(self, filename):
|
|
return 100
|
|
|
|
blueprint = MyBlueprint("blueprint", __name__, static_folder="static")
|
|
app.register_blueprint(blueprint)
|
|
|
|
# try/finally, in case other tests use this app for Blueprint tests.
|
|
max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"]
|
|
try:
|
|
with app.test_request_context():
|
|
unexpected_max_age = 3600
|
|
if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == unexpected_max_age:
|
|
unexpected_max_age = 7200
|
|
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = unexpected_max_age
|
|
rv = blueprint.send_static_file("index.html")
|
|
cc = parse_cache_control_header(rv.headers["Cache-Control"])
|
|
assert cc.max_age == 100
|
|
rv.close()
|
|
finally:
|
|
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default
|
|
|
|
|
|
def test_templates_list(test_apps):
|
|
from blueprintapp import app
|
|
|
|
templates = sorted(app.jinja_env.list_templates())
|
|
assert templates == ["admin/index.html", "frontend/index.html"]
|
|
|
|
|
|
def test_dotted_name_not_allowed(app, client):
|
|
with pytest.raises(ValueError):
|
|
flask.Blueprint("app.ui", __name__)
|
|
|
|
|
|
def test_dotted_names_from_app(app, client):
|
|
test = flask.Blueprint("test", __name__)
|
|
|
|
@app.route("/")
|
|
def app_index():
|
|
return flask.url_for("test.index")
|
|
|
|
@test.route("/test/")
|
|
def index():
|
|
return flask.url_for("app_index")
|
|
|
|
app.register_blueprint(test)
|
|
|
|
rv = client.get("/")
|
|
assert rv.data == b"/test/"
|
|
|
|
|
|
def test_empty_url_defaults(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.route("/", defaults={"page": 1})
|
|
@bp.route("/page/<int:page>")
|
|
def something(page):
|
|
return str(page)
|
|
|
|
app.register_blueprint(bp)
|
|
|
|
assert client.get("/").data == b"1"
|
|
assert client.get("/page/2").data == b"2"
|
|
|
|
|
|
def test_route_decorator_custom_endpoint(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.route("/foo")
|
|
def foo():
|
|
return flask.request.endpoint
|
|
|
|
@bp.route("/bar", endpoint="bar")
|
|
def foo_bar():
|
|
return flask.request.endpoint
|
|
|
|
@bp.route("/bar/123", endpoint="123")
|
|
def foo_bar_foo():
|
|
return flask.request.endpoint
|
|
|
|
@bp.route("/bar/foo")
|
|
def bar_foo():
|
|
return flask.request.endpoint
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.request.endpoint
|
|
|
|
assert client.get("/").data == b"index"
|
|
assert client.get("/py/foo").data == b"bp.foo"
|
|
assert client.get("/py/bar").data == b"bp.bar"
|
|
assert client.get("/py/bar/123").data == b"bp.123"
|
|
assert client.get("/py/bar/foo").data == b"bp.bar_foo"
|
|
|
|
|
|
def test_route_decorator_custom_endpoint_with_dots(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
with pytest.raises(ValueError):
|
|
bp.route("/", endpoint="a.b")(lambda: "")
|
|
|
|
with pytest.raises(ValueError):
|
|
bp.add_url_rule("/", endpoint="a.b")
|
|
|
|
def view():
|
|
return ""
|
|
|
|
view.__name__ = "a.b"
|
|
|
|
with pytest.raises(ValueError):
|
|
bp.add_url_rule("/", view_func=view)
|
|
|
|
|
|
def test_endpoint_decorator(app, client):
|
|
from werkzeug.routing import Rule
|
|
|
|
app.url_map.add(Rule("/foo", endpoint="bar"))
|
|
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.endpoint("bar")
|
|
def foobar():
|
|
return flask.request.endpoint
|
|
|
|
app.register_blueprint(bp, url_prefix="/bp_prefix")
|
|
|
|
assert client.get("/foo").data == b"bar"
|
|
assert client.get("/bp_prefix/bar").status_code == 404
|
|
|
|
|
|
def test_template_filter(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_filter()
|
|
def my_reverse(s):
|
|
return s[::-1]
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "my_reverse" in app.jinja_env.filters.keys()
|
|
assert app.jinja_env.filters["my_reverse"] == my_reverse
|
|
assert app.jinja_env.filters["my_reverse"]("abcd") == "dcba"
|
|
|
|
|
|
def test_add_template_filter(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def my_reverse(s):
|
|
return s[::-1]
|
|
|
|
bp.add_app_template_filter(my_reverse)
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "my_reverse" in app.jinja_env.filters.keys()
|
|
assert app.jinja_env.filters["my_reverse"] == my_reverse
|
|
assert app.jinja_env.filters["my_reverse"]("abcd") == "dcba"
|
|
|
|
|
|
def test_template_filter_with_name(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_filter("strrev")
|
|
def my_reverse(s):
|
|
return s[::-1]
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "strrev" in app.jinja_env.filters.keys()
|
|
assert app.jinja_env.filters["strrev"] == my_reverse
|
|
assert app.jinja_env.filters["strrev"]("abcd") == "dcba"
|
|
|
|
|
|
def test_add_template_filter_with_name(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def my_reverse(s):
|
|
return s[::-1]
|
|
|
|
bp.add_app_template_filter(my_reverse, "strrev")
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "strrev" in app.jinja_env.filters.keys()
|
|
assert app.jinja_env.filters["strrev"] == my_reverse
|
|
assert app.jinja_env.filters["strrev"]("abcd") == "dcba"
|
|
|
|
|
|
def test_template_filter_with_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_filter()
|
|
def super_reverse(s):
|
|
return s[::-1]
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_filter.html", value="abcd")
|
|
|
|
rv = client.get("/")
|
|
assert rv.data == b"dcba"
|
|
|
|
|
|
def test_template_filter_after_route_with_template(app, client):
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_filter.html", value="abcd")
|
|
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_filter()
|
|
def super_reverse(s):
|
|
return s[::-1]
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
rv = client.get("/")
|
|
assert rv.data == b"dcba"
|
|
|
|
|
|
def test_add_template_filter_with_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def super_reverse(s):
|
|
return s[::-1]
|
|
|
|
bp.add_app_template_filter(super_reverse)
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_filter.html", value="abcd")
|
|
|
|
rv = client.get("/")
|
|
assert rv.data == b"dcba"
|
|
|
|
|
|
def test_template_filter_with_name_and_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_filter("super_reverse")
|
|
def my_reverse(s):
|
|
return s[::-1]
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_filter.html", value="abcd")
|
|
|
|
rv = client.get("/")
|
|
assert rv.data == b"dcba"
|
|
|
|
|
|
def test_add_template_filter_with_name_and_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def my_reverse(s):
|
|
return s[::-1]
|
|
|
|
bp.add_app_template_filter(my_reverse, "super_reverse")
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_filter.html", value="abcd")
|
|
|
|
rv = client.get("/")
|
|
assert rv.data == b"dcba"
|
|
|
|
|
|
def test_template_test(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_test()
|
|
def is_boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "is_boolean" in app.jinja_env.tests.keys()
|
|
assert app.jinja_env.tests["is_boolean"] == is_boolean
|
|
assert app.jinja_env.tests["is_boolean"](False)
|
|
|
|
|
|
def test_add_template_test(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def is_boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
bp.add_app_template_test(is_boolean)
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "is_boolean" in app.jinja_env.tests.keys()
|
|
assert app.jinja_env.tests["is_boolean"] == is_boolean
|
|
assert app.jinja_env.tests["is_boolean"](False)
|
|
|
|
|
|
def test_template_test_with_name(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_test("boolean")
|
|
def is_boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "boolean" in app.jinja_env.tests.keys()
|
|
assert app.jinja_env.tests["boolean"] == is_boolean
|
|
assert app.jinja_env.tests["boolean"](False)
|
|
|
|
|
|
def test_add_template_test_with_name(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def is_boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
bp.add_app_template_test(is_boolean, "boolean")
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
assert "boolean" in app.jinja_env.tests.keys()
|
|
assert app.jinja_env.tests["boolean"] == is_boolean
|
|
assert app.jinja_env.tests["boolean"](False)
|
|
|
|
|
|
def test_template_test_with_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_test()
|
|
def boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_test.html", value=False)
|
|
|
|
rv = client.get("/")
|
|
assert b"Success!" in rv.data
|
|
|
|
|
|
def test_template_test_after_route_with_template(app, client):
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_test.html", value=False)
|
|
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_test()
|
|
def boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
rv = client.get("/")
|
|
assert b"Success!" in rv.data
|
|
|
|
|
|
def test_add_template_test_with_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
bp.add_app_template_test(boolean)
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_test.html", value=False)
|
|
|
|
rv = client.get("/")
|
|
assert b"Success!" in rv.data
|
|
|
|
|
|
def test_template_test_with_name_and_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_test("boolean")
|
|
def is_boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_test.html", value=False)
|
|
|
|
rv = client.get("/")
|
|
assert b"Success!" in rv.data
|
|
|
|
|
|
def test_add_template_test_with_name_and_template(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
def is_boolean(value):
|
|
return isinstance(value, bool)
|
|
|
|
bp.add_app_template_test(is_boolean, "boolean")
|
|
app.register_blueprint(bp, url_prefix="/py")
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return flask.render_template("template_test.html", value=False)
|
|
|
|
rv = client.get("/")
|
|
assert b"Success!" in rv.data
|
|
|
|
|
|
def test_context_processing(app, client):
|
|
answer_bp = flask.Blueprint("answer_bp", __name__)
|
|
|
|
template_string = lambda: flask.render_template_string( # noqa: E731
|
|
"{% if notanswer %}{{ notanswer }} is not the answer. {% endif %}"
|
|
"{% if answer %}{{ answer }} is the answer.{% endif %}"
|
|
)
|
|
|
|
# App global context processor
|
|
@answer_bp.app_context_processor
|
|
def not_answer_context_processor():
|
|
return {"notanswer": 43}
|
|
|
|
# Blueprint local context processor
|
|
@answer_bp.context_processor
|
|
def answer_context_processor():
|
|
return {"answer": 42}
|
|
|
|
# Setup endpoints for testing
|
|
@answer_bp.route("/bp")
|
|
def bp_page():
|
|
return template_string()
|
|
|
|
@app.route("/")
|
|
def app_page():
|
|
return template_string()
|
|
|
|
# Register the blueprint
|
|
app.register_blueprint(answer_bp)
|
|
|
|
app_page_bytes = client.get("/").data
|
|
answer_page_bytes = client.get("/bp").data
|
|
|
|
assert b"43" in app_page_bytes
|
|
assert b"42" not in app_page_bytes
|
|
|
|
assert b"42" in answer_page_bytes
|
|
assert b"43" in answer_page_bytes
|
|
|
|
|
|
def test_template_global(app):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
@bp.app_template_global()
|
|
def get_answer():
|
|
return 42
|
|
|
|
# Make sure the function is not in the jinja_env already
|
|
assert "get_answer" not in app.jinja_env.globals.keys()
|
|
app.register_blueprint(bp)
|
|
|
|
# Tests
|
|
assert "get_answer" in app.jinja_env.globals.keys()
|
|
assert app.jinja_env.globals["get_answer"] is get_answer
|
|
assert app.jinja_env.globals["get_answer"]() == 42
|
|
|
|
with app.app_context():
|
|
rv = flask.render_template_string("{{ get_answer() }}")
|
|
assert rv == "42"
|
|
|
|
|
|
def test_request_processing(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
evts = []
|
|
|
|
@bp.before_request
|
|
def before_bp():
|
|
evts.append("before")
|
|
|
|
@bp.after_request
|
|
def after_bp(response):
|
|
response.data += b"|after"
|
|
evts.append("after")
|
|
return response
|
|
|
|
@bp.teardown_request
|
|
def teardown_bp(exc):
|
|
evts.append("teardown")
|
|
|
|
# Setup routes for testing
|
|
@bp.route("/bp")
|
|
def bp_endpoint():
|
|
return "request"
|
|
|
|
app.register_blueprint(bp)
|
|
|
|
assert evts == []
|
|
rv = client.get("/bp")
|
|
assert rv.data == b"request|after"
|
|
assert evts == ["before", "after", "teardown"]
|
|
|
|
|
|
def test_app_request_processing(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
evts = []
|
|
|
|
@bp.before_app_first_request
|
|
def before_first_request():
|
|
evts.append("first")
|
|
|
|
@bp.before_app_request
|
|
def before_app():
|
|
evts.append("before")
|
|
|
|
@bp.after_app_request
|
|
def after_app(response):
|
|
response.data += b"|after"
|
|
evts.append("after")
|
|
return response
|
|
|
|
@bp.teardown_app_request
|
|
def teardown_app(exc):
|
|
evts.append("teardown")
|
|
|
|
app.register_blueprint(bp)
|
|
|
|
# Setup routes for testing
|
|
@app.route("/")
|
|
def bp_endpoint():
|
|
return "request"
|
|
|
|
# before first request
|
|
assert evts == []
|
|
|
|
# first request
|
|
resp = client.get("/").data
|
|
assert resp == b"request|after"
|
|
assert evts == ["first", "before", "after", "teardown"]
|
|
|
|
# second request
|
|
resp = client.get("/").data
|
|
assert resp == b"request|after"
|
|
assert evts == ["first"] + ["before", "after", "teardown"] * 2
|
|
|
|
|
|
def test_app_url_processors(app, client):
|
|
bp = flask.Blueprint("bp", __name__)
|
|
|
|
# Register app-wide url defaults and preprocessor on blueprint
|
|
@bp.app_url_defaults
|
|
def add_language_code(endpoint, values):
|
|
values.setdefault("lang_code", flask.g.lang_code)
|
|
|
|
@bp.app_url_value_preprocessor
|
|
def pull_lang_code(endpoint, values):
|
|
flask.g.lang_code = values.pop("lang_code")
|
|
|
|
# Register route rules at the app level
|
|
@app.route("/<lang_code>/")
|
|
def index():
|
|
return flask.url_for("about")
|
|
|
|
@app.route("/<lang_code>/about")
|
|
def about():
|
|
return flask.url_for("index")
|
|
|
|
app.register_blueprint(bp)
|
|
|
|
assert client.get("/de/").data == b"/de/about"
|
|
assert client.get("/de/about").data == b"/de/"
|
|
|
|
|
|
def test_nested_blueprint(app, client):
|
|
parent = flask.Blueprint("parent", __name__)
|
|
child = flask.Blueprint("child", __name__)
|
|
grandchild = flask.Blueprint("grandchild", __name__)
|
|
|
|
@parent.errorhandler(403)
|
|
def forbidden(e):
|
|
return "Parent no", 403
|
|
|
|
@parent.route("/")
|
|
def parent_index():
|
|
return "Parent yes"
|
|
|
|
@parent.route("/no")
|
|
def parent_no():
|
|
flask.abort(403)
|
|
|
|
@child.route("/")
|
|
def child_index():
|
|
return "Child yes"
|
|
|
|
@child.route("/no")
|
|
def child_no():
|
|
flask.abort(403)
|
|
|
|
@grandchild.errorhandler(403)
|
|
def grandchild_forbidden(e):
|
|
return "Grandchild no", 403
|
|
|
|
@grandchild.route("/")
|
|
def grandchild_index():
|
|
return "Grandchild yes"
|
|
|
|
@grandchild.route("/no")
|
|
def grandchild_no():
|
|
flask.abort(403)
|
|
|
|
child.register_blueprint(grandchild, url_prefix="/grandchild")
|
|
parent.register_blueprint(child, url_prefix="/child")
|
|
app.register_blueprint(parent, url_prefix="/parent")
|
|
|
|
assert client.get("/parent/").data == b"Parent yes"
|
|
assert client.get("/parent/child/").data == b"Child yes"
|
|
assert client.get("/parent/child/grandchild/").data == b"Grandchild yes"
|
|
assert client.get("/parent/no").data == b"Parent no"
|
|
assert client.get("/parent/child/no").data == b"Parent no"
|
|
assert client.get("/parent/child/grandchild/no").data == b"Grandchild no"
|