Ticket #5701: 5701.diff

File 5701.diff, 13.7 KB (added by Gary Wilson, 16 years ago)
  • tests/regressiontests/decorators/models.py

    === added directory 'tests/regressiontests/decorators'
    === added file 'tests/regressiontests/decorators/__init__.py'
    === added file 'tests/regressiontests/decorators/models.py'
     
     1# A models.py so that tests run.
     2
  • tests/regressiontests/decorators/tests.py

    === added file 'tests/regressiontests/decorators/tests.py'
     
     1from unittest import TestCase
     2from sys import version_info
     3
     4from django.views.decorators.http import require_http_methods
     5from django.views.decorators.vary import vary_on_headers, vary_on_cookie
     6from django.views.decorators.cache import cache_page, never_cache, cache_control
     7from django.contrib.auth.decorators import user_passes_test
     8from django.contrib.admin.views.decorators import staff_member_required
     9
     10def fully_decorated(request):
     11    """Expected __doc__"""
     12    return HttpResponse('<html><body>dummy</body></html>')
     13fully_decorated.anything = "Expected __dict__"
     14
     15fully_decorated = require_http_methods(["GET"])(fully_decorated)
     16
     17fully_decorated = vary_on_headers('Accept-language')(fully_decorated)
     18fully_decorated = vary_on_cookie(fully_decorated)
     19
     20fully_decorated = cache_page(60*15)(fully_decorated)
     21fully_decorated = cache_control(private=True)(fully_decorated)
     22fully_decorated = never_cache(fully_decorated)
     23
     24fully_decorated = user_passes_test(lambda u:True)(fully_decorated)
     25fully_decorated = staff_member_required(fully_decorated)
     26
     27
     28class DecoratorsTest(TestCase):
     29
     30    def test_attributes(self):
     31        """
     32        Tests that django decorators set certain attributes of the wrapped
     33        function.
     34        """
     35        self.assertEquals(fully_decorated.__doc__, 'Expected __doc__')
     36        self.assertEquals(fully_decorated.__dict__['anything'], 'Expected __dict__')
     37        # Only run this test on Python 2.4 or later since __name__ can't be
     38        # assigned to in earlier versions.
     39        if version_info[0] >= 2 and version_info[1] >= 4:
     40            self.assertEquals(fully_decorated.__name__, 'fully_decorated')
  • django/contrib/admin/views/decorators.py

    === modified file 'django/contrib/admin/views/decorators.py'
     
     1import base64
     2import md5
     3import cPickle as pickle
     4try:
     5    from functools import wraps
     6except ImportError:
     7    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
     8
    19from django import http, template
    210from django.conf import settings
    311from django.contrib.auth.models import User
     
    513from django.shortcuts import render_to_response
    614from django.utils.translation import ugettext_lazy, ugettext as _
    715from django.utils.safestring import mark_safe
    8 import base64, datetime, md5
    9 import cPickle as pickle
    1016
    1117ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
    1218LOGIN_FORM_KEY = 'this_is_the_login_form'
     
    104110            else:
    105111                return _display_login_form(request, ERROR_MESSAGE)
    106112
    107     return _checklogin
     113    return wraps(view_func)(_checklogin)
  • django/contrib/auth/decorators.py

    === modified file 'django/contrib/auth/decorators.py'
     
     1try:
     2    from functools import wraps
     3except ImportError:
     4    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
     5
    16from django.contrib.auth import REDIRECT_FIELD_NAME
    27from django.http import HttpResponseRedirect
    38from django.utils.http import urlquote
     
    914    that takes the user object and returns True if the user passes.
    1015    """
    1116    def decorate(view_func):
    12         return _CheckLogin(view_func, test_func, login_url, redirect_field_name)
     17        return wraps(view_func)(_CheckLogin(view_func, test_func, login_url, redirect_field_name))
    1318    return decorate
    1419
    1520def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
  • django/template/defaultfilters.py

    === modified file 'django/template/defaultfilters.py'
     
    22
    33import re
    44import random as random_module
     5try:
     6    from functools import wraps
     7except ImportError:
     8    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
    59
    610from django.template import Variable, Library
    711from django.conf import settings
     
    3539    for attr in ('is_safe', 'needs_autoescape'):
    3640        if hasattr(func, attr):
    3741            setattr(_dec, attr, getattr(func, attr))
    38     return _dec
     42    return wraps(func)(_dec)
    3943
    4044###################
    4145# STRINGS         #
  • django/utils/decorators.py

    === modified file 'django/utils/decorators.py'
     
    11"Functions that help with dynamically creating decorators for views."
    22
    33import types
     4try:
     5    from functools import wraps
     6except ImportError:
     7    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
    48
    59def decorator_from_middleware(middleware_class):
    610    """
     
    5357                if result is not None:
    5458                    return result
    5559            return response
    56         return _wrapped_view
     60        return wraps(view_func)(_wrapped_view)
    5761    return _decorator_from_middleware
  • django/utils/functional.py

    === modified file 'django/utils/functional.py'
     
     1# License for code in this file that was taken from Python 2.5.
     2
     3# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
     4# --------------------------------------------
     5#
     6# 1. This LICENSE AGREEMENT is between the Python Software Foundation
     7# ("PSF"), and the Individual or Organization ("Licensee") accessing and
     8# otherwise using this software ("Python") in source or binary form and
     9# its associated documentation.
     10#
     11# 2. Subject to the terms and conditions of this License Agreement, PSF
     12# hereby grants Licensee a nonexclusive, royalty-free, world-wide
     13# license to reproduce, analyze, test, perform and/or display publicly,
     14# prepare derivative works, distribute, and otherwise use Python
     15# alone or in any derivative version, provided, however, that PSF's
     16# License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
     17# 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
     18# All Rights Reserved" are retained in Python alone or in any derivative
     19# version prepared by Licensee.
     20#
     21# 3. In the event Licensee prepares a derivative work that is based on
     22# or incorporates Python or any part thereof, and wants to make
     23# the derivative work available to others as provided herein, then
     24# Licensee hereby agrees to include in any such work a brief summary of
     25# the changes made to Python.
     26#
     27# 4. PSF is making Python available to Licensee on an "AS IS"
     28# basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
     29# IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
     30# DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
     31# FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
     32# INFRINGE ANY THIRD PARTY RIGHTS.
     33#
     34# 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
     35# FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
     36# A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
     37# OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
     38#
     39# 6. This License Agreement will automatically terminate upon a material
     40# breach of its terms and conditions.
     41#
     42# 7. Nothing in this License Agreement shall be deemed to create any
     43# relationship of agency, partnership, or joint venture between PSF and
     44# Licensee.  This License Agreement does not grant permission to use PSF
     45# trademarks or trade name in a trademark sense to endorse or promote
     46# products or services of Licensee, or any third party.
     47#
     48# 8. By copying, installing or otherwise using Python, Licensee
     49# agrees to be bound by the terms and conditions of this License
     50# Agreement.
     51
     52
    153def curry(_curried_func, *args, **kwargs):
    254    def _curried(*moreargs, **morekwargs):
    355        return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
    456    return _curried
    557
     58### Begin from Python 2.5 functools.py ########################################
     59
     60# Changes made to this Python 2.5 code:
     61#   * swapped ``partial`` for ``curry`` to maintain backwards-compatibility
     62#     in Django.
     63#   * Wrapped the setattr call in update_wrapper with a try-except block to
     64#     make it compatible with Python 2.3, which doesn't allow assigning
     65#     to __name__.
     66
     67# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation.
     68# All Rights Reserved.
     69
     70# update_wrapper() and wraps() are tools to help write
     71# wrapper functions that can handle naive introspection
     72
     73WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
     74WRAPPER_UPDATES = ('__dict__',)
     75def update_wrapper(wrapper,
     76                   wrapped,
     77                   assigned = WRAPPER_ASSIGNMENTS,
     78                   updated = WRAPPER_UPDATES):
     79    """Update a wrapper function to look like the wrapped function
     80
     81       wrapper is the function to be updated
     82       wrapped is the original function
     83       assigned is a tuple naming the attributes assigned directly
     84       from the wrapped function to the wrapper function (defaults to
     85       functools.WRAPPER_ASSIGNMENTS)
     86       updated is a tuple naming the attributes off the wrapper that
     87       are updated with the corresponding attribute from the wrapped
     88       function (defaults to functools.WRAPPER_UPDATES)
     89    """
     90    for attr in assigned:
     91        try:
     92            setattr(wrapper, attr, getattr(wrapped, attr))
     93        except TypeError: # Python 2.3 doesn't allow assigning to __name__.
     94            pass
     95    for attr in updated:
     96        getattr(wrapper, attr).update(getattr(wrapped, attr))
     97    # Return the wrapper so this can be used as a decorator via curry()
     98    return wrapper
     99
     100def wraps(wrapped,
     101          assigned = WRAPPER_ASSIGNMENTS,
     102          updated = WRAPPER_UPDATES):
     103    """Decorator factory to apply update_wrapper() to a wrapper function
     104
     105       Returns a decorator that invokes update_wrapper() with the decorated
     106       function as the wrapper argument and the arguments to wraps() as the
     107       remaining arguments. Default arguments are as for update_wrapper().
     108       This is a convenience function to simplify applying curry() to
     109       update_wrapper().
     110    """
     111    return curry(update_wrapper, wrapped=wrapped,
     112                 assigned=assigned, updated=updated)
     113
     114### End from Python 2.5 functools.py ##########################################
     115
    6116def memoize(func, cache, num_args):
    7117    """
    8118    Wrap a function so that results for any argument tuple are stored in
  • django/views/decorators/cache.py

    === modified file 'django/views/decorators/cache.py'
     
    1111account on caching -- just like the middleware does.
    1212"""
    1313
     14try:
     15    from functools import wraps
     16except ImportError:
     17    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
     18
    1419from django.utils.decorators import decorator_from_middleware
    1520from django.utils.cache import patch_cache_control, add_never_cache_headers
    1621from django.middleware.cache import CacheMiddleware
     
    2631            patch_cache_control(response, **kwargs)
    2732            return response
    2833
    29         return _cache_controlled
     34        return wraps(viewfunc)(_cache_controlled)
    3035
    3136    return _cache_controller
    3237
     
    3944        response = view_func(request, *args, **kwargs)
    4045        add_never_cache_headers(response)
    4146        return response
    42     return _wrapped_view_func
     47    return wraps(view_func)(_wrapped_view_func)
  • django/views/decorators/http.py

    === modified file 'django/views/decorators/http.py'
     
    22Decorators for views based on HTTP headers.
    33"""
    44
     5try:
     6    from functools import wraps
     7except ImportError:
     8    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
     9
    510from django.utils.decorators import decorator_from_middleware
    611from django.middleware.http import ConditionalGetMiddleware
    712from django.http import HttpResponseNotAllowed
     
    2429            if request.method not in request_method_list:
    2530                return HttpResponseNotAllowed(request_method_list)
    2631            return func(request, *args, **kwargs)
    27         return inner
     32        return wraps(func)(inner)
    2833    return decorator
    2934
    3035require_GET = require_http_methods(["GET"])
  • django/views/decorators/vary.py

    === modified file 'django/views/decorators/vary.py'
     
     1try:
     2    from functools import wraps
     3except ImportError:
     4    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
     5
    16from django.utils.cache import patch_vary_headers
    27
    38def vary_on_headers(*headers):
     
    1621            response = func(*args, **kwargs)
    1722            patch_vary_headers(response, headers)
    1823            return response
    19         return inner_func
     24        return wraps(func)(inner_func)
    2025    return decorator
    2126
    2227def vary_on_cookie(func):
     
    3237        response = func(*args, **kwargs)
    3338        patch_vary_headers(response, ('Cookie',))
    3439        return response
    35     return inner_func
     40    return wraps(func)(inner_func)
Back to Top