summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2021-05-15 06:08:54 +0200
committerMichele Simionato <michele.simionato@gmail.com>2021-05-15 06:08:54 +0200
commitdbb10360ec5e11126c6c3354038e1d41485c6323 (patch)
tree4e1c72ee9d035ce867333288f85d99014421b4da
parente3c07ea54b6ea08765f01f72042debc66159d0a3 (diff)
downloadpython-decorator-git-dbb10360ec5e11126c6c3354038e1d41485c6323.tar.gz
Decorating builtin functions5.0.8
-rw-r--r--CHANGES.md5
-rw-r--r--docs/documentation.md4
-rw-r--r--src/decorator.py33
-rw-r--r--src/tests/test.py11
4 files changed, 44 insertions, 9 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 8791a72..28105a7 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -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