Opened 17 years ago

Closed 17 years ago

#5701 closed (fixed)

Fix naive introspection when using Django decorators

Reported by: Jeremy Dunck Owned by: Gary Wilson
Component: Uncategorized Version: dev
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.

Example:

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

@decorate
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.

http://docs.python.org/lib/module-functools.html

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 17 years ago.
patch against 6454
5701.diff (13.7 KB ) - added by Gary Wilson 17 years ago.

Download all attachments as: .zip

Change History (13)

by Jeremy Dunck, 17 years ago

patch against 6454

comment:1 by Jeremy Dunck, 17 years ago

Description: modified (diff)

comment:2 by Gary Wilson, 17 years ago

Description: modified (diff)
Triage Stage: UnreviewedAccepted

fixed description formatting.

comment:3 by Gary Wilson, 17 years ago

Owner: changed from nobody to Gary Wilson

comment:4 by Gary Wilson, 17 years ago

#1840 marked as duplicate.

comment:6 by Jacob, 17 years ago

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 by Gary Wilson, 17 years ago

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.

by Gary Wilson, 17 years ago

Attachment: 5701.diff added

comment:8 by Gary Wilson, 17 years ago

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 by Simon Law <simon@…>, 17 years ago

Cc: simon@… added

in reply to:  7 comment:10 by Gary Wilson, 17 years ago

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 by Gary Wilson, 17 years ago

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