mirror of
https://github.com/django/django.git
synced 2025-11-07 07:15:35 +00:00
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.
This commit is contained in:
committed by
Jacob Walls
parent
340e4f832e
commit
6019147229
@@ -1,10 +1,24 @@
|
|||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
|
from django.utils.version import PY314
|
||||||
|
|
||||||
|
if PY314:
|
||||||
|
import annotationlib
|
||||||
|
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=512)
|
@functools.lru_cache(maxsize=512)
|
||||||
def _get_func_parameters(func, remove_first):
|
def _get_func_parameters(func, remove_first):
|
||||||
parameters = tuple(inspect.signature(func).parameters.values())
|
# As the annotations are not used in any case, inspect the signature with
|
||||||
|
# FORWARDREF to leave any deferred annotations unevaluated.
|
||||||
|
if PY314:
|
||||||
|
signature = inspect.signature(
|
||||||
|
func, annotation_format=annotationlib.Format.FORWARDREF
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
signature = inspect.signature(func)
|
||||||
|
|
||||||
|
parameters = tuple(signature.parameters.values())
|
||||||
if remove_first:
|
if remove_first:
|
||||||
parameters = parameters[1:]
|
parameters = parameters[1:]
|
||||||
return parameters
|
return parameters
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import unittest
|
import unittest
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from django.shortcuts import aget_object_or_404
|
from django.shortcuts import aget_object_or_404
|
||||||
from django.utils import inspect
|
from django.utils import inspect
|
||||||
|
from django.utils.version import PY314
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from django.utils.safestring import SafeString
|
||||||
|
|
||||||
|
|
||||||
class Person:
|
class Person:
|
||||||
@@ -103,6 +108,16 @@ class TestInspectMethods(unittest.TestCase):
|
|||||||
self.assertIs(inspect.func_accepts_kwargs(Person.all_kinds), True)
|
self.assertIs(inspect.func_accepts_kwargs(Person.all_kinds), True)
|
||||||
self.assertIs(inspect.func_accepts_kwargs(Person().just_args), False)
|
self.assertIs(inspect.func_accepts_kwargs(Person().just_args), False)
|
||||||
|
|
||||||
|
@unittest.skipUnless(PY314, "Deferred annotations are Python 3.14+ only")
|
||||||
|
def test_func_accepts_kwargs_deferred_annotations(self):
|
||||||
|
|
||||||
|
def func_with_annotations(self, name: str, complex: SafeString) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Inspection fails with deferred annotations with python 3.14+. Earlier
|
||||||
|
# Python versions trigger the NameError on module initialization.
|
||||||
|
self.assertIs(inspect.func_accepts_kwargs(func_with_annotations), False)
|
||||||
|
|
||||||
|
|
||||||
class IsModuleLevelFunctionTestCase(unittest.TestCase):
|
class IsModuleLevelFunctionTestCase(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user