mirror of
				https://forge.chapril.org/tykayn/book_generator
				synced 2025-06-20 01:34:43 +02:00 
			
		
		
		
	⚡ - sauvegarde automatique de l'avancement du livre
This commit is contained in:
		
							parent
							
								
									de532abbb7
								
							
						
					
					
						commit
						375fbb3a7a
					
				
					 1814 changed files with 334236 additions and 0 deletions
				
			
		
							
								
								
									
										6
									
								
								venv/lib/python3.11/site-packages/flask/sansio/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								venv/lib/python3.11/site-packages/flask/sansio/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| # Sansio | ||||
| 
 | ||||
| This folder contains code that can be used by alternative Flask | ||||
| implementations, for example Quart. The code therefore cannot do any | ||||
| IO, nor be part of a likely IO path. Finally this code cannot use the | ||||
| Flask globals. | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										968
									
								
								venv/lib/python3.11/site-packages/flask/sansio/app.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										968
									
								
								venv/lib/python3.11/site-packages/flask/sansio/app.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,968 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import logging | ||||
| import os | ||||
| import sys | ||||
| import typing as t | ||||
| from datetime import timedelta | ||||
| from itertools import chain | ||||
| 
 | ||||
| from werkzeug.exceptions import Aborter | ||||
| from werkzeug.exceptions import BadRequest | ||||
| from werkzeug.exceptions import BadRequestKeyError | ||||
| from werkzeug.routing import BuildError | ||||
| from werkzeug.routing import Map | ||||
| from werkzeug.routing import Rule | ||||
| from werkzeug.sansio.response import Response | ||||
| from werkzeug.utils import cached_property | ||||
| from werkzeug.utils import redirect as _wz_redirect | ||||
| 
 | ||||
| from .. import typing as ft | ||||
| from ..config import Config | ||||
| from ..config import ConfigAttribute | ||||
| from ..ctx import _AppCtxGlobals | ||||
| from ..helpers import _split_blueprint_path | ||||
| from ..helpers import get_debug_flag | ||||
| from ..json.provider import DefaultJSONProvider | ||||
| from ..json.provider import JSONProvider | ||||
| from ..logging import create_logger | ||||
| from ..templating import DispatchingJinjaLoader | ||||
| from ..templating import Environment | ||||
| from .scaffold import _endpoint_from_view_func | ||||
| from .scaffold import find_package | ||||
| from .scaffold import Scaffold | ||||
| from .scaffold import setupmethod | ||||
| 
 | ||||
| if t.TYPE_CHECKING:  # pragma: no cover | ||||
|     from werkzeug.wrappers import Response as BaseResponse | ||||
| 
 | ||||
|     from ..testing import FlaskClient | ||||
|     from ..testing import FlaskCliRunner | ||||
|     from .blueprints import Blueprint | ||||
| 
 | ||||
| T_shell_context_processor = t.TypeVar( | ||||
|     "T_shell_context_processor", bound=ft.ShellContextProcessorCallable | ||||
| ) | ||||
| T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) | ||||
| T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) | ||||
| T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) | ||||
| T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) | ||||
| 
 | ||||
| 
 | ||||
| def _make_timedelta(value: timedelta | int | None) -> timedelta | None: | ||||
|     if value is None or isinstance(value, timedelta): | ||||
|         return value | ||||
| 
 | ||||
|     return timedelta(seconds=value) | ||||
| 
 | ||||
| 
 | ||||
| class App(Scaffold): | ||||
|     """The flask object implements a WSGI application and acts as the central | ||||
|     object.  It is passed the name of the module or package of the | ||||
|     application.  Once it is created it will act as a central registry for | ||||
|     the view functions, the URL rules, template configuration and much more. | ||||
| 
 | ||||
|     The name of the package is used to resolve resources from inside the | ||||
|     package or the folder the module is contained in depending on if the | ||||
|     package parameter resolves to an actual python package (a folder with | ||||
|     an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). | ||||
| 
 | ||||
|     For more information about resource loading, see :func:`open_resource`. | ||||
| 
 | ||||
|     Usually you create a :class:`Flask` instance in your main module or | ||||
|     in the :file:`__init__.py` file of your package like this:: | ||||
| 
 | ||||
|         from flask import Flask | ||||
|         app = Flask(__name__) | ||||
| 
 | ||||
|     .. admonition:: About the First Parameter | ||||
| 
 | ||||
|         The idea of the first parameter is to give Flask an idea of what | ||||
|         belongs to your application.  This name is used to find resources | ||||
|         on the filesystem, can be used by extensions to improve debugging | ||||
|         information and a lot more. | ||||
| 
 | ||||
|         So it's important what you provide there.  If you are using a single | ||||
|         module, `__name__` is always the correct value.  If you however are | ||||
|         using a package, it's usually recommended to hardcode the name of | ||||
|         your package there. | ||||
| 
 | ||||
|         For example if your application is defined in :file:`yourapplication/app.py` | ||||
|         you should create it with one of the two versions below:: | ||||
| 
 | ||||
|             app = Flask('yourapplication') | ||||
|             app = Flask(__name__.split('.')[0]) | ||||
| 
 | ||||
|         Why is that?  The application will work even with `__name__`, thanks | ||||
|         to how resources are looked up.  However it will make debugging more | ||||
|         painful.  Certain extensions can make assumptions based on the | ||||
|         import name of your application.  For example the Flask-SQLAlchemy | ||||
|         extension will look for the code in your application that triggered | ||||
|         an SQL query in debug mode.  If the import name is not properly set | ||||
|         up, that debugging information is lost.  (For example it would only | ||||
|         pick up SQL queries in `yourapplication.app` and not | ||||
|         `yourapplication.views.frontend`) | ||||
| 
 | ||||
|     .. versionadded:: 0.7 | ||||
|        The `static_url_path`, `static_folder`, and `template_folder` | ||||
|        parameters were added. | ||||
| 
 | ||||
|     .. versionadded:: 0.8 | ||||
|        The `instance_path` and `instance_relative_config` parameters were | ||||
|        added. | ||||
| 
 | ||||
|     .. versionadded:: 0.11 | ||||
|        The `root_path` parameter was added. | ||||
| 
 | ||||
|     .. versionadded:: 1.0 | ||||
|        The ``host_matching`` and ``static_host`` parameters were added. | ||||
| 
 | ||||
|     .. versionadded:: 1.0 | ||||
|        The ``subdomain_matching`` parameter was added. Subdomain | ||||
|        matching needs to be enabled manually now. Setting | ||||
|        :data:`SERVER_NAME` does not implicitly enable it. | ||||
| 
 | ||||
|     :param import_name: the name of the application package | ||||
|     :param static_url_path: can be used to specify a different path for the | ||||
|                             static files on the web.  Defaults to the name | ||||
|                             of the `static_folder` folder. | ||||
|     :param static_folder: The folder with static files that is served at | ||||
|         ``static_url_path``. Relative to the application ``root_path`` | ||||
|         or an absolute path. Defaults to ``'static'``. | ||||
|     :param static_host: the host to use when adding the static route. | ||||
|         Defaults to None. Required when using ``host_matching=True`` | ||||
|         with a ``static_folder`` configured. | ||||
|     :param host_matching: set ``url_map.host_matching`` attribute. | ||||
|         Defaults to False. | ||||
|     :param subdomain_matching: consider the subdomain relative to | ||||
|         :data:`SERVER_NAME` when matching routes. Defaults to False. | ||||
|     :param template_folder: the folder that contains the templates that should | ||||
|                             be used by the application.  Defaults to | ||||
|                             ``'templates'`` folder in the root path of the | ||||
|                             application. | ||||
|     :param instance_path: An alternative instance path for the application. | ||||
|                           By default the folder ``'instance'`` next to the | ||||
|                           package or module is assumed to be the instance | ||||
|                           path. | ||||
|     :param instance_relative_config: if set to ``True`` relative filenames | ||||
|                                      for loading the config are assumed to | ||||
|                                      be relative to the instance path instead | ||||
|                                      of the application root. | ||||
|     :param root_path: The path to the root of the application files. | ||||
|         This should only be set manually when it can't be detected | ||||
|         automatically, such as for namespace packages. | ||||
|     """ | ||||
| 
 | ||||
|     #: The class of the object assigned to :attr:`aborter`, created by | ||||
|     #: :meth:`create_aborter`. That object is called by | ||||
|     #: :func:`flask.abort` to raise HTTP errors, and can be | ||||
|     #: called directly as well. | ||||
|     #: | ||||
|     #: Defaults to :class:`werkzeug.exceptions.Aborter`. | ||||
|     #: | ||||
|     #: .. versionadded:: 2.2 | ||||
|     aborter_class = Aborter | ||||
| 
 | ||||
|     #: The class that is used for the Jinja environment. | ||||
|     #: | ||||
|     #: .. versionadded:: 0.11 | ||||
|     jinja_environment = Environment | ||||
| 
 | ||||
|     #: The class that is used for the :data:`~flask.g` instance. | ||||
|     #: | ||||
|     #: Example use cases for a custom class: | ||||
|     #: | ||||
|     #: 1. Store arbitrary attributes on flask.g. | ||||
|     #: 2. Add a property for lazy per-request database connectors. | ||||
|     #: 3. Return None instead of AttributeError on unexpected attributes. | ||||
|     #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. | ||||
|     #: | ||||
|     #: In Flask 0.9 this property was called `request_globals_class` but it | ||||
|     #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the | ||||
|     #: flask.g object is now application context scoped. | ||||
|     #: | ||||
|     #: .. versionadded:: 0.10 | ||||
|     app_ctx_globals_class = _AppCtxGlobals | ||||
| 
 | ||||
|     #: The class that is used for the ``config`` attribute of this app. | ||||
|     #: Defaults to :class:`~flask.Config`. | ||||
|     #: | ||||
|     #: Example use cases for a custom class: | ||||
|     #: | ||||
|     #: 1. Default values for certain config options. | ||||
|     #: 2. Access to config values through attributes in addition to keys. | ||||
|     #: | ||||
|     #: .. versionadded:: 0.11 | ||||
|     config_class = Config | ||||
| 
 | ||||
|     #: The testing flag.  Set this to ``True`` to enable the test mode of | ||||
|     #: Flask extensions (and in the future probably also Flask itself). | ||||
|     #: For example this might activate test helpers that have an | ||||
|     #: additional runtime cost which should not be enabled by default. | ||||
|     #: | ||||
|     #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the | ||||
|     #: default it's implicitly enabled. | ||||
|     #: | ||||
|     #: This attribute can also be configured from the config with the | ||||
|     #: ``TESTING`` configuration key.  Defaults to ``False``. | ||||
|     testing = ConfigAttribute[bool]("TESTING") | ||||
| 
 | ||||
|     #: If a secret key is set, cryptographic components can use this to | ||||
|     #: sign cookies and other things. Set this to a complex random value | ||||
|     #: when you want to use the secure cookie for instance. | ||||
|     #: | ||||
|     #: This attribute can also be configured from the config with the | ||||
|     #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. | ||||
|     secret_key = ConfigAttribute[t.Union[str, bytes, None]]("SECRET_KEY") | ||||
| 
 | ||||
|     #: A :class:`~datetime.timedelta` which is used to set the expiration | ||||
|     #: date of a permanent session.  The default is 31 days which makes a | ||||
|     #: permanent session survive for roughly one month. | ||||
|     #: | ||||
|     #: This attribute can also be configured from the config with the | ||||
|     #: ``PERMANENT_SESSION_LIFETIME`` configuration key.  Defaults to | ||||
|     #: ``timedelta(days=31)`` | ||||
|     permanent_session_lifetime = ConfigAttribute[timedelta]( | ||||
|         "PERMANENT_SESSION_LIFETIME", | ||||
|         get_converter=_make_timedelta,  # type: ignore[arg-type] | ||||
|     ) | ||||
| 
 | ||||
|     json_provider_class: type[JSONProvider] = DefaultJSONProvider | ||||
|     """A subclass of :class:`~flask.json.provider.JSONProvider`. An | ||||
|     instance is created and assigned to :attr:`app.json` when creating | ||||
|     the app. | ||||
| 
 | ||||
|     The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses | ||||
|     Python's built-in :mod:`json` library. A different provider can use | ||||
|     a different JSON library. | ||||
| 
 | ||||
|     .. versionadded:: 2.2 | ||||
|     """ | ||||
| 
 | ||||
|     #: Options that are passed to the Jinja environment in | ||||
|     #: :meth:`create_jinja_environment`. Changing these options after | ||||
|     #: the environment is created (accessing :attr:`jinja_env`) will | ||||
|     #: have no effect. | ||||
|     #: | ||||
|     #: .. versionchanged:: 1.1.0 | ||||
|     #:     This is a ``dict`` instead of an ``ImmutableDict`` to allow | ||||
|     #:     easier configuration. | ||||
|     #: | ||||
|     jinja_options: dict[str, t.Any] = {} | ||||
| 
 | ||||
|     #: The rule object to use for URL rules created.  This is used by | ||||
|     #: :meth:`add_url_rule`.  Defaults to :class:`werkzeug.routing.Rule`. | ||||
|     #: | ||||
|     #: .. versionadded:: 0.7 | ||||
|     url_rule_class = Rule | ||||
| 
 | ||||
|     #: The map object to use for storing the URL rules and routing | ||||
|     #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. | ||||
|     #: | ||||
|     #: .. versionadded:: 1.1.0 | ||||
|     url_map_class = Map | ||||
| 
 | ||||
|     #: The :meth:`test_client` method creates an instance of this test | ||||
|     #: client class. Defaults to :class:`~flask.testing.FlaskClient`. | ||||
|     #: | ||||
|     #: .. versionadded:: 0.7 | ||||
|     test_client_class: type[FlaskClient] | None = None | ||||
| 
 | ||||
|     #: The :class:`~click.testing.CliRunner` subclass, by default | ||||
|     #: :class:`~flask.testing.FlaskCliRunner` that is used by | ||||
|     #: :meth:`test_cli_runner`. Its ``__init__`` method should take a | ||||
|     #: Flask app object as the first argument. | ||||
|     #: | ||||
|     #: .. versionadded:: 1.0 | ||||
|     test_cli_runner_class: type[FlaskCliRunner] | None = None | ||||
| 
 | ||||
|     default_config: dict[str, t.Any] | ||||
|     response_class: type[Response] | ||||
| 
 | ||||
|     def __init__( | ||||
|         self, | ||||
|         import_name: str, | ||||
|         static_url_path: str | None = None, | ||||
|         static_folder: str | os.PathLike[str] | None = "static", | ||||
|         static_host: str | None = None, | ||||
|         host_matching: bool = False, | ||||
|         subdomain_matching: bool = False, | ||||
|         template_folder: str | os.PathLike[str] | None = "templates", | ||||
|         instance_path: str | None = None, | ||||
|         instance_relative_config: bool = False, | ||||
|         root_path: str | None = None, | ||||
|     ): | ||||
|         super().__init__( | ||||
|             import_name=import_name, | ||||
|             static_folder=static_folder, | ||||
|             static_url_path=static_url_path, | ||||
|             template_folder=template_folder, | ||||
|             root_path=root_path, | ||||
|         ) | ||||
| 
 | ||||
|         if instance_path is None: | ||||
|             instance_path = self.auto_find_instance_path() | ||||
|         elif not os.path.isabs(instance_path): | ||||
|             raise ValueError( | ||||
|                 "If an instance path is provided it must be absolute." | ||||
|                 " A relative path was given instead." | ||||
|             ) | ||||
| 
 | ||||
|         #: Holds the path to the instance folder. | ||||
|         #: | ||||
|         #: .. versionadded:: 0.8 | ||||
|         self.instance_path = instance_path | ||||
| 
 | ||||
|         #: The configuration dictionary as :class:`Config`.  This behaves | ||||
|         #: exactly like a regular dictionary but supports additional methods | ||||
|         #: to load a config from files. | ||||
|         self.config = self.make_config(instance_relative_config) | ||||
| 
 | ||||
|         #: An instance of :attr:`aborter_class` created by | ||||
|         #: :meth:`make_aborter`. This is called by :func:`flask.abort` | ||||
|         #: to raise HTTP errors, and can be called directly as well. | ||||
|         #: | ||||
|         #: .. versionadded:: 2.2 | ||||
|         #:     Moved from ``flask.abort``, which calls this object. | ||||
|         self.aborter = self.make_aborter() | ||||
| 
 | ||||
|         self.json: JSONProvider = self.json_provider_class(self) | ||||
|         """Provides access to JSON methods. Functions in ``flask.json`` | ||||
|         will call methods on this provider when the application context | ||||
|         is active. Used for handling JSON requests and responses. | ||||
| 
 | ||||
|         An instance of :attr:`json_provider_class`. Can be customized by | ||||
|         changing that attribute on a subclass, or by assigning to this | ||||
|         attribute afterwards. | ||||
| 
 | ||||
|         The default, :class:`~flask.json.provider.DefaultJSONProvider`, | ||||
|         uses Python's built-in :mod:`json` library. A different provider | ||||
|         can use a different JSON library. | ||||
| 
 | ||||
|         .. versionadded:: 2.2 | ||||
|         """ | ||||
| 
 | ||||
|         #: A list of functions that are called by | ||||
|         #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a | ||||
|         #: :exc:`~werkzeug.routing.BuildError`. Each function is called | ||||
|         #: with ``error``, ``endpoint`` and ``values``. If a function | ||||
|         #: returns ``None`` or raises a ``BuildError``, it is skipped. | ||||
|         #: Otherwise, its return value is returned by ``url_for``. | ||||
|         #: | ||||
|         #: .. versionadded:: 0.9 | ||||
|         self.url_build_error_handlers: list[ | ||||
|             t.Callable[[Exception, str, dict[str, t.Any]], str] | ||||
|         ] = [] | ||||
| 
 | ||||
|         #: A list of functions that are called when the application context | ||||
|         #: is destroyed.  Since the application context is also torn down | ||||
|         #: if the request ends this is the place to store code that disconnects | ||||
|         #: from databases. | ||||
|         #: | ||||
|         #: .. versionadded:: 0.9 | ||||
|         self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] | ||||
| 
 | ||||
|         #: A list of shell context processor functions that should be run | ||||
|         #: when a shell context is created. | ||||
|         #: | ||||
|         #: .. versionadded:: 0.11 | ||||
|         self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] | ||||
| 
 | ||||
|         #: Maps registered blueprint names to blueprint objects. The | ||||
|         #: dict retains the order the blueprints were registered in. | ||||
|         #: Blueprints can be registered multiple times, this dict does | ||||
|         #: not track how often they were attached. | ||||
|         #: | ||||
|         #: .. versionadded:: 0.7 | ||||
|         self.blueprints: dict[str, Blueprint] = {} | ||||
| 
 | ||||
|         #: a place where extensions can store application specific state.  For | ||||
|         #: example this is where an extension could store database engines and | ||||
|         #: similar things. | ||||
|         #: | ||||
|         #: The key must match the name of the extension module. For example in | ||||
|         #: case of a "Flask-Foo" extension in `flask_foo`, the key would be | ||||
|         #: ``'foo'``. | ||||
|         #: | ||||
|         #: .. versionadded:: 0.7 | ||||
|         self.extensions: dict[str, t.Any] = {} | ||||
| 
 | ||||
|         #: The :class:`~werkzeug.routing.Map` for this instance.  You can use | ||||
|         #: this to change the routing converters after the class was created | ||||
|         #: but before any routes are connected.  Example:: | ||||
|         #: | ||||
|         #:    from werkzeug.routing import BaseConverter | ||||
|         #: | ||||
|         #:    class ListConverter(BaseConverter): | ||||
|         #:        def to_python(self, value): | ||||
|         #:            return value.split(',') | ||||
|         #:        def to_url(self, values): | ||||
|         #:            return ','.join(super(ListConverter, self).to_url(value) | ||||
|         #:                            for value in values) | ||||
|         #: | ||||
|         #:    app = Flask(__name__) | ||||
|         #:    app.url_map.converters['list'] = ListConverter | ||||
|         self.url_map = self.url_map_class(host_matching=host_matching) | ||||
| 
 | ||||
|         self.subdomain_matching = subdomain_matching | ||||
| 
 | ||||
|         # tracks internally if the application already handled at least one | ||||
|         # request. | ||||
|         self._got_first_request = False | ||||
| 
 | ||||
|         # Set the name of the Click group in case someone wants to add | ||||
|         # the app's commands to another CLI tool. | ||||
|         self.cli.name = self.name | ||||
| 
 | ||||
|     def _check_setup_finished(self, f_name: str) -> None: | ||||
|         if self._got_first_request: | ||||
|             raise AssertionError( | ||||
|                 f"The setup method '{f_name}' can no longer be called" | ||||
|                 " on the application. It has already handled its first" | ||||
|                 " request, any changes will not be applied" | ||||
|                 " consistently.\n" | ||||
|                 "Make sure all imports, decorators, functions, etc." | ||||
|                 " needed to set up the application are done before" | ||||
|                 " running it." | ||||
|             ) | ||||
| 
 | ||||
|     @cached_property | ||||
|     def name(self) -> str:  # type: ignore | ||||
|         """The name of the application.  This is usually the import name | ||||
|         with the difference that it's guessed from the run file if the | ||||
|         import name is main.  This name is used as a display name when | ||||
|         Flask needs the name of the application.  It can be set and overridden | ||||
|         to change the value. | ||||
| 
 | ||||
|         .. versionadded:: 0.8 | ||||
|         """ | ||||
|         if self.import_name == "__main__": | ||||
|             fn: str | None = getattr(sys.modules["__main__"], "__file__", None) | ||||
|             if fn is None: | ||||
|                 return "__main__" | ||||
|             return os.path.splitext(os.path.basename(fn))[0] | ||||
|         return self.import_name | ||||
| 
 | ||||
|     @cached_property | ||||
|     def logger(self) -> logging.Logger: | ||||
|         """A standard Python :class:`~logging.Logger` for the app, with | ||||
|         the same name as :attr:`name`. | ||||
| 
 | ||||
|         In debug mode, the logger's :attr:`~logging.Logger.level` will | ||||
|         be set to :data:`~logging.DEBUG`. | ||||
| 
 | ||||
|         If there are no handlers configured, a default handler will be | ||||
|         added. See :doc:`/logging` for more information. | ||||
| 
 | ||||
|         .. versionchanged:: 1.1.0 | ||||
|             The logger takes the same name as :attr:`name` rather than | ||||
|             hard-coding ``"flask.app"``. | ||||
| 
 | ||||
|         .. versionchanged:: 1.0.0 | ||||
|             Behavior was simplified. The logger is always named | ||||
|             ``"flask.app"``. The level is only set during configuration, | ||||
|             it doesn't check ``app.debug`` each time. Only one format is | ||||
|             used, not different ones depending on ``app.debug``. No | ||||
|             handlers are removed, and a handler is only added if no | ||||
|             handlers are already configured. | ||||
| 
 | ||||
|         .. versionadded:: 0.3 | ||||
|         """ | ||||
|         return create_logger(self) | ||||
| 
 | ||||
|     @cached_property | ||||
|     def jinja_env(self) -> Environment: | ||||
|         """The Jinja environment used to load templates. | ||||
| 
 | ||||
|         The environment is created the first time this property is | ||||
|         accessed. Changing :attr:`jinja_options` after that will have no | ||||
|         effect. | ||||
|         """ | ||||
|         return self.create_jinja_environment() | ||||
| 
 | ||||
|     def create_jinja_environment(self) -> Environment: | ||||
|         raise NotImplementedError() | ||||
| 
 | ||||
|     def make_config(self, instance_relative: bool = False) -> Config: | ||||
|         """Used to create the config attribute by the Flask constructor. | ||||
|         The `instance_relative` parameter is passed in from the constructor | ||||
|         of Flask (there named `instance_relative_config`) and indicates if | ||||
|         the config should be relative to the instance path or the root path | ||||
|         of the application. | ||||
| 
 | ||||
|         .. versionadded:: 0.8 | ||||
|         """ | ||||
|         root_path = self.root_path | ||||
|         if instance_relative: | ||||
|             root_path = self.instance_path | ||||
|         defaults = dict(self.default_config) | ||||
|         defaults["DEBUG"] = get_debug_flag() | ||||
|         return self.config_class(root_path, defaults) | ||||
| 
 | ||||
|     def make_aborter(self) -> Aborter: | ||||
|         """Create the object to assign to :attr:`aborter`. That object | ||||
|         is called by :func:`flask.abort` to raise HTTP errors, and can | ||||
|         be called directly as well. | ||||
| 
 | ||||
|         By default, this creates an instance of :attr:`aborter_class`, | ||||
|         which defaults to :class:`werkzeug.exceptions.Aborter`. | ||||
| 
 | ||||
|         .. versionadded:: 2.2 | ||||
|         """ | ||||
|         return self.aborter_class() | ||||
| 
 | ||||
|     def auto_find_instance_path(self) -> str: | ||||
|         """Tries to locate the instance path if it was not provided to the | ||||
|         constructor of the application class.  It will basically calculate | ||||
|         the path to a folder named ``instance`` next to your main file or | ||||
|         the package. | ||||
| 
 | ||||
|         .. versionadded:: 0.8 | ||||
|         """ | ||||
|         prefix, package_path = find_package(self.import_name) | ||||
|         if prefix is None: | ||||
|             return os.path.join(package_path, "instance") | ||||
|         return os.path.join(prefix, "var", f"{self.name}-instance") | ||||
| 
 | ||||
|     def create_global_jinja_loader(self) -> DispatchingJinjaLoader: | ||||
|         """Creates the loader for the Jinja2 environment.  Can be used to | ||||
|         override just the loader and keeping the rest unchanged.  It's | ||||
|         discouraged to override this function.  Instead one should override | ||||
|         the :meth:`jinja_loader` function instead. | ||||
| 
 | ||||
|         The global loader dispatches between the loaders of the application | ||||
|         and the individual blueprints. | ||||
| 
 | ||||
|         .. versionadded:: 0.7 | ||||
|         """ | ||||
|         return DispatchingJinjaLoader(self) | ||||
| 
 | ||||
|     def select_jinja_autoescape(self, filename: str) -> bool: | ||||
|         """Returns ``True`` if autoescaping should be active for the given | ||||
|         template name. If no template name is given, returns `True`. | ||||
| 
 | ||||
|         .. versionchanged:: 2.2 | ||||
|             Autoescaping is now enabled by default for ``.svg`` files. | ||||
| 
 | ||||
|         .. versionadded:: 0.5 | ||||
|         """ | ||||
|         if filename is None: | ||||
|             return True | ||||
|         return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) | ||||
| 
 | ||||
|     @property | ||||
|     def debug(self) -> bool: | ||||
|         """Whether debug mode is enabled. When using ``flask run`` to start the | ||||
|         development server, an interactive debugger will be shown for unhandled | ||||
|         exceptions, and the server will be reloaded when code changes. This maps to the | ||||
|         :data:`DEBUG` config key. It may not behave as expected if set late. | ||||
| 
 | ||||
|         **Do not enable debug mode when deploying in production.** | ||||
| 
 | ||||
|         Default: ``False`` | ||||
|         """ | ||||
|         return self.config["DEBUG"]  # type: ignore[no-any-return] | ||||
| 
 | ||||
|     @debug.setter | ||||
|     def debug(self, value: bool) -> None: | ||||
|         self.config["DEBUG"] = value | ||||
| 
 | ||||
|         if self.config["TEMPLATES_AUTO_RELOAD"] is None: | ||||
|             self.jinja_env.auto_reload = value | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: | ||||
|         """Register a :class:`~flask.Blueprint` on the application. Keyword | ||||
|         arguments passed to this method will override the defaults set on the | ||||
|         blueprint. | ||||
| 
 | ||||
|         Calls the blueprint's :meth:`~flask.Blueprint.register` method after | ||||
|         recording the blueprint in the application's :attr:`blueprints`. | ||||
| 
 | ||||
|         :param blueprint: The blueprint to register. | ||||
|         :param url_prefix: Blueprint routes will be prefixed with this. | ||||
|         :param subdomain: Blueprint routes will match on this subdomain. | ||||
|         :param url_defaults: Blueprint routes will use these default values for | ||||
|             view arguments. | ||||
|         :param options: Additional keyword arguments are passed to | ||||
|             :class:`~flask.blueprints.BlueprintSetupState`. They can be | ||||
|             accessed in :meth:`~flask.Blueprint.record` callbacks. | ||||
| 
 | ||||
|         .. versionchanged:: 2.0.1 | ||||
|             The ``name`` option can be used to change the (pre-dotted) | ||||
|             name the blueprint is registered with. This allows the same | ||||
|             blueprint to be registered multiple times with unique names | ||||
|             for ``url_for``. | ||||
| 
 | ||||
|         .. versionadded:: 0.7 | ||||
|         """ | ||||
|         blueprint.register(self, options) | ||||
| 
 | ||||
|     def iter_blueprints(self) -> t.ValuesView[Blueprint]: | ||||
|         """Iterates over all blueprints by the order they were registered. | ||||
| 
 | ||||
|         .. versionadded:: 0.11 | ||||
|         """ | ||||
|         return self.blueprints.values() | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_url_rule( | ||||
|         self, | ||||
|         rule: str, | ||||
|         endpoint: str | None = None, | ||||
|         view_func: ft.RouteCallable | None = None, | ||||
|         provide_automatic_options: bool | None = None, | ||||
|         **options: t.Any, | ||||
|     ) -> None: | ||||
|         if endpoint is None: | ||||
|             endpoint = _endpoint_from_view_func(view_func)  # type: ignore | ||||
|         options["endpoint"] = endpoint | ||||
|         methods = options.pop("methods", None) | ||||
| 
 | ||||
|         # if the methods are not given and the view_func object knows its | ||||
|         # methods we can use that instead.  If neither exists, we go with | ||||
|         # a tuple of only ``GET`` as default. | ||||
|         if methods is None: | ||||
|             methods = getattr(view_func, "methods", None) or ("GET",) | ||||
|         if isinstance(methods, str): | ||||
|             raise TypeError( | ||||
|                 "Allowed methods must be a list of strings, for" | ||||
|                 ' example: @app.route(..., methods=["POST"])' | ||||
|             ) | ||||
|         methods = {item.upper() for item in methods} | ||||
| 
 | ||||
|         # Methods that should always be added | ||||
|         required_methods = set(getattr(view_func, "required_methods", ())) | ||||
| 
 | ||||
|         # starting with Flask 0.8 the view_func object can disable and | ||||
|         # force-enable the automatic options handling. | ||||
|         if provide_automatic_options is None: | ||||
|             provide_automatic_options = getattr( | ||||
|                 view_func, "provide_automatic_options", None | ||||
|             ) | ||||
| 
 | ||||
|         if provide_automatic_options is None: | ||||
|             if "OPTIONS" not in methods: | ||||
|                 provide_automatic_options = True | ||||
|                 required_methods.add("OPTIONS") | ||||
|             else: | ||||
|                 provide_automatic_options = False | ||||
| 
 | ||||
|         # Add the required methods now. | ||||
|         methods |= required_methods | ||||
| 
 | ||||
|         rule_obj = self.url_rule_class(rule, methods=methods, **options) | ||||
|         rule_obj.provide_automatic_options = provide_automatic_options  # type: ignore[attr-defined] | ||||
| 
 | ||||
|         self.url_map.add(rule_obj) | ||||
|         if view_func is not None: | ||||
|             old_func = self.view_functions.get(endpoint) | ||||
|             if old_func is not None and old_func != view_func: | ||||
|                 raise AssertionError( | ||||
|                     "View function mapping is overwriting an existing" | ||||
|                     f" endpoint function: {endpoint}" | ||||
|                 ) | ||||
|             self.view_functions[endpoint] = view_func | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def template_filter( | ||||
|         self, name: str | None = None | ||||
|     ) -> t.Callable[[T_template_filter], T_template_filter]: | ||||
|         """A decorator that is used to register custom template filter. | ||||
|         You can specify a name for the filter, otherwise the function | ||||
|         name will be used. Example:: | ||||
| 
 | ||||
|           @app.template_filter() | ||||
|           def reverse(s): | ||||
|               return s[::-1] | ||||
| 
 | ||||
|         :param name: the optional name of the filter, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_template_filter) -> T_template_filter: | ||||
|             self.add_template_filter(f, name=name) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_template_filter( | ||||
|         self, f: ft.TemplateFilterCallable, name: str | None = None | ||||
|     ) -> None: | ||||
|         """Register a custom template filter.  Works exactly like the | ||||
|         :meth:`template_filter` decorator. | ||||
| 
 | ||||
|         :param name: the optional name of the filter, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
|         self.jinja_env.filters[name or f.__name__] = f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def template_test( | ||||
|         self, name: str | None = None | ||||
|     ) -> t.Callable[[T_template_test], T_template_test]: | ||||
|         """A decorator that is used to register custom template test. | ||||
|         You can specify a name for the test, otherwise the function | ||||
|         name will be used. Example:: | ||||
| 
 | ||||
|           @app.template_test() | ||||
|           def is_prime(n): | ||||
|               if n == 2: | ||||
|                   return True | ||||
|               for i in range(2, int(math.ceil(math.sqrt(n))) + 1): | ||||
|                   if n % i == 0: | ||||
|                       return False | ||||
|               return True | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the test, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_template_test) -> T_template_test: | ||||
|             self.add_template_test(f, name=name) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_template_test( | ||||
|         self, f: ft.TemplateTestCallable, name: str | None = None | ||||
|     ) -> None: | ||||
|         """Register a custom template test.  Works exactly like the | ||||
|         :meth:`template_test` decorator. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the test, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
|         self.jinja_env.tests[name or f.__name__] = f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def template_global( | ||||
|         self, name: str | None = None | ||||
|     ) -> t.Callable[[T_template_global], T_template_global]: | ||||
|         """A decorator that is used to register a custom template global function. | ||||
|         You can specify a name for the global function, otherwise the function | ||||
|         name will be used. Example:: | ||||
| 
 | ||||
|             @app.template_global() | ||||
|             def double(n): | ||||
|                 return 2 * n | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the global function, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_template_global) -> T_template_global: | ||||
|             self.add_template_global(f, name=name) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_template_global( | ||||
|         self, f: ft.TemplateGlobalCallable, name: str | None = None | ||||
|     ) -> None: | ||||
|         """Register a custom template global function. Works exactly like the | ||||
|         :meth:`template_global` decorator. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the global function, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
|         self.jinja_env.globals[name or f.__name__] = f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def teardown_appcontext(self, f: T_teardown) -> T_teardown: | ||||
|         """Registers a function to be called when the application | ||||
|         context is popped. The application context is typically popped | ||||
|         after the request context for each request, at the end of CLI | ||||
|         commands, or after a manually pushed context ends. | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             with app.app_context(): | ||||
|                 ... | ||||
| 
 | ||||
|         When the ``with`` block exits (or ``ctx.pop()`` is called), the | ||||
|         teardown functions are called just before the app context is | ||||
|         made inactive. Since a request context typically also manages an | ||||
|         application context it would also be called when you pop a | ||||
|         request context. | ||||
| 
 | ||||
|         When a teardown function was called because of an unhandled | ||||
|         exception it will be passed an error object. If an | ||||
|         :meth:`errorhandler` is registered, it will handle the exception | ||||
|         and the teardown will not receive it. | ||||
| 
 | ||||
|         Teardown functions must avoid raising exceptions. If they | ||||
|         execute code that might fail they must surround that code with a | ||||
|         ``try``/``except`` block and log any errors. | ||||
| 
 | ||||
|         The return values of teardown functions are ignored. | ||||
| 
 | ||||
|         .. versionadded:: 0.9 | ||||
|         """ | ||||
|         self.teardown_appcontext_funcs.append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def shell_context_processor( | ||||
|         self, f: T_shell_context_processor | ||||
|     ) -> T_shell_context_processor: | ||||
|         """Registers a shell context processor function. | ||||
| 
 | ||||
|         .. versionadded:: 0.11 | ||||
|         """ | ||||
|         self.shell_context_processors.append(f) | ||||
|         return f | ||||
| 
 | ||||
|     def _find_error_handler( | ||||
|         self, e: Exception, blueprints: list[str] | ||||
|     ) -> ft.ErrorHandlerCallable | None: | ||||
|         """Return a registered error handler for an exception in this order: | ||||
|         blueprint handler for a specific code, app handler for a specific code, | ||||
|         blueprint handler for an exception class, app handler for an exception | ||||
|         class, or ``None`` if a suitable handler is not found. | ||||
|         """ | ||||
|         exc_class, code = self._get_exc_class_and_code(type(e)) | ||||
|         names = (*blueprints, None) | ||||
| 
 | ||||
|         for c in (code, None) if code is not None else (None,): | ||||
|             for name in names: | ||||
|                 handler_map = self.error_handler_spec[name][c] | ||||
| 
 | ||||
|                 if not handler_map: | ||||
|                     continue | ||||
| 
 | ||||
|                 for cls in exc_class.__mro__: | ||||
|                     handler = handler_map.get(cls) | ||||
| 
 | ||||
|                     if handler is not None: | ||||
|                         return handler | ||||
|         return None | ||||
| 
 | ||||
|     def trap_http_exception(self, e: Exception) -> bool: | ||||
|         """Checks if an HTTP exception should be trapped or not.  By default | ||||
|         this will return ``False`` for all exceptions except for a bad request | ||||
|         key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``.  It | ||||
|         also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. | ||||
| 
 | ||||
|         This is called for all HTTP exceptions raised by a view function. | ||||
|         If it returns ``True`` for any exception the error handler for this | ||||
|         exception is not called and it shows up as regular exception in the | ||||
|         traceback.  This is helpful for debugging implicitly raised HTTP | ||||
|         exceptions. | ||||
| 
 | ||||
|         .. versionchanged:: 1.0 | ||||
|             Bad request errors are not trapped by default in debug mode. | ||||
| 
 | ||||
|         .. versionadded:: 0.8 | ||||
|         """ | ||||
|         if self.config["TRAP_HTTP_EXCEPTIONS"]: | ||||
|             return True | ||||
| 
 | ||||
|         trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] | ||||
| 
 | ||||
|         # if unset, trap key errors in debug mode | ||||
|         if ( | ||||
|             trap_bad_request is None | ||||
|             and self.debug | ||||
|             and isinstance(e, BadRequestKeyError) | ||||
|         ): | ||||
|             return True | ||||
| 
 | ||||
|         if trap_bad_request: | ||||
|             return isinstance(e, BadRequest) | ||||
| 
 | ||||
|         return False | ||||
| 
 | ||||
|     def should_ignore_error(self, error: BaseException | None) -> bool: | ||||
|         """This is called to figure out if an error should be ignored | ||||
|         or not as far as the teardown system is concerned.  If this | ||||
|         function returns ``True`` then the teardown handlers will not be | ||||
|         passed the error. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
|         """ | ||||
|         return False | ||||
| 
 | ||||
|     def redirect(self, location: str, code: int = 302) -> BaseResponse: | ||||
|         """Create a redirect response object. | ||||
| 
 | ||||
|         This is called by :func:`flask.redirect`, and can be called | ||||
|         directly as well. | ||||
| 
 | ||||
|         :param location: The URL to redirect to. | ||||
|         :param code: The status code for the redirect. | ||||
| 
 | ||||
|         .. versionadded:: 2.2 | ||||
|             Moved from ``flask.redirect``, which calls this method. | ||||
|         """ | ||||
|         return _wz_redirect( | ||||
|             location, | ||||
|             code=code, | ||||
|             Response=self.response_class,  # type: ignore[arg-type] | ||||
|         ) | ||||
| 
 | ||||
|     def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: | ||||
|         """Injects the URL defaults for the given endpoint directly into | ||||
|         the values dictionary passed.  This is used internally and | ||||
|         automatically called on URL building. | ||||
| 
 | ||||
|         .. versionadded:: 0.7 | ||||
|         """ | ||||
|         names: t.Iterable[str | None] = (None,) | ||||
| 
 | ||||
|         # url_for may be called outside a request context, parse the | ||||
|         # passed endpoint instead of using request.blueprints. | ||||
|         if "." in endpoint: | ||||
|             names = chain( | ||||
|                 names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) | ||||
|             ) | ||||
| 
 | ||||
|         for name in names: | ||||
|             if name in self.url_default_functions: | ||||
|                 for func in self.url_default_functions[name]: | ||||
|                     func(endpoint, values) | ||||
| 
 | ||||
|     def handle_url_build_error( | ||||
|         self, error: BuildError, endpoint: str, values: dict[str, t.Any] | ||||
|     ) -> str: | ||||
|         """Called by :meth:`.url_for` if a | ||||
|         :exc:`~werkzeug.routing.BuildError` was raised. If this returns | ||||
|         a value, it will be returned by ``url_for``, otherwise the error | ||||
|         will be re-raised. | ||||
| 
 | ||||
|         Each function in :attr:`url_build_error_handlers` is called with | ||||
|         ``error``, ``endpoint`` and ``values``. If a function returns | ||||
|         ``None`` or raises a ``BuildError``, it is skipped. Otherwise, | ||||
|         its return value is returned by ``url_for``. | ||||
| 
 | ||||
|         :param error: The active ``BuildError`` being handled. | ||||
|         :param endpoint: The endpoint being built. | ||||
|         :param values: The keyword arguments passed to ``url_for``. | ||||
|         """ | ||||
|         for handler in self.url_build_error_handlers: | ||||
|             try: | ||||
|                 rv = handler(error, endpoint, values) | ||||
|             except BuildError as e: | ||||
|                 # make error available outside except block | ||||
|                 error = e | ||||
|             else: | ||||
|                 if rv is not None: | ||||
|                     return rv | ||||
| 
 | ||||
|         # Re-raise if called with an active exception, otherwise raise | ||||
|         # the passed in exception. | ||||
|         if error is sys.exc_info()[1]: | ||||
|             raise | ||||
| 
 | ||||
|         raise error | ||||
							
								
								
									
										632
									
								
								venv/lib/python3.11/site-packages/flask/sansio/blueprints.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										632
									
								
								venv/lib/python3.11/site-packages/flask/sansio/blueprints.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,632 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import os | ||||
| import typing as t | ||||
| from collections import defaultdict | ||||
| from functools import update_wrapper | ||||
| 
 | ||||
| from .. import typing as ft | ||||
| from .scaffold import _endpoint_from_view_func | ||||
| from .scaffold import _sentinel | ||||
| from .scaffold import Scaffold | ||||
| from .scaffold import setupmethod | ||||
| 
 | ||||
| if t.TYPE_CHECKING:  # pragma: no cover | ||||
|     from .app import App | ||||
| 
 | ||||
| DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] | ||||
| T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) | ||||
| T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) | ||||
| T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) | ||||
| T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) | ||||
| T_template_context_processor = t.TypeVar( | ||||
|     "T_template_context_processor", bound=ft.TemplateContextProcessorCallable | ||||
| ) | ||||
| T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) | ||||
| T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) | ||||
| T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) | ||||
| T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) | ||||
| T_url_value_preprocessor = t.TypeVar( | ||||
|     "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| class BlueprintSetupState: | ||||
|     """Temporary holder object for registering a blueprint with the | ||||
|     application.  An instance of this class is created by the | ||||
|     :meth:`~flask.Blueprint.make_setup_state` method and later passed | ||||
|     to all register callback functions. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__( | ||||
|         self, | ||||
|         blueprint: Blueprint, | ||||
|         app: App, | ||||
|         options: t.Any, | ||||
|         first_registration: bool, | ||||
|     ) -> None: | ||||
|         #: a reference to the current application | ||||
|         self.app = app | ||||
| 
 | ||||
|         #: a reference to the blueprint that created this setup state. | ||||
|         self.blueprint = blueprint | ||||
| 
 | ||||
|         #: a dictionary with all options that were passed to the | ||||
|         #: :meth:`~flask.Flask.register_blueprint` method. | ||||
|         self.options = options | ||||
| 
 | ||||
|         #: as blueprints can be registered multiple times with the | ||||
|         #: application and not everything wants to be registered | ||||
|         #: multiple times on it, this attribute can be used to figure | ||||
|         #: out if the blueprint was registered in the past already. | ||||
|         self.first_registration = first_registration | ||||
| 
 | ||||
|         subdomain = self.options.get("subdomain") | ||||
|         if subdomain is None: | ||||
|             subdomain = self.blueprint.subdomain | ||||
| 
 | ||||
|         #: The subdomain that the blueprint should be active for, ``None`` | ||||
|         #: otherwise. | ||||
|         self.subdomain = subdomain | ||||
| 
 | ||||
|         url_prefix = self.options.get("url_prefix") | ||||
|         if url_prefix is None: | ||||
|             url_prefix = self.blueprint.url_prefix | ||||
|         #: The prefix that should be used for all URLs defined on the | ||||
|         #: blueprint. | ||||
|         self.url_prefix = url_prefix | ||||
| 
 | ||||
|         self.name = self.options.get("name", blueprint.name) | ||||
|         self.name_prefix = self.options.get("name_prefix", "") | ||||
| 
 | ||||
|         #: A dictionary with URL defaults that is added to each and every | ||||
|         #: URL that was defined with the blueprint. | ||||
|         self.url_defaults = dict(self.blueprint.url_values_defaults) | ||||
|         self.url_defaults.update(self.options.get("url_defaults", ())) | ||||
| 
 | ||||
|     def add_url_rule( | ||||
|         self, | ||||
|         rule: str, | ||||
|         endpoint: str | None = None, | ||||
|         view_func: ft.RouteCallable | None = None, | ||||
|         **options: t.Any, | ||||
|     ) -> None: | ||||
|         """A helper method to register a rule (and optionally a view function) | ||||
|         to the application.  The endpoint is automatically prefixed with the | ||||
|         blueprint's name. | ||||
|         """ | ||||
|         if self.url_prefix is not None: | ||||
|             if rule: | ||||
|                 rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) | ||||
|             else: | ||||
|                 rule = self.url_prefix | ||||
|         options.setdefault("subdomain", self.subdomain) | ||||
|         if endpoint is None: | ||||
|             endpoint = _endpoint_from_view_func(view_func)  # type: ignore | ||||
|         defaults = self.url_defaults | ||||
|         if "defaults" in options: | ||||
|             defaults = dict(defaults, **options.pop("defaults")) | ||||
| 
 | ||||
|         self.app.add_url_rule( | ||||
|             rule, | ||||
|             f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), | ||||
|             view_func, | ||||
|             defaults=defaults, | ||||
|             **options, | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| class Blueprint(Scaffold): | ||||
|     """Represents a blueprint, a collection of routes and other | ||||
|     app-related functions that can be registered on a real application | ||||
|     later. | ||||
| 
 | ||||
|     A blueprint is an object that allows defining application functions | ||||
|     without requiring an application object ahead of time. It uses the | ||||
|     same decorators as :class:`~flask.Flask`, but defers the need for an | ||||
|     application by recording them for later registration. | ||||
| 
 | ||||
|     Decorating a function with a blueprint creates a deferred function | ||||
|     that is called with :class:`~flask.blueprints.BlueprintSetupState` | ||||
|     when the blueprint is registered on an application. | ||||
| 
 | ||||
|     See :doc:`/blueprints` for more information. | ||||
| 
 | ||||
|     :param name: The name of the blueprint. Will be prepended to each | ||||
|         endpoint name. | ||||
|     :param import_name: The name of the blueprint package, usually | ||||
|         ``__name__``. This helps locate the ``root_path`` for the | ||||
|         blueprint. | ||||
|     :param static_folder: A folder with static files that should be | ||||
|         served by the blueprint's static route. The path is relative to | ||||
|         the blueprint's root path. Blueprint static files are disabled | ||||
|         by default. | ||||
|     :param static_url_path: The url to serve static files from. | ||||
|         Defaults to ``static_folder``. If the blueprint does not have | ||||
|         a ``url_prefix``, the app's static route will take precedence, | ||||
|         and the blueprint's static files won't be accessible. | ||||
|     :param template_folder: A folder with templates that should be added | ||||
|         to the app's template search path. The path is relative to the | ||||
|         blueprint's root path. Blueprint templates are disabled by | ||||
|         default. Blueprint templates have a lower precedence than those | ||||
|         in the app's templates folder. | ||||
|     :param url_prefix: A path to prepend to all of the blueprint's URLs, | ||||
|         to make them distinct from the rest of the app's routes. | ||||
|     :param subdomain: A subdomain that blueprint routes will match on by | ||||
|         default. | ||||
|     :param url_defaults: A dict of default values that blueprint routes | ||||
|         will receive by default. | ||||
|     :param root_path: By default, the blueprint will automatically set | ||||
|         this based on ``import_name``. In certain situations this | ||||
|         automatic detection can fail, so the path can be specified | ||||
|         manually instead. | ||||
| 
 | ||||
|     .. versionchanged:: 1.1.0 | ||||
|         Blueprints have a ``cli`` group to register nested CLI commands. | ||||
|         The ``cli_group`` parameter controls the name of the group under | ||||
|         the ``flask`` command. | ||||
| 
 | ||||
|     .. versionadded:: 0.7 | ||||
|     """ | ||||
| 
 | ||||
|     _got_registered_once = False | ||||
| 
 | ||||
|     def __init__( | ||||
|         self, | ||||
|         name: str, | ||||
|         import_name: str, | ||||
|         static_folder: str | os.PathLike[str] | None = None, | ||||
|         static_url_path: str | None = None, | ||||
|         template_folder: str | os.PathLike[str] | None = None, | ||||
|         url_prefix: str | None = None, | ||||
|         subdomain: str | None = None, | ||||
|         url_defaults: dict[str, t.Any] | None = None, | ||||
|         root_path: str | None = None, | ||||
|         cli_group: str | None = _sentinel,  # type: ignore[assignment] | ||||
|     ): | ||||
|         super().__init__( | ||||
|             import_name=import_name, | ||||
|             static_folder=static_folder, | ||||
|             static_url_path=static_url_path, | ||||
|             template_folder=template_folder, | ||||
|             root_path=root_path, | ||||
|         ) | ||||
| 
 | ||||
|         if not name: | ||||
|             raise ValueError("'name' may not be empty.") | ||||
| 
 | ||||
|         if "." in name: | ||||
|             raise ValueError("'name' may not contain a dot '.' character.") | ||||
| 
 | ||||
|         self.name = name | ||||
|         self.url_prefix = url_prefix | ||||
|         self.subdomain = subdomain | ||||
|         self.deferred_functions: list[DeferredSetupFunction] = [] | ||||
| 
 | ||||
|         if url_defaults is None: | ||||
|             url_defaults = {} | ||||
| 
 | ||||
|         self.url_values_defaults = url_defaults | ||||
|         self.cli_group = cli_group | ||||
|         self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] | ||||
| 
 | ||||
|     def _check_setup_finished(self, f_name: str) -> None: | ||||
|         if self._got_registered_once: | ||||
|             raise AssertionError( | ||||
|                 f"The setup method '{f_name}' can no longer be called on the blueprint" | ||||
|                 f" '{self.name}'. It has already been registered at least once, any" | ||||
|                 " changes will not be applied consistently.\n" | ||||
|                 "Make sure all imports, decorators, functions, etc. needed to set up" | ||||
|                 " the blueprint are done before registering it." | ||||
|             ) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def record(self, func: DeferredSetupFunction) -> None: | ||||
|         """Registers a function that is called when the blueprint is | ||||
|         registered on the application.  This function is called with the | ||||
|         state as argument as returned by the :meth:`make_setup_state` | ||||
|         method. | ||||
|         """ | ||||
|         self.deferred_functions.append(func) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def record_once(self, func: DeferredSetupFunction) -> None: | ||||
|         """Works like :meth:`record` but wraps the function in another | ||||
|         function that will ensure the function is only called once.  If the | ||||
|         blueprint is registered a second time on the application, the | ||||
|         function passed is not called. | ||||
|         """ | ||||
| 
 | ||||
|         def wrapper(state: BlueprintSetupState) -> None: | ||||
|             if state.first_registration: | ||||
|                 func(state) | ||||
| 
 | ||||
|         self.record(update_wrapper(wrapper, func)) | ||||
| 
 | ||||
|     def make_setup_state( | ||||
|         self, app: App, options: dict[str, t.Any], first_registration: bool = False | ||||
|     ) -> BlueprintSetupState: | ||||
|         """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` | ||||
|         object that is later passed to the register callback functions. | ||||
|         Subclasses can override this to return a subclass of the setup state. | ||||
|         """ | ||||
|         return BlueprintSetupState(self, app, options, first_registration) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: | ||||
|         """Register a :class:`~flask.Blueprint` on this blueprint. Keyword | ||||
|         arguments passed to this method will override the defaults set | ||||
|         on the blueprint. | ||||
| 
 | ||||
|         .. versionchanged:: 2.0.1 | ||||
|             The ``name`` option can be used to change the (pre-dotted) | ||||
|             name the blueprint is registered with. This allows the same | ||||
|             blueprint to be registered multiple times with unique names | ||||
|             for ``url_for``. | ||||
| 
 | ||||
|         .. versionadded:: 2.0 | ||||
|         """ | ||||
|         if blueprint is self: | ||||
|             raise ValueError("Cannot register a blueprint on itself") | ||||
|         self._blueprints.append((blueprint, options)) | ||||
| 
 | ||||
|     def register(self, app: App, options: dict[str, t.Any]) -> None: | ||||
|         """Called by :meth:`Flask.register_blueprint` to register all | ||||
|         views and callbacks registered on the blueprint with the | ||||
|         application. Creates a :class:`.BlueprintSetupState` and calls | ||||
|         each :meth:`record` callback with it. | ||||
| 
 | ||||
|         :param app: The application this blueprint is being registered | ||||
|             with. | ||||
|         :param options: Keyword arguments forwarded from | ||||
|             :meth:`~Flask.register_blueprint`. | ||||
| 
 | ||||
|         .. versionchanged:: 2.3 | ||||
|             Nested blueprints now correctly apply subdomains. | ||||
| 
 | ||||
|         .. versionchanged:: 2.1 | ||||
|             Registering the same blueprint with the same name multiple | ||||
|             times is an error. | ||||
| 
 | ||||
|         .. versionchanged:: 2.0.1 | ||||
|             Nested blueprints are registered with their dotted name. | ||||
|             This allows different blueprints with the same name to be | ||||
|             nested at different locations. | ||||
| 
 | ||||
|         .. versionchanged:: 2.0.1 | ||||
|             The ``name`` option can be used to change the (pre-dotted) | ||||
|             name the blueprint is registered with. This allows the same | ||||
|             blueprint to be registered multiple times with unique names | ||||
|             for ``url_for``. | ||||
|         """ | ||||
|         name_prefix = options.get("name_prefix", "") | ||||
|         self_name = options.get("name", self.name) | ||||
|         name = f"{name_prefix}.{self_name}".lstrip(".") | ||||
| 
 | ||||
|         if name in app.blueprints: | ||||
|             bp_desc = "this" if app.blueprints[name] is self else "a different" | ||||
|             existing_at = f" '{name}'" if self_name != name else "" | ||||
| 
 | ||||
|             raise ValueError( | ||||
|                 f"The name '{self_name}' is already registered for" | ||||
|                 f" {bp_desc} blueprint{existing_at}. Use 'name=' to" | ||||
|                 f" provide a unique name." | ||||
|             ) | ||||
| 
 | ||||
|         first_bp_registration = not any(bp is self for bp in app.blueprints.values()) | ||||
|         first_name_registration = name not in app.blueprints | ||||
| 
 | ||||
|         app.blueprints[name] = self | ||||
|         self._got_registered_once = True | ||||
|         state = self.make_setup_state(app, options, first_bp_registration) | ||||
| 
 | ||||
|         if self.has_static_folder: | ||||
|             state.add_url_rule( | ||||
|                 f"{self.static_url_path}/<path:filename>", | ||||
|                 view_func=self.send_static_file,  # type: ignore[attr-defined] | ||||
|                 endpoint="static", | ||||
|             ) | ||||
| 
 | ||||
|         # Merge blueprint data into parent. | ||||
|         if first_bp_registration or first_name_registration: | ||||
|             self._merge_blueprint_funcs(app, name) | ||||
| 
 | ||||
|         for deferred in self.deferred_functions: | ||||
|             deferred(state) | ||||
| 
 | ||||
|         cli_resolved_group = options.get("cli_group", self.cli_group) | ||||
| 
 | ||||
|         if self.cli.commands: | ||||
|             if cli_resolved_group is None: | ||||
|                 app.cli.commands.update(self.cli.commands) | ||||
|             elif cli_resolved_group is _sentinel: | ||||
|                 self.cli.name = name | ||||
|                 app.cli.add_command(self.cli) | ||||
|             else: | ||||
|                 self.cli.name = cli_resolved_group | ||||
|                 app.cli.add_command(self.cli) | ||||
| 
 | ||||
|         for blueprint, bp_options in self._blueprints: | ||||
|             bp_options = bp_options.copy() | ||||
|             bp_url_prefix = bp_options.get("url_prefix") | ||||
|             bp_subdomain = bp_options.get("subdomain") | ||||
| 
 | ||||
|             if bp_subdomain is None: | ||||
|                 bp_subdomain = blueprint.subdomain | ||||
| 
 | ||||
|             if state.subdomain is not None and bp_subdomain is not None: | ||||
|                 bp_options["subdomain"] = bp_subdomain + "." + state.subdomain | ||||
|             elif bp_subdomain is not None: | ||||
|                 bp_options["subdomain"] = bp_subdomain | ||||
|             elif state.subdomain is not None: | ||||
|                 bp_options["subdomain"] = state.subdomain | ||||
| 
 | ||||
|             if bp_url_prefix is None: | ||||
|                 bp_url_prefix = blueprint.url_prefix | ||||
| 
 | ||||
|             if state.url_prefix is not None and bp_url_prefix is not None: | ||||
|                 bp_options["url_prefix"] = ( | ||||
|                     state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") | ||||
|                 ) | ||||
|             elif bp_url_prefix is not None: | ||||
|                 bp_options["url_prefix"] = bp_url_prefix | ||||
|             elif state.url_prefix is not None: | ||||
|                 bp_options["url_prefix"] = state.url_prefix | ||||
| 
 | ||||
|             bp_options["name_prefix"] = name | ||||
|             blueprint.register(app, bp_options) | ||||
| 
 | ||||
|     def _merge_blueprint_funcs(self, app: App, name: str) -> None: | ||||
|         def extend( | ||||
|             bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], | ||||
|             parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], | ||||
|         ) -> None: | ||||
|             for key, values in bp_dict.items(): | ||||
|                 key = name if key is None else f"{name}.{key}" | ||||
|                 parent_dict[key].extend(values) | ||||
| 
 | ||||
|         for key, value in self.error_handler_spec.items(): | ||||
|             key = name if key is None else f"{name}.{key}" | ||||
|             value = defaultdict( | ||||
|                 dict, | ||||
|                 { | ||||
|                     code: {exc_class: func for exc_class, func in code_values.items()} | ||||
|                     for code, code_values in value.items() | ||||
|                 }, | ||||
|             ) | ||||
|             app.error_handler_spec[key] = value | ||||
| 
 | ||||
|         for endpoint, func in self.view_functions.items(): | ||||
|             app.view_functions[endpoint] = func | ||||
| 
 | ||||
|         extend(self.before_request_funcs, app.before_request_funcs) | ||||
|         extend(self.after_request_funcs, app.after_request_funcs) | ||||
|         extend( | ||||
|             self.teardown_request_funcs, | ||||
|             app.teardown_request_funcs, | ||||
|         ) | ||||
|         extend(self.url_default_functions, app.url_default_functions) | ||||
|         extend(self.url_value_preprocessors, app.url_value_preprocessors) | ||||
|         extend(self.template_context_processors, app.template_context_processors) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_url_rule( | ||||
|         self, | ||||
|         rule: str, | ||||
|         endpoint: str | None = None, | ||||
|         view_func: ft.RouteCallable | None = None, | ||||
|         provide_automatic_options: bool | None = None, | ||||
|         **options: t.Any, | ||||
|     ) -> None: | ||||
|         """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for | ||||
|         full documentation. | ||||
| 
 | ||||
|         The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, | ||||
|         used with :func:`url_for`, is prefixed with the blueprint's name. | ||||
|         """ | ||||
|         if endpoint and "." in endpoint: | ||||
|             raise ValueError("'endpoint' may not contain a dot '.' character.") | ||||
| 
 | ||||
|         if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: | ||||
|             raise ValueError("'view_func' name may not contain a dot '.' character.") | ||||
| 
 | ||||
|         self.record( | ||||
|             lambda s: s.add_url_rule( | ||||
|                 rule, | ||||
|                 endpoint, | ||||
|                 view_func, | ||||
|                 provide_automatic_options=provide_automatic_options, | ||||
|                 **options, | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_template_filter( | ||||
|         self, name: str | None = None | ||||
|     ) -> t.Callable[[T_template_filter], T_template_filter]: | ||||
|         """Register a template filter, available in any template rendered by the | ||||
|         application. Equivalent to :meth:`.Flask.template_filter`. | ||||
| 
 | ||||
|         :param name: the optional name of the filter, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_template_filter) -> T_template_filter: | ||||
|             self.add_app_template_filter(f, name=name) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_app_template_filter( | ||||
|         self, f: ft.TemplateFilterCallable, name: str | None = None | ||||
|     ) -> None: | ||||
|         """Register a template filter, available in any template rendered by the | ||||
|         application. Works like the :meth:`app_template_filter` decorator. Equivalent to | ||||
|         :meth:`.Flask.add_template_filter`. | ||||
| 
 | ||||
|         :param name: the optional name of the filter, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def register_template(state: BlueprintSetupState) -> None: | ||||
|             state.app.jinja_env.filters[name or f.__name__] = f | ||||
| 
 | ||||
|         self.record_once(register_template) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_template_test( | ||||
|         self, name: str | None = None | ||||
|     ) -> t.Callable[[T_template_test], T_template_test]: | ||||
|         """Register a template test, available in any template rendered by the | ||||
|         application. Equivalent to :meth:`.Flask.template_test`. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the test, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_template_test) -> T_template_test: | ||||
|             self.add_app_template_test(f, name=name) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_app_template_test( | ||||
|         self, f: ft.TemplateTestCallable, name: str | None = None | ||||
|     ) -> None: | ||||
|         """Register a template test, available in any template rendered by the | ||||
|         application. Works like the :meth:`app_template_test` decorator. Equivalent to | ||||
|         :meth:`.Flask.add_template_test`. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the test, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def register_template(state: BlueprintSetupState) -> None: | ||||
|             state.app.jinja_env.tests[name or f.__name__] = f | ||||
| 
 | ||||
|         self.record_once(register_template) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_template_global( | ||||
|         self, name: str | None = None | ||||
|     ) -> t.Callable[[T_template_global], T_template_global]: | ||||
|         """Register a template global, available in any template rendered by the | ||||
|         application. Equivalent to :meth:`.Flask.template_global`. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the global, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_template_global) -> T_template_global: | ||||
|             self.add_app_template_global(f, name=name) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_app_template_global( | ||||
|         self, f: ft.TemplateGlobalCallable, name: str | None = None | ||||
|     ) -> None: | ||||
|         """Register a template global, available in any template rendered by the | ||||
|         application. Works like the :meth:`app_template_global` decorator. Equivalent to | ||||
|         :meth:`.Flask.add_template_global`. | ||||
| 
 | ||||
|         .. versionadded:: 0.10 | ||||
| 
 | ||||
|         :param name: the optional name of the global, otherwise the | ||||
|                      function name will be used. | ||||
|         """ | ||||
| 
 | ||||
|         def register_template(state: BlueprintSetupState) -> None: | ||||
|             state.app.jinja_env.globals[name or f.__name__] = f | ||||
| 
 | ||||
|         self.record_once(register_template) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def before_app_request(self, f: T_before_request) -> T_before_request: | ||||
|         """Like :meth:`before_request`, but before every request, not only those handled | ||||
|         by the blueprint. Equivalent to :meth:`.Flask.before_request`. | ||||
|         """ | ||||
|         self.record_once( | ||||
|             lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) | ||||
|         ) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def after_app_request(self, f: T_after_request) -> T_after_request: | ||||
|         """Like :meth:`after_request`, but after every request, not only those handled | ||||
|         by the blueprint. Equivalent to :meth:`.Flask.after_request`. | ||||
|         """ | ||||
|         self.record_once( | ||||
|             lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) | ||||
|         ) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def teardown_app_request(self, f: T_teardown) -> T_teardown: | ||||
|         """Like :meth:`teardown_request`, but after every request, not only those | ||||
|         handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. | ||||
|         """ | ||||
|         self.record_once( | ||||
|             lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) | ||||
|         ) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_context_processor( | ||||
|         self, f: T_template_context_processor | ||||
|     ) -> T_template_context_processor: | ||||
|         """Like :meth:`context_processor`, but for templates rendered by every view, not | ||||
|         only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. | ||||
|         """ | ||||
|         self.record_once( | ||||
|             lambda s: s.app.template_context_processors.setdefault(None, []).append(f) | ||||
|         ) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_errorhandler( | ||||
|         self, code: type[Exception] | int | ||||
|     ) -> t.Callable[[T_error_handler], T_error_handler]: | ||||
|         """Like :meth:`errorhandler`, but for every request, not only those handled by | ||||
|         the blueprint. Equivalent to :meth:`.Flask.errorhandler`. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_error_handler) -> T_error_handler: | ||||
|             def from_blueprint(state: BlueprintSetupState) -> None: | ||||
|                 state.app.errorhandler(code)(f) | ||||
| 
 | ||||
|             self.record_once(from_blueprint) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_url_value_preprocessor( | ||||
|         self, f: T_url_value_preprocessor | ||||
|     ) -> T_url_value_preprocessor: | ||||
|         """Like :meth:`url_value_preprocessor`, but for every request, not only those | ||||
|         handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. | ||||
|         """ | ||||
|         self.record_once( | ||||
|             lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) | ||||
|         ) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: | ||||
|         """Like :meth:`url_defaults`, but for every request, not only those handled by | ||||
|         the blueprint. Equivalent to :meth:`.Flask.url_defaults`. | ||||
|         """ | ||||
|         self.record_once( | ||||
|             lambda s: s.app.url_default_functions.setdefault(None, []).append(f) | ||||
|         ) | ||||
|         return f | ||||
							
								
								
									
										805
									
								
								venv/lib/python3.11/site-packages/flask/sansio/scaffold.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										805
									
								
								venv/lib/python3.11/site-packages/flask/sansio/scaffold.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,805 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import importlib.util | ||||
| import os | ||||
| import pathlib | ||||
| import sys | ||||
| import typing as t | ||||
| from collections import defaultdict | ||||
| from functools import update_wrapper | ||||
| 
 | ||||
| import click | ||||
| from jinja2 import BaseLoader | ||||
| from jinja2 import FileSystemLoader | ||||
| from werkzeug.exceptions import default_exceptions | ||||
| from werkzeug.exceptions import HTTPException | ||||
| from werkzeug.utils import cached_property | ||||
| 
 | ||||
| from .. import typing as ft | ||||
| from ..cli import AppGroup | ||||
| from ..helpers import get_root_path | ||||
| from ..templating import _default_template_ctx_processor | ||||
| 
 | ||||
| # a singleton sentinel value for parameter defaults | ||||
| _sentinel = object() | ||||
| 
 | ||||
| F = t.TypeVar("F", bound=t.Callable[..., t.Any]) | ||||
| T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) | ||||
| T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) | ||||
| T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) | ||||
| T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) | ||||
| T_template_context_processor = t.TypeVar( | ||||
|     "T_template_context_processor", bound=ft.TemplateContextProcessorCallable | ||||
| ) | ||||
| T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) | ||||
| T_url_value_preprocessor = t.TypeVar( | ||||
|     "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable | ||||
| ) | ||||
| T_route = t.TypeVar("T_route", bound=ft.RouteCallable) | ||||
| 
 | ||||
| 
 | ||||
| def setupmethod(f: F) -> F: | ||||
|     f_name = f.__name__ | ||||
| 
 | ||||
|     def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any: | ||||
|         self._check_setup_finished(f_name) | ||||
|         return f(self, *args, **kwargs) | ||||
| 
 | ||||
|     return t.cast(F, update_wrapper(wrapper_func, f)) | ||||
| 
 | ||||
| 
 | ||||
| class Scaffold: | ||||
|     """Common behavior shared between :class:`~flask.Flask` and | ||||
|     :class:`~flask.blueprints.Blueprint`. | ||||
| 
 | ||||
|     :param import_name: The import name of the module where this object | ||||
|         is defined. Usually :attr:`__name__` should be used. | ||||
|     :param static_folder: Path to a folder of static files to serve. | ||||
|         If this is set, a static route will be added. | ||||
|     :param static_url_path: URL prefix for the static route. | ||||
|     :param template_folder: Path to a folder containing template files. | ||||
|         for rendering. If this is set, a Jinja loader will be added. | ||||
|     :param root_path: The path that static, template, and resource files | ||||
|         are relative to. Typically not set, it is discovered based on | ||||
|         the ``import_name``. | ||||
| 
 | ||||
|     .. versionadded:: 2.0 | ||||
|     """ | ||||
| 
 | ||||
|     name: str | ||||
|     _static_folder: str | None = None | ||||
|     _static_url_path: str | None = None | ||||
| 
 | ||||
|     def __init__( | ||||
|         self, | ||||
|         import_name: str, | ||||
|         static_folder: str | os.PathLike[str] | None = None, | ||||
|         static_url_path: str | None = None, | ||||
|         template_folder: str | os.PathLike[str] | None = None, | ||||
|         root_path: str | None = None, | ||||
|     ): | ||||
|         #: The name of the package or module that this object belongs | ||||
|         #: to. Do not change this once it is set by the constructor. | ||||
|         self.import_name = import_name | ||||
| 
 | ||||
|         self.static_folder = static_folder  # type: ignore | ||||
|         self.static_url_path = static_url_path | ||||
| 
 | ||||
|         #: The path to the templates folder, relative to | ||||
|         #: :attr:`root_path`, to add to the template loader. ``None`` if | ||||
|         #: templates should not be added. | ||||
|         self.template_folder = template_folder | ||||
| 
 | ||||
|         if root_path is None: | ||||
|             root_path = get_root_path(self.import_name) | ||||
| 
 | ||||
|         #: Absolute path to the package on the filesystem. Used to look | ||||
|         #: up resources contained in the package. | ||||
|         self.root_path = root_path | ||||
| 
 | ||||
|         #: The Click command group for registering CLI commands for this | ||||
|         #: object. The commands are available from the ``flask`` command | ||||
|         #: once the application has been discovered and blueprints have | ||||
|         #: been registered. | ||||
|         self.cli: click.Group = AppGroup() | ||||
| 
 | ||||
|         #: A dictionary mapping endpoint names to view functions. | ||||
|         #: | ||||
|         #: To register a view function, use the :meth:`route` decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.view_functions: dict[str, ft.RouteCallable] = {} | ||||
| 
 | ||||
|         #: A data structure of registered error handlers, in the format | ||||
|         #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is | ||||
|         #: the name of a blueprint the handlers are active for, or | ||||
|         #: ``None`` for all requests. The ``code`` key is the HTTP | ||||
|         #: status code for ``HTTPException``, or ``None`` for | ||||
|         #: other exceptions. The innermost dictionary maps exception | ||||
|         #: classes to handler functions. | ||||
|         #: | ||||
|         #: To register an error handler, use the :meth:`errorhandler` | ||||
|         #: decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.error_handler_spec: dict[ | ||||
|             ft.AppOrBlueprintKey, | ||||
|             dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], | ||||
|         ] = defaultdict(lambda: defaultdict(dict)) | ||||
| 
 | ||||
|         #: A data structure of functions to call at the beginning of | ||||
|         #: each request, in the format ``{scope: [functions]}``. The | ||||
|         #: ``scope`` key is the name of a blueprint the functions are | ||||
|         #: active for, or ``None`` for all requests. | ||||
|         #: | ||||
|         #: To register a function, use the :meth:`before_request` | ||||
|         #: decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.before_request_funcs: dict[ | ||||
|             ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] | ||||
|         ] = defaultdict(list) | ||||
| 
 | ||||
|         #: A data structure of functions to call at the end of each | ||||
|         #: request, in the format ``{scope: [functions]}``. The | ||||
|         #: ``scope`` key is the name of a blueprint the functions are | ||||
|         #: active for, or ``None`` for all requests. | ||||
|         #: | ||||
|         #: To register a function, use the :meth:`after_request` | ||||
|         #: decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.after_request_funcs: dict[ | ||||
|             ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]] | ||||
|         ] = defaultdict(list) | ||||
| 
 | ||||
|         #: A data structure of functions to call at the end of each | ||||
|         #: request even if an exception is raised, in the format | ||||
|         #: ``{scope: [functions]}``. The ``scope`` key is the name of a | ||||
|         #: blueprint the functions are active for, or ``None`` for all | ||||
|         #: requests. | ||||
|         #: | ||||
|         #: To register a function, use the :meth:`teardown_request` | ||||
|         #: decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.teardown_request_funcs: dict[ | ||||
|             ft.AppOrBlueprintKey, list[ft.TeardownCallable] | ||||
|         ] = defaultdict(list) | ||||
| 
 | ||||
|         #: A data structure of functions to call to pass extra context | ||||
|         #: values when rendering templates, in the format | ||||
|         #: ``{scope: [functions]}``. The ``scope`` key is the name of a | ||||
|         #: blueprint the functions are active for, or ``None`` for all | ||||
|         #: requests. | ||||
|         #: | ||||
|         #: To register a function, use the :meth:`context_processor` | ||||
|         #: decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.template_context_processors: dict[ | ||||
|             ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] | ||||
|         ] = defaultdict(list, {None: [_default_template_ctx_processor]}) | ||||
| 
 | ||||
|         #: A data structure of functions to call to modify the keyword | ||||
|         #: arguments passed to the view function, in the format | ||||
|         #: ``{scope: [functions]}``. The ``scope`` key is the name of a | ||||
|         #: blueprint the functions are active for, or ``None`` for all | ||||
|         #: requests. | ||||
|         #: | ||||
|         #: To register a function, use the | ||||
|         #: :meth:`url_value_preprocessor` decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.url_value_preprocessors: dict[ | ||||
|             ft.AppOrBlueprintKey, | ||||
|             list[ft.URLValuePreprocessorCallable], | ||||
|         ] = defaultdict(list) | ||||
| 
 | ||||
|         #: A data structure of functions to call to modify the keyword | ||||
|         #: arguments when generating URLs, in the format | ||||
|         #: ``{scope: [functions]}``. The ``scope`` key is the name of a | ||||
|         #: blueprint the functions are active for, or ``None`` for all | ||||
|         #: requests. | ||||
|         #: | ||||
|         #: To register a function, use the :meth:`url_defaults` | ||||
|         #: decorator. | ||||
|         #: | ||||
|         #: This data structure is internal. It should not be modified | ||||
|         #: directly and its format may change at any time. | ||||
|         self.url_default_functions: dict[ | ||||
|             ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] | ||||
|         ] = defaultdict(list) | ||||
| 
 | ||||
|     def __repr__(self) -> str: | ||||
|         return f"<{type(self).__name__} {self.name!r}>" | ||||
| 
 | ||||
|     def _check_setup_finished(self, f_name: str) -> None: | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     @property | ||||
|     def static_folder(self) -> str | None: | ||||
|         """The absolute path to the configured static folder. ``None`` | ||||
|         if no static folder is set. | ||||
|         """ | ||||
|         if self._static_folder is not None: | ||||
|             return os.path.join(self.root_path, self._static_folder) | ||||
|         else: | ||||
|             return None | ||||
| 
 | ||||
|     @static_folder.setter | ||||
|     def static_folder(self, value: str | os.PathLike[str] | None) -> None: | ||||
|         if value is not None: | ||||
|             value = os.fspath(value).rstrip(r"\/") | ||||
| 
 | ||||
|         self._static_folder = value | ||||
| 
 | ||||
|     @property | ||||
|     def has_static_folder(self) -> bool: | ||||
|         """``True`` if :attr:`static_folder` is set. | ||||
| 
 | ||||
|         .. versionadded:: 0.5 | ||||
|         """ | ||||
|         return self.static_folder is not None | ||||
| 
 | ||||
|     @property | ||||
|     def static_url_path(self) -> str | None: | ||||
|         """The URL prefix that the static route will be accessible from. | ||||
| 
 | ||||
|         If it was not configured during init, it is derived from | ||||
|         :attr:`static_folder`. | ||||
|         """ | ||||
|         if self._static_url_path is not None: | ||||
|             return self._static_url_path | ||||
| 
 | ||||
|         if self.static_folder is not None: | ||||
|             basename = os.path.basename(self.static_folder) | ||||
|             return f"/{basename}".rstrip("/") | ||||
| 
 | ||||
|         return None | ||||
| 
 | ||||
|     @static_url_path.setter | ||||
|     def static_url_path(self, value: str | None) -> None: | ||||
|         if value is not None: | ||||
|             value = value.rstrip("/") | ||||
| 
 | ||||
|         self._static_url_path = value | ||||
| 
 | ||||
|     @cached_property | ||||
|     def jinja_loader(self) -> BaseLoader | None: | ||||
|         """The Jinja loader for this object's templates. By default this | ||||
|         is a class :class:`jinja2.loaders.FileSystemLoader` to | ||||
|         :attr:`template_folder` if it is set. | ||||
| 
 | ||||
|         .. versionadded:: 0.5 | ||||
|         """ | ||||
|         if self.template_folder is not None: | ||||
|             return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) | ||||
|         else: | ||||
|             return None | ||||
| 
 | ||||
|     def _method_route( | ||||
|         self, | ||||
|         method: str, | ||||
|         rule: str, | ||||
|         options: dict[str, t.Any], | ||||
|     ) -> t.Callable[[T_route], T_route]: | ||||
|         if "methods" in options: | ||||
|             raise TypeError("Use the 'route' decorator to use the 'methods' argument.") | ||||
| 
 | ||||
|         return self.route(rule, methods=[method], **options) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: | ||||
|         """Shortcut for :meth:`route` with ``methods=["GET"]``. | ||||
| 
 | ||||
|         .. versionadded:: 2.0 | ||||
|         """ | ||||
|         return self._method_route("GET", rule, options) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: | ||||
|         """Shortcut for :meth:`route` with ``methods=["POST"]``. | ||||
| 
 | ||||
|         .. versionadded:: 2.0 | ||||
|         """ | ||||
|         return self._method_route("POST", rule, options) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: | ||||
|         """Shortcut for :meth:`route` with ``methods=["PUT"]``. | ||||
| 
 | ||||
|         .. versionadded:: 2.0 | ||||
|         """ | ||||
|         return self._method_route("PUT", rule, options) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: | ||||
|         """Shortcut for :meth:`route` with ``methods=["DELETE"]``. | ||||
| 
 | ||||
|         .. versionadded:: 2.0 | ||||
|         """ | ||||
|         return self._method_route("DELETE", rule, options) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: | ||||
|         """Shortcut for :meth:`route` with ``methods=["PATCH"]``. | ||||
| 
 | ||||
|         .. versionadded:: 2.0 | ||||
|         """ | ||||
|         return self._method_route("PATCH", rule, options) | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: | ||||
|         """Decorate a view function to register it with the given URL | ||||
|         rule and options. Calls :meth:`add_url_rule`, which has more | ||||
|         details about the implementation. | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             @app.route("/") | ||||
|             def index(): | ||||
|                 return "Hello, World!" | ||||
| 
 | ||||
|         See :ref:`url-route-registrations`. | ||||
| 
 | ||||
|         The endpoint name for the route defaults to the name of the view | ||||
|         function if the ``endpoint`` parameter isn't passed. | ||||
| 
 | ||||
|         The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and | ||||
|         ``OPTIONS`` are added automatically. | ||||
| 
 | ||||
|         :param rule: The URL rule string. | ||||
|         :param options: Extra options passed to the | ||||
|             :class:`~werkzeug.routing.Rule` object. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_route) -> T_route: | ||||
|             endpoint = options.pop("endpoint", None) | ||||
|             self.add_url_rule(rule, endpoint, f, **options) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def add_url_rule( | ||||
|         self, | ||||
|         rule: str, | ||||
|         endpoint: str | None = None, | ||||
|         view_func: ft.RouteCallable | None = None, | ||||
|         provide_automatic_options: bool | None = None, | ||||
|         **options: t.Any, | ||||
|     ) -> None: | ||||
|         """Register a rule for routing incoming requests and building | ||||
|         URLs. The :meth:`route` decorator is a shortcut to call this | ||||
|         with the ``view_func`` argument. These are equivalent: | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             @app.route("/") | ||||
|             def index(): | ||||
|                 ... | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             def index(): | ||||
|                 ... | ||||
| 
 | ||||
|             app.add_url_rule("/", view_func=index) | ||||
| 
 | ||||
|         See :ref:`url-route-registrations`. | ||||
| 
 | ||||
|         The endpoint name for the route defaults to the name of the view | ||||
|         function if the ``endpoint`` parameter isn't passed. An error | ||||
|         will be raised if a function has already been registered for the | ||||
|         endpoint. | ||||
| 
 | ||||
|         The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is | ||||
|         always added automatically, and ``OPTIONS`` is added | ||||
|         automatically by default. | ||||
| 
 | ||||
|         ``view_func`` does not necessarily need to be passed, but if the | ||||
|         rule should participate in routing an endpoint name must be | ||||
|         associated with a view function at some point with the | ||||
|         :meth:`endpoint` decorator. | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             app.add_url_rule("/", endpoint="index") | ||||
| 
 | ||||
|             @app.endpoint("index") | ||||
|             def index(): | ||||
|                 ... | ||||
| 
 | ||||
|         If ``view_func`` has a ``required_methods`` attribute, those | ||||
|         methods are added to the passed and automatic methods. If it | ||||
|         has a ``provide_automatic_methods`` attribute, it is used as the | ||||
|         default if the parameter is not passed. | ||||
| 
 | ||||
|         :param rule: The URL rule string. | ||||
|         :param endpoint: The endpoint name to associate with the rule | ||||
|             and view function. Used when routing and building URLs. | ||||
|             Defaults to ``view_func.__name__``. | ||||
|         :param view_func: The view function to associate with the | ||||
|             endpoint name. | ||||
|         :param provide_automatic_options: Add the ``OPTIONS`` method and | ||||
|             respond to ``OPTIONS`` requests automatically. | ||||
|         :param options: Extra options passed to the | ||||
|             :class:`~werkzeug.routing.Rule` object. | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def endpoint(self, endpoint: str) -> t.Callable[[F], F]: | ||||
|         """Decorate a view function to register it for the given | ||||
|         endpoint. Used if a rule is added without a ``view_func`` with | ||||
|         :meth:`add_url_rule`. | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             app.add_url_rule("/ex", endpoint="example") | ||||
| 
 | ||||
|             @app.endpoint("example") | ||||
|             def example(): | ||||
|                 ... | ||||
| 
 | ||||
|         :param endpoint: The endpoint name to associate with the view | ||||
|             function. | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: F) -> F: | ||||
|             self.view_functions[endpoint] = f | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def before_request(self, f: T_before_request) -> T_before_request: | ||||
|         """Register a function to run before each request. | ||||
| 
 | ||||
|         For example, this can be used to open a database connection, or | ||||
|         to load the logged in user from the session. | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             @app.before_request | ||||
|             def load_user(): | ||||
|                 if "user_id" in session: | ||||
|                     g.user = db.session.get(session["user_id"]) | ||||
| 
 | ||||
|         The function will be called without any arguments. If it returns | ||||
|         a non-``None`` value, the value is handled as if it was the | ||||
|         return value from the view, and further request handling is | ||||
|         stopped. | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         executes before every request. When used on a blueprint, this executes before | ||||
|         every request that the blueprint handles. To register with a blueprint and | ||||
|         execute before every request, use :meth:`.Blueprint.before_app_request`. | ||||
|         """ | ||||
|         self.before_request_funcs.setdefault(None, []).append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def after_request(self, f: T_after_request) -> T_after_request: | ||||
|         """Register a function to run after each request to this object. | ||||
| 
 | ||||
|         The function is called with the response object, and must return | ||||
|         a response object. This allows the functions to modify or | ||||
|         replace the response before it is sent. | ||||
| 
 | ||||
|         If a function raises an exception, any remaining | ||||
|         ``after_request`` functions will not be called. Therefore, this | ||||
|         should not be used for actions that must execute, such as to | ||||
|         close resources. Use :meth:`teardown_request` for that. | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         executes after every request. When used on a blueprint, this executes after | ||||
|         every request that the blueprint handles. To register with a blueprint and | ||||
|         execute after every request, use :meth:`.Blueprint.after_app_request`. | ||||
|         """ | ||||
|         self.after_request_funcs.setdefault(None, []).append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def teardown_request(self, f: T_teardown) -> T_teardown: | ||||
|         """Register a function to be called when the request context is | ||||
|         popped. Typically this happens at the end of each request, but | ||||
|         contexts may be pushed manually as well during testing. | ||||
| 
 | ||||
|         .. code-block:: python | ||||
| 
 | ||||
|             with app.test_request_context(): | ||||
|                 ... | ||||
| 
 | ||||
|         When the ``with`` block exits (or ``ctx.pop()`` is called), the | ||||
|         teardown functions are called just before the request context is | ||||
|         made inactive. | ||||
| 
 | ||||
|         When a teardown function was called because of an unhandled | ||||
|         exception it will be passed an error object. If an | ||||
|         :meth:`errorhandler` is registered, it will handle the exception | ||||
|         and the teardown will not receive it. | ||||
| 
 | ||||
|         Teardown functions must avoid raising exceptions. If they | ||||
|         execute code that might fail they must surround that code with a | ||||
|         ``try``/``except`` block and log any errors. | ||||
| 
 | ||||
|         The return values of teardown functions are ignored. | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         executes after every request. When used on a blueprint, this executes after | ||||
|         every request that the blueprint handles. To register with a blueprint and | ||||
|         execute after every request, use :meth:`.Blueprint.teardown_app_request`. | ||||
|         """ | ||||
|         self.teardown_request_funcs.setdefault(None, []).append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def context_processor( | ||||
|         self, | ||||
|         f: T_template_context_processor, | ||||
|     ) -> T_template_context_processor: | ||||
|         """Registers a template context processor function. These functions run before | ||||
|         rendering a template. The keys of the returned dict are added as variables | ||||
|         available in the template. | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         is called for every rendered template. When used on a blueprint, this is called | ||||
|         for templates rendered from the blueprint's views. To register with a blueprint | ||||
|         and affect every template, use :meth:`.Blueprint.app_context_processor`. | ||||
|         """ | ||||
|         self.template_context_processors[None].append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def url_value_preprocessor( | ||||
|         self, | ||||
|         f: T_url_value_preprocessor, | ||||
|     ) -> T_url_value_preprocessor: | ||||
|         """Register a URL value preprocessor function for all view | ||||
|         functions in the application. These functions will be called before the | ||||
|         :meth:`before_request` functions. | ||||
| 
 | ||||
|         The function can modify the values captured from the matched url before | ||||
|         they are passed to the view. For example, this can be used to pop a | ||||
|         common language code value and place it in ``g`` rather than pass it to | ||||
|         every view. | ||||
| 
 | ||||
|         The function is passed the endpoint name and values dict. The return | ||||
|         value is ignored. | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         is called for every request. When used on a blueprint, this is called for | ||||
|         requests that the blueprint handles. To register with a blueprint and affect | ||||
|         every request, use :meth:`.Blueprint.app_url_value_preprocessor`. | ||||
|         """ | ||||
|         self.url_value_preprocessors[None].append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def url_defaults(self, f: T_url_defaults) -> T_url_defaults: | ||||
|         """Callback function for URL defaults for all view functions of the | ||||
|         application.  It's called with the endpoint and values and should | ||||
|         update the values passed in place. | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         is called for every request. When used on a blueprint, this is called for | ||||
|         requests that the blueprint handles. To register with a blueprint and affect | ||||
|         every request, use :meth:`.Blueprint.app_url_defaults`. | ||||
|         """ | ||||
|         self.url_default_functions[None].append(f) | ||||
|         return f | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def errorhandler( | ||||
|         self, code_or_exception: type[Exception] | int | ||||
|     ) -> t.Callable[[T_error_handler], T_error_handler]: | ||||
|         """Register a function to handle errors by code or exception class. | ||||
| 
 | ||||
|         A decorator that is used to register a function given an | ||||
|         error code.  Example:: | ||||
| 
 | ||||
|             @app.errorhandler(404) | ||||
|             def page_not_found(error): | ||||
|                 return 'This page does not exist', 404 | ||||
| 
 | ||||
|         You can also register handlers for arbitrary exceptions:: | ||||
| 
 | ||||
|             @app.errorhandler(DatabaseError) | ||||
|             def special_exception_handler(error): | ||||
|                 return 'Database connection failed', 500 | ||||
| 
 | ||||
|         This is available on both app and blueprint objects. When used on an app, this | ||||
|         can handle errors from every request. When used on a blueprint, this can handle | ||||
|         errors from requests that the blueprint handles. To register with a blueprint | ||||
|         and affect every request, use :meth:`.Blueprint.app_errorhandler`. | ||||
| 
 | ||||
|         .. versionadded:: 0.7 | ||||
|             Use :meth:`register_error_handler` instead of modifying | ||||
|             :attr:`error_handler_spec` directly, for application wide error | ||||
|             handlers. | ||||
| 
 | ||||
|         .. versionadded:: 0.7 | ||||
|            One can now additionally also register custom exception types | ||||
|            that do not necessarily have to be a subclass of the | ||||
|            :class:`~werkzeug.exceptions.HTTPException` class. | ||||
| 
 | ||||
|         :param code_or_exception: the code as integer for the handler, or | ||||
|                                   an arbitrary exception | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(f: T_error_handler) -> T_error_handler: | ||||
|             self.register_error_handler(code_or_exception, f) | ||||
|             return f | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @setupmethod | ||||
|     def register_error_handler( | ||||
|         self, | ||||
|         code_or_exception: type[Exception] | int, | ||||
|         f: ft.ErrorHandlerCallable, | ||||
|     ) -> None: | ||||
|         """Alternative error attach function to the :meth:`errorhandler` | ||||
|         decorator that is more straightforward to use for non decorator | ||||
|         usage. | ||||
| 
 | ||||
|         .. versionadded:: 0.7 | ||||
|         """ | ||||
|         exc_class, code = self._get_exc_class_and_code(code_or_exception) | ||||
|         self.error_handler_spec[None][code][exc_class] = f | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _get_exc_class_and_code( | ||||
|         exc_class_or_code: type[Exception] | int, | ||||
|     ) -> tuple[type[Exception], int | None]: | ||||
|         """Get the exception class being handled. For HTTP status codes | ||||
|         or ``HTTPException`` subclasses, return both the exception and | ||||
|         status code. | ||||
| 
 | ||||
|         :param exc_class_or_code: Any exception class, or an HTTP status | ||||
|             code as an integer. | ||||
|         """ | ||||
|         exc_class: type[Exception] | ||||
| 
 | ||||
|         if isinstance(exc_class_or_code, int): | ||||
|             try: | ||||
|                 exc_class = default_exceptions[exc_class_or_code] | ||||
|             except KeyError: | ||||
|                 raise ValueError( | ||||
|                     f"'{exc_class_or_code}' is not a recognized HTTP" | ||||
|                     " error code. Use a subclass of HTTPException with" | ||||
|                     " that code instead." | ||||
|                 ) from None | ||||
|         else: | ||||
|             exc_class = exc_class_or_code | ||||
| 
 | ||||
|         if isinstance(exc_class, Exception): | ||||
|             raise TypeError( | ||||
|                 f"{exc_class!r} is an instance, not a class. Handlers" | ||||
|                 " can only be registered for Exception classes or HTTP" | ||||
|                 " error codes." | ||||
|             ) | ||||
| 
 | ||||
|         if not issubclass(exc_class, Exception): | ||||
|             raise ValueError( | ||||
|                 f"'{exc_class.__name__}' is not a subclass of Exception." | ||||
|                 " Handlers can only be registered for Exception classes" | ||||
|                 " or HTTP error codes." | ||||
|             ) | ||||
| 
 | ||||
|         if issubclass(exc_class, HTTPException): | ||||
|             return exc_class, exc_class.code | ||||
|         else: | ||||
|             return exc_class, None | ||||
| 
 | ||||
| 
 | ||||
| def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str: | ||||
|     """Internal helper that returns the default endpoint for a given | ||||
|     function.  This always is the function name. | ||||
|     """ | ||||
|     assert view_func is not None, "expected view func if endpoint is not provided." | ||||
|     return view_func.__name__ | ||||
| 
 | ||||
| 
 | ||||
| def _path_is_relative_to(path: pathlib.PurePath, base: str) -> bool: | ||||
|     # Path.is_relative_to doesn't exist until Python 3.9 | ||||
|     try: | ||||
|         path.relative_to(base) | ||||
|         return True | ||||
|     except ValueError: | ||||
|         return False | ||||
| 
 | ||||
| 
 | ||||
| def _find_package_path(import_name: str) -> str: | ||||
|     """Find the path that contains the package or module.""" | ||||
|     root_mod_name, _, _ = import_name.partition(".") | ||||
| 
 | ||||
|     try: | ||||
|         root_spec = importlib.util.find_spec(root_mod_name) | ||||
| 
 | ||||
|         if root_spec is None: | ||||
|             raise ValueError("not found") | ||||
|     except (ImportError, ValueError): | ||||
|         # ImportError: the machinery told us it does not exist | ||||
|         # ValueError: | ||||
|         #    - the module name was invalid | ||||
|         #    - the module name is __main__ | ||||
|         #    - we raised `ValueError` due to `root_spec` being `None` | ||||
|         return os.getcwd() | ||||
| 
 | ||||
|     if root_spec.submodule_search_locations: | ||||
|         if root_spec.origin is None or root_spec.origin == "namespace": | ||||
|             # namespace package | ||||
|             package_spec = importlib.util.find_spec(import_name) | ||||
| 
 | ||||
|             if package_spec is not None and package_spec.submodule_search_locations: | ||||
|                 # Pick the path in the namespace that contains the submodule. | ||||
|                 package_path = pathlib.Path( | ||||
|                     os.path.commonpath(package_spec.submodule_search_locations) | ||||
|                 ) | ||||
|                 search_location = next( | ||||
|                     location | ||||
|                     for location in root_spec.submodule_search_locations | ||||
|                     if _path_is_relative_to(package_path, location) | ||||
|                 ) | ||||
|             else: | ||||
|                 # Pick the first path. | ||||
|                 search_location = root_spec.submodule_search_locations[0] | ||||
| 
 | ||||
|             return os.path.dirname(search_location) | ||||
|         else: | ||||
|             # package with __init__.py | ||||
|             return os.path.dirname(os.path.dirname(root_spec.origin)) | ||||
|     else: | ||||
|         # module | ||||
|         return os.path.dirname(root_spec.origin)  # type: ignore[type-var, return-value] | ||||
| 
 | ||||
| 
 | ||||
| def find_package(import_name: str) -> tuple[str | None, str]: | ||||
|     """Find the prefix that a package is installed under, and the path | ||||
|     that it would be imported from. | ||||
| 
 | ||||
|     The prefix is the directory containing the standard directory | ||||
|     hierarchy (lib, bin, etc.). If the package is not installed to the | ||||
|     system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), | ||||
|     ``None`` is returned. | ||||
| 
 | ||||
|     The path is the entry in :attr:`sys.path` that contains the package | ||||
|     for import. If the package is not installed, it's assumed that the | ||||
|     package was imported from the current working directory. | ||||
|     """ | ||||
|     package_path = _find_package_path(import_name) | ||||
|     py_prefix = os.path.abspath(sys.prefix) | ||||
| 
 | ||||
|     # installed to the system | ||||
|     if _path_is_relative_to(pathlib.PurePath(package_path), py_prefix): | ||||
|         return py_prefix, package_path | ||||
| 
 | ||||
|     site_parent, site_folder = os.path.split(package_path) | ||||
| 
 | ||||
|     # installed to a virtualenv | ||||
|     if site_folder.lower() == "site-packages": | ||||
|         parent, folder = os.path.split(site_parent) | ||||
| 
 | ||||
|         # Windows (prefix/lib/site-packages) | ||||
|         if folder.lower() == "lib": | ||||
|             return parent, package_path | ||||
| 
 | ||||
|         # Unix (prefix/lib/pythonX.Y/site-packages) | ||||
|         if os.path.basename(parent).lower() == "lib": | ||||
|             return os.path.dirname(parent), package_path | ||||
| 
 | ||||
|         # something else (prefix/site-packages) | ||||
|         return site_parent, package_path | ||||
| 
 | ||||
|     # not installed | ||||
|     return None, package_path | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tykayn
						Tykayn