diff options
author | Michele Simionato <michele.simionato@gmail.com> | 2021-09-11 07:25:02 +0200 |
---|---|---|
committer | Michele Simionato <michele.simionato@gmail.com> | 2021-09-11 07:25:02 +0200 |
commit | a159961aa32b876d313b8db8f23a1dba0fca4438 (patch) | |
tree | fa8877e24f78ea3aac8386ba0c17501797ec92d2 | |
parent | 7394c953f3c85ff542b8614c53c6e35207ce8a00 (diff) | |
download | python-decorator-git-a159961aa32b876d313b8db8f23a1dba0fca4438.tar.gz |
Added decoratorx and bumped version to 5.1.0
-rw-r--r-- | CHANGES.md | 16 | ||||
-rw-r--r-- | docs/documentation.md | 38 | ||||
-rw-r--r-- | src/decorator.py | 17 | ||||
-rw-r--r-- | src/tests/documentation.py | 34 |
4 files changed, 96 insertions, 9 deletions
@@ -1,11 +1,15 @@ HISTORY -------- -## unreleased +## 5.1.0 (2021-09-11) -`decorator.decorator` was not passing the kwsyntax argument. -Functions decorated with `decorator.contextmanager` were one-shot. -This is now fixed, thanks to Alex Pizarro for the report. +Added a function `decoratorx` using the `FunctionMaker` and thus +preserving the signature of `__code__` objects. Then fixed three small bugs: +- Sphinx was printing a few warnings when building the documentation, as + signaled by Tomasz Kłoczko +- functions decorated with `decorator.contextmanager` were one-shot, + as discovered by Alex Pizarro. +- `decorator.decorator` was not passing the kwsyntax argument. ## 5.0.9 (2021-05-16) @@ -25,8 +29,8 @@ Christian Clauss. ## 5.0.6 (2021-04-08) -The decorator module was not copying the __module__ attribute anymore. Thanks to -Nikolay Markov for the notice. +The decorator module was not copying the __module__ attribute anymore. +Thanks to Nikolay Markov for the notice. ## 5.0.5 (2021-04-04) diff --git a/docs/documentation.md b/docs/documentation.md index bd2b4ad..d7f282d 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -3,9 +3,9 @@ |Author | Michele Simionato| |---|---| |E-mail | michele.simionato@gmail.com| -|Version| 5.0.9 (2021-09-11)| +|Version| 5.1.0 (2021-09-11)| |Supports| Python 3.5, 3.6, 3.7, 3.8, 3.9| -|Download page| http://pypi.python.org/pypi/decorator/5.0.9| +|Download page| http://pypi.python.org/pypi/decorator/5.1.0| |Installation| ``pip install decorator``| |License | BSD license| @@ -1523,6 +1523,40 @@ which I will never support in the decorator module - I suggest you to look at the [wrapt](https://wrapt.readthedocs.io/en/latest/) project by Graeme Dumpleton. +Since version 5 the ``decorator`` module uses the ``inspect.Signature`` +object in the standard library. Unfortunaly, for legacy reasons, some +applications introspect decorated functions by using low-level entities like +the ``__code__`` object and not signature objects. An example will make +the issue clear: + +```python +>>> def f(a, b): pass +>>> f_dec = decorator(_trace)(f) +>>> f_dec.__code__.co_argcount +0 +>>> f_dec.__code__.co_varnames +('args', 'kw') + +``` +This is not what one would expect: the `argcount` should be 2 since +the original functions has two arguments and the `varnames` should be +`a` and `b`. The only way to fix the issue is to go back to an implementation +of the decorator using ``exec``, which is provided for convenience since +version 5.1: + +```python +>>> from decorator import decoratorx +>>> f_dec = decoratorx(_trace)(f) +>>> f_dec.__code__.co_argcount +2 +>>> f_dec.__code__.co_varnames +('a', 'b') + +``` +Rather than using `decoratorx`, you should fix your introspection +routines to use ``inspect.Signature`` without fiddling with the +``__code__`` object. + There is a strange quirk when decorating functions with keyword arguments, if one of the arguments has the same name used in the caller function for the first argument. The quirk was reported by diff --git a/src/decorator.py b/src/decorator.py index 9435841..7980acf 100644 --- a/src/decorator.py +++ b/src/decorator.py @@ -40,7 +40,7 @@ import itertools from contextlib import _GeneratorContextManager from inspect import getfullargspec, iscoroutinefunction, isgeneratorfunction -__version__ = '5.0.9' +__version__ = '5.1.0' DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(') POS = inspect.Parameter.POSITIONAL_OR_KEYWORD @@ -259,6 +259,21 @@ def decorate(func, caller, extras=(), kwsyntax=False): return fun +def decoratorx(caller): + """ + A version of "decorator" implemented via "exec" and not via the + Signature object. Use this if you are want to preserve the `.__code__` + object properties (https://github.com/micheles/decorator/issues/129). + """ + def dec(func): + return FunctionMaker.create( + func, + "return _call_(_func_, %(shortsignature)s)", + dict(_call_=caller, _func_=func), + __wrapped__=func, __qualname__=func.__qualname__) + return dec + + def decorator(caller, _func=None, kwsyntax=False): """ decorator(caller) converts a caller function into a decorator diff --git a/src/tests/documentation.py b/src/tests/documentation.py index 4b717ff..506733b 100644 --- a/src/tests/documentation.py +++ b/src/tests/documentation.py @@ -1202,6 +1202,40 @@ which I will never support in the decorator module - I suggest you to look at the [wrapt](https://wrapt.readthedocs.io/en/latest/) project by Graeme Dumpleton. +Since version 5 the ``decorator`` module uses the ``inspect.Signature`` +object in the standard library. Unfortunaly, for legacy reasons, some +applications introspect decorated functions by using low-level entities like +the ``__code__`` object and not signature objects. An example will make +the issue clear: + +```python +>>> def f(a, b): pass +>>> f_dec = decorator(_trace)(f) +>>> f_dec.__code__.co_argcount +0 +>>> f_dec.__code__.co_varnames +('args', 'kw') + +``` +This is not what one would expect: the `argcount` should be 2 since +the original functions has two arguments and the `varnames` should be +`a` and `b`. The only way to fix the issue is to go back to an implementation +of the decorator using ``exec``, which is provided for convenience since +version 5.1: + +```python +>>> from decorator import decoratorx +>>> f_dec = decoratorx(_trace)(f) +>>> f_dec.__code__.co_argcount +2 +>>> f_dec.__code__.co_varnames +('a', 'b') + +``` +Rather than using `decoratorx`, you should fix your introspection +routines to use ``inspect.Signature`` without fiddling with the +``__code__`` object. + There is a strange quirk when decorating functions with keyword arguments, if one of the arguments has the same name used in the caller function for the first argument. The quirk was reported by |