diff options
| author | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-11-29 18:45:39 -0500 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-12-01 20:49:53 -0500 |
| commit | ec7327453d266d31a00060aeb5b9f19e5adfb0a4 (patch) | |
| tree | 991b15a8439d4d768ae6256e378b8e2036c2f51e /django/utils/inspect.py | |
| parent | 2e3953f0a2de7bb702d393279d9dbbe2581a21a5 (diff) | |
[6.0.x] Fixed #36712 -- Evaluated type annotations lazily in template tag registration.
Ideally, this will be reverted when an upstream solution is available for
https://github.com/python/cpython/issues/141560.
Thanks Patrick Rauscher for the report and Augusto Pontes for the
first iteration and test.
Backport of 34186e731ca20a2344b1f88fd543a854d6b13a00 from main.
Diffstat (limited to 'django/utils/inspect.py')
| -rw-r--r-- | django/utils/inspect.py | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/django/utils/inspect.py b/django/utils/inspect.py index ac5e82ca14..f0f43ae17e 100644 --- a/django/utils/inspect.py +++ b/django/utils/inspect.py @@ -1,11 +1,19 @@ import functools import inspect +import threading +from contextlib import contextmanager from django.utils.version import PY314 if PY314: import annotationlib + lock = threading.Lock() + safe_signature_from_callable = functools.partial( + inspect._signature_from_callable, + annotation_format=annotationlib.Format.FORWARDREF, + ) + @functools.lru_cache(maxsize=512) def _get_func_parameters(func, remove_first): @@ -98,3 +106,27 @@ def is_module_level_function(func): return False return True + + +@contextmanager +def lazy_annotations(): + """ + inspect.getfullargspec eagerly evaluates type annotations. To add + compatibility with Python 3.14+ deferred evaluation, patch the module-level + helper to provide the annotation_format that we are using elsewhere. + + This private helper could be removed when there is an upstream solution for + https://github.com/python/cpython/issues/141560. + + This context manager is not reentrant. + """ + if not PY314: + yield + return + with lock: + original_helper = inspect._signature_from_callable + inspect._signature_from_callable = safe_signature_from_callable + try: + yield + finally: + inspect._signature_from_callable = original_helper |
