Skip to content

Commit

Permalink
cache blueprint path calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism authored and pgjones committed May 21, 2021
1 parent c2920e2 commit 67b0b7e
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 29 deletions.
13 changes: 6 additions & 7 deletions src/flask/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from .globals import g
from .globals import request
from .globals import session
from .helpers import _split_blueprint_path
from .helpers import get_debug_flag
from .helpers import get_env
from .helpers import get_flashed_messages
Expand Down Expand Up @@ -1790,13 +1791,11 @@ def inject_url_defaults(self, endpoint: str, values: dict) -> None:
funcs: t.Iterable[URLDefaultCallable] = self.url_default_functions[None]

if "." in endpoint:
bps: t.List[str] = [endpoint.rsplit(".", 1)[0]]

while "." in bps[-1]:
bps.append(bps[-1].rpartition(".")[0])

for bp in bps:
funcs = chain(funcs, self.url_default_functions[bp])
# This is called by url_for, which can be called outside a
# request, can't use request.blueprints.
bps = _split_blueprint_path(endpoint.rpartition(".")[0])
bp_funcs = chain.from_iterable(self.url_default_functions[bp] for bp in bps)
funcs = chain(funcs, bp_funcs)

for func in funcs:
func(endpoint, values)
Expand Down
11 changes: 11 additions & 0 deletions src/flask/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import warnings
from datetime import datetime
from datetime import timedelta
from functools import lru_cache
from functools import update_wrapper
from threading import RLock

Expand Down Expand Up @@ -821,3 +822,13 @@ def is_ip(value: str) -> bool:
return True

return False


@lru_cache(maxsize=None)
def _split_blueprint_path(name: str) -> t.List[str]:
out: t.List[str] = [name]

if "." in name:
out.extend(_split_blueprint_path(name.rpartition(".")[0]))

return out
60 changes: 38 additions & 22 deletions src/flask/wrappers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import typing as t

from werkzeug.exceptions import BadRequest
from werkzeug.utils import cached_property
from werkzeug.wrappers import Request as RequestBase
from werkzeug.wrappers import Response as ResponseBase

from . import json
from .globals import current_app
from .helpers import _split_blueprint_path

if t.TYPE_CHECKING:
import typing_extensions as te
Expand Down Expand Up @@ -60,38 +60,54 @@ def max_content_length(self) -> t.Optional[int]: # type: ignore

@property
def endpoint(self) -> t.Optional[str]:
"""The endpoint that matched the request. This in combination with
:attr:`view_args` can be used to reconstruct the same or a
modified URL. If an exception happened when matching, this will
be ``None``.
"""The endpoint that matched the request URL.
This will be ``None`` if matching failed or has not been
performed yet.
This in combination with :attr:`view_args` can be used to
reconstruct the same URL or a modified URL.
"""
if self.url_rule is not None:
return self.url_rule.endpoint
else:
return None

return None

@property
def blueprint(self) -> t.Optional[str]:
"""The name of the current blueprint"""
if self.url_rule and "." in self.url_rule.endpoint:
return self.url_rule.endpoint.rsplit(".", 1)[0]
else:
return None
"""The registered name of the current blueprint.
@cached_property
def blueprints(self) -> t.List[str]:
"""The names of the current blueprint upwards through parent
blueprints.
This will be ``None`` if the endpoint is not part of a
blueprint, or if URL matching failed or has not been performed
yet.
This does not necessarily match the name the blueprint was
created with. It may have been nested, or registered with a
different name.
"""
if self.blueprint is None:
return []
endpoint = self.endpoint

if endpoint is not None and "." in endpoint:
return endpoint.rpartition(".")[0]

return None

bps: t.List[str] = [self.blueprint]
@property
def blueprints(self) -> t.List[str]:
"""The registered names of the current blueprint upwards through
parent blueprints.
while "." in bps[-1]:
bps.append(bps[-1].rpartition(".")[0])
This will be an empty list if there is no current blueprint, or
if URL matching failed.
.. versionadded:: 2.0.1
"""
name = self.blueprint

if name is None:
return []

return bps
return _split_blueprint_path(name)

def _load_form_data(self) -> None:
RequestBase._load_form_data(self)
Expand Down

0 comments on commit 67b0b7e

Please sign in to comment.