python-hypothesis: FTBFS against python 3.15rc1

Maximiliano Curia <[email protected]>
Newsgroups gmane.linux.debian.devel.python
Message-ID <[email protected]>
Package: src:python-hypothesis
Version: 6.155.7-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-hypothesis fails to build from source [1]. 

The problem has already been fixed upstream with [2], included in
v6.165.7.

I applied the upstream fix in the sandbox [3] to be able to build the
packages that depend on python-hypothesis, please consider applying the
patch to support the upcoming 3.15 version.

As a side note, the patch also applies to the version in salsa's
repository, but using that package also required us to finishing the
repackaging for the rust + maturin version (arch:all to arch:any, docs
need to be build explicitly, fix installation paths avoid installing in
usr/lib/python3.XX).

Happy hacking,

[1]: https://debusine.debian.net/debian/r-python-python3.15/artifact/4436475/
[2]: https://github.com/HypothesisWorks/hypothesis/commit/37999eb97e416a19881c3cc463f9f7a73623d0e7
[3]: 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 /\/\ /\ >< `/
0006-Support-Python-3.15.patch (text/x-diff, 5.6 KB)
Description: claude: support Python 3.15
 Backport upstream commit 37999eb97e416a19881c3cc463f9f7a73623d0e7:
Origin: backport, https://github.com/HypothesisWorks/hypothesis/commit/37999eb97e416a19881c3cc463f9f7a73623d0e7
Author: Liam DeVoe <[email protected]>

Index: python-hypothesis-6.155.7/hypothesis/src/hypothesis/internal/lambda_sources.py
===================================================================
--- python-hypothesis-6.155.7.orig/hypothesis/src/hypothesis/internal/lambda_sources.py
+++ python-hypothesis-6.155.7/hypothesis/src/hypothesis/internal/lambda_sources.py
@@ -9,6 +9,7 @@
 # obtain one at https://mozilla.org/MPL/2.0/.
 
 import ast
+import dis
 import hashlib
 import inspect
 import linecache
@@ -101,12 +102,21 @@ def _function_key(f, *, bounded_size=Fal
 
 
 class _op:
-    # Opcodes, from dis.opmap. These may change between major versions.
-    NOP = 9
-    LOAD_FAST = 85
-    LOAD_FAST_LOAD_FAST = 88
-    LOAD_FAST_BORROW = 86
-    LOAD_FAST_BORROW_LOAD_FAST_BORROW = 87
+    # Look up the opcode values dynamically, since they can change between versions. If
+    # the opcode does not exist on a version, we set it to None.
+    NOP = dis.opmap["NOP"]
+    LOAD_FAST = dis.opmap["LOAD_FAST"]
+    LOAD_FAST_LOAD_FAST = (
+        dis.opmap["LOAD_FAST_LOAD_FAST"] if sys.version_info[:2] >= (3, 13) else None
+    )
+    LOAD_FAST_BORROW = (
+        dis.opmap["LOAD_FAST_BORROW"] if sys.version_info[:2] >= (3, 14) else None
+    )
+    LOAD_FAST_BORROW_LOAD_FAST_BORROW = (
+        dis.opmap["LOAD_FAST_BORROW_LOAD_FAST_BORROW"]
+        if sys.version_info[:2] >= (3, 14)
+        else None
+    )
 
 
 def _normalize_code(f, l):
@@ -129,6 +139,8 @@ def _normalize_code(f, l):
             lambda a, b: a == [b[0] >> 4, b[0] & 15],
         ),
     ]
+    # Avoid applying any transform with an opcode that doesn't exist on this python version.
+    transforms = [t for t in transforms if None not in t[0] + t[1]]
     # augment with converse
     transforms += [
         (
Index: python-hypothesis-6.155.7/hypothesis/src/hypothesis/internal/reflection.py
===================================================================
--- python-hypothesis-6.155.7.orig/hypothesis/src/hypothesis/internal/reflection.py
+++ python-hypothesis-6.155.7/hypothesis/src/hypothesis/internal/reflection.py
@@ -346,6 +346,13 @@ def source_exec_as_module(source: str) -
 
     hexdigest = hashlib.sha384(source.encode()).hexdigest()
     result = ModuleType("hypothesis_temporary_module_" + hexdigest)
+    # ModuleType() sets __spec__ = None. Later, we call @impersonate on functions defined
+    # in the module, which gives it a real co_filename. Python traceback formatting then
+    # calls internal linecache code which warns on the combination of "real on-disk file"
+    # + "null __spec__".
+    #
+    # Sidestep this by deleting __spec__; we don't need it.
+    del result.__spec__
     assert isinstance(source, str)
     exec(source, result.__dict__)
     eval_cache[source] = result
Index: python-hypothesis-6.155.7/hypothesis/src/hypothesis/strategies/_internal/types.py
===================================================================
--- python-hypothesis-6.155.7.orig/hypothesis/src/hypothesis/strategies/_internal/types.py
+++ python-hypothesis-6.155.7/hypothesis/src/hypothesis/strategies/_internal/types.py
@@ -917,6 +917,12 @@ if sys.version_info[:2] < (3, 14):
 
     _global_type_lookup[memoryview] = st.binary().map(memoryview)
 
+if sys.version_info[:2] >= (3, 15):
+    _global_type_lookup[builtins.sentinel] = st.builds(  # type: ignore
+        builtins.sentinel,  # type: ignore
+        st.text(),
+    )
+
 
 _global_type_lookup.update(
     {
Index: python-hypothesis-6.155.7/hypothesis/tests/cover/test_interactive_example.py
===================================================================
--- python-hypothesis-6.155.7.orig/hypothesis/tests/cover/test_interactive_example.py
+++ python-hypothesis-6.155.7/hypothesis/tests/cover/test_interactive_example.py
@@ -141,6 +141,9 @@ def test_script_example_does_not_emit_wa
 
 @skipif_emscripten
 @pytest.mark.skipif(WINDOWS, reason="pexpect.spawn not supported on Windows")
+# pexpect forks, and 3.15 warns about forking from a process with threads in it,
+# which we are under xdist.
[email protected]("ignore:.*is multi-threaded.*:DeprecationWarning")
 def test_interactive_example_does_not_emit_warning():
     import pexpect
 
Index: python-hypothesis-6.155.7/hypothesis/tests/cover/test_lookup.py
===================================================================
--- python-hypothesis-6.155.7.orig/hypothesis/tests/cover/test_lookup.py
+++ python-hypothesis-6.155.7/hypothesis/tests/cover/test_lookup.py
@@ -74,12 +74,9 @@ generics = sorted(
         t
         for t in types._global_type_lookup
         # We ignore TypeVar, because it is not a Generic type:
-        if isinstance(t, types.typing_root_type)
-        and t != typing.TypeVar
-        and (
-            sys.version_info[:2] <= (3, 11)
-            or t != getattr(typing, "ByteString", object())
-        )
+        if isinstance(t, types.typing_root_type) and t != typing.TypeVar
+        # accessing ByteString warns on 3.15
+        and (not ((3, 12) <= sys.version_info[:2] < (3, 14)) or t != typing.ByteString)
     ),
     key=str,
 )
@@ -139,7 +136,8 @@ def test_typing_Type_Union(ex):
     "typ",
     [
         pytest.param(
-            getattr(collections.abc, "ByteString", ...),
+            # accessing ByteString warns on 3.15
+            collections.abc.ByteString if sys.version_info[:2] < (3, 14) else ...,
             marks=pytest.mark.skipif(sys.version_info[:2] >= (3, 14), reason="removed"),
         ),
         typing.Match,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.