summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2017-01-15 10:06:58 +0100
committerMichele Simionato <michele.simionato@gmail.com>2017-01-15 10:06:58 +0100
commit8608a4672a5c4ae390040d56ef049980a144c280 (patch)
tree61d474c04ae721cf5c51a4b9963f3c93973329ec /src
parent7d24926595c7719a7118e8b821a865f33a0445c0 (diff)
downloadpython-decorator-git-8608a4672a5c4ae390040d56ef049980a144c280.tar.gz
Tested with Python 3.6
Diffstat (limited to 'src')
-rw-r--r--src/decorator.py39
-rw-r--r--src/tests/documentation.py49
2 files changed, 47 insertions, 41 deletions
diff --git a/src/decorator.py b/src/decorator.py
index 09a466e..6362c02 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -1,6 +1,6 @@
# ######################### LICENSE ############################ #
-# Copyright (c) 2005-2016, Michele Simionato
+# Copyright (c) 2005-2017, Michele Simionato
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ import operator
import itertools
import collections
-__version__ = '4.0.10'
+__version__ = '4.0.11'
if sys.version >= '3':
from inspect import getfullargspec
@@ -48,21 +48,13 @@ if sys.version >= '3':
def get_init(cls):
return cls.__init__
else:
- class getfullargspec(object):
- "A quick and dirty replacement for getfullargspec for Python 2.X"
- def __init__(self, f):
- self.args, self.varargs, self.varkw, self.defaults = \
- inspect.getargspec(f)
- self.kwonlyargs = []
- self.kwonlydefaults = None
-
- def __iter__(self):
- yield self.args
- yield self.varargs
- yield self.varkw
- yield self.defaults
+ FullArgSpec = collections.namedtuple(
+ 'FullArgSpec', 'args varargs varkw defaults '
+ 'kwonlyargs kwonlydefaults')
- getargspec = inspect.getargspec
+ def getfullargspec(f):
+ "A quick and dirty replacement for getfullargspec for Python 2.X"
+ return FullArgSpec._make(inspect.getargspec(f) + ([], None))
def get_init(cls):
return cls.__init__.__func__
@@ -78,7 +70,7 @@ def getargspec(f):
return ArgSpec(spec.args, spec.varargs, spec.varkw, spec.defaults)
-DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
+DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(')
# basic functionality
@@ -92,6 +84,9 @@ class FunctionMaker(object):
# Atomic get-and-increment provided by the GIL
_compile_count = itertools.count()
+ # make pylint happy
+ args = varargs = varkw = defaults = kwonlyargs = kwonlydefaults = ()
+
def __init__(self, func=None, name=None, signature=None,
defaults=None, doc=None, module=None, funcdict=None):
self.shortsignature = signature
@@ -154,8 +149,8 @@ class FunctionMaker(object):
func.__name__ = self.name
func.__doc__ = getattr(self, 'doc', None)
func.__dict__ = getattr(self, 'dict', {})
- func.__defaults__ = getattr(self, 'defaults', ())
- func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None)
+ func.__defaults__ = self.defaults
+ func.__kwdefaults__ = self.kwonlydefaults or None
func.__annotations__ = getattr(self, 'annotations', None)
try:
frame = sys._getframe(3)
@@ -346,7 +341,7 @@ def dispatch_on(*dispatch_args):
ras = [[] for _ in range(len(dispatch_args))]
for types_ in typemap:
for t, type_, ra in zip(types, types_, ras):
- if issubclass(t, type_) and type_ not in t.__mro__:
+ if issubclass(t, type_) and type_ not in t.mro():
append(type_, ra)
return [set(ra) for ra in ras]
@@ -363,9 +358,9 @@ def dispatch_on(*dispatch_args):
'Ambiguous dispatch for %s: %s' % (t, vas))
elif n_vas == 1:
va, = vas
- mro = type('t', (t, va), {}).__mro__[1:]
+ mro = type('t', (t, va), {}).mro()[1:]
else:
- mro = t.__mro__
+ mro = t.mro()
lists.append(mro[:-1]) # discard t and object
return lists
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index e651281..6b5d90c 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -1,6 +1,6 @@
from __future__ import print_function
-doc = r"""
+doc = r"""\
The ``decorator`` module
=============================================================
@@ -33,12 +33,12 @@ trivial to distribute the module as an universal wheel_ since 2to3 is no more
required. Since Python 2.5 has been released 9 years ago, I felt that
it was reasonable to drop the support for it. If you need to support
ancient versions of Python, stick with the decorator module version
-3.4.2. The current version supports all Python releases from 2.6 up to 3.5.
+3.4.2. The current version supports all Python releases from 2.6 up to 3.6.
.. _wheel: http://pythonwheels.com/
-What's New
----------------------
+What's New in version 4
+-----------------------
- **New documentation**
There is now a single manual for all Python versions, so I took the
@@ -596,7 +596,7 @@ decorated functions. In IPython, this means that the usual ``??`` trick
will give you the (right on the spot) message ``Dynamically generated
function. No source code available``.
-In the past, I have considered this acceptable, since ``inspect.getsource``
+In the past, I considered this acceptable, since ``inspect.getsource``
does not really work with "regular" decorators. In those cases,
``inspect.getsource`` gives you the wrapper source code, which is probably
not what you want:
@@ -725,10 +725,12 @@ $$XMLWriter
Here, you want to dispatch on the *second* argument; the first is already
taken by ``self``. The ``dispatch_on`` decorator factory allows you to specify
-the dispatch argument simplpy by passing its name as a string. (Note
+the dispatch argument simply by passing its name as a string. (Note
that if you misspell the name you will get an error.)
-The decorated function decorated is turned into a generic function,
+The decorated function `write` is turned into a generic function (
+`write` is a function at the idea it is decorated; it will be turned
+into a method later, at class instantiation time),
and it is called if there are no more specialized implementations.
Usually, default functions should raise a ``NotImplementedError``, thus
@@ -972,7 +974,7 @@ not use any cache, whereas the ``singledispatch`` implementation does.
Caveats and limitations
-------------------------------------------
-One thing you should be aware of is the performance penalty of decorators.
+One thing you should be aware of, is the performance penalty of decorators.
The worse case is shown by the following example:
.. code-block:: bash
@@ -1003,9 +1005,9 @@ plain function is five times slower::
1000000 loops, best of 3: 0.278 usec per loop
Of course, a real life function probably does something more useful
-than ``f`` here, so the real life performance penalty *could* be negligible.
-As always, the only way to know if there is a penalty in your specific use case
-is to measure it.
+than the function ``f`` here, so the real life performance penalty
+*could* be negligible. As always, the only way to know if there is a
+penalty in your specific use case is to measure it.
More importantly, you should be aware that decorators will make your
tracebacks longer and more difficult to understand.
@@ -1036,7 +1038,7 @@ But since the function is decorated, the traceback is longer:
You see here the inner call to the decorator ``trace``, which calls
``f(*args, **kw)``, and a reference to ``File "<string>", line 2, in f``.
-This latter reference is due to the fact that internally, the decorator
+This latter reference is due to the fact that, internally, the decorator
module uses ``exec`` to generate the decorated function. Notice that
``exec`` is *not* responsible for the performance penalty, since is the
called *only once* (at function decoration time); it is *not* called
@@ -1056,9 +1058,9 @@ been made: you can decorate a function with
``func_tools.update_wrapper``, and ``pydoc`` will see the correct
signature. Unfortunately, the function will still have an incorrect
signature internally, as you can see by using
-``inspect.getfullargspec``; so, all documentation tools using the
-function (which has rightly been deprecated) will see the wrong
-signature.
+``inspect.getfullargspec``; so, all documentation tools using
+``inspect.getfullargspec`` - which has been rightly deprecated -
+will see the wrong signature.
.. _362: http://www.python.org/dev/peps/pep-0362
@@ -1066,7 +1068,13 @@ In the present implementation, decorators generated by ``decorator``
can only be used on user-defined Python functions or methods.
They cannot be used on generic callable objects or built-in functions,
due to limitations of the standard library's ``inspect`` module, especially
-for Python 2. (In Python 3.5, many such limitations have been removed.)
+for Python 2. In Python 3.5, many such limitations have been removed, but
+I still think that it is cleaner and safer to decorate only
+functions. If you want to decorate things like classmethods/staticmethods
+and general callables - which I will never support in the decorator module -
+I suggest you to look at the wrapt_ project by Graeme Dumpleton.
+
+.. _wrapt: https://wrapt.readthedocs.io/en/latest/
There is a strange quirk when decorating functions with keyword
arguments, if one of the arguments has the same name used in the
@@ -1109,7 +1117,10 @@ or to change the implementation like so:
This avoids the need to name the first argument, so the problem
simply disappears. This is a technique that you should keep in mind
-when writing decorators for functions with keyword arguments.
+when writing decorators for functions with keyword arguments. Also,
+notice that lately I have come to believe that decorating functions with
+keyword arguments is not such a good idea, and you may want not to do
+that.
On a similar note, there is a restriction on argument names. For instance,
if you name an argument ``_call_`` or ``_func_``, you will get a ``NameError``:
@@ -1146,10 +1157,10 @@ a (shallow) copy of the original function dictionary:
.. _docutils: http://docutils.sourceforge.net/
.. _pygments: http://pygments.org/
-LICENSE
+LICENSE (2-clause BSD)
---------------------------------------------
-Copyright (c) 2005-2016, Michele Simionato
+Copyright (c) 2005-2017, Michele Simionato
All rights reserved.
Redistribution and use in source and binary forms, with or without