#36696: django.utils.inspect leads to NameError with Python 3.14
-------------------------------------+-------------------------------------
     Reporter:  Patrick Rauscher     |                     Type:
                                     |  Uncategorized
       Status:  new                  |                Component:  Utilities
      Version:  5.2                  |                 Severity:  Normal
     Keywords:  typing,inspect       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
 Starting with Python 3.14, deferred evaluation of annotations (PEP-649) is
 default now. This would suggest that using annotations in templatetags or
 signals should be as easy as:

 {{{
 from typing import TYPE_CHECKING
 from django.contrib.auth.signals import user_logged_in
 from django.dispatch import receiver

 if TYPE_CHECKING:
     from django.http import HttpRequest

 @receiver(user_logged_in)
 def handle_successful_login(request: HttpRequest, *args, **kwargs) ->
 None:
     print("Someone logged in successful - this would contain useful code")
 }}}

 Weirdly, as long as DEBUG is set to False, this code will run without
 problems. However, if DEBUG is turned to True, Signal.connect will use
 func_accepts_kwargs from django.utils.inspect to check if
 handle_successful_login accepts kwargs. func_accepts_kwargs will
 ultimatively use inspect.signature on the function, which triggers
 evaluation of the annotations and leads to NameError, as TYPE_CHECKING is
 False here.

 This can be resolved in various ways:
 1. One can add from __future__ import annotations to switch back to
 Stringified annotations. However, this is called to be deprecated in the
 future
 2. One can switch to always include HttpRequest. This would work, but code
 linters will fight this, argueing that HttpRequest is only used as an type
 annotation here (which is correct)
 3. As django.utils.inspect does not actually care for the annotations,
 inspect.inspect(..., annotation_format=annotationlib.Format.STRING) can be
 used (sadly this works only in Python 3.14).

 My suggestion would be to something around

 {{{
 @functools.lru_cache(maxsize=512)
 def _get_func_parameters(func, remove_first):
     if sys.version_info[0:2] >= (3, 14):
         import annotationlib
         signature = inspect.signature(func,
 annotation_format=annotationlib.Format.STRING)
     else:
         signature = inspect.signature(func)
     parameters = tuple(signature.parameters.values())
     if remove_first:
         parameters = parameters[1:]
     return parameters
 }}}

 But I agree that it might not be the nicest solution.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36696>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019a306e9940-e028f7e1-e2dd-47ff-bb02-c8db16fa0615-000000%40eu-central-1.amazonses.com.

Reply via email to