forked from orbit-oss/flask
blueprint name may not contain a dot
This commit is contained in:
parent
d8c37f4372
commit
7c5261407d
4 changed files with 28 additions and 85 deletions
|
|
@ -15,6 +15,9 @@ Unreleased
|
||||||
- Fix some types that weren't available in Python 3.6.0. :issue:`4040`
|
- Fix some types that weren't available in Python 3.6.0. :issue:`4040`
|
||||||
- Improve typing for ``send_file``, ``send_from_directory``, and
|
- Improve typing for ``send_file``, ``send_from_directory``, and
|
||||||
``get_send_file_max_age``. :issue:`4044`, :pr:`4026`
|
``get_send_file_max_age``. :issue:`4044`, :pr:`4026`
|
||||||
|
- Show an error when a blueprint name contains a dot. The ``.`` has
|
||||||
|
special meaning, it is used to separate (nested) blueprint names and
|
||||||
|
the endpoint name. :issue:`4041`
|
||||||
|
|
||||||
|
|
||||||
Version 2.0.0
|
Version 2.0.0
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,10 @@ class Blueprint(Scaffold):
|
||||||
template_folder=template_folder,
|
template_folder=template_folder,
|
||||||
root_path=root_path,
|
root_path=root_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if "." in name:
|
||||||
|
raise ValueError("'name' may not contain a dot '.' character.")
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.url_prefix = url_prefix
|
self.url_prefix = url_prefix
|
||||||
self.subdomain = subdomain
|
self.subdomain = subdomain
|
||||||
|
|
@ -360,12 +364,12 @@ class Blueprint(Scaffold):
|
||||||
"""Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
|
"""Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
|
||||||
the :func:`url_for` function is prefixed with the name of the blueprint.
|
the :func:`url_for` function is prefixed with the name of the blueprint.
|
||||||
"""
|
"""
|
||||||
if endpoint:
|
if endpoint and "." in endpoint:
|
||||||
assert "." not in endpoint, "Blueprint endpoints should not contain dots"
|
raise ValueError("'endpoint' may not contain a dot '.' character.")
|
||||||
if view_func and hasattr(view_func, "__name__"):
|
|
||||||
assert (
|
if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__:
|
||||||
"." not in view_func.__name__
|
raise ValueError("'view_func' name may not contain a dot '.' character.")
|
||||||
), "Blueprint view function name should not contain dots"
|
|
||||||
self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))
|
self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))
|
||||||
|
|
||||||
def app_template_filter(self, name: t.Optional[str] = None) -> t.Callable:
|
def app_template_filter(self, name: t.Optional[str] = None) -> t.Callable:
|
||||||
|
|
|
||||||
|
|
@ -1631,7 +1631,7 @@ def test_url_processors(app, client):
|
||||||
|
|
||||||
|
|
||||||
def test_inject_blueprint_url_defaults(app):
|
def test_inject_blueprint_url_defaults(app):
|
||||||
bp = flask.Blueprint("foo.bar.baz", __name__, template_folder="template")
|
bp = flask.Blueprint("foo", __name__, template_folder="template")
|
||||||
|
|
||||||
@bp.url_defaults
|
@bp.url_defaults
|
||||||
def bp_defaults(endpoint, values):
|
def bp_defaults(endpoint, values):
|
||||||
|
|
@ -1644,12 +1644,12 @@ def test_inject_blueprint_url_defaults(app):
|
||||||
app.register_blueprint(bp)
|
app.register_blueprint(bp)
|
||||||
|
|
||||||
values = dict()
|
values = dict()
|
||||||
app.inject_url_defaults("foo.bar.baz.view", values)
|
app.inject_url_defaults("foo.view", values)
|
||||||
expected = dict(page="login")
|
expected = dict(page="login")
|
||||||
assert values == expected
|
assert values == expected
|
||||||
|
|
||||||
with app.test_request_context("/somepage"):
|
with app.test_request_context("/somepage"):
|
||||||
url = flask.url_for("foo.bar.baz.view")
|
url = flask.url_for("foo.view")
|
||||||
expected = "/login"
|
expected = "/login"
|
||||||
assert url == expected
|
assert url == expected
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import functools
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from jinja2 import TemplateNotFound
|
from jinja2 import TemplateNotFound
|
||||||
from werkzeug.http import parse_cache_control_header
|
from werkzeug.http import parse_cache_control_header
|
||||||
|
|
@ -253,28 +251,9 @@ def test_templates_list(test_apps):
|
||||||
assert templates == ["admin/index.html", "frontend/index.html"]
|
assert templates == ["admin/index.html", "frontend/index.html"]
|
||||||
|
|
||||||
|
|
||||||
def test_dotted_names(app, client):
|
def test_dotted_name_not_allowed(app, client):
|
||||||
frontend = flask.Blueprint("myapp.frontend", __name__)
|
with pytest.raises(ValueError):
|
||||||
backend = flask.Blueprint("myapp.backend", __name__)
|
flask.Blueprint("app.ui", __name__)
|
||||||
|
|
||||||
@frontend.route("/fe")
|
|
||||||
def frontend_index():
|
|
||||||
return flask.url_for("myapp.backend.backend_index")
|
|
||||||
|
|
||||||
@frontend.route("/fe2")
|
|
||||||
def frontend_page2():
|
|
||||||
return flask.url_for(".frontend_index")
|
|
||||||
|
|
||||||
@backend.route("/be")
|
|
||||||
def backend_index():
|
|
||||||
return flask.url_for("myapp.frontend.frontend_index")
|
|
||||||
|
|
||||||
app.register_blueprint(frontend)
|
|
||||||
app.register_blueprint(backend)
|
|
||||||
|
|
||||||
assert client.get("/fe").data.strip() == b"/be"
|
|
||||||
assert client.get("/fe2").data.strip() == b"/fe"
|
|
||||||
assert client.get("/be").data.strip() == b"/fe"
|
|
||||||
|
|
||||||
|
|
||||||
def test_dotted_names_from_app(app, client):
|
def test_dotted_names_from_app(app, client):
|
||||||
|
|
@ -343,62 +322,19 @@ def test_route_decorator_custom_endpoint(app, client):
|
||||||
def test_route_decorator_custom_endpoint_with_dots(app, client):
|
def test_route_decorator_custom_endpoint_with_dots(app, client):
|
||||||
bp = flask.Blueprint("bp", __name__)
|
bp = flask.Blueprint("bp", __name__)
|
||||||
|
|
||||||
@bp.route("/foo")
|
with pytest.raises(ValueError):
|
||||||
def foo():
|
bp.route("/", endpoint="a.b")(lambda: "")
|
||||||
return flask.request.endpoint
|
|
||||||
|
|
||||||
try:
|
with pytest.raises(ValueError):
|
||||||
|
bp.add_url_rule("/", endpoint="a.b")
|
||||||
|
|
||||||
@bp.route("/bar", endpoint="bar.bar")
|
def view():
|
||||||
def foo_bar():
|
return ""
|
||||||
return flask.request.endpoint
|
|
||||||
|
|
||||||
except AssertionError:
|
view.__name__ = "a.b"
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise AssertionError("expected AssertionError not raised")
|
|
||||||
|
|
||||||
try:
|
with pytest.raises(ValueError):
|
||||||
|
bp.add_url_rule("/", view_func=view)
|
||||||
@bp.route("/bar/123", endpoint="bar.123")
|
|
||||||
def foo_bar_foo():
|
|
||||||
return flask.request.endpoint
|
|
||||||
|
|
||||||
except AssertionError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise AssertionError("expected AssertionError not raised")
|
|
||||||
|
|
||||||
def foo_foo_foo():
|
|
||||||
pass
|
|
||||||
|
|
||||||
pytest.raises(
|
|
||||||
AssertionError,
|
|
||||||
lambda: bp.add_url_rule("/bar/123", endpoint="bar.123", view_func=foo_foo_foo),
|
|
||||||
)
|
|
||||||
|
|
||||||
pytest.raises(
|
|
||||||
AssertionError, bp.route("/bar/123", endpoint="bar.123"), lambda: None
|
|
||||||
)
|
|
||||||
|
|
||||||
foo_foo_foo.__name__ = "bar.123"
|
|
||||||
|
|
||||||
pytest.raises(
|
|
||||||
AssertionError, lambda: bp.add_url_rule("/bar/123", view_func=foo_foo_foo)
|
|
||||||
)
|
|
||||||
|
|
||||||
bp.add_url_rule(
|
|
||||||
"/bar/456", endpoint="foofoofoo", view_func=functools.partial(foo_foo_foo)
|
|
||||||
)
|
|
||||||
|
|
||||||
app.register_blueprint(bp, url_prefix="/py")
|
|
||||||
|
|
||||||
assert client.get("/py/foo").data == b"bp.foo"
|
|
||||||
# The rule's didn't actually made it through
|
|
||||||
rv = client.get("/py/bar")
|
|
||||||
assert rv.status_code == 404
|
|
||||||
rv = client.get("/py/bar/123")
|
|
||||||
assert rv.status_code == 404
|
|
||||||
|
|
||||||
|
|
||||||
def test_endpoint_decorator(app, client):
|
def test_endpoint_decorator(app, client):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue