@setupmethod defroute(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. """
# scaffold.py @setupmethod defadd_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
# 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 isNone: methods = getattr(view_func, "methods", None) or ("GET",) ifisinstance(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 isNone: provide_automatic_options = getattr( view_func, "provide_automatic_options", 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 isnotNone, "expected view func if endpoint is not provided." return view_func.__name__
# 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 isNone: methods = getattr(view_func, "methods", None) or ("GET",) ifisinstance(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 isNone: provide_automatic_options = getattr( view_func, "provide_automatic_options", None )
classFlask(App): defcreate_url_adapter(self, request: Request | None) -> MapAdapter | None: """Creates a URL adapter for the given request. The URL adapter is created at a point where the request context is not yet set up so the request is passed explicitly. .. versionadded:: 0.6 .. versionchanged:: 0.9 This can now also be called without a request object when the URL adapter is created for the application context. .. versionchanged:: 1.0 :data:`SERVER_NAME` no longer implicitly enables subdomain matching. Use :attr:`subdomain_matching` instead. """ if request isnotNone: # If subdomain matching is disabled (the default), use the # default subdomain in all cases. This should be the default # in Werkzeug but it currently does not have that feature. ifnotself.subdomain_matching: subdomain = self.url_map.default_subdomain orNone else: subdomain = None
returnself.url_map.bind_to_environ( request.environ, server_name=self.config["SERVER_NAME"], subdomain=subdomain, ) # We need at the very least the server name to be set for this # to work. ifself.config["SERVER_NAME"] isnotNone: returnself.url_map.bind( self.config["SERVER_NAME"], script_name=self.config["APPLICATION_ROOT"], url_scheme=self.config["PREFERRED_URL_SCHEME"], )
returnNone
classRequestContext: def__init__( self, app: Flask, environ: WSGIEnvironment, request: Request | None = None, session: SessionMixin | None = None, ) -> None: self.app = app if request isNone: request = app.request_class(environ) request.json_module = app.json self.request: Request = request self.url_adapter = None try: self.url_adapter = app.create_url_adapter(self.request) except HTTPException as e: self.request.routing_exception = e self.flashes: list[tuple[str, str]] | None = None self.session: SessionMixin | None = session # Functions that should be executed after the request on the response # object. These will be called before the regular "after_request" # functions. self._after_request_functions: list[ft.AfterRequestCallable[t.Any]] = []
defmatch_request(self) -> None: """Can be overridden by a subclass to hook into the matching of the request. """ try: result = self.url_adapter.match(return_rule=True) # type: ignore self.request.url_rule, self.request.view_args = result # type: ignore except HTTPException as e: self.request.routing_exception = e
defdispatch_request(self) -> ft.ResponseReturnValue: """Does the request dispatching. Matches the URL and returns the return value of the view or error handler. This does not have to be a response object. In order to convert the return value to a proper response object, call :func:`make_response`. .. versionchanged:: 0.7 This no longer does the exception handling, this code was moved to the new :meth:`full_dispatch_request`. """ req = request_ctx.request if req.routing_exception isnotNone: self.raise_routing_exception(req) rule: Rule = req.url_rule # type: ignore[assignment] # if we provide automatic options for this URL and the # request came with the OPTIONS method, reply automatically if ( getattr(rule, "provide_automatic_options", False) and req.method == "OPTIONS" ): returnself.make_default_options_response() # otherwise dispatch to the handler for that endpoint view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] returnself.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
defmake_default_options_response(self) -> Response: """This method is called to create the default ``OPTIONS`` response. This can be changed through subclassing to change the default behavior of ``OPTIONS`` responses. .. versionadded:: 0.7 """ adapter = request_ctx.url_adapter methods = adapter.allowed_methods() # type: ignore[union-attr] rv = self.response_class() rv.allow.update(methods) return rv