diff options
author | Michele Simionato <michele.simionato@gmail.com> | 2021-05-15 06:08:54 +0200 |
---|---|---|
committer | Michele Simionato <michele.simionato@gmail.com> | 2021-05-15 06:08:54 +0200 |
commit | dbb10360ec5e11126c6c3354038e1d41485c6323 (patch) | |
tree | 4e1c72ee9d035ce867333288f85d99014421b4da | |
parent | e3c07ea54b6ea08765f01f72042debc66159d0a3 (diff) | |
download | python-decorator-git-dbb10360ec5e11126c6c3354038e1d41485c6323.tar.gz |
Decorating builtin functions5.0.8
-rw-r--r-- | CHANGES.md | 5 | ||||
-rw-r--r-- | docs/documentation.md | 4 | ||||
-rw-r--r-- | src/decorator.py | 33 | ||||
-rw-r--r-- | src/tests/test.py | 11 |
4 files changed, 44 insertions, 9 deletions
@@ -3,6 +3,11 @@ HISTORY ## unreleased +## 5.0.8 (2021-05-15) + +Made the decorator module more robust when decorating builtin functions +lacking dunder attributes, like `dict.__setitem__`. + ## 5.0.7 (2021-04-14) The decorator module was not passing correctly the defaults inside the diff --git a/docs/documentation.md b/docs/documentation.md index 7d8fede..2637055 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -4,9 +4,9 @@ Decorators for Humans |Author | Michele Simionato| |---|---| |E-mail | michele.simionato@gmail.com| -|Version| 5.0.7 (2021-04-14)| +|Version| 5.0.8 (2021-05-15)| |Supports| Python 3.5, 3.6, 3.7, 3.8, 3.9| -|Download page| http://pypi.python.org/pypi/decorator/5.0.7| +|Download page| http://pypi.python.org/pypi/decorator/5.0.8| |Installation| ``pip install decorator``| |License | BSD license| diff --git a/src/decorator.py b/src/decorator.py index d8db26d..1cffad4 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.7' +__version__ = '5.0.8' DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(') POS = inspect.Parameter.POSITIONAL_OR_KEYWORD @@ -232,14 +232,33 @@ def decorate(func, caller, extras=(), kwsyntax=False): return caller(func, *(extras + args), **kw) fun.__name__ = func.__name__ fun.__doc__ = func.__doc__ - fun.__defaults__ = func.__defaults__ - fun.__kwdefaults__ = func.__kwdefaults__ - fun.__annotations__ = func.__annotations__ - fun.__module__ = func.__module__ - fun.__signature__ = sig fun.__wrapped__ = func + # builtin functions like defaultdict.__setitem__ lack many attributes + try: + fun.__defaults__ = func.__defaults__ + except AttributeError: + pass + try: + fun.__kwdefaults__ = func.__kwdefaults__ + except AttributeError: + pass + try: + fun.__annotations__ = func.__annotations__ + except AttributeError: + pass + try: + fun.__module__ = func.__module__ + except AttributeError: + pass + try: + fun.__signature__ = sig + except ValueError: + pass fun.__qualname__ = func.__qualname__ - fun.__dict__.update(func.__dict__) + try: + fun.__dict__.update(func.__dict__) + except AttributeError: + pass return fun diff --git a/src/tests/test.py b/src/tests/test.py index acdaf93..4531ce3 100644 --- a/src/tests/test.py +++ b/src/tests/test.py @@ -183,6 +183,17 @@ class ExtraTestCase(unittest.TestCase): self.assertEqual(f(0, 1), [0, 1, None]) + def test_slow_wrapper(self): + # see https://github.com/micheles/decorator/issues/123 + dd = defaultdict(list) + doc.trace(defaultdict.__setitem__)(dd, 'x', [1]) + self.assertEqual(dd['x'], [1]) + # NB: defaultdict.__getitem__ has no signature and cannot be decorated + with self.assertRaises(ValueError): + doc.trace(defaultdict.__getitem__) + doc.trace(defaultdict.__delitem__)(dd, 'x') + self.assertEqual(dd['x'], []) + # ################### test dispatch_on ############################# # # adapted from test_functools in Python 3.5 |