Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
app.py1537 linesDownload Raw Back to flask
1from __future__ import annotations2 3import collections.abc as cabc4import os5import sys6import typing as t7import weakref8from datetime import timedelta9from inspect import iscoroutinefunction10from itertools import chain11from types import TracebackType12from urllib.parse import quote as _url_quote13 14import click15from werkzeug.datastructures import Headers16from werkzeug.datastructures import ImmutableDict17from werkzeug.exceptions import BadRequestKeyError18from werkzeug.exceptions import HTTPException19from werkzeug.exceptions import InternalServerError20from werkzeug.routing import BuildError21from werkzeug.routing import MapAdapter22from werkzeug.routing import RequestRedirect23from werkzeug.routing import RoutingException24from werkzeug.routing import Rule25from werkzeug.serving import is_running_from_reloader26from werkzeug.wrappers import Response as BaseResponse27from werkzeug.wsgi import get_host28 29from . import cli30from . import typing as ft31from .ctx import AppContext32from .ctx import RequestContext33from .globals import _cv_app34from .globals import _cv_request35from .globals import current_app36from .globals import g37from .globals import request38from .globals import request_ctx39from .globals import session40from .helpers import get_debug_flag41from .helpers import get_flashed_messages42from .helpers import get_load_dotenv43from .helpers import send_from_directory44from .sansio.app import App45from .sansio.scaffold import _sentinel46from .sessions import SecureCookieSessionInterface47from .sessions import SessionInterface48from .signals import appcontext_tearing_down49from .signals import got_request_exception50from .signals import request_finished51from .signals import request_started52from .signals import request_tearing_down53from .templating import Environment54from .wrappers import Request55from .wrappers import Response56 57if t.TYPE_CHECKING:  # pragma: no cover58    from _typeshed.wsgi import StartResponse59    from _typeshed.wsgi import WSGIEnvironment60 61    from .testing import FlaskClient62    from .testing import FlaskCliRunner63    from .typing import HeadersValue64 65T_shell_context_processor = t.TypeVar(66    "T_shell_context_processor", bound=ft.ShellContextProcessorCallable67)68T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)69T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable)70T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable)71T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable)72 73 74def _make_timedelta(value: timedelta | int | None) -> timedelta | None:75    if value is None or isinstance(value, timedelta):76        return value77 78    return timedelta(seconds=value)79 80 81class Flask(App):82    """The flask object implements a WSGI application and acts as the central83    object.  It is passed the name of the module or package of the84    application.  Once it is created it will act as a central registry for85    the view functions, the URL rules, template configuration and much more.86 87    The name of the package is used to resolve resources from inside the88    package or the folder the module is contained in depending on if the89    package parameter resolves to an actual python package (a folder with90    an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).91 92    For more information about resource loading, see :func:`open_resource`.93 94    Usually you create a :class:`Flask` instance in your main module or95    in the :file:`__init__.py` file of your package like this::96 97        from flask import Flask98        app = Flask(__name__)99 100    .. admonition:: About the First Parameter101 102        The idea of the first parameter is to give Flask an idea of what103        belongs to your application.  This name is used to find resources104        on the filesystem, can be used by extensions to improve debugging105        information and a lot more.106 107        So it's important what you provide there.  If you are using a single108        module, `__name__` is always the correct value.  If you however are109        using a package, it's usually recommended to hardcode the name of110        your package there.111 112        For example if your application is defined in :file:`yourapplication/app.py`113        you should create it with one of the two versions below::114 115            app = Flask('yourapplication')116            app = Flask(__name__.split('.')[0])117 118        Why is that?  The application will work even with `__name__`, thanks119        to how resources are looked up.  However it will make debugging more120        painful.  Certain extensions can make assumptions based on the121        import name of your application.  For example the Flask-SQLAlchemy122        extension will look for the code in your application that triggered123        an SQL query in debug mode.  If the import name is not properly set124        up, that debugging information is lost.  (For example it would only125        pick up SQL queries in `yourapplication.app` and not126        `yourapplication.views.frontend`)127 128    .. versionadded:: 0.7129       The `static_url_path`, `static_folder`, and `template_folder`130       parameters were added.131 132    .. versionadded:: 0.8133       The `instance_path` and `instance_relative_config` parameters were134       added.135 136    .. versionadded:: 0.11137       The `root_path` parameter was added.138 139    .. versionadded:: 1.0140       The ``host_matching`` and ``static_host`` parameters were added.141 142    .. versionadded:: 1.0143       The ``subdomain_matching`` parameter was added. Subdomain144       matching needs to be enabled manually now. Setting145       :data:`SERVER_NAME` does not implicitly enable it.146 147    :param import_name: the name of the application package148    :param static_url_path: can be used to specify a different path for the149                            static files on the web.  Defaults to the name150                            of the `static_folder` folder.151    :param static_folder: The folder with static files that is served at152        ``static_url_path``. Relative to the application ``root_path``153        or an absolute path. Defaults to ``'static'``.154    :param static_host: the host to use when adding the static route.155        Defaults to None. Required when using ``host_matching=True``156        with a ``static_folder`` configured.157    :param host_matching: set ``url_map.host_matching`` attribute.158        Defaults to False.159    :param subdomain_matching: consider the subdomain relative to160        :data:`SERVER_NAME` when matching routes. Defaults to False.161    :param template_folder: the folder that contains the templates that should162                            be used by the application.  Defaults to163                            ``'templates'`` folder in the root path of the164                            application.165    :param instance_path: An alternative instance path for the application.166                          By default the folder ``'instance'`` next to the167                          package or module is assumed to be the instance168                          path.169    :param instance_relative_config: if set to ``True`` relative filenames170                                     for loading the config are assumed to171                                     be relative to the instance path instead172                                     of the application root.173    :param root_path: The path to the root of the application files.174        This should only be set manually when it can't be detected175        automatically, such as for namespace packages.176    """177 178    default_config = ImmutableDict(179        {180            "DEBUG": None,181            "TESTING": False,182            "PROPAGATE_EXCEPTIONS": None,183            "SECRET_KEY": None,184            "SECRET_KEY_FALLBACKS": None,185            "PERMANENT_SESSION_LIFETIME": timedelta(days=31),186            "USE_X_SENDFILE": False,187            "TRUSTED_HOSTS": None,188            "SERVER_NAME": None,189            "APPLICATION_ROOT": "/",190            "SESSION_COOKIE_NAME": "session",191            "SESSION_COOKIE_DOMAIN": None,192            "SESSION_COOKIE_PATH": None,193            "SESSION_COOKIE_HTTPONLY": True,194            "SESSION_COOKIE_SECURE": False,195            "SESSION_COOKIE_PARTITIONED": False,196            "SESSION_COOKIE_SAMESITE": None,197            "SESSION_REFRESH_EACH_REQUEST": True,198            "MAX_CONTENT_LENGTH": None,199            "MAX_FORM_MEMORY_SIZE": 500_000,200            "MAX_FORM_PARTS": 1_000,201            "SEND_FILE_MAX_AGE_DEFAULT": None,202            "TRAP_BAD_REQUEST_ERRORS": None,203            "TRAP_HTTP_EXCEPTIONS": False,204            "EXPLAIN_TEMPLATE_LOADING": False,205            "PREFERRED_URL_SCHEME": "http",206            "TEMPLATES_AUTO_RELOAD": None,207            "MAX_COOKIE_SIZE": 4093,208            "PROVIDE_AUTOMATIC_OPTIONS": True,209        }210    )211 212    #: The class that is used for request objects.  See :class:`~flask.Request`213    #: for more information.214    request_class: type[Request] = Request215 216    #: The class that is used for response objects.  See217    #: :class:`~flask.Response` for more information.218    response_class: type[Response] = Response219 220    #: the session interface to use.  By default an instance of221    #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.222    #:223    #: .. versionadded:: 0.8224    session_interface: SessionInterface = SecureCookieSessionInterface()225 226    def __init__(227        self,228        import_name: str,229        static_url_path: str | None = None,230        static_folder: str | os.PathLike[str] | None = "static",231        static_host: str | None = None,232        host_matching: bool = False,233        subdomain_matching: bool = False,234        template_folder: str | os.PathLike[str] | None = "templates",235        instance_path: str | None = None,236        instance_relative_config: bool = False,237        root_path: str | None = None,238    ):239        super().__init__(240            import_name=import_name,241            static_url_path=static_url_path,242            static_folder=static_folder,243            static_host=static_host,244            host_matching=host_matching,245            subdomain_matching=subdomain_matching,246            template_folder=template_folder,247            instance_path=instance_path,248            instance_relative_config=instance_relative_config,249            root_path=root_path,250        )251 252        #: The Click command group for registering CLI commands for this253        #: object. The commands are available from the ``flask`` command254        #: once the application has been discovered and blueprints have255        #: been registered.256        self.cli = cli.AppGroup()257 258        # Set the name of the Click group in case someone wants to add259        # the app's commands to another CLI tool.260        self.cli.name = self.name261 262        # Add a static route using the provided static_url_path, static_host,263        # and static_folder if there is a configured static_folder.264        # Note we do this without checking if static_folder exists.265        # For one, it might be created while the server is running (e.g. during266        # development). Also, Google App Engine stores static files somewhere267        if self.has_static_folder:268            assert bool(static_host) == host_matching, (269                "Invalid static_host/host_matching combination"270            )271            # Use a weakref to avoid creating a reference cycle between the app272            # and the view function (see #3761).273            self_ref = weakref.ref(self)274            self.add_url_rule(275                f"{self.static_url_path}/<path:filename>",276                endpoint="static",277                host=static_host,278                view_func=lambda **kw: self_ref().send_static_file(**kw),  # type: ignore279            )280 281    def get_send_file_max_age(self, filename: str | None) -> int | None:282        """Used by :func:`send_file` to determine the ``max_age`` cache283        value for a given file path if it wasn't passed.284 285        By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from286        the configuration of :data:`~flask.current_app`. This defaults287        to ``None``, which tells the browser to use conditional requests288        instead of a timed cache, which is usually preferable.289 290        Note this is a duplicate of the same method in the Flask291        class.292 293        .. versionchanged:: 2.0294            The default configuration is ``None`` instead of 12 hours.295 296        .. versionadded:: 0.9297        """298        value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"]299 300        if value is None:301            return None302 303        if isinstance(value, timedelta):304            return int(value.total_seconds())305 306        return value  # type: ignore[no-any-return]307 308    def send_static_file(self, filename: str) -> Response:309        """The view function used to serve files from310        :attr:`static_folder`. A route is automatically registered for311        this view at :attr:`static_url_path` if :attr:`static_folder` is312        set.313 314        Note this is a duplicate of the same method in the Flask315        class.316 317        .. versionadded:: 0.5318 319        """320        if not self.has_static_folder:321            raise RuntimeError("'static_folder' must be set to serve static_files.")322 323        # send_file only knows to call get_send_file_max_age on the app,324        # call it here so it works for blueprints too.325        max_age = self.get_send_file_max_age(filename)326        return send_from_directory(327            t.cast(str, self.static_folder), filename, max_age=max_age328        )329 330    def open_resource(331        self, resource: str, mode: str = "rb", encoding: str | None = None332    ) -> t.IO[t.AnyStr]:333        """Open a resource file relative to :attr:`root_path` for reading.334 335        For example, if the file ``schema.sql`` is next to the file336        ``app.py`` where the ``Flask`` app is defined, it can be opened337        with:338 339        .. code-block:: python340 341            with app.open_resource("schema.sql") as f:342                conn.executescript(f.read())343 344        :param resource: Path to the resource relative to :attr:`root_path`.345        :param mode: Open the file in this mode. Only reading is supported,346            valid values are ``"r"`` (or ``"rt"``) and ``"rb"``.347        :param encoding: Open the file with this encoding when opening in text348            mode. This is ignored when opening in binary mode.349 350        .. versionchanged:: 3.1351            Added the ``encoding`` parameter.352        """353        if mode not in {"r", "rt", "rb"}:354            raise ValueError("Resources can only be opened for reading.")355 356        path = os.path.join(self.root_path, resource)357 358        if mode == "rb":359            return open(path, mode)  # pyright: ignore360 361        return open(path, mode, encoding=encoding)362 363    def open_instance_resource(364        self, resource: str, mode: str = "rb", encoding: str | None = "utf-8"365    ) -> t.IO[t.AnyStr]:366        """Open a resource file relative to the application's instance folder367        :attr:`instance_path`. Unlike :meth:`open_resource`, files in the368        instance folder can be opened for writing.369 370        :param resource: Path to the resource relative to :attr:`instance_path`.371        :param mode: Open the file in this mode.372        :param encoding: Open the file with this encoding when opening in text373            mode. This is ignored when opening in binary mode.374 375        .. versionchanged:: 3.1376            Added the ``encoding`` parameter.377        """378        path = os.path.join(self.instance_path, resource)379 380        if "b" in mode:381            return open(path, mode)382 383        return open(path, mode, encoding=encoding)384 385    def create_jinja_environment(self) -> Environment:386        """Create the Jinja environment based on :attr:`jinja_options`387        and the various Jinja-related methods of the app. Changing388        :attr:`jinja_options` after this will have no effect. Also adds389        Flask-related globals and filters to the environment.390 391        .. versionchanged:: 0.11392           ``Environment.auto_reload`` set in accordance with393           ``TEMPLATES_AUTO_RELOAD`` configuration option.394 395        .. versionadded:: 0.5396        """397        options = dict(self.jinja_options)398 399        if "autoescape" not in options:400            options["autoescape"] = self.select_jinja_autoescape401 402        if "auto_reload" not in options:403            auto_reload = self.config["TEMPLATES_AUTO_RELOAD"]404 405            if auto_reload is None:406                auto_reload = self.debug407 408            options["auto_reload"] = auto_reload409 410        rv = self.jinja_environment(self, **options)411        rv.globals.update(412            url_for=self.url_for,413            get_flashed_messages=get_flashed_messages,414            config=self.config,415            # request, session and g are normally added with the416            # context processor for efficiency reasons but for imported417            # templates we also want the proxies in there.418            request=request,419            session=session,420            g=g,421        )422        rv.policies["json.dumps_function"] = self.json.dumps423        return rv424 425    def create_url_adapter(self, request: Request | None) -> MapAdapter | None:426        """Creates a URL adapter for the given request. The URL adapter427        is created at a point where the request context is not yet set428        up so the request is passed explicitly.429 430        .. versionchanged:: 3.1431            If :data:`SERVER_NAME` is set, it does not restrict requests to432            only that domain, for both ``subdomain_matching`` and433            ``host_matching``.434 435        .. versionchanged:: 1.0436            :data:`SERVER_NAME` no longer implicitly enables subdomain437            matching. Use :attr:`subdomain_matching` instead.438 439        .. versionchanged:: 0.9440           This can be called outside a request when the URL adapter is created441           for an application context.442 443        .. versionadded:: 0.6444        """445        if request is not None:446            if (trusted_hosts := self.config["TRUSTED_HOSTS"]) is not None:447                request.trusted_hosts = trusted_hosts448 449            # Check trusted_hosts here until bind_to_environ does.450            request.host = get_host(request.environ, request.trusted_hosts)  # pyright: ignore451            subdomain = None452            server_name = self.config["SERVER_NAME"]453 454            if self.url_map.host_matching:455                # Don't pass SERVER_NAME, otherwise it's used and the actual456                # host is ignored, which breaks host matching.457                server_name = None458            elif not self.subdomain_matching:459                # Werkzeug doesn't implement subdomain matching yet. Until then,460                # disable it by forcing the current subdomain to the default, or461                # the empty string.462                subdomain = self.url_map.default_subdomain or ""463 464            return self.url_map.bind_to_environ(465                request.environ, server_name=server_name, subdomain=subdomain466            )467 468        # Need at least SERVER_NAME to match/build outside a request.469        if self.config["SERVER_NAME"] is not None:470            return self.url_map.bind(471                self.config["SERVER_NAME"],472                script_name=self.config["APPLICATION_ROOT"],473                url_scheme=self.config["PREFERRED_URL_SCHEME"],474            )475 476        return None477 478    def raise_routing_exception(self, request: Request) -> t.NoReturn:479        """Intercept routing exceptions and possibly do something else.480 481        In debug mode, intercept a routing redirect and replace it with482        an error if the body will be discarded.483 484        With modern Werkzeug this shouldn't occur, since it now uses a485        308 status which tells the browser to resend the method and486        body.487 488        .. versionchanged:: 2.1489            Don't intercept 307 and 308 redirects.490 491        :meta private:492        :internal:493        """494        if (495            not self.debug496            or not isinstance(request.routing_exception, RequestRedirect)497            or request.routing_exception.code in {307, 308}498            or request.method in {"GET", "HEAD", "OPTIONS"}499        ):500            raise request.routing_exception  # type: ignore[misc]501 502        from .debughelpers import FormDataRoutingRedirect503 504        raise FormDataRoutingRedirect(request)505 506    def update_template_context(self, context: dict[str, t.Any]) -> None:507        """Update the template context with some commonly used variables.508        This injects request, session, config and g into the template509        context as well as everything template context processors want510        to inject.  Note that the as of Flask 0.6, the original values511        in the context will not be overridden if a context processor512        decides to return a value with the same key.513 514        :param context: the context as a dictionary that is updated in place515                        to add extra variables.516        """517        names: t.Iterable[str | None] = (None,)518 519        # A template may be rendered outside a request context.520        if request:521            names = chain(names, reversed(request.blueprints))522 523        # The values passed to render_template take precedence. Keep a524        # copy to re-apply after all context functions.525        orig_ctx = context.copy()526 527        for name in names:528            if name in self.template_context_processors:529                for func in self.template_context_processors[name]:530                    context.update(self.ensure_sync(func)())531 532        context.update(orig_ctx)533 534    def make_shell_context(self) -> dict[str, t.Any]:535        """Returns the shell context for an interactive shell for this536        application.  This runs all the registered shell context537        processors.538 539        .. versionadded:: 0.11540        """541        rv = {"app": self, "g": g}542        for processor in self.shell_context_processors:543            rv.update(processor())544        return rv545 546    def run(547        self,548        host: str | None = None,549        port: int | None = None,550        debug: bool | None = None,551        load_dotenv: bool = True,552        **options: t.Any,553    ) -> None:554        """Runs the application on a local development server.555 556        Do not use ``run()`` in a production setting. It is not intended to557        meet security and performance requirements for a production server.558        Instead, see :doc:`/deploying/index` for WSGI server recommendations.559 560        If the :attr:`debug` flag is set the server will automatically reload561        for code changes and show a debugger in case an exception happened.562 563        If you want to run the application in debug mode, but disable the564        code execution on the interactive debugger, you can pass565        ``use_evalex=False`` as parameter.  This will keep the debugger's566        traceback screen active, but disable code execution.567 568        It is not recommended to use this function for development with569        automatic reloading as this is badly supported.  Instead you should570        be using the :command:`flask` command line script's ``run`` support.571 572        .. admonition:: Keep in Mind573 574           Flask will suppress any server error with a generic error page575           unless it is in debug mode.  As such to enable just the576           interactive debugger without the code reloading, you have to577           invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.578           Setting ``use_debugger`` to ``True`` without being in debug mode579           won't catch any exceptions because there won't be any to580           catch.581 582        :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to583            have the server available externally as well. Defaults to584            ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable585            if present.586        :param port: the port of the webserver. Defaults to ``5000`` or the587            port defined in the ``SERVER_NAME`` config variable if present.588        :param debug: if given, enable or disable debug mode. See589            :attr:`debug`.590        :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`591            files to set environment variables. Will also change the working592            directory to the directory containing the first file found.593        :param options: the options to be forwarded to the underlying Werkzeug594            server. See :func:`werkzeug.serving.run_simple` for more595            information.596 597        .. versionchanged:: 1.0598            If installed, python-dotenv will be used to load environment599            variables from :file:`.env` and :file:`.flaskenv` files.600 601            The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`.602 603            Threaded mode is enabled by default.604 605        .. versionchanged:: 0.10606            The default port is now picked from the ``SERVER_NAME``607            variable.608        """609        # Ignore this call so that it doesn't start another server if610        # the 'flask run' command is used.611        if os.environ.get("FLASK_RUN_FROM_CLI") == "true":612            if not is_running_from_reloader():613                click.secho(614                    " * Ignoring a call to 'app.run()' that would block"615                    " the current 'flask' CLI command.\n"616                    "   Only call 'app.run()' in an 'if __name__ =="617                    ' "__main__"\' guard.',618                    fg="red",619                )620 621            return622 623        if get_load_dotenv(load_dotenv):624            cli.load_dotenv()625 626            # if set, env var overrides existing value627            if "FLASK_DEBUG" in os.environ:628                self.debug = get_debug_flag()629 630        # debug passed to method overrides all other sources631        if debug is not None:632            self.debug = bool(debug)633 634        server_name = self.config.get("SERVER_NAME")635        sn_host = sn_port = None636 637        if server_name:638            sn_host, _, sn_port = server_name.partition(":")639 640        if not host:641            if sn_host:642                host = sn_host643            else:644                host = "127.0.0.1"645 646        if port or port == 0:647            port = int(port)648        elif sn_port:649            port = int(sn_port)650        else:651            port = 5000652 653        options.setdefault("use_reloader", self.debug)654        options.setdefault("use_debugger", self.debug)655        options.setdefault("threaded", True)656 657        cli.show_server_banner(self.debug, self.name)658 659        from werkzeug.serving import run_simple660 661        try:662            run_simple(t.cast(str, host), port, self, **options)663        finally:664            # reset the first request information if the development server665            # reset normally.  This makes it possible to restart the server666            # without reloader and that stuff from an interactive shell.667            self._got_first_request = False668 669    def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient:670        """Creates a test client for this application.  For information671        about unit testing head over to :doc:`/testing`.672 673        Note that if you are testing for assertions or exceptions in your674        application code, you must set ``app.testing = True`` in order for the675        exceptions to propagate to the test client.  Otherwise, the exception676        will be handled by the application (not visible to the test client) and677        the only indication of an AssertionError or other exception will be a678        500 status code response to the test client.  See the :attr:`testing`679        attribute.  For example::680 681            app.testing = True682            client = app.test_client()683 684        The test client can be used in a ``with`` block to defer the closing down685        of the context until the end of the ``with`` block.  This is useful if686        you want to access the context locals for testing::687 688            with app.test_client() as c:689                rv = c.get('/?vodka=42')690                assert request.args['vodka'] == '42'691 692        Additionally, you may pass optional keyword arguments that will then693        be passed to the application's :attr:`test_client_class` constructor.694        For example::695 696            from flask.testing import FlaskClient697 698            class CustomClient(FlaskClient):699                def __init__(self, *args, **kwargs):700                    self._authentication = kwargs.pop("authentication")701                    super(CustomClient,self).__init__( *args, **kwargs)702 703            app.test_client_class = CustomClient704            client = app.test_client(authentication='Basic ....')705 706        See :class:`~flask.testing.FlaskClient` for more information.707 708        .. versionchanged:: 0.4709           added support for ``with`` block usage for the client.710 711        .. versionadded:: 0.7712           The `use_cookies` parameter was added as well as the ability713           to override the client to be used by setting the714           :attr:`test_client_class` attribute.715 716        .. versionchanged:: 0.11717           Added `**kwargs` to support passing additional keyword arguments to718           the constructor of :attr:`test_client_class`.719        """720        cls = self.test_client_class721        if cls is None:722            from .testing import FlaskClient as cls723        return cls(  # type: ignore724            self, self.response_class, use_cookies=use_cookies, **kwargs725        )726 727    def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner:728        """Create a CLI runner for testing CLI commands.729        See :ref:`testing-cli`.730 731        Returns an instance of :attr:`test_cli_runner_class`, by default732        :class:`~flask.testing.FlaskCliRunner`. The Flask app object is733        passed as the first argument.734 735        .. versionadded:: 1.0736        """737        cls = self.test_cli_runner_class738 739        if cls is None:740            from .testing import FlaskCliRunner as cls741 742        return cls(self, **kwargs)  # type: ignore743 744    def handle_http_exception(745        self, e: HTTPException746    ) -> HTTPException | ft.ResponseReturnValue:747        """Handles an HTTP exception.  By default this will invoke the748        registered error handlers and fall back to returning the749        exception as response.750 751        .. versionchanged:: 1.0.3752            ``RoutingException``, used internally for actions such as753             slash redirects during routing, is not passed to error754             handlers.755 756        .. versionchanged:: 1.0757            Exceptions are looked up by code *and* by MRO, so758            ``HTTPException`` subclasses can be handled with a catch-all759            handler for the base ``HTTPException``.760 761        .. versionadded:: 0.3762        """763        # Proxy exceptions don't have error codes.  We want to always return764        # those unchanged as errors765        if e.code is None:766            return e767 768        # RoutingExceptions are used internally to trigger routing769        # actions, such as slash redirects raising RequestRedirect. They770        # are not raised or handled in user code.771        if isinstance(e, RoutingException):772            return e773 774        handler = self._find_error_handler(e, request.blueprints)775        if handler is None:776            return e777        return self.ensure_sync(handler)(e)  # type: ignore[no-any-return]778 779    def handle_user_exception(780        self, e: Exception781    ) -> HTTPException | ft.ResponseReturnValue:782        """This method is called whenever an exception occurs that783        should be handled. A special case is :class:`~werkzeug784        .exceptions.HTTPException` which is forwarded to the785        :meth:`handle_http_exception` method. This function will either786        return a response value or reraise the exception with the same787        traceback.788 789        .. versionchanged:: 1.0790            Key errors raised from request data like ``form`` show the791            bad key in debug mode rather than a generic bad request792            message.793 794        .. versionadded:: 0.7795        """796        if isinstance(e, BadRequestKeyError) and (797            self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]798        ):799            e.show_exception = True800 801        if isinstance(e, HTTPException) and not self.trap_http_exception(e):802            return self.handle_http_exception(e)803 804        handler = self._find_error_handler(e, request.blueprints)805 806        if handler is None:807            raise808 809        return self.ensure_sync(handler)(e)  # type: ignore[no-any-return]810 811    def handle_exception(self, e: Exception) -> Response:812        """Handle an exception that did not have an error handler813        associated with it, or that was raised from an error handler.814        This always causes a 500 ``InternalServerError``.815 816        Always sends the :data:`got_request_exception` signal.817 818        If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug819        mode, the error will be re-raised so that the debugger can820        display it. Otherwise, the original exception is logged, and821        an :exc:`~werkzeug.exceptions.InternalServerError` is returned.822 823        If an error handler is registered for ``InternalServerError`` or824        ``500``, it will be used. For consistency, the handler will825        always receive the ``InternalServerError``. The original826        unhandled exception is available as ``e.original_exception``.827 828        .. versionchanged:: 1.1.0829            Always passes the ``InternalServerError`` instance to the830            handler, setting ``original_exception`` to the unhandled831            error.832 833        .. versionchanged:: 1.1.0834            ``after_request`` functions and other finalization is done835            even for the default 500 response when there is no handler.836 837        .. versionadded:: 0.3838        """839        exc_info = sys.exc_info()840        got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e)841        propagate = self.config["PROPAGATE_EXCEPTIONS"]842 843        if propagate is None:844            propagate = self.testing or self.debug845 846        if propagate:847            # Re-raise if called with an active exception, otherwise848            # raise the passed in exception.849            if exc_info[1] is e:850                raise851 852            raise e853 854        self.log_exception(exc_info)855        server_error: InternalServerError | ft.ResponseReturnValue856        server_error = InternalServerError(original_exception=e)857        handler = self._find_error_handler(server_error, request.blueprints)858 859        if handler is not None:860            server_error = self.ensure_sync(handler)(server_error)861 862        return self.finalize_request(server_error, from_error_handler=True)863 864    def log_exception(865        self,866        exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]),867    ) -> None:868        """Logs an exception.  This is called by :meth:`handle_exception`869        if debugging is disabled and right before the handler is called.870        The default implementation logs the exception as error on the871        :attr:`logger`.872 873        .. versionadded:: 0.8874        """875        self.logger.error(876            f"Exception on {request.path} [{request.method}]", exc_info=exc_info877        )878 879    def dispatch_request(self) -> ft.ResponseReturnValue:880        """Does the request dispatching.  Matches the URL and returns the881        return value of the view or error handler.  This does not have to882        be a response object.  In order to convert the return value to a883        proper response object, call :func:`make_response`.884 885        .. versionchanged:: 0.7886           This no longer does the exception handling, this code was887           moved to the new :meth:`full_dispatch_request`.888        """889        req = request_ctx.request890        if req.routing_exception is not None:891            self.raise_routing_exception(req)892        rule: Rule = req.url_rule  # type: ignore[assignment]893        # if we provide automatic options for this URL and the894        # request came with the OPTIONS method, reply automatically895        if (896            getattr(rule, "provide_automatic_options", False)897            and req.method == "OPTIONS"898        ):899            return self.make_default_options_response()900        # otherwise dispatch to the handler for that endpoint901        view_args: dict[str, t.Any] = req.view_args  # type: ignore[assignment]902        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]903 904    def full_dispatch_request(self) -> Response:905        """Dispatches the request and on top of that performs request906        pre and postprocessing as well as HTTP exception catching and907        error handling.908 909        .. versionadded:: 0.7910        """911        self._got_first_request = True912 913        try:914            request_started.send(self, _async_wrapper=self.ensure_sync)915            rv = self.preprocess_request()916            if rv is None:917                rv = self.dispatch_request()918        except Exception as e:919            rv = self.handle_user_exception(e)920        return self.finalize_request(rv)921 922    def finalize_request(923        self,924        rv: ft.ResponseReturnValue | HTTPException,925        from_error_handler: bool = False,926    ) -> Response:927        """Given the return value from a view function this finalizes928        the request by converting it into a response and invoking the929        postprocessing functions.  This is invoked for both normal930        request dispatching as well as error handlers.931 932        Because this means that it might be called as a result of a933        failure a special safe mode is available which can be enabled934        with the `from_error_handler` flag.  If enabled, failures in935        response processing will be logged and otherwise ignored.936 937        :internal:938        """939        response = self.make_response(rv)940        try:941            response = self.process_response(response)942            request_finished.send(943                self, _async_wrapper=self.ensure_sync, response=response944            )945        except Exception:946            if not from_error_handler:947                raise948            self.logger.exception(949                "Request finalizing failed with an error while handling an error"950            )951        return response952 953    def make_default_options_response(self) -> Response:954        """This method is called to create the default ``OPTIONS`` response.955        This can be changed through subclassing to change the default956        behavior of ``OPTIONS`` responses.957 958        .. versionadded:: 0.7959        """960        adapter = request_ctx.url_adapter961        methods = adapter.allowed_methods()  # type: ignore[union-attr]962        rv = self.response_class()963        rv.allow.update(methods)964        return rv965 966    def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:967        """Ensure that the function is synchronous for WSGI workers.968        Plain ``def`` functions are returned as-is. ``async def``969        functions are wrapped to run and wait for the response.970 971        Override this method to change how the app runs async views.972 973        .. versionadded:: 2.0974        """975        if iscoroutinefunction(func):976            return self.async_to_sync(func)977 978        return func979 980    def async_to_sync(981        self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]]982    ) -> t.Callable[..., t.Any]:983        """Return a sync function that will run the coroutine function.984 985        .. code-block:: python986 987            result = app.async_to_sync(func)(*args, **kwargs)988 989        Override this method to change how the app converts async code990        to be synchronously callable.991 992        .. versionadded:: 2.0993        """994        try:995            from asgiref.sync import async_to_sync as asgiref_async_to_sync996        except ImportError:997            raise RuntimeError(998                "Install Flask with the 'async' extra in order to use async views."999            ) from None1000 1001        return asgiref_async_to_sync(func)1002 1003    def url_for(1004        self,1005        /,1006        endpoint: str,1007        *,1008        _anchor: str | None = None,1009        _method: str | None = None,1010        _scheme: str | None = None,1011        _external: bool | None = None,1012        **values: t.Any,1013    ) -> str:1014        """Generate a URL to the given endpoint with the given values.1015 1016        This is called by :func:`flask.url_for`, and can be called1017        directly as well.1018 1019        An *endpoint* is the name of a URL rule, usually added with1020        :meth:`@app.route() <route>`, and usually the same name as the1021        view function. A route defined in a :class:`~flask.Blueprint`1022        will prepend the blueprint's name separated by a ``.`` to the1023        endpoint.1024 1025        In some cases, such as email messages, you want URLs to include1026        the scheme and domain, like ``https://example.com/hello``. When1027        not in an active request, URLs will be external by default, but1028        this requires setting :data:`SERVER_NAME` so Flask knows what1029        domain to use. :data:`APPLICATION_ROOT` and1030        :data:`PREFERRED_URL_SCHEME` should also be configured as1031        needed. This config is only used when not in an active request.1032 1033        Functions can be decorated with :meth:`url_defaults` to modify1034        keyword arguments before the URL is built.1035 1036        If building fails for some reason, such as an unknown endpoint1037        or incorrect values, the app's :meth:`handle_url_build_error`1038        method is called. If that returns a string, that is returned,1039        otherwise a :exc:`~werkzeug.routing.BuildError` is raised.1040 1041        :param endpoint: The endpoint name associated with the URL to1042            generate. If this starts with a ``.``, the current blueprint1043            name (if any) will be used.1044        :param _anchor: If given, append this as ``#anchor`` to the URL.1045        :param _method: If given, generate the URL associated with this1046            method for the endpoint.1047        :param _scheme: If given, the URL will have this scheme if it1048            is external.1049        :param _external: If given, prefer the URL to be internal1050            (False) or require it to be external (True). External URLs1051            include the scheme and domain. When not in an active1052            request, URLs are external by default.1053        :param values: Values to use for the variable parts of the URL1054            rule. Unknown keys are appended as query string arguments,1055            like ``?a=b&c=d``.1056 1057        .. versionadded:: 2.21058            Moved from ``flask.url_for``, which calls this method.1059        """1060        req_ctx = _cv_request.get(None)1061 1062        if req_ctx is not None:1063            url_adapter = req_ctx.url_adapter1064            blueprint_name = req_ctx.request.blueprint1065 1066            # If the endpoint starts with "." and the request matches a1067            # blueprint, the endpoint is relative to the blueprint.1068            if endpoint[:1] == ".":1069                if blueprint_name is not None:1070                    endpoint = f"{blueprint_name}{endpoint}"1071                else:1072                    endpoint = endpoint[1:]1073 1074            # When in a request, generate a URL without scheme and1075            # domain by default, unless a scheme is given.1076            if _external is None:1077                _external = _scheme is not None1078        else:1079            app_ctx = _cv_app.get(None)1080 1081            # If called by helpers.url_for, an app context is active,1082            # use its url_adapter. Otherwise, app.url_for was called1083            # directly, build an adapter.1084            if app_ctx is not None:1085                url_adapter = app_ctx.url_adapter1086            else:1087                url_adapter = self.create_url_adapter(None)1088 1089            if url_adapter is None:1090                raise RuntimeError(1091                    "Unable to build URLs outside an active request"1092                    " without 'SERVER_NAME' configured. Also configure"1093                    " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as"1094                    " needed."1095                )1096 1097            # When outside a request, generate a URL with scheme and1098            # domain by default.1099            if _external is None:1100                _external = True1101 1102        # It is an error to set _scheme when _external=False, in order1103        # to avoid accidental insecure URLs.1104        if _scheme is not None and not _external:1105            raise ValueError("When specifying '_scheme', '_external' must be True.")1106 1107        self.inject_url_defaults(endpoint, values)1108 1109        try:1110            rv = url_adapter.build(  # type: ignore[union-attr]1111                endpoint,1112                values,1113                method=_method,1114                url_scheme=_scheme,1115                force_external=_external,1116            )1117        except BuildError as error:1118            values.update(1119                _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external1120            )1121            return self.handle_url_build_error(error, endpoint, values)1122 1123        if _anchor is not None:1124            _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@")1125            rv = f"{rv}#{_anchor}"1126 1127        return rv1128 1129    def make_response(self, rv: ft.ResponseReturnValue) -> Response:1130        """Convert the return value from a view function to an instance of1131        :attr:`response_class`.1132 1133        :param rv: the return value from the view function. The view function1134            must return a response. Returning ``None``, or the view ending1135            without returning, is not allowed. The following types are allowed1136            for ``view_rv``:1137 1138            ``str``1139                A response object is created with the string encoded to UTF-81140                as the body.1141 1142            ``bytes``1143                A response object is created with the bytes as the body.1144 1145            ``dict``1146                A dictionary that will be jsonify'd before being returned.1147 1148            ``list``1149                A list that will be jsonify'd before being returned.1150 1151            ``generator`` or ``iterator``1152                A generator that returns ``str`` or ``bytes`` to be1153                streamed as the response.1154 1155            ``tuple``1156                Either ``(body, status, headers)``, ``(body, status)``, or1157                ``(body, headers)``, where ``body`` is any of the other types1158                allowed here, ``status`` is a string or an integer, and1159                ``headers`` is a dictionary or a list of ``(key, value)``1160                tuples. If ``body`` is a :attr:`response_class` instance,1161                ``status`` overwrites the exiting value and ``headers`` are1162                extended.1163 1164            :attr:`response_class`1165                The object is returned unchanged.1166 1167            other :class:`~werkzeug.wrappers.Response` class1168                The object is coerced to :attr:`response_class`.1169 1170            :func:`callable`1171                The function is called as a WSGI application. The result is1172                used to create a response object.1173 1174        .. versionchanged:: 2.21175            A generator will be converted to a streaming response.1176            A list will be converted to a JSON response.1177 1178        .. versionchanged:: 1.11179            A dict will be converted to a JSON response.1180 1181        .. versionchanged:: 0.91182           Previously a tuple was interpreted as the arguments for the1183           response object.1184        """1185 1186        status: int | None = None1187        headers: HeadersValue | None = None1188 1189        # unpack tuple returns1190        if isinstance(rv, tuple):1191            len_rv = len(rv)1192 1193            # a 3-tuple is unpacked directly1194            if len_rv == 3:1195                rv, status, headers = rv  # type: ignore[misc]1196            # decide if a 2-tuple has status or headers1197            elif len_rv == 2:1198                if isinstance(rv[1], (Headers, dict, tuple, list)):1199                    rv, headers = rv  # pyright: ignore1200                else:

Showing the first 1,200 of 1537 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai