summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2010-11-28 09:39:29 +0100
committerMichele Simionato <michele.simionato@gmail.com>2010-11-28 09:39:29 +0100
commit8f7a9ed288687da7b79ef6f67673b4020ed0d561 (patch)
tree08266a5c3a7e79519b83e6726d3091af5da6bcc2
parent48e4405481f6ca1db715b11367e88a4d63f1c7ba (diff)
downloadmicheles-8f7a9ed288687da7b79ef6f67673b4020ed0d561.tar.gz
Fixed func_globals in the decorated function (release 3.2.1)
-rw-r--r--decorator/CHANGES.txt2
-rw-r--r--decorator/documentation.py6
-rw-r--r--decorator/documentation3.py2
-rw-r--r--decorator/src/decorator.py34
-rw-r--r--decorator/test.py24
5 files changed, 51 insertions, 17 deletions
diff --git a/decorator/CHANGES.txt b/decorator/CHANGES.txt
index 0b75d2c..30af4b4 100644
--- a/decorator/CHANGES.txt
+++ b/decorator/CHANGES.txt
@@ -1,6 +1,8 @@
HISTORY
----------
+3.2.1. Now the .func_globals of the decorated function are the same of
+ the undecorated function, as requested by Paul Ollis (28/12/2010)
3.2. Added __version__ (thanks to Gregg Lind), removed functionality which
has been deprecated for years, removed the confusing decorator_factory
example and added official support for Python 3 (requested by Claus Klein).
diff --git a/decorator/documentation.py b/decorator/documentation.py
index 6827ca9..4e9dfba 100644
--- a/decorator/documentation.py
+++ b/decorator/documentation.py
@@ -502,7 +502,7 @@ $$identity_dec
<BLANKLINE>
(see bug report 1764286_ for an explanation of what is happening).
-Unfortunately the bug is still there, even in Python 2.6 and 3.0.
+Unfortunately the bug is still there, even in Python 2.7 and 3.1.
There is however a workaround. The decorator module adds an
attribute ``.undecorated`` to the decorated function, containing
a reference to the original function. The easy way to get
@@ -710,7 +710,9 @@ you will get a ``NameError``:
def f(_func_):
return _call_(_func_, _func_)
-Finally, the implementation is such that the decorated function contains
+Finally, the implementation is such that the decorated function
+attribute ``.func_globals`` is a *copy* of the original function
+attribute. Moreover the decorated function contains
a *copy* of the original function dictionary
(``vars(decorated_f) is not vars(f)``):
diff --git a/decorator/documentation3.py b/decorator/documentation3.py
index 94641ab..8e3c95d 100644
--- a/decorator/documentation3.py
+++ b/decorator/documentation3.py
@@ -486,7 +486,7 @@ $$identity_dec
<BLANKLINE>
(see bug report 1764286_ for an explanation of what is happening).
-Unfortunately the bug is still there, even in Python 2.6 and 3.0.
+Unfortunately the bug is still there, even in Python 2.7 and 3.1.
There is however a workaround. The decorator module adds an
attribute ``.undecorated`` to the decorated function, containing
a reference to the original function. The easy way to get
diff --git a/decorator/src/decorator.py b/decorator/src/decorator.py
index a005230..5077833 100644
--- a/decorator/src/decorator.py
+++ b/decorator/src/decorator.py
@@ -28,11 +28,11 @@ Decorator module, see http://pypi.python.org/pypi/decorator
for the documentation.
"""
-__version__ = '3.2.0'
+__version__ = '3.2.1'
__all__ = ["decorator", "FunctionMaker", "partial"]
-import os, sys, re, inspect
+import sys, re, inspect
try:
from functools import partial
@@ -109,13 +109,13 @@ class FunctionMaker(object):
if mo is None:
raise SyntaxError('not a valid function template\n%s' % src)
name = mo.group(1) # extract the function name
- reserved_names = set([name] + [
- arg.strip(' *') for arg in self.signature.split(',')])
- for n, v in evaldict.iteritems():
- if n in reserved_names:
+ names = set([name] + [arg.strip(' *') for arg in
+ self.signature.split(',')])
+ for n in names:
+ if n in ('_func_', '_call_'):
raise NameError('%s is overridden in\n%s' % (n, src))
if not src.endswith('\n'): # add a newline just for safety
- src += '\n'
+ src += '\n' # this is needed in old versions of Python
try:
code = compile(src, '<string>', 'single')
exec code in evaldict
@@ -146,9 +146,9 @@ class FunctionMaker(object):
name = None
signature = None
func = obj
- fun = cls(func, name, signature, defaults, doc, module)
+ self = cls(func, name, signature, defaults, doc, module)
ibody = '\n'.join(' ' + line for line in body.splitlines())
- return fun.make('def %(name)s(%(signature)s):\n' + ibody,
+ return self.make('def %(name)s(%(signature)s):\n' + ibody,
evaldict, addsource, **attrs)
def decorator(caller, func=None):
@@ -157,16 +157,22 @@ def decorator(caller, func=None):
decorator(caller, func) decorates a function using a caller.
"""
if func is not None: # returns a decorated function
+ evaldict = func.func_globals.copy()
+ evaldict['_call_'] = caller
+ evaldict['_func_'] = func
return FunctionMaker.create(
func, "return _call_(_func_, %(signature)s)",
- dict(_call_=caller, _func_=func), undecorated=func)
+ evaldict, undecorated=func)
else: # returns a decorator
if isinstance(caller, partial):
return partial(decorator, caller)
# otherwise assume caller is a function
- f = inspect.getargspec(caller)[0][0] # first arg
+ first = inspect.getargspec(caller)[0][0] # first arg
+ evaldict = caller.func_globals.copy()
+ evaldict['_call_'] = caller
+ evaldict['decorator'] = decorator
return FunctionMaker.create(
- '%s(%s)' % (caller.__name__, f),
- 'return decorator(_call_, %s)' % f,
- dict(_call_=caller, decorator=decorator), undecorated=caller,
+ '%s(%s)' % (caller.__name__, first),
+ 'return decorator(_call_, %s)' % first,
+ evaldict, undecorated=caller,
doc=caller.__doc__, module=caller.__module__)
diff --git a/decorator/test.py b/decorator/test.py
new file mode 100644
index 0000000..b21fe4d
--- /dev/null
+++ b/decorator/test.py
@@ -0,0 +1,24 @@
+"""
+Some simple tests executable with nose or py.test
+"""
+
+import os
+from decorator import decorator
+
+@decorator
+def identity(f, *a, **k):
+ "do nothing decorator"
+ return f(*a, **k)
+
+@identity
+def f1():
+ "f1"
+
+def test0():
+ assert os.path.basename(identity.func_globals['__file__']) == 'test.py'
+ print identity.__doc__
+
+def test1():
+ assert os.path.basename(f1.func_globals['__file__']) == 'test.py'
+ print f1.__doc__
+