public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
To: git-commits@fedoraproject.org
Subject: [rpms/python3.13] epel9: On EL 9, also supports reparse deferral in expat
Date: Tue, 18 Aug 2026 08:20:46 GMT	[thread overview]
Message-ID: <178704124606.1.9604433200549725292.rpms-python3.13-0ca3f59c07cb@fedoraproject.org> (raw)

            A new commit has been pushed.

            Repo   : rpms/python3.13
            Branch : epel9
            Commit : 0ca3f59c07cb0d9bf01a0746d00773ed0c625755
            Author : Miro Hrončok <miro@hroncok.cz>
            Date   : 2026-08-13T12:47:37+02:00
            Stats  : +160/-86 in 4 file(s)
            URL    : https://src.fedoraproject.org/rpms/python3.13/c/0ca3f59c07cb0d9bf01a0746d00773ed0c625755?branch=epel9

            Log:
            On EL 9, also supports reparse deferral in expat

This replaces one downstream-only patch with another.
Yet arguably, this is the safer thing to do.

Read the patch description for details; won't copy paste them here.

Also, require expat >= version-release when expat < 2.7.4.

Assisted-By: Claude Opus 4.6

---
diff --git a/00466-downstream-only-lower-xml_combined_version-threshold-for-reparse-deferral.patch b/00466-downstream-only-lower-xml_combined_version-threshold-for-reparse-deferral.patch
new file mode 100644
index 0000000..15de467
--- /dev/null
+++ b/00466-downstream-only-lower-xml_combined_version-threshold-for-reparse-deferral.patch
@@ -0,0 +1,133 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
+Date: Wed, 12 Aug 2026 15:18:39 +0200
+Subject: 00466: Downstream only: Lower XML_COMBINED_VERSION threshold for
+ reparse deferral
+
+RHEL 9 expat 2.5.0 has XML_SetReparseDeferralEnabled backported
+via the CVE-2023-52425 fix, but XML_COMBINED_VERSION remains 20500.
+CPython's #if XML_COMBINED_VERSION >= 20600 guards compile the setter
+as a no-op, so SetReparseDeferralEnabled silently does nothing and
+GetReparseDeferralEnabled always returns False, even though the expat
+library actually supports (and enables) reparse deferral.
+
+Lower the threshold from 20600 to 20500 so that CPython uses the
+backported function. This makes the Python API actually work on RHEL 9
+and fixes test failures (test_reparse_deferral_disabled,
+test_flush_reparse_deferral_disabled, test_simple_xml_chunk_*).
+
+The spec file BuildRequires expat-devel >= 2.5.0-2 to ensure the
+backported function is available.
+---
+ Lib/test/test_pyexpat.py   | 6 +++---
+ Lib/test/test_sax.py       | 4 ++--
+ Lib/test/test_xml_etree.py | 4 ++--
+ Modules/pyexpat.c          | 6 +++---
+ 4 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
+index ae7cec6540..7f73a8c5e7 100644
+--- a/Lib/test/test_pyexpat.py
++++ b/Lib/test/test_pyexpat.py
+@@ -1001,7 +1001,7 @@ def test_error_path_no_crash(self):
+ class ReparseDeferralTest(unittest.TestCase):
+     def test_getter_setter_round_trip(self):
+         parser = expat.ParserCreate()
+-        enabled = (expat.version_info >= (2, 6, 0))
++        enabled = (expat.version_info >= (2, 5, 0))
+ 
+         self.assertIs(parser.GetReparseDeferralEnabled(), enabled)
+         parser.SetReparseDeferralEnabled(False)
+@@ -1010,7 +1010,7 @@ def test_getter_setter_round_trip(self):
+         self.assertIs(parser.GetReparseDeferralEnabled(), enabled)
+ 
+     def test_reparse_deferral_enabled(self):
+-        if expat.version_info < (2, 6, 0):
++        if expat.version_info < (2, 5, 0):
+             self.skipTest(f'Expat {expat.version_info} does not '
+                           'support reparse deferral')
+ 
+@@ -1041,7 +1041,7 @@ def start_element(name, _):
+ 
+         parser = expat.ParserCreate()
+         parser.StartElementHandler = start_element
+-        if expat.version_info >= (2, 6, 0):
++        if expat.version_info >= (2, 5, 0):
+             parser.SetReparseDeferralEnabled(False)
+         self.assertFalse(parser.GetReparseDeferralEnabled())
+ 
+diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
+index 9b3014a94a..0e38c9488e 100644
+--- a/Lib/test/test_sax.py
++++ b/Lib/test/test_sax.py
+@@ -1215,7 +1215,7 @@ def test_expat_incremental_reset(self):
+ 
+         self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
+ 
+-    @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
++    @unittest.skipIf(pyexpat.version_info < (2, 5, 0),
+                      f'Expat {pyexpat.version_info} does not '
+                      'support reparse deferral')
+     def test_flush_reparse_deferral_enabled(self):
+@@ -1249,7 +1249,7 @@ def test_flush_reparse_deferral_disabled(self):
+         for chunk in ("<doc", ">"):
+             parser.feed(chunk)
+ 
+-        if pyexpat.version_info >= (2, 6, 0):
++        if pyexpat.version_info >= (2, 5, 0):
+             parser._parser.SetReparseDeferralEnabled(False)
+             self.assertEqual(result.getvalue(), start)  # i.e. no elements started
+ 
+diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
+index 4a76a5be1e..effb899d7b 100644
+--- a/Lib/test/test_xml_etree.py
++++ b/Lib/test/test_xml_etree.py
+@@ -1804,7 +1804,7 @@ def test_unknown_event(self):
+         with self.assertRaisesRegex(ValueError, "unknown event 'bogus'"):
+             ET.XMLPullParser(events=(x.decode() for x in (b'start', b'end', b'bogus')))
+ 
+-    @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
++    @unittest.skipIf(pyexpat.version_info < (2, 5, 0),
+                      f'Expat {pyexpat.version_info} does not '
+                      'support reparse deferral')
+     def test_flush_reparse_deferral_enabled(self):
+@@ -1834,7 +1834,7 @@ def test_flush_reparse_deferral_disabled(self):
+         for chunk in ("<doc", ">"):
+             parser.feed(chunk)
+ 
+-        if pyexpat.version_info >= (2, 6, 0):
++        if pyexpat.version_info >= (2, 5, 0):
+             if not ET is pyET:
+                 self.skipTest(f'XMLParser.(Get|Set)ReparseDeferralEnabled '
+                               'methods not available in C')
+diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
+index 9e5d84eb5e..b008fe66c1 100644
+--- a/Modules/pyexpat.c
++++ b/Modules/pyexpat.c
+@@ -781,7 +781,7 @@ pyexpat_xmlparser_SetReparseDeferralEnabled_impl(xmlparseobject *self,
+                                                  int enabled)
+ /*[clinic end generated code: output=5ec539e3b63c8c49 input=021eb9e0bafc32c5]*/
+ {
+-#if XML_COMBINED_VERSION >= 20600
++#if XML_COMBINED_VERSION >= 20500
+     XML_SetReparseDeferralEnabled(self->itself, enabled ? XML_TRUE : XML_FALSE);
+     self->reparse_deferral_enabled = (bool)enabled;
+ #endif
+@@ -1446,7 +1446,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
+     self->ns_prefixes = 0;
+     self->handlers = NULL;
+     self->intern = Py_XNewRef(intern);
+-#if XML_COMBINED_VERSION >= 20600
++#if XML_COMBINED_VERSION >= 20500
+     self->reparse_deferral_enabled = true;
+ #else
+     self->reparse_deferral_enabled = false;
+@@ -2332,7 +2332,7 @@ pyexpat_exec(PyObject *mod)
+ #else
+     capi->SetHashSalt16Bytes = NULL;
+ #endif
+-#if XML_COMBINED_VERSION >= 20600
++#if XML_COMBINED_VERSION >= 20500
+     capi->SetReparseDeferralEnabled = XML_SetReparseDeferralEnabled;
+ #else
+     capi->SetReparseDeferralEnabled = NULL;

diff --git a/00466-downstream-only-skip-tests-not-working-with-older-expat-version.patch b/00466-downstream-only-skip-tests-not-working-with-older-expat-version.patch
deleted file mode 100644
index 349deeb..0000000
--- a/00466-downstream-only-skip-tests-not-working-with-older-expat-version.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Karolina Surma <ksurma@redhat.com>
-Date: Tue, 24 Jun 2025 11:12:13 +0200
-Subject: 00466: Downstream only: Skip tests not working with older expat
- version
-
-We want to run these tests in Fedora and EPEL 10, but not in EPEL 9,
-which has too old version of expat. We set the upper bound version
-in the conditionalized skip to a release available in CentOS Stream 10,
-which is tested as working.
----
- Lib/test/test_pyexpat.py   | 2 ++
- Lib/test/test_sax.py       | 2 ++
- Lib/test/test_xml_etree.py | 6 ++++++
- 3 files changed, 10 insertions(+)
-
-diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
-index ae7cec6540..4770c5cc4f 100644
---- a/Lib/test/test_pyexpat.py
-+++ b/Lib/test/test_pyexpat.py
-@@ -1033,6 +1033,8 @@ def start_element(name, _):
- 
-         self.assertEqual(started, ['doc'])
- 
-+    @unittest.skipIf(expat.version_info < (2, 7, 1),
-+                     f"Skip for expat < 2.7.1 (version available in RHEL 10)")
-     def test_reparse_deferral_disabled(self):
-         started = []
- 
-diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
-index 9b3014a94a..90401e0d8f 100644
---- a/Lib/test/test_sax.py
-+++ b/Lib/test/test_sax.py
-@@ -1240,6 +1240,8 @@ def test_flush_reparse_deferral_enabled(self):
- 
-         self.assertEqual(result.getvalue(), start + b"<doc></doc>")
- 
-+    @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
-+                     f"Skip for expat < 2.7.1 (version available in RHEL 10)")
-     def test_flush_reparse_deferral_disabled(self):
-         result = BytesIO()
-         xmlgen = XMLGenerator(result)
-diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
-index 4a76a5be1e..d740e30123 100644
---- a/Lib/test/test_xml_etree.py
-+++ b/Lib/test/test_xml_etree.py
-@@ -1599,9 +1599,13 @@ def test_simple_xml(self, chunk_size=None, flush=False):
-         self.assert_event_tags(parser, [('end', 'root')])
-         self.assertIsNone(parser.close())
- 
-+    @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
-+                     f"Skip for expat < 2.7.1 (version available in RHEL 10)")
-     def test_simple_xml_chunk_1(self):
-         self.test_simple_xml(chunk_size=1, flush=True)
- 
-+    @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
-+                     f"Skip for expat < 2.7.1 (version available in RHEL 10)")
-     def test_simple_xml_chunk_5(self):
-         self.test_simple_xml(chunk_size=5, flush=True)
- 
-@@ -1828,6 +1832,8 @@ def test_flush_reparse_deferral_enabled(self):
- 
-         self.assert_event_tags(parser, [('end', 'doc')])
- 
-+    @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
-+                     f"Skip for expat < 2.7.1 (version available in RHEL 10)")
-     def test_flush_reparse_deferral_disabled(self):
-         parser = ET.XMLPullParser(events=('start', 'end'))
- 

diff --git a/plan.fmf b/plan.fmf
index 71d0124..9c9afb8 100644
--- a/plan.fmf
+++ b/plan.fmf
@@ -24,11 +24,10 @@ discover:
       test: "PYTHON=python${pybasever}d TOX=false VERSION=${pybasever} CYTHON=false ./venv.sh"
     - name: selftest
       path: /selftest
-      # test_subparser_inherits_reparse_deferral fails on EPEL9: https://github.com/python/cpython/issues/155485
-      test: "VERSION=${pybasever} X='-i test_check_probes -i test_subparser_inherits_reparse_deferral' ./parallel.sh"
+      test: "VERSION=${pybasever} X='-i test_check_probes' ./parallel.sh"
     - name: debugtest
       path: /selftest
-      test: "VERSION=${pybasever} PYTHON=python${pybasever}d X='-i test_check_probes -i test_subparser_inherits_reparse_deferral' ./parallel.sh"
+      test: "VERSION=${pybasever} PYTHON=python${pybasever}d X='-i test_check_probes' ./parallel.sh"
     - name: optimizedflags
       path: /flags
       test: "python${pybasever} ./assertflags.py -O3 CFLAGS PY_BUILTIN_MODULE_CFLAGS PY_CFLAGS PY_CORE_CFLAGS PY_CFLAGS_NODIST PY_STDMODULE_CFLAGS"

diff --git a/python3.13.spec b/python3.13.spec
index 0879de7..4045e62 100644
--- a/python3.13.spec
+++ b/python3.13.spec
@@ -49,7 +49,7 @@ URL: https://www.python.org/
 #global prerel ...
 %global upstream_version %{general_version}%{?prerel}
 Version: %{general_version}%{?prerel:~%{prerel}}
-Release: 1%{?dist}
+Release: 2%{?dist}
 License: Python-2.0.1
 
 
@@ -254,7 +254,7 @@ Obsoletes: python%{pybasever}%{?1:-%{1}}\
 BuildRequires: autoconf
 BuildRequires: bluez-libs-devel
 BuildRequires: bzip2-devel
-BuildRequires: expat-devel
+BuildRequires: expat-devel >= 2.5.0-2
 BuildRequires: findutils
 BuildRequires: gcc
 BuildRequires: gdbm-devel
@@ -370,14 +370,24 @@ Source11: idle3.appdata.xml
 # pypa/distutils integration: https://github.com/pypa/distutils/pull/70
 Patch251: 00251-change-user-install-location.patch
 
-# 00466 # e10760fb955ee33d2917f8a57bb4e24d71e5341c
-# Downstream only: Skip tests not working with older expat version
+# 00466 # 713a1368544eddd55088d67f88a23ce31722a4cb
+# Downstream only: Lower XML_COMBINED_VERSION threshold for reparse deferral
 #
-# We want to run these tests in Fedora and EPEL 10, but not in EPEL 9,
-# which has too old version of expat. We set the upper bound version
-# in the conditionalized skip to a release available in CentOS Stream 10,
-# which is tested as working.
-Patch466: 00466-downstream-only-skip-tests-not-working-with-older-expat-version.patch
+# RHEL 9 expat 2.5.0 has XML_SetReparseDeferralEnabled backported
+# via the CVE-2023-52425 fix, but XML_COMBINED_VERSION remains 20500.
+# CPython's #if XML_COMBINED_VERSION >= 20600 guards compile the setter
+# as a no-op, so SetReparseDeferralEnabled silently does nothing and
+# GetReparseDeferralEnabled always returns False, even though the expat
+# library actually supports (and enables) reparse deferral.
+#
+# Lower the threshold from 20600 to 20500 so that CPython uses the
+# backported function. This makes the Python API actually work on RHEL 9
+# and fixes test failures (test_reparse_deferral_disabled,
+# test_flush_reparse_deferral_disabled, test_simple_xml_chunk_*).
+#
+# The spec file BuildRequires expat-devel >= 2.5.0-2 to ensure the
+# backported function is available.
+Patch466: 00466-downstream-only-lower-xml_combined_version-threshold-for-reparse-deferral.patch
 
 # 00475 # d44fac01037662db286449a78c8fb819788f764c
 # CVE-2025-15367
@@ -598,10 +608,12 @@ Requires: tzdata
 # This breaks many things, including python -m venv.
 # We avoid this problem by requiring at least the same version of expat that
 # was used during the build time.
+# We also include release, in case pyxpat uses ABI that was backported
+# (e.g. XML_SetReparseDeferralEnabled was added in c9s expat 2.5.0-2).
 # Other subpackages (like -debug) also need this, but they all depend on -libs.
 # Since expat 2.7.4, the library has versioned symbols and this is no longer needed,
 # as the generated requirement will be in the form of libexpat.so.1(LIBEXPAT_2.7.2) etc.
-%global expat_version %(LANG=C rpm -q --qf '%%{version}' expat.%{_target_cpu} | sed 's/.*not installed/0/')
+%global expat_version %(LANG=C rpm -q --qf '%%{version}-%%{release}' expat.%{_target_cpu} | sed 's/.*not installed/0/')
 %if v"%{expat_version}" < v"2.7.4"
 Requires: expat%{?_isa} >= %{expat_version}
 %endif
@@ -1359,7 +1371,6 @@ CheckPython() {
   # test.test_concurrent_futures.test_deadlock tends to time out on s390x and ppc64le in
   # freethreading{,-debug} build, skipping it to shorten the build time
   # see: https://github.com/python/cpython/issues/121719
-  # test_subparser_inherits_reparse_deferral: https://github.com/python/cpython/issues/155485
   LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \
     -wW --slowest %{_smp_mflags} \
     %ifarch riscv64
@@ -1376,9 +1387,6 @@ CheckPython() {
     -x test_signal \
     -i test_deadlock \
     %endif
-    %if 0%{?rhel} == 9
-    -i test_subparser_inherits_reparse_deferral \
-    %endif
 
   echo FINISHED: CHECKING OF PYTHON FOR CONFIGURATION: $ConfName
 
@@ -1810,6 +1818,9 @@ CheckPython freethreading
 # ======================================================
 
 %changelog
+* Wed Aug 12 2026 Miro Hrončok <mhroncok@redhat.com> - 3.13.15-2
+- On EPEL 9, also supports reparse deferral in expat
+
 * Mon Aug 10 2026 Karolina Surma <ksurma@redhat.com> - 3.13.15-1
 - Update to Python 3.13.15
 

                 reply	other threads:[~2026-08-18  8:20 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178704124606.1.9604433200549725292.rpms-python3.13-0ca3f59c07cb@fedoraproject.org \
    --to=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox