summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormichele.simionato <devnull@localhost>2010-01-21 05:56:23 +0000
committermichele.simionato <devnull@localhost>2010-01-21 05:56:23 +0000
commit4ccf1399ef31e1860b8e89f2d04b4e116ac5889b (patch)
tree545d7e3b9ef258b19f90be0e2ca9f63f36d865b1
parent1182961a2b82500a00f948437fa7f8736537c521 (diff)
downloadpython-decorator-git-4ccf1399ef31e1860b8e89f2d04b4e116ac5889b.tar.gz
Work for decorator version 3.2
-rwxr-xr-xCHANGES.txt3
-rwxr-xr-xREADME.txt4
-rwxr-xr-xdecorator.py88
-rw-r--r--documentation.py120
-rw-r--r--setup.py2
5 files changed, 48 insertions, 169 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 0827995..a18d568 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,9 @@
HISTORY
----------
+3.2. Added __version__, removed functionality which has been deprecated for
+ more than one year, removed the confusing decorator_factory example
+ from the documentation (21/01/2010)
3.1.2. Added attributes args, varargs, keywords and arg0, ..., argN
to FunctionMaker objects generated from a function; fixed another
Pylons-breaking bug signaled by Lawrence Oluyede (25/08/2009)
diff --git a/README.txt b/README.txt
index b78c600..b6e0b62 100755
--- a/README.txt
+++ b/README.txt
@@ -15,6 +15,6 @@ Run
$ python documentation.py
-This should work perfectly with Python 2.4 and Python 2.5 and give
-minor errors with Python 2.6 (some inner details such as the
+This should work perfectly with Python 2.7 and Python 2.6 and give a few
+expected errors with Python 2.5 and 2.4 (some inner details such as the
introduction of the ArgSpec namedtuple and Thread.__repr__ changed).
diff --git a/decorator.py b/decorator.py
index 091d6ff..7d511fa 100755
--- a/decorator.py
+++ b/decorator.py
@@ -28,8 +28,9 @@ Decorator module, see http://pypi.python.org/pypi/decorator
for the documentation.
"""
-__all__ = ["decorator", "FunctionMaker", "partial",
- "deprecated", "getinfo", "new_wrapper"]
+__version__ = '3.2.0'
+
+__all__ = ["decorator", "FunctionMaker", "partial"]
import os, sys, re, inspect, string, warnings
try:
@@ -168,86 +169,3 @@ def decorator(caller, func=None):
'return decorator(_call_, %s)' % f,
dict(_call_=caller, decorator=decorator), undecorated=caller,
doc=caller.__doc__, module=caller.__module__)
-
-###################### deprecated functionality #########################
-
-@decorator
-def deprecated(func, *args, **kw):
- "A decorator for deprecated functions"
- warnings.warn(
- ('Calling the deprecated function %r\n'
- 'Downgrade to decorator 2.3 if you want to use this functionality')
- % func.__name__, DeprecationWarning, stacklevel=3)
- return func(*args, **kw)
-
-@deprecated
-def getinfo(func):
- """
- Returns an info dictionary containing:
- - name (the name of the function : str)
- - argnames (the names of the arguments : list)
- - defaults (the values of the default arguments : tuple)
- - signature (the signature : str)
- - doc (the docstring : str)
- - module (the module name : str)
- - dict (the function __dict__ : str)
-
- >>> def f(self, x=1, y=2, *args, **kw): pass
-
- >>> info = getinfo(f)
-
- >>> info["name"]
- 'f'
- >>> info["argnames"]
- ['self', 'x', 'y', 'args', 'kw']
-
- >>> info["defaults"]
- (1, 2)
-
- >>> info["signature"]
- 'self, x, y, *args, **kw'
- """
- assert inspect.ismethod(func) or inspect.isfunction(func)
- regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
- argnames = list(regargs)
- if varargs:
- argnames.append(varargs)
- if varkwargs:
- argnames.append(varkwargs)
- signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
- formatvalue=lambda value: "")[1:-1]
- return dict(name=func.__name__, argnames=argnames, signature=signature,
- defaults = func.func_defaults, doc=func.__doc__,
- module=func.__module__, dict=func.__dict__,
- globals=func.func_globals, closure=func.func_closure)
-
-@deprecated
-def update_wrapper(wrapper, model, infodict=None):
- "A replacement for functools.update_wrapper"
- infodict = infodict or getinfo(model)
- wrapper.__name__ = infodict['name']
- wrapper.__doc__ = infodict['doc']
- wrapper.__module__ = infodict['module']
- wrapper.__dict__.update(infodict['dict'])
- wrapper.func_defaults = infodict['defaults']
- wrapper.undecorated = model
- return wrapper
-
-@deprecated
-def new_wrapper(wrapper, model):
- """
- An improvement over functools.update_wrapper. The wrapper is a generic
- callable object. It works by generating a copy of the wrapper with the
- right signature and by updating the copy, not the original.
- Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module',
- 'dict', 'defaults'.
- """
- if isinstance(model, dict):
- infodict = model
- else: # assume model is a function
- infodict = getinfo(model)
- assert not '_wrapper_' in infodict["argnames"], (
- '"_wrapper_" is a reserved argument name!')
- src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict
- funcopy = eval(src, dict(_wrapper_=wrapper))
- return update_wrapper(funcopy, model, infodict)
diff --git a/documentation.py b/documentation.py
index 96b3d45..cdd4fae 100644
--- a/documentation.py
+++ b/documentation.py
@@ -119,8 +119,8 @@ keyword arguments:
.. code-block:: python
>>> from inspect import getargspec
- >>> print getargspec(f1)
- ([], 'args', 'kw', None)
+ >>> print getargspec(f1)
+ ArgSpec(args=[], varargs='args', keywords='kw', defaults=None)
This means that introspection tools such as pydoc will give
wrong informations about the signature of ``f1``. This is pretty bad:
@@ -186,7 +186,7 @@ The signature of ``heavy_computation`` is the one you would expect:
.. code-block:: python
>>> print getargspec(heavy_computation)
- ([], None, None, None)
+ ArgSpec(args=[], varargs=None, keywords=None, defaults=None)
A ``trace`` decorator
------------------------------------------------------
@@ -219,7 +219,7 @@ and it that it has the correct signature:
.. code-block:: python
>>> print getargspec(f1)
- (['x'], None, None, None)
+ ArgSpec(args=['x'], varargs=None, keywords=None, defaults=None)
The same decorator works with functions of any signature:
@@ -233,7 +233,7 @@ The same decorator works with functions of any signature:
calling f with args (0, 3, 2), {}
>>> print getargspec(f)
- (['x', 'y', 'z'], 'args', 'kw', (1, 2))
+ ArgSpec(args=['x', 'y', 'z'], varargs='args', keywords='kw', defaults=(1, 2))
That includes even functions with exotic signatures like the following:
@@ -243,7 +243,7 @@ That includes even functions with exotic signatures like the following:
... def exotic_signature((x, y)=(1,2)): return x+y
>>> print getargspec(exotic_signature)
- ([['x', 'y']], None, None, ((1, 2),))
+ ArgSpec(args=[['x', 'y']], varargs=None, keywords=None, defaults=((1, 2),))
>>> exotic_signature()
calling exotic_signature with args ((1, 2),), {}
3
@@ -297,49 +297,6 @@ If you are using an old Python version (Python 2.4) the
``decorator`` module provides a poor man replacement for
``functools.partial``.
-There is also an easy way to create one-parameter factories of
-decorators, based on the following
-``decorator_factory`` utility:
-
-$$decorator_factory
-
-``decorator_factory`` converts a function with signature
-``(param, func, *args, **kw)`` into a one-parameter family
-of decorators. Suppose for instance you want to generated different
-tracing generator, with different tracing messages.
-Here is how to do it:
-
-.. code-block:: python
-
- >>> @decorator_factory
- ... def trace_factory(message_template, f, *args, **kw):
- ... name = f.func_name
- ... print message_template % locals()
- ... return f(*args, **kw)
-
-.. code-block:: python
-
- >>> trace_factory # doctest: +ELLIPSIS
- <functools.partial object at 0x...>
-
- >>> trace = trace_factory('Calling %(name)s with args %(args)s '
- ... 'and keywords %(kw)s')
-
-In this example the parameter (``message_template``) is
-just a string, but in general it can be a tuple, a dictionary, or
-a generic object, so there is no real restriction (for instance,
-if you want to define a two-parameter family of decorators just
-use a tuple with two arguments as parameter).
-Here is an example of usage:
-
-.. code-block:: python
-
- >>> @trace
- ... def func(): pass
-
- >>> func()
- Calling func with args () and keywords {}
-
``blocking``
-------------------------------------------
@@ -794,10 +751,6 @@ Finally ``decorator`` cannot be used as a class decorator and the
`functionality introduced in version 2.3`_ has been removed. That
means that in order to define decorator factories with classes you
need to define the ``__call__`` method explicitly (no magic anymore).
-Since there is
-an easy way to define decorator factories by using ``decorator_factory``,
-there is less need to use classes to implement decorator factories.
-
All these changes should not cause any trouble, since they were
all rarely used features. Should you have any trouble, you can always
downgrade to the 2.3 version.
@@ -866,10 +819,6 @@ today = time.strftime('%Y-%m-%d')
__doc__ = __doc__.replace('$VERSION', VERSION).replace('$DATE', today)
-def decorator_factory(decfac): # partial is functools.partial
- "decorator_factory(decfac) returns a one-parameter family of decorators"
- return partial(lambda df, param: decorator(partial(df, param)), decfac)
-
def decorator_apply(dec, func):
"""
Decorate a function by preserving the signature even if dec
@@ -972,19 +921,20 @@ def _memoize(func, *args, **kw):
def memoize(f):
f.cache = {}
return decorator(_memoize, f)
-
-@decorator_factory
-def blocking(not_avail, f, *args, **kw):
- if not hasattr(f, "thread"): # no thread running
- def set_result(): f.result = f(*args, **kw)
- f.thread = threading.Thread(None, set_result)
- f.thread.start()
- return not_avail
- elif f.thread.isAlive():
- return not_avail
- else: # the thread is ended, return the stored result
- del f.thread
- return f.result
+
+def blocking(not_avail):
+ def blocking(f, *args, **kw):
+ if not hasattr(f, "thread"): # no thread running
+ def set_result(): f.result = f(*args, **kw)
+ f.thread = threading.Thread(None, set_result)
+ f.thread.start()
+ return not_avail
+ elif f.thread.isAlive():
+ return not_avail
+ else: # the thread is ended, return the stored result
+ del f.thread
+ return f.result
+ return decorator(blocking)
class User(object):
"Will just be able to see a page"
@@ -1001,16 +951,17 @@ def get_userclass():
class PermissionError(Exception):
pass
-@decorator_factory
-def restricted(user_class, func, *args, **kw):
- "Restrict access to a given class of users"
- userclass = get_userclass()
- if issubclass(userclass, user_class):
- return func(*args, **kw)
- else:
- raise PermissionError(
- '%s does not have the permission to run %s!'
- % (userclass.__name__, func.__name__))
+def restricted(user_class):
+ def restricted(func, *args, **kw):
+ "Restrict access to a given class of users"
+ userclass = get_userclass()
+ if issubclass(userclass, user_class):
+ return func(*args, **kw)
+ else:
+ raise PermissionError(
+ '%s does not have the permission to run %s!'
+ % (userclass.__name__, func.__name__))
+ return decorator(restricted)
class Action(object):
"""
@@ -1077,7 +1028,6 @@ def fact(n): # this is not tail-recursive
if n == 0: return 1
return n * fact(n-1)
-
def atest_for_pylons():
"""
In version 3.1.0 decorator(caller) returned a nameless partial
@@ -1092,5 +1042,13 @@ def atest_for_pylons():
'A decorator for deprecated functions'
"""
+@decorator
+def deprecated(func, *args, **kw):
+ "A decorator for deprecated functions"
+ warnings.warn(
+ 'Calling the deprecated function %r\n' % func.__name__,
+ DeprecationWarning, stacklevel=3)
+ return func(*args, **kw)
+
if __name__ == '__main__':
import doctest; doctest.testmod()
diff --git a/setup.py b/setup.py
index f8dc862..7269d1f 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@ try:
except ImportError:
from distutils.core import setup
-VERSION = '3.1.2'
+from decorator import __version__ as VERSION
if __name__ == '__main__':
try: