Skip to content

Commit 6775888

Browse files
Patrick Rauscherjacobtylerwalls
authored andcommitted
[5.2.x] Fixed #36696 -- Fixed NameError when inspecting functions with deferred annotations.
In Python 3.14, annotations are deferred by default, so we should not assume that the names in them have been imported unconditionally.
1 parent d5dfffa commit 6775888

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

django/utils/inspect.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
import functools
22
import inspect
33

4+
from django.utils.version import PY314
5+
6+
if PY314:
7+
import annotationlib
8+
49

510
@functools.lru_cache(maxsize=512)
611
def _get_func_parameters(func, remove_first):
7-
parameters = tuple(inspect.signature(func).parameters.values())
12+
# As the annotations are not used in any case, inspect the signature with
13+
# FORWARDREF to leave any deferred annotations unevaluated.
14+
if PY314:
15+
signature = inspect.signature(
16+
func, annotation_format=annotationlib.Format.FORWARDREF
17+
)
18+
else:
19+
signature = inspect.signature(func)
20+
21+
parameters = tuple(signature.parameters.values())
822
if remove_first:
923
parameters = parameters[1:]
1024
return parameters

tests/utils_tests/test_inspect.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import unittest
2+
from typing import TYPE_CHECKING
23

34
from django.utils import inspect
5+
from django.utils.version import PY314
6+
7+
if TYPE_CHECKING:
8+
from django.utils.safestring import SafeString
49

510

611
class Person:
@@ -100,3 +105,13 @@ def test_func_accepts_kwargs(self):
100105
self.assertIs(inspect.func_accepts_kwargs(Person().just_args), False)
101106
self.assertIs(inspect.func_accepts_kwargs(Person.all_kinds), True)
102107
self.assertIs(inspect.func_accepts_kwargs(Person().just_args), False)
108+
109+
@unittest.skipUnless(PY314, "Deferred annotations are Python 3.14+ only")
110+
def test_func_accepts_kwargs_deferred_annotations(self):
111+
112+
def func_with_annotations(self, name: str, complex: SafeString) -> None:
113+
pass
114+
115+
# Inspection fails with deferred annotations with python 3.14+. Earlier
116+
# Python versions trigger the NameError on module initialization.
117+
self.assertIs(inspect.func_accepts_kwargs(func_with_annotations), False)

0 commit comments

Comments
 (0)