Modified bluprints.py and debughelpers.py to adhere more to PEP8 standards

This commit is contained in:
Stacey C 2022-06-17 18:39:18 -07:00
parent 7f2a0f4806
commit 8a72c556d6
2 changed files with 55 additions and 13 deletions

View file

@ -12,6 +12,7 @@ from .scaffold import setupmethod
if t.TYPE_CHECKING: # pragma: no cover
from .app import Flask
DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable]
@ -68,6 +69,7 @@ class BlueprintSetupState:
self.url_defaults = dict(self.blueprint.url_values_defaults)
self.url_defaults.update(self.options.get("url_defaults", ()))
def add_url_rule(
self,
rule: str,
@ -82,12 +84,17 @@ class BlueprintSetupState:
if self.url_prefix is not None:
if rule:
rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/")))
else:
rule = self.url_prefix
options.setdefault("subdomain", self.subdomain)
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func) # type: ignore
defaults = self.url_defaults
if "defaults" in options:
defaults = dict(defaults, **options.pop("defaults"))
@ -162,6 +169,7 @@ class Blueprint(Scaffold):
#: the app's :class:`~flask.Flask.json_decoder`.
json_decoder = None
def __init__(
self,
name: str,
@ -198,7 +206,9 @@ class Blueprint(Scaffold):
self.cli_group = cli_group
self._blueprints: t.List[t.Tuple["Blueprint", dict]] = []
def _check_setup_finished(self, f_name: str) -> None:
# TODO - This method is missing a docstring - please advise
if self._got_registered_once:
import warnings
@ -215,6 +225,7 @@ class Blueprint(Scaffold):
stacklevel=3,
)
@setupmethod
def record(self, func: t.Callable) -> None:
"""Registers a function that is called when the blueprint is
@ -224,6 +235,7 @@ class Blueprint(Scaffold):
"""
self.deferred_functions.append(func)
@setupmethod
def record_once(self, func: t.Callable) -> None:
"""Works like :meth:`record` but wraps the function in another
@ -231,13 +243,13 @@ class Blueprint(Scaffold):
blueprint is registered a second time on the application, the
function passed is not called.
"""
def wrapper(state: BlueprintSetupState) -> None:
if state.first_registration:
func(state)
return self.record(update_wrapper(wrapper, func))
def make_setup_state(
self, app: "Flask", options: dict, first_registration: bool = False
) -> BlueprintSetupState:
@ -247,6 +259,7 @@ class Blueprint(Scaffold):
"""
return BlueprintSetupState(self, app, options, first_registration)
@setupmethod
def register_blueprint(self, blueprint: "Blueprint", **options: t.Any) -> None:
"""Register a :class:`~flask.Blueprint` on this blueprint. Keyword
@ -265,6 +278,7 @@ class Blueprint(Scaffold):
raise ValueError("Cannot register a blueprint on itself")
self._blueprints.append((blueprint, options))
def register(self, app: "Flask", options: dict) -> None:
"""Called by :meth:`Flask.register_blueprint` to register all
views and callbacks registered on the blueprint with the
@ -322,11 +336,13 @@ class Blueprint(Scaffold):
# Merge blueprint data into parent.
if first_bp_registration or first_name_registration:
def extend(bp_dict, parent_dict):
for key, values in bp_dict.items():
key = name if key is None else f"{name}.{key}"
parent_dict[key].extend(values)
for key, value in self.error_handler_spec.items():
key = name if key is None else f"{name}.{key}"
value = defaultdict(
@ -361,9 +377,11 @@ class Blueprint(Scaffold):
if self.cli.commands:
if cli_resolved_group is None:
app.cli.commands.update(self.cli.commands)
elif cli_resolved_group is _sentinel:
self.cli.name = name
app.cli.add_command(self.cli)
else:
self.cli.name = cli_resolved_group
app.cli.add_command(self.cli)
@ -379,14 +397,17 @@ class Blueprint(Scaffold):
bp_options["url_prefix"] = (
state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/")
)
elif bp_url_prefix is not None:
bp_options["url_prefix"] = bp_url_prefix
elif state.url_prefix is not None:
bp_options["url_prefix"] = state.url_prefix
bp_options["name_prefix"] = name
blueprint.register(app, bp_options)
@setupmethod
def add_url_rule(
self,
@ -415,6 +436,7 @@ class Blueprint(Scaffold):
)
)
@setupmethod
def app_template_filter(
self, name: t.Optional[str] = None
@ -425,13 +447,13 @@ class Blueprint(Scaffold):
:param name: the optional name of the filter, otherwise the
function name will be used.
"""
def decorator(f: ft.TemplateFilterCallable) -> ft.TemplateFilterCallable:
self.add_app_template_filter(f, name=name)
return f
return decorator
@setupmethod
def add_app_template_filter(
self, f: ft.TemplateFilterCallable, name: t.Optional[str] = None
@ -443,12 +465,12 @@ class Blueprint(Scaffold):
:param name: the optional name of the filter, otherwise the
function name will be used.
"""
def register_template(state: BlueprintSetupState) -> None:
state.app.jinja_env.filters[name or f.__name__] = f
self.record_once(register_template)
@setupmethod
def app_template_test(
self, name: t.Optional[str] = None
@ -461,7 +483,6 @@ class Blueprint(Scaffold):
:param name: the optional name of the test, otherwise the
function name will be used.
"""
def decorator(f: ft.TemplateTestCallable) -> ft.TemplateTestCallable:
self.add_app_template_test(f, name=name)
return f
@ -481,12 +502,12 @@ class Blueprint(Scaffold):
:param name: the optional name of the test, otherwise the
function name will be used.
"""
def register_template(state: BlueprintSetupState) -> None:
state.app.jinja_env.tests[name or f.__name__] = f
self.record_once(register_template)
@setupmethod
def app_template_global(
self, name: t.Optional[str] = None
@ -499,13 +520,13 @@ class Blueprint(Scaffold):
:param name: the optional name of the global, otherwise the
function name will be used.
"""
def decorator(f: ft.TemplateGlobalCallable) -> ft.TemplateGlobalCallable:
self.add_app_template_global(f, name=name)
return f
return decorator
@setupmethod
def add_app_template_global(
self, f: ft.TemplateGlobalCallable, name: t.Optional[str] = None
@ -519,12 +540,12 @@ class Blueprint(Scaffold):
:param name: the optional name of the global, otherwise the
function name will be used.
"""
def register_template(state: BlueprintSetupState) -> None:
state.app.jinja_env.globals[name or f.__name__] = f
self.record_once(register_template)
@setupmethod
def before_app_request(
self, f: ft.BeforeRequestCallable
@ -537,6 +558,7 @@ class Blueprint(Scaffold):
)
return f
@setupmethod
def before_app_first_request(
self, f: ft.BeforeFirstRequestCallable
@ -557,9 +579,11 @@ class Blueprint(Scaffold):
DeprecationWarning,
stacklevel=2,
)
self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
return f
def after_app_request(self, f: ft.AfterRequestCallable) -> ft.AfterRequestCallable:
"""Like :meth:`Flask.after_request` but for a blueprint. Such a function
is executed after each request, even if outside of the blueprint.
@ -569,6 +593,7 @@ class Blueprint(Scaffold):
)
return f
@setupmethod
def teardown_app_request(self, f: ft.TeardownCallable) -> ft.TeardownCallable:
"""Like :meth:`Flask.teardown_request` but for a blueprint. Such a
@ -580,6 +605,7 @@ class Blueprint(Scaffold):
)
return f
@setupmethod
def app_context_processor(
self, f: ft.TemplateContextProcessorCallable
@ -592,6 +618,7 @@ class Blueprint(Scaffold):
)
return f
@setupmethod
def app_errorhandler(
self, code: t.Union[t.Type[Exception], int]
@ -599,13 +626,13 @@ class Blueprint(Scaffold):
"""Like :meth:`Flask.errorhandler` but for a blueprint. This
handler is used for all requests, even if outside of the blueprint.
"""
def decorator(f: ft.ErrorHandlerDecorator) -> ft.ErrorHandlerDecorator:
self.record_once(lambda s: s.app.errorhandler(code)(f))
return f
return decorator
@setupmethod
def app_url_value_preprocessor(
self, f: ft.URLValuePreprocessorCallable
@ -616,6 +643,7 @@ class Blueprint(Scaffold):
)
return f
@setupmethod
def app_url_defaults(self, f: ft.URLDefaultCallable) -> ft.URLDefaultCallable:
"""Same as :meth:`url_defaults` but application wide."""

View file

@ -9,6 +9,7 @@ class UnexpectedUnicodeError(AssertionError, UnicodeError):
"""Raised in places where we want some better error reporting for
unexpected unicode or binary data.
"""
pass
class DebugFilesKeyError(KeyError, AssertionError):
@ -26,6 +27,7 @@ class DebugFilesKeyError(KeyError, AssertionError):
" were transmitted. To fix this error you should provide"
' enctype="multipart/form-data" in your form.'
]
if form_matches:
names = ", ".join(repr(x) for x in form_matches)
buf.append(
@ -71,16 +73,16 @@ class FormDataRoutingRedirect(AssertionError):
def attach_enctype_error_multidict(request):
"""Patch ``request.files.__getitem__`` to raise a descriptive error
about ``enctype=multipart/form-data``.
:param request: The request to patch.
:meta private:
"""
oldcls = request.files.__class__
class newcls(oldcls):
class NewCls(oldcls):
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError as e:
if key not in request.form:
raise
@ -89,23 +91,28 @@ def attach_enctype_error_multidict(request):
e.__traceback__
) from None
newcls.__name__ = oldcls.__name__
newcls.__module__ = oldcls.__module__
request.files.__class__ = newcls
NewCls.__name__ = oldcls.__name__
NewCls.__module__ = oldcls.__module__
request.files.__class__ = NewCls
def _dump_loader_info(loader) -> t.Generator:
# TODO - This method is missing a docstring - please advise
yield f"class: {type(loader).__module__}.{type(loader).__name__}"
for key, value in sorted(loader.__dict__.items()):
if key.startswith("_"):
continue
if isinstance(value, (tuple, list)):
if not all(isinstance(x, str) for x in value):
continue
yield f"{key}:"
for item in value:
yield f" - {item}"
continue
elif not isinstance(value, (str, int, float, bool)):
continue
yield f"{key}: {value!r}"
@ -117,14 +124,17 @@ def explain_template_loading_attempts(app: Flask, template, attempts) -> None:
total_found = 0
blueprint = None
reqctx = _request_ctx_stack.top
if reqctx is not None and reqctx.request.blueprint is not None:
blueprint = reqctx.request.blueprint
for idx, (loader, srcobj, triple) in enumerate(attempts):
if isinstance(srcobj, Flask):
src_info = f"application {srcobj.import_name!r}"
elif isinstance(srcobj, Blueprint):
src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})"
else:
src_info = repr(srcobj)
@ -135,15 +145,19 @@ def explain_template_loading_attempts(app: Flask, template, attempts) -> None:
if triple is None:
detail = "no match"
else:
detail = f"found ({triple[1] or '<string>'!r})"
total_found += 1
info.append(f" -> {detail}")
seems_fishy = False
if total_found == 0:
info.append("Error: the template could not be found.")
seems_fishy = True
elif total_found > 1:
info.append("Warning: multiple loaders returned a match for the template.")
seems_fishy = True