only extend on first registration

This commit is contained in:
David Lord 2021-03-10 10:51:06 -08:00
parent ef52e3e4a3
commit 3dfc12e8d8
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8

View file

@ -90,13 +90,6 @@ class Blueprint(Scaffold):
See :doc:`/blueprints` for more information. See :doc:`/blueprints` for more information.
.. versionchanged:: 1.1.0
Blueprints have a ``cli`` group to register nested CLI commands.
The ``cli_group`` parameter controls the name of the group under
the ``flask`` command.
.. versionadded:: 0.7
:param name: The name of the blueprint. Will be prepended to each :param name: The name of the blueprint. Will be prepended to each
endpoint name. endpoint name.
:param import_name: The name of the blueprint package, usually :param import_name: The name of the blueprint package, usually
@ -121,10 +114,17 @@ class Blueprint(Scaffold):
default. default.
:param url_defaults: A dict of default values that blueprint routes :param url_defaults: A dict of default values that blueprint routes
will receive by default. will receive by default.
:param root_path: By default, the blueprint will automatically set this :param root_path: By default, the blueprint will automatically set
based on ``import_name``. In certain situations this automatic this based on ``import_name``. In certain situations this
detection can fail, so the path can be specified manually automatic detection can fail, so the path can be specified
instead. manually instead.
.. versionchanged:: 1.1.0
Blueprints have a ``cli`` group to register nested CLI commands.
The ``cli_group`` parameter controls the name of the group under
the ``flask`` command.
.. versionadded:: 0.7
""" """
warn_on_modifications = False warn_on_modifications = False
@ -161,8 +161,10 @@ class Blueprint(Scaffold):
self.url_prefix = url_prefix self.url_prefix = url_prefix
self.subdomain = subdomain self.subdomain = subdomain
self.deferred_functions = [] self.deferred_functions = []
if url_defaults is None: if url_defaults is None:
url_defaults = {} url_defaults = {}
self.url_values_defaults = url_defaults self.url_values_defaults = url_defaults
self.cli_group = cli_group self.cli_group = cli_group
@ -180,9 +182,9 @@ class Blueprint(Scaffold):
warn( warn(
Warning( Warning(
"The blueprint was already registered once " "The blueprint was already registered once but is"
"but is getting modified now. These changes " " getting modified now. These changes will not show"
"will not show up." " up."
) )
) )
self.deferred_functions.append(func) self.deferred_functions.append(func)
@ -208,12 +210,13 @@ class Blueprint(Scaffold):
return BlueprintSetupState(self, app, options, first_registration) return BlueprintSetupState(self, app, options, first_registration)
def register(self, app, options, first_registration=False): def register(self, app, options, first_registration=False):
"""Called by :meth:`Flask.register_blueprint` to register all views """Called by :meth:`Flask.register_blueprint` to register all
and callbacks registered on the blueprint with the application. Creates views and callbacks registered on the blueprint with the
a :class:`.BlueprintSetupState` and calls each :meth:`record` callback application. Creates a :class:`.BlueprintSetupState` and calls
with it. each :meth:`record` callbackwith it.
:param app: The application this blueprint is being registered with. :param app: The application this blueprint is being registered
with.
:param options: Keyword arguments forwarded from :param options: Keyword arguments forwarded from
:meth:`~Flask.register_blueprint`. :meth:`~Flask.register_blueprint`.
:param first_registration: Whether this is the first time this :param first_registration: Whether this is the first time this
@ -229,44 +232,36 @@ class Blueprint(Scaffold):
endpoint="static", endpoint="static",
) )
# Merge app and self dictionaries. # Merge blueprint data into parent.
def merge_dict_lists(self_dict, app_dict): if first_registration:
"""Merges self_dict into app_dict. Replaces None keys with self.name.
Values of dict must be lists.
"""
for key, values in self_dict.items():
key = self.name if key is None else f"{self.name}.{key}"
app_dict[key].extend(values)
def merge_dict_nested(self_dict, app_dict): def extend(bp_dict, parent_dict):
"""Merges self_dict into app_dict. Replaces None keys with self.name. for key, values in bp_dict.items():
Values of dict must be dict. key = self.name if key is None else f"{self.name}.{key}"
""" parent_dict[key].extend(values)
for key, value in self_dict.items():
key = self.name if key is None else f"{self.name}.{key}"
app_dict[key] = value
app.view_functions.update(self.view_functions) def update(bp_dict, parent_dict):
for key, value in bp_dict.items():
key = self.name if key is None else f"{self.name}.{key}"
parent_dict[key] = value
merge_dict_lists(self.before_request_funcs, app.before_request_funcs) app.view_functions.update(self.view_functions)
merge_dict_lists(self.after_request_funcs, app.after_request_funcs) extend(self.before_request_funcs, app.before_request_funcs)
merge_dict_lists(self.teardown_request_funcs, app.teardown_request_funcs) extend(self.after_request_funcs, app.after_request_funcs)
merge_dict_lists(self.url_default_functions, app.url_default_functions) extend(self.teardown_request_funcs, app.teardown_request_funcs)
merge_dict_lists(self.url_value_preprocessors, app.url_value_preprocessors) extend(self.url_default_functions, app.url_default_functions)
merge_dict_lists( extend(self.url_value_preprocessors, app.url_value_preprocessors)
self.template_context_processors, app.template_context_processors extend(self.template_context_processors, app.template_context_processors)
) update(self.error_handler_spec, app.error_handler_spec)
merge_dict_nested(self.error_handler_spec, app.error_handler_spec)
for deferred in self.deferred_functions: for deferred in self.deferred_functions:
deferred(state) deferred(state)
cli_resolved_group = options.get("cli_group", self.cli_group)
if not self.cli.commands: if not self.cli.commands:
return return
cli_resolved_group = options.get("cli_group", self.cli_group)
if cli_resolved_group is None: if cli_resolved_group is None:
app.cli.commands.update(self.cli.commands) app.cli.commands.update(self.cli.commands)
elif cli_resolved_group is _sentinel: elif cli_resolved_group is _sentinel: