With PEP 649 evaluation of annotations is deferred, this replaces the commonly used from __future__ import annotations which achieved a similar result by storing all the annotations as plain strings.
When migrating from one approach to the other, the use of inspect.getfullargspec is problematic, since under the hood it uses inspect.signature with the default parameters, which will cause annotation_format to end up as Format.VALUE which will cause exceptions, if the annotation cannot be properly evaluated, because e.g. a typing-only import was moved into a if TYPE_CHECKING: block, in order to improve application startup times.
reg.arginfo should switch to inspect.signature and pass in annotation_format=Format.FORWARDREF if sys.version_info >= (3, 14) since reg doesn't really care about the annotations on the function. While inspect.signature returns a slightly different object structure, it should also be a little bit more robust by handling things like __wrapped__ properly. So there's reasons to switch to the new API other than this bug, now that Python 2.7 support is no longer a concern.
To reproduce
from reg import dispatch_method
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from foo import Foo
class Bar:
@dispatch_method()
def bar(obj: Foo) -> None:
pass
Bar.bar
This raises a NameError: name 'Foo' is not defined from inspect.signature, which gets re-raised from inspect.getfullargspec as TypeError: unsupported callable
Additional context
To make your life a little easier it might be worth adding a small compat.py module with the following code:
import inspect
import sys
if sys.version_info < (3, 14):
def get_signature(fn):
return inspect.signature(fn)
else:
from annotationlib import Format
def get_signature(fn):
return inspect.signature(fn, annotation_format=Format.FORWARDREF)
You can then use get_signature from that module.
With PEP 649 evaluation of annotations is deferred, this replaces the commonly used
from __future__ import annotationswhich achieved a similar result by storing all the annotations as plain strings.When migrating from one approach to the other, the use of
inspect.getfullargspecis problematic, since under the hood it usesinspect.signaturewith the default parameters, which will causeannotation_formatto end up asFormat.VALUEwhich will cause exceptions, if the annotation cannot be properly evaluated, because e.g. a typing-only import was moved into aif TYPE_CHECKING:block, in order to improve application startup times.reg.arginfoshould switch toinspect.signatureand pass inannotation_format=Format.FORWARDREFifsys.version_info >= (3, 14)since reg doesn't really care about the annotations on the function. Whileinspect.signaturereturns a slightly different object structure, it should also be a little bit more robust by handling things like__wrapped__properly. So there's reasons to switch to the new API other than this bug, now that Python 2.7 support is no longer a concern.To reproduce
This raises a
NameError: name 'Foo' is not definedfrominspect.signature, which gets re-raised frominspect.getfullargspecasTypeError: unsupported callableAdditional context
To make your life a little easier it might be worth adding a small
compat.pymodule with the following code:You can then use
get_signaturefrom that module.