﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
34204	Django cannot load when Python is compiled with --without-doc-strings enabled	Jon Janzen	nobody	"I'm not sure that this is even a supported configuration for Django, but CPython's `./configure` script offers an option called [https://docs.python.org/3/using/configure.html#cmdoption-without-doc-strings --without-doc-strings] which improves memory utilization slightly.

Quoting the relevant portion from CPython docs:

> --without-doc-strings
> Disable static documentation strings to reduce the memory footprint (enabled by default). Documentation strings defined in Python are not affected.

I have an use-case where I need to deploy a Django service on a device with low available memory. I'd like to disable built-in doc strings as part of an overall strategy to reduce memory but compiling CPython with that option and running the django service crashes:


{{{
  File "".../asgi.py"", line 3, in <module>
    from django.core.asgi import get_asgi_application
  File "".../lib/python3.11/site-packages/django/core/asgi.py"", line 2, in <module>
    from django.core.handlers.asgi import ASGIHandler
  File "".../lib/python3.11/site-packages/django/core/handlers/asgi.py"", line 11, in <module>
    from django.core.handlers import base
  File "".../lib/python3.11/site-packages/django/core/handlers/base.py"", line 11, in <module>
    from django.urls import get_resolver, set_urlconf
  File "".../lib/python3.11/site-packages/django/urls/__init__.py"", line 1, in <module>
    from .base import (
  File "".../lib/python3.11/site-packages/django/urls/base.py"", line 8, in <module>
    from .exceptions import NoReverseMatch, Resolver404
  File "".../lib/python3.11/site-packages/django/urls/exceptions.py"", line 1, in <module>
    from django.http import Http404
  File "".../lib/python3.11/site-packages/django/http/__init__.py"", line 2, in <module>
    from django.http.request import (
  File "".../lib/python3.11/site-packages/django/http/request.py"", line 8, in <module>
    from django.core import signing
  File "".../lib/python3.11/site-packages/django/core/signing.py"", line 43, in <module>
    from django.utils.crypto import constant_time_compare, salted_hmac
  File "".../lib/python3.11/site-packages/django/utils/crypto.py"", line 85, in <module>
    if func_supports_parameter(hashlib.md5, 'usedforsecurity'):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "".../lib/python3.11/site-packages/django/utils/inspect.py"", line 74, in func_supports_parameter
    return any(param.name == name for param in _get_callable_parameters(func))
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "".../lib/python3.11/site-packages/django/utils/inspect.py"", line 16, in _get_callable_parameters
    return _get_func_parameters(func, remove_first=is_method)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "".../lib/python3.11/site-packages/django/utils/inspect.py"", line 7, in _get_func_parameters
    parameters = tuple(inspect.signature(func).parameters.values())
                       ^^^^^^^^^^^^^^^^^^^^^^^
  File "".../cpython/Lib/inspect.py"", line 3270, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "".../cpython/Lib/inspect.py"", line 3018, in from_callable
    return _signature_from_callable(obj, sigcls=cls,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "".../cpython/Lib/inspect.py"", line 2510, in _signature_from_callable
    return _signature_from_builtin(sigcls, obj,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "".../cpython/Lib/inspect.py"", line 2317, in _signature_from_builtin
    raise ValueError(""no signature found for builtin {!r}"".format(func))
ValueError: no signature found for builtin <built-in function openssl_md5>
}}}

(irrelevant information lightly censored)

Looking through this stack trace the problem looks to be [https://github.com/django/django/blob/d10c7bfe56f025ccc690721c9f13e7029b777b9c/django/utils/crypto.py#L80-L92 some code] that executes at module import to determine whether or not md5 supports the `usedforsecurity` parameter.

If this ticket is accepted I'm happy to put up a PR to fix this, I've included my proposed solution on this ticket to save a roundtrip in discussion:

{{{
diff --git a/django/utils/inspect.py b/django/utils/inspect.py
index 28418f7312..d8622a22df 100644
--- a/django/utils/inspect.py
+++ b/django/utils/inspect.py
@@ -70,4 +70,12 @@ def method_has_no_args(meth):
 
 
 def func_supports_parameter(func, name):
-    return any(param.name == name for param in _get_callable_parameters(func))
+    try:
+        callable_parameters = _get_callable_parameters(func)
+    except ValueError:
+        # When Python is compiled with the --without-doc-strings
+        # argument to ./configure the signatures for built-in
+        # functions are not available. In such a case, be
+        # conservative and assume no:
+        return False
+    return any(param.name == name for param in callable_parameters)
}}}
"	Uncategorized	new	Uncategorized	4.1	Normal				Unreviewed	0	0	0	0	0	0
