Opened 8 years ago

Closed 7 years ago

#5701 closed (fixed)

Fix naive introspection when using Django decorators

Reported by: jdunck Owned by: gwilson
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: UI/UX:

Description (last modified by gwilson)

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 jdunck 8 years ago.
patch against 6454
5701.diff (13.7 KB) - added by gwilson 8 years ago.

Download all attachments as: .zip

Change History (13)

Changed 8 years ago by jdunck

patch against 6454

comment:1 Changed 8 years ago by jdunck

  • Description modified (diff)

comment:2 Changed 8 years ago by gwilson

  • Description modified (diff)
  • Triage Stage changed from Unreviewed to Accepted

fixed description formatting.

comment:3 Changed 8 years ago by gwilson

  • Owner changed from nobody to gwilson

comment:4 Changed 8 years ago by gwilson

#1840 marked as duplicate.

comment:6 Changed 8 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 follow-up: Changed 8 years ago by gwilson

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 8 years ago by gwilson

comment:8 Changed 8 years ago by gwilson

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

  • Cc simon@… added

comment:10 in reply to: ↑ 7 Changed 7 years ago by gwilson

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 7 years ago by gwilson

  • Resolution set to fixed
  • Status changed from new to closed

(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