mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			151 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- coding: utf-8 -*-
 | 
						|
"""
 | 
						|
    flask.views
 | 
						|
    ~~~~~~~~~~~
 | 
						|
 | 
						|
    This module provides class-based views inspired by the ones in Django.
 | 
						|
 | 
						|
    :copyright: (c) 2011 by Armin Ronacher.
 | 
						|
    :license: BSD, see LICENSE for more details.
 | 
						|
"""
 | 
						|
from .globals import request
 | 
						|
 | 
						|
 | 
						|
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 for which methods this pluggable view can handle.
 | 
						|
    methods = 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
 | 
						|
        return view
 | 
						|
 | 
						|
 | 
						|
class MethodViewType(type):
 | 
						|
 | 
						|
    def __new__(cls, name, bases, d):
 | 
						|
        rv = type.__new__(cls, name, bases, d)
 | 
						|
        if 'methods' not in d:
 | 
						|
            methods = set(rv.methods or [])
 | 
						|
            for key in d:
 | 
						|
                if key in http_method_funcs:
 | 
						|
                    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 baseclass or another subclass of a base method view
 | 
						|
            # that does not introduce new methods).
 | 
						|
            if methods:
 | 
						|
                rv.methods = sorted(methods)
 | 
						|
        return rv
 | 
						|
 | 
						|
 | 
						|
class MethodView(View):
 | 
						|
    """Like a regular class-based view but that dispatches requests to
 | 
						|
    particular methods.  For instance if you implement a method called
 | 
						|
    :meth:`get` it means you will response to ``'GET'`` requests and
 | 
						|
    the :meth:`dispatch_request` implementation will automatically
 | 
						|
    forward your request to that.  Also :attr:`options` is set for you
 | 
						|
    automatically::
 | 
						|
 | 
						|
        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'))
 | 
						|
    """
 | 
						|
    __metaclass__ = MethodViewType
 | 
						|
 | 
						|
    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)
 |