Opened 12 years ago

Closed 12 years ago

#5701 closed (fixed)

Fix naive introspection when using Django decorators

Reported by: Jeremy Dunck Owned by: Gary Wilson
Component: Uncategorized Version: master
Severity: Keywords: decorators views
Cc: simon@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Gary Wilson)

It's fairly well-known that decorators are useful, but raise some issues.


def decorate(f):
   def wrap(*args, **kwargs):
       print "called"
       return f(*args, **kwargs)
   return wrap

def add_to(augend, addend):
   "Adds stuff"
   return augend + addend

Introspecting add_to, undecorated, would have a __name__ of 'add_to'
and __doc__ of 'Adds stuff'.

After decorating, add_to.__name__ becomes 'wrap' and __doc__ becomes None.


In Python 2.5+, there's functools.wraps, which takes care of the
problem of introspection on decorated functions by copying attributes
from the wrapped function.

Django already includes curry, which is roughly the same as
functools.partial, so it's pretty easy to implement functools.wraps.

The attached patch implements django.utils.functional.wraps, updates all Django decorators to use it, and includes tests to verify that the fixing-up works.

Attachments (2)

dj-functools-decorators.diff (9.2 KB) - added by Jeremy Dunck 12 years ago.
patch against 6454
5701.diff (13.7 KB) - added by Gary Wilson 12 years ago.

Download all attachments as: .zip

Change History (13)

Changed 12 years ago by Jeremy Dunck

patch against 6454

comment:1 Changed 12 years ago by Jeremy Dunck

Description: modified (diff)

comment:2 Changed 12 years ago by Gary Wilson

Description: modified (diff)
Triage Stage: UnreviewedAccepted

fixed description formatting.

comment:3 Changed 12 years ago by Gary Wilson

Owner: changed from nobody to Gary Wilson

comment:4 Changed 12 years ago by Gary Wilson

#1840 marked as duplicate.

comment:6 Changed 12 years ago by Jacob

A few questions that need to be asked before this gets checked in:

  • Does it work against Python 2.3?
  • Do we have explicit permission from the PSF to include that code?
  • If so, who?
  • Is there any potential backwards-incompatible behavior here?

If the answers to these questions are "yes", "yes", "<some name>", and "no", we'll need to stuff the PSF license at the top of the file.

comment:7 Changed 12 years ago by Gary Wilson

Yes, it works in Python 2.3. Only thing is that Python 2.3 doesn't allow assignment to the __name__ attribute, but I have modified the functools code slightly to use a try-except clause around a setattr() call so that it won't fail. In the tests, the __name__ test is also skipped if running version 2.3 or earlier.

I have emailed the PSF for permission, will note their response when it comes.

AFAIK, the only backwards-incompatible behavior here would be that wrapped functions now look like the wrapped function instead of the wrapper function.

Changed 12 years ago by Gary Wilson

Attachment: 5701.diff added

comment:8 Changed 12 years ago by Gary Wilson

A few serializers_regress tests seem to be failing with python 2.3 and postgresql_psycopg2 backend, but it looks like that is not related as I'm getting the same failures without the patch.

comment:9 Changed 12 years ago by Simon Law <simon@…>

Cc: simon@… added

comment:10 in reply to:  7 Changed 12 years ago by Gary Wilson

Replying to gwilson:

I have emailed the PSF for permission, will note their response when it comes.

FYI, in the response I got back from Stephan Deibel with the PSF he said that he doesn't believe we need the permission of the PSF as long as we meet the license requirements. He also suggested that we put the Python license in the main LICENSE file (or reference it from the main LICENSE file) so that anyone looking for legal details would see it there.

I went ahead and put the license in the same file as the code as Jacob requested above. Jacob, feel free to move it if you so desire.

comment:11 Changed 12 years ago by Gary Wilson

Resolution: fixed
Status: newclosed

(In [7153]) Fixed #5701 -- Fixed decorators to take the name, attributes, and docstring of the function they decorate by adding a modified version of the functools.wraps function from Python 2.5. wraps has been altered to work with Django's curry function and with Python 2.3, which doesn't allow assignment of a function's __name__ attribute. This fixes severaly annoyances, such as the online documentation for template filters served by the admin app. This change is backwards incompatible if, for some reason, you were relying on the name of a Django decorator instead of the function it decorates.

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