diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2025-01-16 19:09:30 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2025-01-16 19:38:51 +0300 |
commit | 7a23ad1fa2a5561a3575177d7240d8a1aa499718 (patch) | |
tree | b4932bad31f595149e7a42e88cf729919995d735 /contrib/python/Flask/py3/flask/views.py | |
parent | fbb15f5ab8a61fc7c50500e2757af0b47174d825 (diff) | |
download | ydb-7a23ad1fa2a5561a3575177d7240d8a1aa499718.tar.gz |
Intermediate changes
commit_hash:ae9e37c897fc6d514389f7089184df33bf781005
Diffstat (limited to 'contrib/python/Flask/py3/flask/views.py')
-rw-r--r-- | contrib/python/Flask/py3/flask/views.py | 188 |
1 files changed, 109 insertions, 79 deletions
diff --git a/contrib/python/Flask/py3/flask/views.py b/contrib/python/Flask/py3/flask/views.py index 1dd560c62bf..f86172b43cc 100644 --- a/contrib/python/Flask/py3/flask/views.py +++ b/contrib/python/Flask/py3/flask/views.py @@ -11,77 +11,106 @@ http_method_funcs = frozenset( class View: - """Alternative way to use view functions. A subclass has to implement - :meth:`dispatch_request` which is called with the view arguments from - the URL routing system. If :attr:`methods` is provided the methods - do not have to be passed to the :meth:`~flask.Flask.add_url_rule` - method explicitly:: + """Subclass this class and override :meth:`dispatch_request` to + create a generic class-based view. Call :meth:`as_view` to create a + view function that creates an instance of the class with the given + arguments and calls its ``dispatch_request`` method with any URL + variables. - class MyView(View): - methods = ['GET'] + See :doc:`views` for a detailed guide. - def dispatch_request(self, name): - return f"Hello {name}!" + .. code-block:: python + + class Hello(View): + init_every_request = False - app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview')) + def dispatch_request(self, name): + return f"Hello, {name}!" - When you want to decorate a pluggable view you will have to either do that - when the view function is created (by wrapping the return value of - :meth:`as_view`) or you can use the :attr:`decorators` attribute:: + app.add_url_rule( + "/hello/<name>", view_func=Hello.as_view("hello") + ) - class SecretView(View): - methods = ['GET'] - decorators = [superuser_required] + Set :attr:`methods` on the class to change what methods the view + accepts. - def dispatch_request(self): - ... + Set :attr:`decorators` on the class to apply a list of decorators to + the generated view function. Decorators applied to the class itself + will not be applied to the generated view function! - The decorators stored in the decorators list are applied one after another - when the view function is created. Note that you can *not* use the class - based decorators since those would decorate the view class and not the - generated view function! + Set :attr:`init_every_request` to ``False`` for efficiency, unless + you need to store request-global data on ``self``. """ - #: A list of methods this view can handle. - methods: t.Optional[t.List[str]] = None + #: The methods this view is registered for. Uses the same default + #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and + #: ``add_url_rule`` by default. + methods: t.ClassVar[t.Optional[t.Collection[str]]] = None - #: Setting this disables or force-enables the automatic options handling. - provide_automatic_options: t.Optional[bool] = None + #: Control whether the ``OPTIONS`` method is handled automatically. + #: Uses the same default (``True``) as ``route`` and + #: ``add_url_rule`` by default. + provide_automatic_options: t.ClassVar[t.Optional[bool]] = None - #: The canonical way to decorate class-based views is to decorate the - #: return value of as_view(). However since this moves parts of the - #: logic from the class declaration to the place where it's hooked - #: into the routing system. - #: - #: You can place one or more decorators in this list and whenever the - #: view function is created the result is automatically decorated. + #: A list of decorators to apply, in order, to the generated view + #: function. Remember that ``@decorator`` syntax is applied bottom + #: to top, so the first decorator in the list would be the bottom + #: decorator. #: #: .. versionadded:: 0.8 - decorators: t.List[t.Callable] = [] + decorators: t.ClassVar[t.List[t.Callable]] = [] + + #: Create a new instance of this view class for every request by + #: default. If a view subclass sets this to ``False``, the same + #: instance is used for every request. + #: + #: A single instance is more efficient, especially if complex setup + #: is done during init. However, storing data on ``self`` is no + #: longer safe across requests, and :data:`~flask.g` should be used + #: instead. + #: + #: .. versionadded:: 2.2 + init_every_request: t.ClassVar[bool] = True def dispatch_request(self) -> ft.ResponseReturnValue: - """Subclasses have to override this method to implement the - actual view function code. This method is called with all - the arguments from the URL rule. + """The actual view function behavior. Subclasses must override + this and return a valid response. Any variables from the URL + rule are passed as keyword arguments. """ raise NotImplementedError() @classmethod def as_view( cls, name: str, *class_args: t.Any, **class_kwargs: t.Any - ) -> t.Callable: - """Converts the class into an actual view function that can be used - with the routing system. Internally this generates a function on the - fly which will instantiate the :class:`View` on each request and call - the :meth:`dispatch_request` method on it. - - The arguments passed to :meth:`as_view` are forwarded to the - constructor of the class. + ) -> ft.RouteCallable: + """Convert the class into a view function that can be registered + for a route. + + By default, the generated view will create a new instance of the + view class for every request and call its + :meth:`dispatch_request` method. If the view class sets + :attr:`init_every_request` to ``False``, the same instance will + be used for every request. + + Except for ``name``, all other arguments passed to this method + are forwarded to the view class ``__init__`` method. + + .. versionchanged:: 2.2 + Added the ``init_every_request`` class attribute. """ + if cls.init_every_request: + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + self = view.view_class( # type: ignore[attr-defined] + *class_args, **class_kwargs + ) + return current_app.ensure_sync(self.dispatch_request)(**kwargs) + + else: + self = cls(*class_args, **class_kwargs) - def view(*args: t.Any, **kwargs: t.Any) -> ft.ResponseReturnValue: - self = view.view_class(*class_args, **class_kwargs) # type: ignore - return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs) + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) if cls.decorators: view.__name__ = name @@ -103,50 +132,51 @@ class View: return view -class MethodViewType(type): - """Metaclass for :class:`MethodView` that determines what methods the view - defines. +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) """ - def __init__(cls, name, bases, d): - super().__init__(name, bases, d) + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) - if "methods" not in d: + if "methods" not in cls.__dict__: methods = set() - for base in bases: + for base in cls.__bases__: if getattr(base, "methods", None): - methods.update(base.methods) + methods.update(base.methods) # type: ignore[attr-defined] for key in http_method_funcs: if hasattr(cls, key): methods.add(key.upper()) - # If we have no method at all in there we don't want to add a - # method list. This is for instance the case for the base class - # or another subclass of a base method view that does not introduce - # new methods. if methods: cls.methods = methods - -class MethodView(View, metaclass=MethodViewType): - """A class-based view that dispatches request methods to the corresponding - class methods. For example, if you implement a ``get`` method, it will be - used to handle ``GET`` requests. :: - - class CounterAPI(MethodView): - def get(self): - return session.get('counter', 0) - - def post(self): - session['counter'] = session.get('counter', 0) + 1 - return 'OK' - - app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter')) - """ - - def dispatch_request(self, *args: t.Any, **kwargs: t.Any) -> ft.ResponseReturnValue: + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: meth = getattr(self, request.method.lower(), None) # If the request method is HEAD and we don't have a handler for it @@ -155,4 +185,4 @@ class MethodView(View, metaclass=MethodViewType): meth = getattr(self, "get", None) assert meth is not None, f"Unimplemented method {request.method!r}" - return current_app.ensure_sync(meth)(*args, **kwargs) + return current_app.ensure_sync(meth)(**kwargs) |