--- Begin Message ---
Package: src:python-django
Version: 3:5.2.17-1
User: [email protected]
Usertags: python3.15
Tags: patch, ftbfs, forky, sid
Hi!
While rebuilding the python related packages against the Python 3.15rc1
version we found that python-django fails to build from source [1].
There are three separate issues related to python 3.15.
First, tests failing with `NameError: name 'SomeType' is not defined.
Did you mean: 'TokenType'?`. This was fixed upstream with Commit e7f539f
[2].
Second, the error message for `test_invalid_choice_db_option` has
changed. To fix this, it required applying a few upstream patches [3]
[4].
Third, test_strip_tags failed with `sys.version_info >=
min_fixed_security[sys.version_info[:2]] KeyError: (3, 15)`, this is
caused by line 136 of tests/utils_tests/test_html.py, which defines
htmlparser_fixed_security but that's never used and it's later recrated
in line 151 in a way that avoids the error, the related upstream fix
about this is in [5], but backporting the fix is actually only deleting
the line 136.
I applied the upstream fixes in the sandbox [5] to be able to build the
packages that depend on python-django, please consider applying the
patch to support the upcoming 3.15 version.
Happy hacking,
[1]:
https://debusine.debian.net/debian/r-python-python3.15/artifact/4415709/raw/python-django_5.2.17-1+py315.1_amd64-2026-08-22T01:25:30Z.build
[2]:
https://github.com/django/django/commit/e7f539f813bd56a71ca3c1fbf379f47691002086
[3]: https://github.com/django/django/pull/20021
[4]:
https://github.com/django/django/commit/ed13a58bf63df94508c8a0fe779da0b6a2bc26bb
[5]: https://github.com/django/django/commit/185b049
[6]: https://debusine.debian.net/debian/r-python-python3.15/
--
"Can you imagine what I would do if I could do all I can?" -- Sun Tzu
Saludos /\/\ /\ >< `/
From: Jacob Walls <[email protected]>
Date: Wed, 6 May 2026 15:39:41 -0400
Subject: [PATCH] Refs #36712, #36664 -- Used annotation_format parameter of
getfullargspec() on Python 3.15.
https://github.com/python/cpython/pull/149457
Origin: upstream, https://github.com/django/django/commit/e7f539f813bd56a71ca3c1fbf379f47691002086
---
django/contrib/admin/templatetags/base.py | 9 +++------
django/template/base.py | 5 ++---
django/template/library.py | 23 ++++++++++-------------
django/utils/inspect.py | 27 ++++++++++++++++++++++-----
4 files changed, 37 insertions(+), 27 deletions(-)
Index: python-django/django/contrib/admin/templatetags/base.py
===================================================================
--- python-django.orig/django/contrib/admin/templatetags/base.py
+++ python-django/django/contrib/admin/templatetags/base.py
@@ -1,7 +1,5 @@
-from inspect import getfullargspec
-
from django.template.library import InclusionNode, parse_bits
-from django.utils.inspect import lazy_annotations
+from django.utils.inspect import getfullargspec
class InclusionAdminNode(InclusionNode):
@@ -12,10 +10,9 @@ class InclusionAdminNode(InclusionNode):
def __init__(self, parser, token, func, template_name, takes_context=True):
self.template_name = template_name
- with lazy_annotations():
- params, varargs, varkw, defaults, kwonly, kwonly_defaults, _ = (
- getfullargspec(func)
- )
+ params, varargs, varkw, defaults, kwonly, kwonly_defaults, _ = getfullargspec(
+ func
+ )
bits = token.split_contents()
args, kwargs = parse_bits(
parser,
Index: python-django/django/template/base.py
===================================================================
--- python-django.orig/django/template/base.py
+++ python-django/django/template/base.py
@@ -58,7 +58,7 @@ from enum import Enum
from django.template.context import BaseContext
from django.utils.formats import localize
from django.utils.html import conditional_escape
-from django.utils.inspect import lazy_annotations, signature
+from django.utils.inspect import getfullargspec, signature
from django.utils.regex_helper import _lazy_re_compile
from django.utils.safestring import SafeData, SafeString, mark_safe
from django.utils.text import get_text_list, smart_split, unescape_string_literal
@@ -761,8 +761,7 @@ class FilterExpression:
# Check to see if a decorator is providing the real function.
func = inspect.unwrap(func)
- with lazy_annotations():
- args, _, _, defaults, _, _, _ = inspect.getfullargspec(func)
+ args, _, _, defaults, _, _, _ = getfullargspec(func)
alen = len(args)
dlen = len(defaults or [])
# Not enough OR Too many
Index: python-django/django/template/library.py
===================================================================
--- python-django.orig/django/template/library.py
+++ python-django/django/template/library.py
@@ -1,10 +1,10 @@
from collections.abc import Iterable
from functools import wraps
from importlib import import_module
-from inspect import getfullargspec, unwrap
+from inspect import unwrap
from django.utils.html import conditional_escape
-from django.utils.inspect import lazy_annotations
+from django.utils.inspect import getfullargspec
from .base import Node, Template, token_kwargs
from .exceptions import TemplateSyntaxError
@@ -110,16 +110,15 @@ class Library:
"""
def dec(func):
- with lazy_annotations():
- (
- params,
- varargs,
- varkw,
- defaults,
- kwonly,
- kwonly_defaults,
- _,
- ) = getfullargspec(unwrap(func))
+ (
+ params,
+ varargs,
+ varkw,
+ defaults,
+ kwonly,
+ kwonly_defaults,
+ _,
+ ) = getfullargspec(unwrap(func))
function_name = name or func.__name__
@wraps(func)
@@ -166,16 +165,15 @@ class Library:
def dec(func):
nonlocal end_name
- with lazy_annotations():
- (
- params,
- varargs,
- varkw,
- defaults,
- kwonly,
- kwonly_defaults,
- _,
- ) = getfullargspec(unwrap(func))
+ (
+ params,
+ varargs,
+ varkw,
+ defaults,
+ kwonly,
+ kwonly_defaults,
+ _,
+ ) = getfullargspec(unwrap(func))
function_name = name or func.__name__
if end_name is None:
@@ -250,16 +248,15 @@ class Library:
"""
def dec(func):
- with lazy_annotations():
- (
- params,
- varargs,
- varkw,
- defaults,
- kwonly,
- kwonly_defaults,
- _,
- ) = getfullargspec(unwrap(func))
+ (
+ params,
+ varargs,
+ varkw,
+ defaults,
+ kwonly,
+ kwonly_defaults,
+ _,
+ ) = getfullargspec(unwrap(func))
function_name = name or func.__name__
@wraps(func)
Index: python-django/django/utils/inspect.py
===================================================================
--- python-django.orig/django/utils/inspect.py
+++ python-django/django/utils/inspect.py
@@ -3,16 +3,17 @@ import inspect
import threading
from contextlib import contextmanager
-from django.utils.version import PY314
+from django.utils.version import PY314, PY315
if PY314:
import annotationlib
- lock = threading.Lock()
- safe_signature_from_callable = functools.partial(
- inspect._signature_from_callable,
- annotation_format=annotationlib.Format.FORWARDREF,
- )
+ if not PY315:
+ lock = threading.Lock()
+ safe_signature_from_callable = functools.partial(
+ inspect._signature_from_callable,
+ annotation_format=annotationlib.Format.FORWARDREF,
+ )
@functools.lru_cache(maxsize=512)
@@ -96,12 +97,12 @@ def lazy_annotations():
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 private helper should only be used for Python 3.14, as
+ https://github.com/python/cpython/issues/141560 was fixed in 3.15.
This context manager is not reentrant.
"""
- if not PY314:
+ if PY315 or not PY314:
yield
return
with lock:
@@ -113,6 +114,22 @@ def lazy_annotations():
inspect._signature_from_callable = original_helper
+def getfullargspec(*args, annotation_format=None, **kwargs):
+ """
+ A wrapper around inspect.getfullargspec that leaves deferred annotations
+ unevaluated on Python 3.14+, since they are not used in our case.
+ """
+ if PY315:
+ return inspect.getfullargspec(
+ *args, **kwargs, annotation_format=annotationlib.Format.FORWARDREF
+ )
+ if PY314:
+ with lazy_annotations():
+ return inspect.getfullargspec(*args, **kwargs)
+ else:
+ return inspect.getfullargspec(*args, **kwargs)
+
+
def signature(obj):
"""
A wrapper around inspect.signature that leaves deferred annotations
From: kihuni <[email protected]>
Date: Sun, 2 Nov 2025 08:50:45 +0300
Subject: [PATCH] Fixed #36321 -- Defaulted suggest_on_error=True in management
commands.
Python 3.15 defaults suggest_on_error=True, but the feature is available
from 3.14, so this change opts in earlier. This change can be reverted
when Python 3.15 is the minimum supported version.
Origin: upstream, https://github.com/django/django/commit/b1a65eac7c09250d36e12464fc8fff2a401246b6
---
django/core/management/base.py | 3 +++
django/utils/version.py | 1 +
tests/admin_scripts/tests.py | 8 +++++++-
tests/user_commands/tests.py | 16 ++++++++++++++++
4 files changed, 27 insertions(+), 1 deletion(-)
Index: python-django/django/core/management/base.py
===================================================================
--- python-django.orig/django/core/management/base.py
+++ python-django/django/core/management/base.py
@@ -15,7 +15,7 @@ from django.core import checks
from django.core.exceptions import ImproperlyConfigured
from django.core.management.color import color_style, no_style
from django.db import DEFAULT_DB_ALIAS, connections
-from django.utils.version import PY314
+from django.utils.version import PY314, PY315
ALL_CHECKS = "__all__"
@@ -58,6 +58,8 @@ class CommandParser(ArgumentParser):
):
self.missing_args_message = missing_args_message
self.called_from_command_line = called_from_command_line
+ if PY314 and not PY315:
+ kwargs.setdefault("suggest_on_error", True)
if PY314:
if os.environ.get("DJANGO_COLORS") == "nocolor" or "--no-color" in sys.argv:
kwargs.setdefault("color", False)
Index: python-django/django/utils/version.py
===================================================================
--- python-django.orig/django/utils/version.py
+++ python-django/django/utils/version.py
@@ -20,6 +20,7 @@ PY311 = sys.version_info >= (3, 11)
PY312 = sys.version_info >= (3, 12)
PY313 = sys.version_info >= (3, 13)
PY314 = sys.version_info >= (3, 14)
+PY315 = sys.version_info >= (3, 15)
def get_version(version=None):
Index: python-django/tests/admin_scripts/tests.py
===================================================================
--- python-django.orig/tests/admin_scripts/tests.py
+++ python-django/tests/admin_scripts/tests.py
@@ -38,7 +38,7 @@ from django.db.migrations.recorder impor
from django.test import LiveServerTestCase, SimpleTestCase, TestCase, override_settings
from django.test.utils import captured_stderr, captured_stdout
from django.urls import path
-from django.utils.version import PY313, get_docs_version
+from django.utils.version import PY313, PY314, get_docs_version
from django.views.static import serve
from . import urls
@@ -2405,10 +2405,16 @@ class Discovery(SimpleTestCase):
class CommandDBOptionChoiceTests(SimpleTestCase):
def test_invalid_choice_db_option(self):
- expected_error = (
- r"Error: argument --database: invalid choice: 'deflaut' "
- r"\(choose from '?default'?, '?other'?\)"
- )
+ if PY314:
+ expected_error = (
+ r"Error: argument --database: invalid choice: 'deflaut', "
+ r"maybe you meant 'default'\? \(choose from default, other\)"
+ )
+ else:
+ expected_error = (
+ r"Error: argument --database: invalid choice: 'deflaut' "
+ r"\(choose from '?default'?, '?other'?\)"
+ )
args = [
"changepassword",
"createsuperuser",
From: kasey <[email protected]>
Date: Tue, 12 May 2026 00:15:15 -0500
Subject: [PATCH] Fixed #37096 -- Fixed test_invalid_choice_db_option on Python
3.14.5+.
Origin: upstream, https://github.com/django/django/commit/ed13a58bf63df94508c8a0fe779da0b6a2bc26bb
---
tests/admin_scripts/tests.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: python-django/tests/admin_scripts/tests.py
===================================================================
--- python-django.orig/tests/admin_scripts/tests.py
+++ python-django/tests/admin_scripts/tests.py
@@ -2408,7 +2408,8 @@ class CommandDBOptionChoiceTests(SimpleT
if PY314:
expected_error = (
r"Error: argument --database: invalid choice: 'deflaut', "
- r"maybe you meant 'default'\? \(choose from default, other\)"
+ r"maybe you meant 'default'\? "
+ r"\(choose from '?default'?, '?other'?\)"
)
else:
expected_error = (
From: Mariusz Felisiak <[email protected]>
Date: Wed, 22 Oct 2025 10:04:38 +0200
Subject: [PATCH] Refs #36499 -- Made TestUtilsHtml.test_strip_tags() assume
behavior change in X.Y.0 version for Python 3.14+.
This also removes unsupported versions of Python from the test dict.
Origin: upstream, https://github.com/django/django/commit/185b049e9e72a5ff4b07e33605e10eb4f52ca74c
---
tests/utils_tests/test_html.py | 11 -----------
1 file changed, 11 deletions(-)
Index: python-django/tests/utils_tests/test_html.py
===================================================================
--- python-django.orig/tests/utils_tests/test_html.py
+++ python-django/tests/utils_tests/test_html.py
@@ -126,16 +126,9 @@ class TestUtilsHtml(SimpleTestCase):
# Python versions and CI workers include the fix. See:
# https://github.com/python/cpython/commit/6eb6c5db
min_fixed_security = {
- (3, 14): (3, 14),
(3, 13): (3, 13, 6),
(3, 12): (3, 12, 12),
- (3, 11): (3, 11, 14),
- (3, 10): (3, 10, 19),
- (3, 9): (3, 9, 24),
}
- htmlparser_fixed_security = (
- sys.version_info >= min_fixed_security[sys.version_info[:2]]
- )
# Similarly, there was a fix for terminating incomplete entities. See:
# https://github.com/python/cpython/commit/95296a9d
min_fixed_incomplete_entities = {
--- End Message ---