Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
app.py1499 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 BaseResponse27 28from . import cli29from . import typing as ft30from .ctx import AppContext31from .ctx import RequestContext32from .globals import _cv_app33from .globals import _cv_request34from .globals import current_app35from .globals import g36from .globals import request37from .globals import request_ctx38from .globals import session39from .helpers import get_debug_flag40from .helpers import get_flashed_messages41from .helpers import get_load_dotenv42from .helpers import send_from_directory43from .sansio.app import App44from .sansio.scaffold import _sentinel45from .sessions import SecureCookieSessionInterface46from .sessions import SessionInterface47from .signals import appcontext_tearing_down48from .signals import got_request_exception49from .signals import request_finished50from .signals import request_started51from .signals import request_tearing_down52from .templating import Environment53from .wrappers import Request54from .wrappers import Response55 56if t.TYPE_CHECKING:  # pragma: no cover57    from _typeshed.wsgi import StartResponse58    from _typeshed.wsgi import WSGIEnvironment59 60    from .testing import FlaskClient61    from .testing import FlaskCliRunner62 63T_shell_context_processor = t.TypeVar(64    "T_shell_context_processor", bound=ft.ShellContextProcessorCallable65)66T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)67T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable)68T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable)69T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable)70 71 72def _make_timedelta(value: timedelta | int | None) -> timedelta | None:73    if value is None or isinstance(value, timedelta):74        return value75 76    return timedelta(seconds=value)77 78 79class Flask(App):80    """The flask object implements a WSGI application and acts as the central81    object.  It is passed the name of the module or package of the82    application.  Once it is created it will act as a central registry for83    the view functions, the URL rules, template configuration and much more.84 85    The name of the package is used to resolve resources from inside the86    package or the folder the module is contained in depending on if the87    package parameter resolves to an actual python package (a folder with88    an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).89 90    For more information about resource loading, see :func:`open_resource`.91 92    Usually you create a :class:`Flask` instance in your main module or93    in the :file:`__init__.py` file of your package like this::94 95        from flask import Flask96        app = Flask(__name__)97 98    .. admonition:: About the First Parameter99 100        The idea of the first parameter is to give Flask an idea of what101        belongs to your application.  This name is used to find resources102        on the filesystem, can be used by extensions to improve debugging103        information and a lot more.104 105        So it's important what you provide there.  If you are using a single106        module, `__name__` is always the correct value.  If you however are107        using a package, it's usually recommended to hardcode the name of108        your package there.109 110        For example if your application is defined in :file:`yourapplication/app.py`111        you should create it with one of the two versions below::112 113            app = Flask('yourapplication')114            app = Flask(__name__.split('.')[0])115 116        Why is that?  The application will work even with `__name__`, thanks117        to how resources are looked up.  However it will make debugging more118        painful.  Certain extensions can make assumptions based on the119        import name of your application.  For example the Flask-SQLAlchemy120        extension will look for the code in your application that triggered121        an SQL query in debug mode.  If the import name is not properly set122        up, that debugging information is lost.  (For example it would only123        pick up SQL queries in `yourapplication.app` and not124        `yourapplication.views.frontend`)125 126    .. versionadded:: 0.7127       The `static_url_path`, `static_folder`, and `template_folder`128       parameters were added.129 130    .. versionadded:: 0.8131       The `instance_path` and `instance_relative_config` parameters were132       added.133 134    .. versionadded:: 0.11135       The `root_path` parameter was added.136 137    .. versionadded:: 1.0138       The ``host_matching`` and ``static_host`` parameters were added.139 140    .. versionadded:: 1.0141       The ``subdomain_matching`` parameter was added. Subdomain142       matching needs to be enabled manually now. Setting143       :data:`SERVER_NAME` does not implicitly enable it.144 145    :param import_name: the name of the application package146    :param static_url_path: can be used to specify a different path for the147                            static files on the web.  Defaults to the name148                            of the `static_folder` folder.149    :param static_folder: The folder with static files that is served at150        ``static_url_path``. Relative to the application ``root_path``151        or an absolute path. Defaults to ``'static'``.152    :param static_host: the host to use when adding the static route.153        Defaults to None. Required when using ``host_matching=True``154        with a ``static_folder`` configured.155    :param host_matching: set ``url_map.host_matching`` attribute.156        Defaults to False.157    :param subdomain_matching: consider the subdomain relative to158        :data:`SERVER_NAME` when matching routes. Defaults to False.159    :param template_folder: the folder that contains the templates that should160                            be used by the application.  Defaults to161                            ``'templates'`` folder in the root path of the162                            application.163    :param instance_path: An alternative instance path for the application.164                          By default the folder ``'instance'`` next to the165                          package or module is assumed to be the instance166                          path.167    :param instance_relative_config: if set to ``True`` relative filenames168                                     for loading the config are assumed to169                                     be relative to the instance path instead170                                     of the application root.171    :param root_path: The path to the root of the application files.172        This should only be set manually when it can't be detected173        automatically, such as for namespace packages.174    """175 176    default_config = ImmutableDict(177        {178            "DEBUG": None,179            "TESTING": False,180            "PROPAGATE_EXCEPTIONS": None,181            "SECRET_KEY": None,182            "PERMANENT_SESSION_LIFETIME": timedelta(days=31),183            "USE_X_SENDFILE": False,184            "SERVER_NAME": None,185            "APPLICATION_ROOT": "/",186            "SESSION_COOKIE_NAME": "session",187            "SESSION_COOKIE_DOMAIN": None,188            "SESSION_COOKIE_PATH": None,189            "SESSION_COOKIE_HTTPONLY": True,190            "SESSION_COOKIE_SECURE": False,191            "SESSION_COOKIE_SAMESITE": None,192            "SESSION_REFRESH_EACH_REQUEST": True,193            "MAX_CONTENT_LENGTH": None,194            "SEND_FILE_MAX_AGE_DEFAULT": None,195            "TRAP_BAD_REQUEST_ERRORS": None,196            "TRAP_HTTP_EXCEPTIONS": False,197            "EXPLAIN_TEMPLATE_LOADING": False,198            "PREFERRED_URL_SCHEME": "http",199            "TEMPLATES_AUTO_RELOAD": None,200            "MAX_COOKIE_SIZE": 4093,201        }202    )203 204    #: The class that is used for request objects.  See :class:`~flask.Request`205    #: for more information.206    request_class: type[Request] = Request207 208    #: The class that is used for response objects.  See209    #: :class:`~flask.Response` for more information.210    response_class: type[Response] = Response211 212    #: the session interface to use.  By default an instance of213    #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.214    #:215    #: .. versionadded:: 0.8216    session_interface: SessionInterface = SecureCookieSessionInterface()217 218    def __init__(219        self,220        import_name: str,221        static_url_path: str | None = None,222        static_folder: str | os.PathLike[str] | None = "static",223        static_host: str | None = None,224        host_matching: bool = False,225        subdomain_matching: bool = False,226        template_folder: str | os.PathLike[str] | None = "templates",227        instance_path: str | None = None,228        instance_relative_config: bool = False,229        root_path: str | None = None,230    ):231        super().__init__(232            import_name=import_name,233            static_url_path=static_url_path,234            static_folder=static_folder,235            static_host=static_host,236            host_matching=host_matching,237            subdomain_matching=subdomain_matching,238            template_folder=template_folder,239            instance_path=instance_path,240            instance_relative_config=instance_relative_config,241            root_path=root_path,242        )243 244        #: The Click command group for registering CLI commands for this245        #: object. The commands are available from the ``flask`` command246        #: once the application has been discovered and blueprints have247        #: been registered.248        self.cli = cli.AppGroup()249 250        # Set the name of the Click group in case someone wants to add251        # the app's commands to another CLI tool.252        self.cli.name = self.name253 254        # Add a static route using the provided static_url_path, static_host,255        # and static_folder if there is a configured static_folder.256        # Note we do this without checking if static_folder exists.257        # For one, it might be created while the server is running (e.g. during258        # development). Also, Google App Engine stores static files somewhere259        if self.has_static_folder:260            assert (261                bool(static_host) == host_matching262            ), "Invalid static_host/host_matching combination"263            # Use a weakref to avoid creating a reference cycle between the app264            # and the view function (see #3761).265            self_ref = weakref.ref(self)266            self.add_url_rule(267                f"{self.static_url_path}/<path:filename>",268                endpoint="static",269                host=static_host,270                view_func=lambda **kw: self_ref().send_static_file(**kw),  # type: ignore # noqa: B950271            )272 273    def get_send_file_max_age(self, filename: str | None) -> int | None:274        """Used by :func:`send_file` to determine the ``max_age`` cache275        value for a given file path if it wasn't passed.276 277        By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from278        the configuration of :data:`~flask.current_app`. This defaults279        to ``None``, which tells the browser to use conditional requests280        instead of a timed cache, which is usually preferable.281 282        Note this is a duplicate of the same method in the Flask283        class.284 285        .. versionchanged:: 2.0286            The default configuration is ``None`` instead of 12 hours.287 288        .. versionadded:: 0.9289        """290        value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"]291 292        if value is None:293            return None294 295        if isinstance(value, timedelta):296            return int(value.total_seconds())297 298        return value  # type: ignore[no-any-return]299 300    def send_static_file(self, filename: str) -> Response:301        """The view function used to serve files from302        :attr:`static_folder`. A route is automatically registered for303        this view at :attr:`static_url_path` if :attr:`static_folder` is304        set.305 306        Note this is a duplicate of the same method in the Flask307        class.308 309        .. versionadded:: 0.5310 311        """312        if not self.has_static_folder:313            raise RuntimeError("'static_folder' must be set to serve static_files.")314 315        # send_file only knows to call get_send_file_max_age on the app,316        # call it here so it works for blueprints too.317        max_age = self.get_send_file_max_age(filename)318        return send_from_directory(319            t.cast(str, self.static_folder), filename, max_age=max_age320        )321 322    def open_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]:323        """Open a resource file relative to :attr:`root_path` for324        reading.325 326        For example, if the file ``schema.sql`` is next to the file327        ``app.py`` where the ``Flask`` app is defined, it can be opened328        with:329 330        .. code-block:: python331 332            with app.open_resource("schema.sql") as f:333                conn.executescript(f.read())334 335        :param resource: Path to the resource relative to336            :attr:`root_path`.337        :param mode: Open the file in this mode. Only reading is338            supported, valid values are "r" (or "rt") and "rb".339 340        Note this is a duplicate of the same method in the Flask341        class.342 343        """344        if mode not in {"r", "rt", "rb"}:345            raise ValueError("Resources can only be opened for reading.")346 347        return open(os.path.join(self.root_path, resource), mode)348 349    def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]:350        """Opens a resource from the application's instance folder351        (:attr:`instance_path`).  Otherwise works like352        :meth:`open_resource`.  Instance resources can also be opened for353        writing.354 355        :param resource: the name of the resource.  To access resources within356                         subfolders use forward slashes as separator.357        :param mode: resource file opening mode, default is 'rb'.358        """359        return open(os.path.join(self.instance_path, resource), mode)360 361    def create_jinja_environment(self) -> Environment:362        """Create the Jinja environment based on :attr:`jinja_options`363        and the various Jinja-related methods of the app. Changing364        :attr:`jinja_options` after this will have no effect. Also adds365        Flask-related globals and filters to the environment.366 367        .. versionchanged:: 0.11368           ``Environment.auto_reload`` set in accordance with369           ``TEMPLATES_AUTO_RELOAD`` configuration option.370 371        .. versionadded:: 0.5372        """373        options = dict(self.jinja_options)374 375        if "autoescape" not in options:376            options["autoescape"] = self.select_jinja_autoescape377 378        if "auto_reload" not in options:379            auto_reload = self.config["TEMPLATES_AUTO_RELOAD"]380 381            if auto_reload is None:382                auto_reload = self.debug383 384            options["auto_reload"] = auto_reload385 386        rv = self.jinja_environment(self, **options)387        rv.globals.update(388            url_for=self.url_for,389            get_flashed_messages=get_flashed_messages,390            config=self.config,391            # request, session and g are normally added with the392            # context processor for efficiency reasons but for imported393            # templates we also want the proxies in there.394            request=request,395            session=session,396            g=g,397        )398        rv.policies["json.dumps_function"] = self.json.dumps399        return rv400 401    def create_url_adapter(self, request: Request | None) -> MapAdapter | None:402        """Creates a URL adapter for the given request. The URL adapter403        is created at a point where the request context is not yet set404        up so the request is passed explicitly.405 406        .. versionadded:: 0.6407 408        .. versionchanged:: 0.9409           This can now also be called without a request object when the410           URL adapter is created for the application context.411 412        .. versionchanged:: 1.0413            :data:`SERVER_NAME` no longer implicitly enables subdomain414            matching. Use :attr:`subdomain_matching` instead.415        """416        if request is not None:417            # If subdomain matching is disabled (the default), use the418            # default subdomain in all cases. This should be the default419            # in Werkzeug but it currently does not have that feature.420            if not self.subdomain_matching:421                subdomain = self.url_map.default_subdomain or None422            else:423                subdomain = None424 425            return self.url_map.bind_to_environ(426                request.environ,427                server_name=self.config["SERVER_NAME"],428                subdomain=subdomain,429            )430        # We need at the very least the server name to be set for this431        # to work.432        if self.config["SERVER_NAME"] is not None:433            return self.url_map.bind(434                self.config["SERVER_NAME"],435                script_name=self.config["APPLICATION_ROOT"],436                url_scheme=self.config["PREFERRED_URL_SCHEME"],437            )438 439        return None440 441    def raise_routing_exception(self, request: Request) -> t.NoReturn:442        """Intercept routing exceptions and possibly do something else.443 444        In debug mode, intercept a routing redirect and replace it with445        an error if the body will be discarded.446 447        With modern Werkzeug this shouldn't occur, since it now uses a448        308 status which tells the browser to resend the method and449        body.450 451        .. versionchanged:: 2.1452            Don't intercept 307 and 308 redirects.453 454        :meta private:455        :internal:456        """457        if (458            not self.debug459            or not isinstance(request.routing_exception, RequestRedirect)460            or request.routing_exception.code in {307, 308}461            or request.method in {"GET", "HEAD", "OPTIONS"}462        ):463            raise request.routing_exception  # type: ignore[misc]464 465        from .debughelpers import FormDataRoutingRedirect466 467        raise FormDataRoutingRedirect(request)468 469    def update_template_context(self, context: dict[str, t.Any]) -> None:470        """Update the template context with some commonly used variables.471        This injects request, session, config and g into the template472        context as well as everything template context processors want473        to inject.  Note that the as of Flask 0.6, the original values474        in the context will not be overridden if a context processor475        decides to return a value with the same key.476 477        :param context: the context as a dictionary that is updated in place478                        to add extra variables.479        """480        names: t.Iterable[str | None] = (None,)481 482        # A template may be rendered outside a request context.483        if request:484            names = chain(names, reversed(request.blueprints))485 486        # The values passed to render_template take precedence. Keep a487        # copy to re-apply after all context functions.488        orig_ctx = context.copy()489 490        for name in names:491            if name in self.template_context_processors:492                for func in self.template_context_processors[name]:493                    context.update(self.ensure_sync(func)())494 495        context.update(orig_ctx)496 497    def make_shell_context(self) -> dict[str, t.Any]:498        """Returns the shell context for an interactive shell for this499        application.  This runs all the registered shell context500        processors.501 502        .. versionadded:: 0.11503        """504        rv = {"app": self, "g": g}505        for processor in self.shell_context_processors:506            rv.update(processor())507        return rv508 509    def run(510        self,511        host: str | None = None,512        port: int | None = None,513        debug: bool | None = None,514        load_dotenv: bool = True,515        **options: t.Any,516    ) -> None:517        """Runs the application on a local development server.518 519        Do not use ``run()`` in a production setting. It is not intended to520        meet security and performance requirements for a production server.521        Instead, see :doc:`/deploying/index` for WSGI server recommendations.522 523        If the :attr:`debug` flag is set the server will automatically reload524        for code changes and show a debugger in case an exception happened.525 526        If you want to run the application in debug mode, but disable the527        code execution on the interactive debugger, you can pass528        ``use_evalex=False`` as parameter.  This will keep the debugger's529        traceback screen active, but disable code execution.530 531        It is not recommended to use this function for development with532        automatic reloading as this is badly supported.  Instead you should533        be using the :command:`flask` command line script's ``run`` support.534 535        .. admonition:: Keep in Mind536 537           Flask will suppress any server error with a generic error page538           unless it is in debug mode.  As such to enable just the539           interactive debugger without the code reloading, you have to540           invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.541           Setting ``use_debugger`` to ``True`` without being in debug mode542           won't catch any exceptions because there won't be any to543           catch.544 545        :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to546            have the server available externally as well. Defaults to547            ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable548            if present.549        :param port: the port of the webserver. Defaults to ``5000`` or the550            port defined in the ``SERVER_NAME`` config variable if present.551        :param debug: if given, enable or disable debug mode. See552            :attr:`debug`.553        :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`554            files to set environment variables. Will also change the working555            directory to the directory containing the first file found.556        :param options: the options to be forwarded to the underlying Werkzeug557            server. See :func:`werkzeug.serving.run_simple` for more558            information.559 560        .. versionchanged:: 1.0561            If installed, python-dotenv will be used to load environment562            variables from :file:`.env` and :file:`.flaskenv` files.563 564            The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`.565 566            Threaded mode is enabled by default.567 568        .. versionchanged:: 0.10569            The default port is now picked from the ``SERVER_NAME``570            variable.571        """572        # Ignore this call so that it doesn't start another server if573        # the 'flask run' command is used.574        if os.environ.get("FLASK_RUN_FROM_CLI") == "true":575            if not is_running_from_reloader():576                click.secho(577                    " * Ignoring a call to 'app.run()' that would block"578                    " the current 'flask' CLI command.\n"579                    "   Only call 'app.run()' in an 'if __name__ =="580                    ' "__main__"\' guard.',581                    fg="red",582                )583 584            return585 586        if get_load_dotenv(load_dotenv):587            cli.load_dotenv()588 589            # if set, env var overrides existing value590            if "FLASK_DEBUG" in os.environ:591                self.debug = get_debug_flag()592 593        # debug passed to method overrides all other sources594        if debug is not None:595            self.debug = bool(debug)596 597        server_name = self.config.get("SERVER_NAME")598        sn_host = sn_port = None599 600        if server_name:601            sn_host, _, sn_port = server_name.partition(":")602 603        if not host:604            if sn_host:605                host = sn_host606            else:607                host = "127.0.0.1"608 609        if port or port == 0:610            port = int(port)611        elif sn_port:612            port = int(sn_port)613        else:614            port = 5000615 616        options.setdefault("use_reloader", self.debug)617        options.setdefault("use_debugger", self.debug)618        options.setdefault("threaded", True)619 620        cli.show_server_banner(self.debug, self.name)621 622        from werkzeug.serving import run_simple623 624        try:625            run_simple(t.cast(str, host), port, self, **options)626        finally:627            # reset the first request information if the development server628            # reset normally.  This makes it possible to restart the server629            # without reloader and that stuff from an interactive shell.630            self._got_first_request = False631 632    def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient:633        """Creates a test client for this application.  For information634        about unit testing head over to :doc:`/testing`.635 636        Note that if you are testing for assertions or exceptions in your637        application code, you must set ``app.testing = True`` in order for the638        exceptions to propagate to the test client.  Otherwise, the exception639        will be handled by the application (not visible to the test client) and640        the only indication of an AssertionError or other exception will be a641        500 status code response to the test client.  See the :attr:`testing`642        attribute.  For example::643 644            app.testing = True645            client = app.test_client()646 647        The test client can be used in a ``with`` block to defer the closing down648        of the context until the end of the ``with`` block.  This is useful if649        you want to access the context locals for testing::650 651            with app.test_client() as c:652                rv = c.get('/?vodka=42')653                assert request.args['vodka'] == '42'654 655        Additionally, you may pass optional keyword arguments that will then656        be passed to the application's :attr:`test_client_class` constructor.657        For example::658 659            from flask.testing import FlaskClient660 661            class CustomClient(FlaskClient):662                def __init__(self, *args, **kwargs):663                    self._authentication = kwargs.pop("authentication")664                    super(CustomClient,self).__init__( *args, **kwargs)665 666            app.test_client_class = CustomClient667            client = app.test_client(authentication='Basic ....')668 669        See :class:`~flask.testing.FlaskClient` for more information.670 671        .. versionchanged:: 0.4672           added support for ``with`` block usage for the client.673 674        .. versionadded:: 0.7675           The `use_cookies` parameter was added as well as the ability676           to override the client to be used by setting the677           :attr:`test_client_class` attribute.678 679        .. versionchanged:: 0.11680           Added `**kwargs` to support passing additional keyword arguments to681           the constructor of :attr:`test_client_class`.682        """683        cls = self.test_client_class684        if cls is None:685            from .testing import FlaskClient as cls686        return cls(  # type: ignore687            self, self.response_class, use_cookies=use_cookies, **kwargs688        )689 690    def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner:691        """Create a CLI runner for testing CLI commands.692        See :ref:`testing-cli`.693 694        Returns an instance of :attr:`test_cli_runner_class`, by default695        :class:`~flask.testing.FlaskCliRunner`. The Flask app object is696        passed as the first argument.697 698        .. versionadded:: 1.0699        """700        cls = self.test_cli_runner_class701 702        if cls is None:703            from .testing import FlaskCliRunner as cls704 705        return cls(self, **kwargs)  # type: ignore706 707    def handle_http_exception(708        self, e: HTTPException709    ) -> HTTPException | ft.ResponseReturnValue:710        """Handles an HTTP exception.  By default this will invoke the711        registered error handlers and fall back to returning the712        exception as response.713 714        .. versionchanged:: 1.0.3715            ``RoutingException``, used internally for actions such as716             slash redirects during routing, is not passed to error717             handlers.718 719        .. versionchanged:: 1.0720            Exceptions are looked up by code *and* by MRO, so721            ``HTTPException`` subclasses can be handled with a catch-all722            handler for the base ``HTTPException``.723 724        .. versionadded:: 0.3725        """726        # Proxy exceptions don't have error codes.  We want to always return727        # those unchanged as errors728        if e.code is None:729            return e730 731        # RoutingExceptions are used internally to trigger routing732        # actions, such as slash redirects raising RequestRedirect. They733        # are not raised or handled in user code.734        if isinstance(e, RoutingException):735            return e736 737        handler = self._find_error_handler(e, request.blueprints)738        if handler is None:739            return e740        return self.ensure_sync(handler)(e)  # type: ignore[no-any-return]741 742    def handle_user_exception(743        self, e: Exception744    ) -> HTTPException | ft.ResponseReturnValue:745        """This method is called whenever an exception occurs that746        should be handled. A special case is :class:`~werkzeug747        .exceptions.HTTPException` which is forwarded to the748        :meth:`handle_http_exception` method. This function will either749        return a response value or reraise the exception with the same750        traceback.751 752        .. versionchanged:: 1.0753            Key errors raised from request data like ``form`` show the754            bad key in debug mode rather than a generic bad request755            message.756 757        .. versionadded:: 0.7758        """759        if isinstance(e, BadRequestKeyError) and (760            self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]761        ):762            e.show_exception = True763 764        if isinstance(e, HTTPException) and not self.trap_http_exception(e):765            return self.handle_http_exception(e)766 767        handler = self._find_error_handler(e, request.blueprints)768 769        if handler is None:770            raise771 772        return self.ensure_sync(handler)(e)  # type: ignore[no-any-return]773 774    def handle_exception(self, e: Exception) -> Response:775        """Handle an exception that did not have an error handler776        associated with it, or that was raised from an error handler.777        This always causes a 500 ``InternalServerError``.778 779        Always sends the :data:`got_request_exception` signal.780 781        If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug782        mode, the error will be re-raised so that the debugger can783        display it. Otherwise, the original exception is logged, and784        an :exc:`~werkzeug.exceptions.InternalServerError` is returned.785 786        If an error handler is registered for ``InternalServerError`` or787        ``500``, it will be used. For consistency, the handler will788        always receive the ``InternalServerError``. The original789        unhandled exception is available as ``e.original_exception``.790 791        .. versionchanged:: 1.1.0792            Always passes the ``InternalServerError`` instance to the793            handler, setting ``original_exception`` to the unhandled794            error.795 796        .. versionchanged:: 1.1.0797            ``after_request`` functions and other finalization is done798            even for the default 500 response when there is no handler.799 800        .. versionadded:: 0.3801        """802        exc_info = sys.exc_info()803        got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e)804        propagate = self.config["PROPAGATE_EXCEPTIONS"]805 806        if propagate is None:807            propagate = self.testing or self.debug808 809        if propagate:810            # Re-raise if called with an active exception, otherwise811            # raise the passed in exception.812            if exc_info[1] is e:813                raise814 815            raise e816 817        self.log_exception(exc_info)818        server_error: InternalServerError | ft.ResponseReturnValue819        server_error = InternalServerError(original_exception=e)820        handler = self._find_error_handler(server_error, request.blueprints)821 822        if handler is not None:823            server_error = self.ensure_sync(handler)(server_error)824 825        return self.finalize_request(server_error, from_error_handler=True)826 827    def log_exception(828        self,829        exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]),830    ) -> None:831        """Logs an exception.  This is called by :meth:`handle_exception`832        if debugging is disabled and right before the handler is called.833        The default implementation logs the exception as error on the834        :attr:`logger`.835 836        .. versionadded:: 0.8837        """838        self.logger.error(839            f"Exception on {request.path} [{request.method}]", exc_info=exc_info840        )841 842    def dispatch_request(self) -> ft.ResponseReturnValue:843        """Does the request dispatching.  Matches the URL and returns the844        return value of the view or error handler.  This does not have to845        be a response object.  In order to convert the return value to a846        proper response object, call :func:`make_response`.847 848        .. versionchanged:: 0.7849           This no longer does the exception handling, this code was850           moved to the new :meth:`full_dispatch_request`.851        """852        req = request_ctx.request853        if req.routing_exception is not None:854            self.raise_routing_exception(req)855        rule: Rule = req.url_rule  # type: ignore[assignment]856        # if we provide automatic options for this URL and the857        # request came with the OPTIONS method, reply automatically858        if (859            getattr(rule, "provide_automatic_options", False)860            and req.method == "OPTIONS"861        ):862            return self.make_default_options_response()863        # otherwise dispatch to the handler for that endpoint864        view_args: dict[str, t.Any] = req.view_args  # type: ignore[assignment]865        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]866 867    def full_dispatch_request(self) -> Response:868        """Dispatches the request and on top of that performs request869        pre and postprocessing as well as HTTP exception catching and870        error handling.871 872        .. versionadded:: 0.7873        """874        self._got_first_request = True875 876        try:877            request_started.send(self, _async_wrapper=self.ensure_sync)878            rv = self.preprocess_request()879            if rv is None:880                rv = self.dispatch_request()881        except Exception as e:882            rv = self.handle_user_exception(e)883        return self.finalize_request(rv)884 885    def finalize_request(886        self,887        rv: ft.ResponseReturnValue | HTTPException,888        from_error_handler: bool = False,889    ) -> Response:890        """Given the return value from a view function this finalizes891        the request by converting it into a response and invoking the892        postprocessing functions.  This is invoked for both normal893        request dispatching as well as error handlers.894 895        Because this means that it might be called as a result of a896        failure a special safe mode is available which can be enabled897        with the `from_error_handler` flag.  If enabled, failures in898        response processing will be logged and otherwise ignored.899 900        :internal:901        """902        response = self.make_response(rv)903        try:904            response = self.process_response(response)905            request_finished.send(906                self, _async_wrapper=self.ensure_sync, response=response907            )908        except Exception:909            if not from_error_handler:910                raise911            self.logger.exception(912                "Request finalizing failed with an error while handling an error"913            )914        return response915 916    def make_default_options_response(self) -> Response:917        """This method is called to create the default ``OPTIONS`` response.918        This can be changed through subclassing to change the default919        behavior of ``OPTIONS`` responses.920 921        .. versionadded:: 0.7922        """923        adapter = request_ctx.url_adapter924        methods = adapter.allowed_methods()  # type: ignore[union-attr]925        rv = self.response_class()926        rv.allow.update(methods)927        return rv928 929    def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:930        """Ensure that the function is synchronous for WSGI workers.931        Plain ``def`` functions are returned as-is. ``async def``932        functions are wrapped to run and wait for the response.933 934        Override this method to change how the app runs async views.935 936        .. versionadded:: 2.0937        """938        if iscoroutinefunction(func):939            return self.async_to_sync(func)940 941        return func942 943    def async_to_sync(944        self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]]945    ) -> t.Callable[..., t.Any]:946        """Return a sync function that will run the coroutine function.947 948        .. code-block:: python949 950            result = app.async_to_sync(func)(*args, **kwargs)951 952        Override this method to change how the app converts async code953        to be synchronously callable.954 955        .. versionadded:: 2.0956        """957        try:958            from asgiref.sync import async_to_sync as asgiref_async_to_sync959        except ImportError:960            raise RuntimeError(961                "Install Flask with the 'async' extra in order to use async views."962            ) from None963 964        return asgiref_async_to_sync(func)965 966    def url_for(967        self,968        /,969        endpoint: str,970        *,971        _anchor: str | None = None,972        _method: str | None = None,973        _scheme: str | None = None,974        _external: bool | None = None,975        **values: t.Any,976    ) -> str:977        """Generate a URL to the given endpoint with the given values.978 979        This is called by :func:`flask.url_for`, and can be called980        directly as well.981 982        An *endpoint* is the name of a URL rule, usually added with983        :meth:`@app.route() <route>`, and usually the same name as the984        view function. A route defined in a :class:`~flask.Blueprint`985        will prepend the blueprint's name separated by a ``.`` to the986        endpoint.987 988        In some cases, such as email messages, you want URLs to include989        the scheme and domain, like ``https://example.com/hello``. When990        not in an active request, URLs will be external by default, but991        this requires setting :data:`SERVER_NAME` so Flask knows what992        domain to use. :data:`APPLICATION_ROOT` and993        :data:`PREFERRED_URL_SCHEME` should also be configured as994        needed. This config is only used when not in an active request.995 996        Functions can be decorated with :meth:`url_defaults` to modify997        keyword arguments before the URL is built.998 999        If building fails for some reason, such as an unknown endpoint1000        or incorrect values, the app's :meth:`handle_url_build_error`1001        method is called. If that returns a string, that is returned,1002        otherwise a :exc:`~werkzeug.routing.BuildError` is raised.1003 1004        :param endpoint: The endpoint name associated with the URL to1005            generate. If this starts with a ``.``, the current blueprint1006            name (if any) will be used.1007        :param _anchor: If given, append this as ``#anchor`` to the URL.1008        :param _method: If given, generate the URL associated with this1009            method for the endpoint.1010        :param _scheme: If given, the URL will have this scheme if it1011            is external.1012        :param _external: If given, prefer the URL to be internal1013            (False) or require it to be external (True). External URLs1014            include the scheme and domain. When not in an active1015            request, URLs are external by default.1016        :param values: Values to use for the variable parts of the URL1017            rule. Unknown keys are appended as query string arguments,1018            like ``?a=b&c=d``.1019 1020        .. versionadded:: 2.21021            Moved from ``flask.url_for``, which calls this method.1022        """1023        req_ctx = _cv_request.get(None)1024 1025        if req_ctx is not None:1026            url_adapter = req_ctx.url_adapter1027            blueprint_name = req_ctx.request.blueprint1028 1029            # If the endpoint starts with "." and the request matches a1030            # blueprint, the endpoint is relative to the blueprint.1031            if endpoint[:1] == ".":1032                if blueprint_name is not None:1033                    endpoint = f"{blueprint_name}{endpoint}"1034                else:1035                    endpoint = endpoint[1:]1036 1037            # When in a request, generate a URL without scheme and1038            # domain by default, unless a scheme is given.1039            if _external is None:1040                _external = _scheme is not None1041        else:1042            app_ctx = _cv_app.get(None)1043 1044            # If called by helpers.url_for, an app context is active,1045            # use its url_adapter. Otherwise, app.url_for was called1046            # directly, build an adapter.1047            if app_ctx is not None:1048                url_adapter = app_ctx.url_adapter1049            else:1050                url_adapter = self.create_url_adapter(None)1051 1052            if url_adapter is None:1053                raise RuntimeError(1054                    "Unable to build URLs outside an active request"1055                    " without 'SERVER_NAME' configured. Also configure"1056                    " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as"1057                    " needed."1058                )1059 1060            # When outside a request, generate a URL with scheme and1061            # domain by default.1062            if _external is None:1063                _external = True1064 1065        # It is an error to set _scheme when _external=False, in order1066        # to avoid accidental insecure URLs.1067        if _scheme is not None and not _external:1068            raise ValueError("When specifying '_scheme', '_external' must be True.")1069 1070        self.inject_url_defaults(endpoint, values)1071 1072        try:1073            rv = url_adapter.build(  # type: ignore[union-attr]1074                endpoint,1075                values,1076                method=_method,1077                url_scheme=_scheme,1078                force_external=_external,1079            )1080        except BuildError as error:1081            values.update(1082                _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external1083            )1084            return self.handle_url_build_error(error, endpoint, values)1085 1086        if _anchor is not None:1087            _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@")1088            rv = f"{rv}#{_anchor}"1089 1090        return rv1091 1092    def make_response(self, rv: ft.ResponseReturnValue) -> Response:1093        """Convert the return value from a view function to an instance of1094        :attr:`response_class`.1095 1096        :param rv: the return value from the view function. The view function1097            must return a response. Returning ``None``, or the view ending1098            without returning, is not allowed. The following types are allowed1099            for ``view_rv``:1100 1101            ``str``1102                A response object is created with the string encoded to UTF-81103                as the body.1104 1105            ``bytes``1106                A response object is created with the bytes as the body.1107 1108            ``dict``1109                A dictionary that will be jsonify'd before being returned.1110 1111            ``list``1112                A list that will be jsonify'd before being returned.1113 1114            ``generator`` or ``iterator``1115                A generator that returns ``str`` or ``bytes`` to be1116                streamed as the response.1117 1118            ``tuple``1119                Either ``(body, status, headers)``, ``(body, status)``, or1120                ``(body, headers)``, where ``body`` is any of the other types1121                allowed here, ``status`` is a string or an integer, and1122                ``headers`` is a dictionary or a list of ``(key, value)``1123                tuples. If ``body`` is a :attr:`response_class` instance,1124                ``status`` overwrites the exiting value and ``headers`` are1125                extended.1126 1127            :attr:`response_class`1128                The object is returned unchanged.1129 1130            other :class:`~werkzeug.wrappers.Response` class1131                The object is coerced to :attr:`response_class`.1132 1133            :func:`callable`1134                The function is called as a WSGI application. The result is1135                used to create a response object.1136 1137        .. versionchanged:: 2.21138            A generator will be converted to a streaming response.1139            A list will be converted to a JSON response.1140 1141        .. versionchanged:: 1.11142            A dict will be converted to a JSON response.1143 1144        .. versionchanged:: 0.91145           Previously a tuple was interpreted as the arguments for the1146           response object.1147        """1148 1149        status = headers = None1150 1151        # unpack tuple returns1152        if isinstance(rv, tuple):1153            len_rv = len(rv)1154 1155            # a 3-tuple is unpacked directly1156            if len_rv == 3:1157                rv, status, headers = rv  # type: ignore[misc]1158            # decide if a 2-tuple has status or headers1159            elif len_rv == 2:1160                if isinstance(rv[1], (Headers, dict, tuple, list)):1161                    rv, headers = rv1162                else:1163                    rv, status = rv  # type: ignore[assignment,misc]1164            # other sized tuples are not allowed1165            else:1166                raise TypeError(1167                    "The view function did not return a valid response tuple."1168                    " The tuple must have the form (body, status, headers),"1169                    " (body, status), or (body, headers)."1170                )1171 1172        # the body must not be None1173        if rv is None:1174            raise TypeError(1175                f"The view function for {request.endpoint!r} did not"1176                " return a valid response. The function either returned"1177                " None or ended without a return statement."1178            )1179 1180        # make sure the body is an instance of the response class1181        if not isinstance(rv, self.response_class):1182            if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator):1183                # let the response class set the status and headers instead of1184                # waiting to do it manually, so that the class can handle any1185                # special logic1186                rv = self.response_class(1187                    rv,1188                    status=status,1189                    headers=headers,  # type: ignore[arg-type]1190                )1191                status = headers = None1192            elif isinstance(rv, (dict, list)):1193                rv = self.json.response(rv)1194            elif isinstance(rv, BaseResponse) or callable(rv):1195                # evaluate a WSGI callable, or coerce a different response1196                # class to the correct type1197                try:1198                    rv = self.response_class.force_type(1199                        rv,  # type: ignore[arg-type]1200                        request.environ,

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

codekingpro/portable-devtools · Team Ai