66from .scaffold import _endpoint_from_view_func
77from .scaffold import _sentinel
88from .scaffold import Scaffold
9+ from .scaffold import setupmethod
910from .typing import AfterRequestCallable
1011from .typing import BeforeFirstRequestCallable
1112from .typing import BeforeRequestCallable
@@ -162,7 +163,6 @@ class Blueprint(Scaffold):
162163 .. versionadded:: 0.7
163164 """
164165
165- warn_on_modifications = False
166166 _got_registered_once = False
167167
168168 #: Blueprint local JSON encoder class to use. Set to ``None`` to use
@@ -208,27 +208,33 @@ def __init__(
208208 self .cli_group = cli_group
209209 self ._blueprints : t .List [t .Tuple ["Blueprint" , dict ]] = []
210210
211- def _is_setup_finished (self ) -> bool :
212- return self .warn_on_modifications and self ._got_registered_once
211+ def _check_setup_finished (self , f_name : str ) -> None :
212+ if self ._got_registered_once :
213+ import warnings
214+
215+ warnings .warn (
216+ f"The setup method '{ f_name } ' can no longer be called on"
217+ f" the blueprint '{ self .name } '. It has already been"
218+ " registered at least once, any changes will not be"
219+ " applied consistently.\n "
220+ "Make sure all imports, decorators, functions, etc."
221+ " needed to set up the blueprint are done before"
222+ " registering it.\n "
223+ "This warning will become an exception in Flask 2.3." ,
224+ UserWarning ,
225+ stacklevel = 3 ,
226+ )
213227
228+ @setupmethod
214229 def record (self , func : t .Callable ) -> None :
215230 """Registers a function that is called when the blueprint is
216231 registered on the application. This function is called with the
217232 state as argument as returned by the :meth:`make_setup_state`
218233 method.
219234 """
220- if self ._got_registered_once and self .warn_on_modifications :
221- from warnings import warn
222-
223- warn (
224- Warning (
225- "The blueprint was already registered once but is"
226- " getting modified now. These changes will not show"
227- " up."
228- )
229- )
230235 self .deferred_functions .append (func )
231236
237+ @setupmethod
232238 def record_once (self , func : t .Callable ) -> None :
233239 """Works like :meth:`record` but wraps the function in another
234240 function that will ensure the function is only called once. If the
@@ -251,6 +257,7 @@ def make_setup_state(
251257 """
252258 return BlueprintSetupState (self , app , options , first_registration )
253259
260+ @setupmethod
254261 def register_blueprint (self , blueprint : "Blueprint" , ** options : t .Any ) -> None :
255262 """Register a :class:`~flask.Blueprint` on this blueprint. Keyword
256263 arguments passed to this method will override the defaults set
@@ -390,6 +397,7 @@ def extend(bp_dict, parent_dict):
390397 bp_options ["name_prefix" ] = name
391398 blueprint .register (app , bp_options )
392399
400+ @setupmethod
393401 def add_url_rule (
394402 self ,
395403 rule : str ,
@@ -417,6 +425,7 @@ def add_url_rule(
417425 )
418426 )
419427
428+ @setupmethod
420429 def app_template_filter (
421430 self , name : t .Optional [str ] = None
422431 ) -> t .Callable [[TemplateFilterCallable ], TemplateFilterCallable ]:
@@ -433,6 +442,7 @@ def decorator(f: TemplateFilterCallable) -> TemplateFilterCallable:
433442
434443 return decorator
435444
445+ @setupmethod
436446 def add_app_template_filter (
437447 self , f : TemplateFilterCallable , name : t .Optional [str ] = None
438448 ) -> None :
@@ -449,6 +459,7 @@ def register_template(state: BlueprintSetupState) -> None:
449459
450460 self .record_once (register_template )
451461
462+ @setupmethod
452463 def app_template_test (
453464 self , name : t .Optional [str ] = None
454465 ) -> t .Callable [[TemplateTestCallable ], TemplateTestCallable ]:
@@ -467,6 +478,7 @@ def decorator(f: TemplateTestCallable) -> TemplateTestCallable:
467478
468479 return decorator
469480
481+ @setupmethod
470482 def add_app_template_test (
471483 self , f : TemplateTestCallable , name : t .Optional [str ] = None
472484 ) -> None :
@@ -485,6 +497,7 @@ def register_template(state: BlueprintSetupState) -> None:
485497
486498 self .record_once (register_template )
487499
500+ @setupmethod
488501 def app_template_global (
489502 self , name : t .Optional [str ] = None
490503 ) -> t .Callable [[TemplateGlobalCallable ], TemplateGlobalCallable ]:
@@ -503,6 +516,7 @@ def decorator(f: TemplateGlobalCallable) -> TemplateGlobalCallable:
503516
504517 return decorator
505518
519+ @setupmethod
506520 def add_app_template_global (
507521 self , f : TemplateGlobalCallable , name : t .Optional [str ] = None
508522 ) -> None :
@@ -521,6 +535,7 @@ def register_template(state: BlueprintSetupState) -> None:
521535
522536 self .record_once (register_template )
523537
538+ @setupmethod
524539 def before_app_request (self , f : BeforeRequestCallable ) -> BeforeRequestCallable :
525540 """Like :meth:`Flask.before_request`. Such a function is executed
526541 before each request, even if outside of a blueprint.
@@ -530,6 +545,7 @@ def before_app_request(self, f: BeforeRequestCallable) -> BeforeRequestCallable:
530545 )
531546 return f
532547
548+ @setupmethod
533549 def before_app_first_request (
534550 self , f : BeforeFirstRequestCallable
535551 ) -> BeforeFirstRequestCallable :
@@ -548,6 +564,7 @@ def after_app_request(self, f: AfterRequestCallable) -> AfterRequestCallable:
548564 )
549565 return f
550566
567+ @setupmethod
551568 def teardown_app_request (self , f : TeardownCallable ) -> TeardownCallable :
552569 """Like :meth:`Flask.teardown_request` but for a blueprint. Such a
553570 function is executed when tearing down each request, even if outside of
@@ -558,6 +575,7 @@ def teardown_app_request(self, f: TeardownCallable) -> TeardownCallable:
558575 )
559576 return f
560577
578+ @setupmethod
561579 def app_context_processor (
562580 self , f : TemplateContextProcessorCallable
563581 ) -> TemplateContextProcessorCallable :
@@ -569,6 +587,7 @@ def app_context_processor(
569587 )
570588 return f
571589
590+ @setupmethod
572591 def app_errorhandler (self , code : t .Union [t .Type [Exception ], int ]) -> t .Callable :
573592 """Like :meth:`Flask.errorhandler` but for a blueprint. This
574593 handler is used for all requests, even if outside of the blueprint.
@@ -580,6 +599,7 @@ def decorator(f: "ErrorHandlerCallable") -> "ErrorHandlerCallable":
580599
581600 return decorator
582601
602+ @setupmethod
583603 def app_url_value_preprocessor (
584604 self , f : URLValuePreprocessorCallable
585605 ) -> URLValuePreprocessorCallable :
@@ -589,6 +609,7 @@ def app_url_value_preprocessor(
589609 )
590610 return f
591611
612+ @setupmethod
592613 def app_url_defaults (self , f : URLDefaultCallable ) -> URLDefaultCallable :
593614 """Same as :meth:`url_defaults` but application wide."""
594615 self .record_once (
0 commit comments