Closed
Description
The current implementation of PEP-649 and PEP-749 on main simply copies functions' __annotate__
in functools.update_wrapper
(and thence functools.wraps
):
>>> def f(x: y): pass
...
>>> from functools import wraps
>>> @wraps(f)
... def g(x): pass
...
>>> g.__annotate__ is f.__annotate__
True
But as @ncoghlan pointed out (larryhastings/co_annotations#21, https://discuss.python.org/t/pep-749-implementing-pep-649/54974/4), this may not be what we want in the case where the original function's __annotations__
have been modified:
>>> def f(x: int): pass
...
>>> f.__annotations__["x"] = 42
>>> @wraps(f)
... def g(x): pass
...
>>> f.__annotations__
{'x': 42}
>>> g.__annotations__
{'x': <class 'int'>}
Alyssa therefore suggests making update_wrapper
create a wrapper __annotate__
function that looks in the original function's __annotations__
first. This doesn't fit neatly into update_wrapper
's current structure of WRAPPER_ASSIGNMENTS and WRAPPER_UPDATES, so we should add a third bucket, maybe WRAPPER_DELEGATIONS.