Bug Report
Describe the bug
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.
The two utility functions that make use of inspect.getfullargspec should switch to inspect.signature and pass annotation_format=Format.STRING or anotation_format=Format.FORWARDREF if sys.version_info >= (3, 14).
To Reproduce
from pyramid.config import Configurator
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pyramid.interfaces import IRequest
def home_view(request: IRequest) -> None:
pass
with Configurator() as config:
config.add_route('home', '/')
config.add_view(home_view, route_name='home')
On Python 3.14+ this will result in a TypeError in inspect.getfullargspec as a direct result of the NameError for IRequest emitted by inspect.signature. The same code will work if from __future__ import annotations is present.
Expected behavior
Since Pyramid doesn't do anything with the annotations, it shouldn't really care whether or not they can be evaluated using annotationlib.Format.VALUE, so it should switch to Format.FORWARDREF. This provides a clear upgrade path for people that previously relied on from __future__ import annotations and would like to switch to the new PEP 649 semantics in Python 3.14+ without any necessary code changes.
Additional context
Switching from inspect.getfullargspec to inspect.signature should simplify some of the code and make it more reliable too, since it properly respects __wrapped__ and automatically removes the first parameter from bound methods.
In order to ensure proper backwards compatibility I would add a new utility function get_signature to pyramid.util which is defined as follows (you could also put this inside a compat module):
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)
Bug Report
Describe the bug
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.The two utility functions that make use of
inspect.getfullargspecshould switch toinspect.signatureand passannotation_format=Format.STRINGoranotation_format=Format.FORWARDREFifsys.version_info >= (3, 14).To Reproduce
On Python 3.14+ this will result in a
TypeErrorininspect.getfullargspecas a direct result of theNameErrorforIRequestemitted byinspect.signature. The same code will work iffrom __future__ import annotationsis present.Expected behavior
Since Pyramid doesn't do anything with the annotations, it shouldn't really care whether or not they can be evaluated using
annotationlib.Format.VALUE, so it should switch toFormat.FORWARDREF. This provides a clear upgrade path for people that previously relied onfrom __future__ import annotationsand would like to switch to the new PEP 649 semantics in Python 3.14+ without any necessary code changes.Additional context
Switching from
inspect.getfullargspectoinspect.signatureshould simplify some of the code and make it more reliable too, since it properly respects__wrapped__and automatically removes the first parameter from bound methods.In order to ensure proper backwards compatibility I would add a new utility function
get_signaturetopyramid.utilwhich is defined as follows (you could also put this inside acompatmodule):