diff options
| author | Michele Simionato <michele.simionato@gmail.com> | 2020-03-15 11:50:28 +0100 |
|---|---|---|
| committer | Michele Simionato <michele.simionato@gmail.com> | 2020-03-15 11:50:28 +0100 |
| commit | e6de7a108ad9837655c33f80723a9adcf07aa69f (patch) | |
| tree | 77ca0db8be4defd0722b16bd683b5e85c5f1dc67 | |
| parent | f6cdd8ad46439b4cec437fd0080c54ec4252ebdf (diff) | |
| download | python-decorator-git-e6de7a108ad9837655c33f80723a9adcf07aa69f.tar.gz | |
Initial work for decorator 4.5
| -rw-r--r-- | src/decorator.py | 30 | ||||
| -rw-r--r-- | src/tests/documentation.py | 37 | ||||
| -rw-r--r-- | src/tests/test.py | 12 |
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 |
