diff --git a/CHANGES.rst b/CHANGES.rst index f50a7ad90a..2698276eaa 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -33,7 +33,8 @@ Unreleased - ``register_blueprint`` takes a ``name`` option to change the (pre-dotted) name the blueprint is registered with. This allows the same blueprint to be registered multiple times with unique names for - ``url_for``. :issue:`1091` + ``url_for``. Registering the same blueprint with the same name + multiple times is deprecated. :issue:`1091` Version 2.0.0 diff --git a/src/flask/blueprints.py b/src/flask/blueprints.py index 6b4e27149a..fc999c7553 100644 --- a/src/flask/blueprints.py +++ b/src/flask/blueprints.py @@ -283,23 +283,35 @@ def register(self, app: "Flask", options: dict) -> None: name the blueprint is registered with. This allows the same blueprint to be registered multiple times with unique names for ``url_for``. - """ - first_registration = True - - for blueprint in app.blueprints.values(): - if blueprint is self: - first_registration = False + .. versionchanged:: 2.0.1 + Registering the same blueprint with the same name multiple + times is deprecated and will become an error in Flask 2.1. + """ + first_registration = not any(bp is self for bp in app.blueprints.values()) name_prefix = options.get("name_prefix", "") self_name = options.get("name", self.name) name = f"{name_prefix}.{self_name}".lstrip(".") - if name in app.blueprints and app.blueprints[name] is not self: - raise ValueError( - f"Blueprint name '{self.name}' " - f"is already registered by {app.blueprints[self.name]}. " - "Blueprints must have unique names." - ) + if name in app.blueprints: + existing_at = f" '{name}'" if self_name != name else "" + + if app.blueprints[name] is not self: + raise ValueError( + f"The name '{self_name}' is already registered for" + f" a different blueprint{existing_at}. Use 'name='" + " to provide a unique name." + ) + else: + import warnings + + warnings.warn( + f"The name '{self_name}' is already registered for" + f" this blueprint{existing_at}. Use 'name=' to" + " provide a unique name. This will become an error" + " in Flask 2.1.", + stacklevel=4, + ) app.blueprints[name] = self self._got_registered_once = True diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 2a93e8fa27..2977f69c27 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -140,7 +140,7 @@ def bar(bar): return str(bar) app.register_blueprint(bp, url_prefix="/1", url_defaults={"bar": 23}) - app.register_blueprint(bp, url_prefix="/2", url_defaults={"bar": 19}) + app.register_blueprint(bp, name="test2", url_prefix="/2", url_defaults={"bar": 19}) assert client.get("/1/foo").data == b"23/42" assert client.get("/2/foo").data == b"19/42" @@ -873,9 +873,13 @@ def test_unique_blueprint_names(app, client) -> None: bp2 = flask.Blueprint("bp", __name__) app.register_blueprint(bp) - app.register_blueprint(bp) # same name, same object, no error + + with pytest.warns(UserWarning): + app.register_blueprint(bp) # same bp, same name, warning + + app.register_blueprint(bp, name="again") # same bp, different name, ok with pytest.raises(ValueError): - app.register_blueprint(bp2) # same name, different object + app.register_blueprint(bp2) # different bp, same name, error - app.register_blueprint(bp2, name="alt") # different name + app.register_blueprint(bp2, name="alt") # different bp, different name, ok