diff options
author | James Taylor <user234683@users.noreply.github.com> | 2019-08-09 22:01:04 -0700 |
---|---|---|
committer | James Taylor <user234683@users.noreply.github.com> | 2019-08-09 22:01:04 -0700 |
commit | 2e75c6d9603f8a5edf6495f8d4fb3115a67d823c (patch) | |
tree | 8fb2d1bec2cf0e50c5fce6bc718f755485419db0 /python/flask/views.py | |
parent | cc9283ad5332f59a69a91d9d0fab299779de513c (diff) | |
parent | adc40bc760345a23678a01f27d7697dfd3811914 (diff) | |
download | yt-local-2e75c6d9603f8a5edf6495f8d4fb3115a67d823c.tar.lz yt-local-2e75c6d9603f8a5edf6495f8d4fb3115a67d823c.tar.xz yt-local-2e75c6d9603f8a5edf6495f8d4fb3115a67d823c.zip |
Merge flask framework and other stuff from master
Diffstat (limited to 'python/flask/views.py')
-rw-r--r-- | python/flask/views.py | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/python/flask/views.py b/python/flask/views.py new file mode 100644 index 0000000..1f2c997 --- /dev/null +++ b/python/flask/views.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +""" + flask.views + ~~~~~~~~~~~ + + This module provides class-based views inspired by the ones in Django. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +from .globals import request +from ._compat import with_metaclass + + +http_method_funcs = frozenset(['get', 'post', 'head', 'options', + 'delete', 'put', 'trace', 'patch']) + + +class View(object): + """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:: + + class MyView(View): + methods = ['GET'] + + def dispatch_request(self, name): + return 'Hello %s!' % name + + app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview')) + + 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:: + + class SecretView(View): + methods = ['GET'] + decorators = [superuser_required] + + def dispatch_request(self): + ... + + 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! + """ + + #: A list of methods this view can handle. + methods = None + + #: Setting this disables or force-enables the automatic options handling. + provide_automatic_options = 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. + #: + #: .. versionadded:: 0.8 + decorators = () + + def dispatch_request(self): + """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. + """ + raise NotImplementedError() + + @classmethod + def as_view(cls, name, *class_args, **class_kwargs): + """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. + """ + def view(*args, **kwargs): + self = view.view_class(*class_args, **class_kwargs) + return self.dispatch_request(*args, **kwargs) + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods + view.provide_automatic_options = cls.provide_automatic_options + return view + + +class MethodViewType(type): + """Metaclass for :class:`MethodView` that determines what methods the view + defines. + """ + + def __init__(cls, name, bases, d): + super(MethodViewType, cls).__init__(name, bases, d) + + if 'methods' not in d: + methods = set() + + 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(with_metaclass(MethodViewType, View)): + """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, **kwargs): + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == 'HEAD': + meth = getattr(self, 'get', None) + + assert meth is not None, 'Unimplemented method %r' % request.method + return meth(*args, **kwargs) |