From b71e79a4827a753a09f82e4a9e7de2cb9d8c13a7 Mon Sep 17 00:00:00 2001 From: pgjones Date: Sun, 1 Oct 2023 16:37:05 +0100 Subject: [PATCH] Don't set the cli attribute in the sansio scaffold It is (currently) Flask specific and hence cannot be shared in the sansio shared code. --- CHANGES.rst | 9 +++++++++ src/flask/app.py | 10 ++++++++++ src/flask/blueprints.py | 38 ++++++++++++++++++++++++++++++++++++ src/flask/sansio/app.py | 4 ---- src/flask/sansio/scaffold.py | 11 ++++------- src/flask/testing.py | 2 +- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index ab1aafe324..c46d8461d0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,12 @@ +Version 3.0.1 +------------- + +Unreleased + +- Don't set the cli attribute in the sansio scaffold, but rather in + the Flask concrete classes. :pr:`5270` + + Version 3.0.0 ------------- diff --git a/src/flask/app.py b/src/flask/app.py index d710cb96a4..a59fcce429 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -238,6 +238,16 @@ def __init__( root_path=root_path, ) + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = cli.AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + # Add a static route using the provided static_url_path, static_host, # and static_folder if there is a configured static_folder. # Note we do this without checking if static_folder exists. diff --git a/src/flask/blueprints.py b/src/flask/blueprints.py index 3a37a2c422..9d2ddaed40 100644 --- a/src/flask/blueprints.py +++ b/src/flask/blueprints.py @@ -4,16 +4,54 @@ import typing as t from datetime import timedelta +from .cli import AppGroup from .globals import current_app from .helpers import send_from_directory from .sansio.blueprints import Blueprint as SansioBlueprint from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa +from .sansio.scaffold import _sentinel if t.TYPE_CHECKING: # pragma: no cover from .wrappers import Response class Blueprint(SansioBlueprint): + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore + ) -> None: + super().__init__( + name, + import_name, + static_folder, + static_url_path, + template_folder, + url_prefix, + subdomain, + url_defaults, + root_path, + cli_group, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + def get_send_file_max_age(self, filename: str | None) -> int | None: """Used by :func:`send_file` to determine the ``max_age`` cache value for a given file path if it wasn't passed. diff --git a/src/flask/sansio/app.py b/src/flask/sansio/app.py index 0f7d2cbf14..4ff61ad7cb 100644 --- a/src/flask/sansio/app.py +++ b/src/flask/sansio/app.py @@ -408,10 +408,6 @@ def __init__( # request. self._got_first_request = False - # Set the name of the Click group in case someone wants to add - # the app's commands to another CLI tool. - self.cli.name = self.name - def _check_setup_finished(self, f_name: str) -> None: if self._got_first_request: raise AssertionError( diff --git a/src/flask/sansio/scaffold.py b/src/flask/sansio/scaffold.py index a43f6fd794..2f827d8a90 100644 --- a/src/flask/sansio/scaffold.py +++ b/src/flask/sansio/scaffold.py @@ -14,10 +14,12 @@ from werkzeug.utils import cached_property from .. import typing as ft -from ..cli import AppGroup from ..helpers import get_root_path from ..templating import _default_template_ctx_processor +if t.TYPE_CHECKING: # pragma: no cover + from click import Group + # a singleton sentinel value for parameter defaults _sentinel = object() @@ -64,6 +66,7 @@ class Scaffold: .. versionadded:: 2.0 """ + cli: Group name: str _static_folder: str | None = None _static_url_path: str | None = None @@ -95,12 +98,6 @@ def __init__( #: up resources contained in the package. self.root_path = root_path - #: The Click command group for registering CLI commands for this - #: object. The commands are available from the ``flask`` command - #: once the application has been discovered and blueprints have - #: been registered. - self.cli = AppGroup() - #: A dictionary mapping endpoint names to view functions. #: #: To register a view function, use the :meth:`route` decorator. diff --git a/src/flask/testing.py b/src/flask/testing.py index 69aa785188..99788e3533 100644 --- a/src/flask/testing.py +++ b/src/flask/testing.py @@ -287,7 +287,7 @@ def invoke( # type: ignore :return: a :class:`~click.testing.Result` object. """ if cli is None: - cli = self.app.cli # type: ignore + cli = self.app.cli if "obj" not in kwargs: kwargs["obj"] = ScriptInfo(create_app=lambda: self.app)