Opened 14 years ago

Closed 14 years ago

Last modified 14 years ago

#13854 closed (wontfix)

List of used decorators on a function

Reported by: Mitar Owned by: nobody
Component: Core (Other) Version: 1.2
Severity: Keywords:
Cc: mmitar@… Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Sometimes it is useful to be able to check which decorators are already applied to a function (view mostly), especially when you are constructing them dynamically. I am proposing that all decorators in Django maintain a list of used decorators on a function. It is required that all decorators do this for the idea to be useful.

def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME, decorator_id=None):
    """
    Decorator for views that checks that the user passes the given test,
    redirecting to the log-in page if necessary. The test should be a callable
    that takes the user object and returns True if the user passes.

    It maintains `decorators` attribute on wrapped function with list of all
    ids of used decorators, where the first one is the first one used.
    """
    if not login_url:
        from django.conf import settings
        login_url = settings.LOGIN_URL
    if decorator_id is None:
        decorator_id = id(user_test_required)

    def decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            if test_func(request.user):
                return view_func(request, *args, **kwargs)
            path = urlquote(request.get_full_path())
            tup = login_url, redirect_field_name, path
            return HttpResponseRedirect('%s?%s=%s' % tup)

        wrapped_view_func = wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
        wrapped_view_func.decorators = []
        if hasattr(view_func, 'decorators'):
            wrapped_view_func.decorators += view_func.decorators
        wrapped_view_func.decorators.append(decorator_id)
        
        return wrapped_view_func

    return decorator

decorator_id can in fact be anything. Developer can for example use a tuple with additional information. In this case it could be maybe useful to use (id(user_test_required), id(test_func)) to differentiate between different uses of decorator. Or in the case of permission_required decorator perm parameter could be stored in the tuple.

Of course this functionally can be also made into a decorator. ;-) So we could have a decorator which we would apply to decorators to have them registered in decorators attribute.

I am willing to make a patch if there will be confirmation for this idea.

Change History (5)

comment:1 by Russell Keith-Magee, 14 years ago

Resolution: wontfix
Status: newclosed

Erm... no.

Firstly, any proposal that starts with "Assumes that every implementation in the world does X" is a non-starter, especially when there are so many decorators already in the field.

However, most importantly, the whole point of decorators is the anonymous black-box wrapping of functions. Trying to define decorators in a way that requires internal implementations to inspect what they are wrapped in defeats the purpose of being a black box.

If you really want this, a better place to pursue this would be at the language level -- after all, decorators aren't a Django feature, they're a Python language feature. However, I strongly suspect you'll get the same response from the Python core developers.

in reply to:  1 comment:2 by Mitar, 14 years ago

Replying to russellm:

Trying to define decorators in a way that requires internal implementations to inspect what they are wrapped in defeats the purpose of being a black box.

Not require, but allow them to inspect. It is the same reasoning why inspect module is in Python - to be able to inspect Python structures, to have this possibility. If you do not want it then you do can use Python structures as they were given to you. But you have an option.

And I would like the same to see from decorators. It is not really so important that all decorators update this. If they would not then they would be hidden from inspection. But if developer wants to use inspection then he would choose such decorators which use this (or change them in this way). If all Django's decorators would already be such it would be much easier to use them.

So for backwards compatibility available_attrs would return also decorators which would then make this attribute to be passed through decorated function. If decorator wants to add itself (it supports decorators attribute) it can add itself. So there is no need that all decorators immediately start doing that - by extending available_attrs and extending all Django decorators we would just make it easier to start doing that.

If you really want this, a better place to pursue this would be at the language level -- after all, decorators aren't a Django feature, they're a Python language feature.

Django defines its own decorators not just use Python decorators. Decorators in Python are mostly syntax question. How does they behave is open to developers. And Django developers could opt for such extension.

comment:3 by Russell Keith-Magee, 14 years ago

There is exactly *zero* difference between a decorator in Python and a decorator in Django. The syntax is identical, and the intended mode of usage is identical. If you want inspect-like features, then -- again -- you should be talking to the Python core team and convincing them to add decorator inspection to the features of the language. I'm not in favor of adding language-level features to Django. Django is a Python library. It shouldn't be trying to change the language.

comment:4 by Russell Keith-Magee, 14 years ago

Also - if you want to continue this discussion, please do so on Django-developers. Trac is a really bad place to hold design discussions.

comment:5 by Mitar, 14 years ago

I have opened Python #9157.

Note: See TracTickets for help on using tickets.
Back to Top