summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2020-03-15 11:50:28 +0100
committerMichele Simionato <michele.simionato@gmail.com>2020-03-15 11:50:28 +0100
commite6de7a108ad9837655c33f80723a9adcf07aa69f (patch)
tree77ca0db8be4defd0722b16bd683b5e85c5f1dc67
parentf6cdd8ad46439b4cec437fd0080c54ec4252ebdf (diff)
downloadpython-decorator-git-e6de7a108ad9837655c33f80723a9adcf07aa69f.tar.gz
Initial work for decorator 4.5
-rw-r--r--src/decorator.py30
-rw-r--r--src/tests/documentation.py37
-rw-r--r--src/tests/test.py12
3 files changed, 32 insertions, 47 deletions
diff --git a/src/decorator.py b/src/decorator.py
index a5081e0..ce8644c 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -235,24 +235,22 @@ def decorate(func, caller, extras=()):
evaldict[ex] = extra
es += ex + ', '
- if '3.5' <= sys.version < '3.6':
- # with Python 3.5 isgeneratorfunction returns True for all coroutines
- # however we know that it is NOT possible to have a generator
- # coroutine in python 3.5: PEP525 was not there yet
- generatorcaller = isgeneratorfunction(
- caller) and not iscoroutinefunction(caller)
+ if iscoroutinefunction(caller):
+ async def fun(*args, **kw):
+ return await caller(func, *(extras + args), **kw)
+ elif isgeneratorfunction(caller):
+ def fun(*args, **kw):
+ for res in caller(func, *(extras + args), **kw):
+ yield res
else:
- generatorcaller = isgeneratorfunction(caller)
- if generatorcaller:
- fun = FunctionMaker.create(
- func, "for res in _call_(_func_, %s%%(shortsignature)s):\n"
- " yield res" % es, evaldict, __wrapped__=func)
- else:
- fun = FunctionMaker.create(
- func, "return _call_(_func_, %s%%(shortsignature)s)" % es,
- evaldict, __wrapped__=func)
- if hasattr(func, '__qualname__'):
+ def fun(*args, **kw):
+ return caller(func, *(extras + args), **kw)
+ fun.__signature__ = inspect.signature(func)
+ fun.__wrapped__ = func
+ if hasattr(func, '__qualname__'): # >= Python 3.3
fun.__qualname__ = func.__qualname__
+ fun.__annotations__ = func.__annotations__
+ fun.__dict__.update(func.__dict__)
return fun
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index 70f5c3c..c9f6265 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -53,7 +53,7 @@ What's New in version 4
- **New documentation**
There is now a single manual for all Python versions, so I took the
- opportunity to overhaul the documentation and to move it to readthedocs.org.
+ opportunity to overhaul the documentation.
Even if you are a long-time user, you may want to revisit the docs, since
several examples have been improved.
@@ -316,16 +316,17 @@ The decorator works with functions of any signature:
```python
>>> @trace
-... def f(x, y=1, z=2, *args, **kw):
+... def f(x, y=1, *args, **kw):
... pass
>>> f(0, 3)
-calling f with args (0, 3, 2), {}
+calling f with args (0, 3), {}
>>> print(getfullargspec(f))
-FullArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={})
+FullArgSpec(args=['x', 'y'], varargs='args', varkw='kw', defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={})
```
+
$FUNCTION_ANNOTATIONS
``decorator.decorator``
@@ -1298,20 +1299,11 @@ 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``:
-
-```python
->>> @trace
-... def f(_func_): print(f)
-...
-Traceback (most recent call last):
- ...
-NameError: _func_ is overridden in
-def f(_func_):
- return _call_(_func_, _func_)
-
-```
+On a similar note, for old versions of the decorator module (< 4.5)
+there is a restriction on argument names. For instance,
+if you have an argument cakked ``_call_`` or ``_func_``, you will get a
+``NameError`` when decorating the function. This restriction has been
+lifted in version 4.5.
Finally, the implementation is such that the decorated function makes
a (shallow) copy of the original function dictionary:
@@ -1656,15 +1648,6 @@ def a_test_for_pylons():
if sys.version_info >= (3,): # tests for signatures specific to Python 3
- def test_kwonlydefaults():
- """
- >>> @trace
- ... def f(arg, defarg=1, *args, kwonly=2): pass
- ...
- >>> f.__kwdefaults__
- {'kwonly': 2}
- """
-
def test_kwonlyargs():
"""
>>> @trace
diff --git a/src/tests/test.py b/src/tests/test.py
index 7ddfaf4..bff23bd 100644
--- a/src/tests/test.py
+++ b/src/tests/test.py
@@ -125,10 +125,14 @@ class ExtraTestCase(unittest.TestCase):
@d1
def f1(x, y, z):
pass
- self.assertNotEqual(d1.__code__.co_filename, d2.__code__.co_filename)
- self.assertNotEqual(f1.__code__.co_filename, f2.__code__.co_filename)
- self.assertNotEqual(f1_orig.__code__.co_filename,
- f1.__code__.co_filename)
+
+ if sys.version_info < (3, 5):
+ self.assertNotEqual(d1.__code__.co_filename,
+ d2.__code__.co_filename)
+ self.assertNotEqual(f1.__code__.co_filename,
+ f2.__code__.co_filename)
+ self.assertNotEqual(f1_orig.__code__.co_filename,
+ f1.__code__.co_filename)
def test_no_first_arg(self):
@decorator