Your message dated Tue, 20 Oct 2026 09:19:39 +0000
with message-id <[email protected]>
and subject line Bug#1147454: fixed in python-enaml 0.19.0-2
has caused the Debian Bug report #1147454,
regarding python-enaml: FTBFS against python 3.15rc2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1147454: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1147454
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: src:python-enaml
Version: 0.19.0-1
User: [email protected]
Usertags: python3.15
Tags: patch, ftbfs, forky, sid
Severity: important

Hi!

While rebuilding the python related packages against the Python 3.15rc2
version we found that TODO fails to build from source [1].
I had to do various changes to get it to work:
- PyWeakref_GET_OBJECT is deprecated since 3.13 and removed in 3.15,
  replace it by PyWeakref_GetRef
- Update pegen related code for 3.15 changes:
  - Add `LOAD_COMMON_CONSTANT` as the return type when returning None.
  - Add `is_lazy` field.
  - Force the `__cached__` field on modules, as the code assumes it will
    be there.

There's now also a PR in the upstream tracker to add 3.15 support, with
a different approach as the one I took [2].

I've applied my fixes in the sandbox [3] to verify that it builds
successfully, please consider applying the patch to support the upcoming
3.15 version.

Setting the severity to important for now. Once Python 3.15 is released,
it will be added to python3-defaults and this bug will become release
critical.

Happy hacking,

[1]: https://debusine.debian.net/debian/r-python-python3.15/artifact/4670760/
[2]: https://github.com/nucleic/enaml/pull/630
[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 /\/\ /\ >< `/
Subject: Fix build with Python 3.15
Author: Maximiliano Curia <[email protected]>
Forwarded: not-needed

PyWeakref_GET_OBJECT (and PyWeakref_GetObject) were removed in Python 3.15,
deprecated since Python 3.13 in favor of PyWeakref_GetRef.

Index: python-enaml/enaml/src/callableref.cpp
===================================================================
--- python-enaml.orig/enaml/src/callableref.cpp
+++ python-enaml/enaml/src/callableref.cpp
@@ -8,6 +8,7 @@
 #include <iostream>
 #include <sstream>
 #include <cppy/cppy.h>
+#include "pyweakref_compat.h"
 
 #ifdef __clang__
 #pragma clang diagnostic ignored "-Wdeprecated-writable-strings"
@@ -99,7 +100,11 @@ PyObject*
 CallableRef_call( CallableRef* self, PyObject* args, PyObject* kwargs )
 {
     cppy::ptr objrefptr( cppy::incref( self->objref ) );
-    cppy::ptr objptr( cppy::incref( PyWeakref_GET_OBJECT( objrefptr.get() ) ) );
+    cppy::ptr objptr( weakref_get_object( objrefptr.get() ) );
+    if( !objptr )
+    {
+        return 0;
+    }
     if( objptr.is_none() )
     {
         Py_RETURN_NONE;
Index: python-enaml/enaml/src/signaling.cpp
===================================================================
--- python-enaml.orig/enaml/src/signaling.cpp
+++ python-enaml/enaml/src/signaling.cpp
@@ -9,6 +9,7 @@
 #include <sstream>
 #include <vector>
 #include <cppy/cppy.h>
+#include "pyweakref_compat.h"
 
 
 #ifdef __clang__
@@ -398,7 +399,11 @@ _Disconnector_call( _Disconnector* self,
     }
 
     cppy::ptr objref( cppy::incref( self->objref ) );
-    cppy::ptr obj( cppy::incref( PyWeakref_GET_OBJECT( objref.get() ) ) );
+    cppy::ptr obj( weakref_get_object( objref.get() ) );
+    if( !obj )
+    {
+        return 0;
+    }
     if( obj.is_none() )
     {
         Py_RETURN_NONE;
@@ -633,7 +638,11 @@ PyObject*
 BoundSignal_emit( BoundSignal* self, PyObject* args, PyObject* kwargs )
 {
     cppy::ptr objref( cppy::incref( self->objref ) );
-    cppy::ptr obj( cppy::incref( PyWeakref_GET_OBJECT( objref.get() ) ) );
+    cppy::ptr obj( weakref_get_object( objref.get() ) );
+    if( !obj )
+    {
+        return 0;
+    }
     if( obj.is_none() )
     {
         Py_RETURN_NONE;
@@ -720,7 +729,11 @@ PyObject*
 BoundSignal_connect( BoundSignal* self, PyObject* slot )
 {
     cppy::ptr objref( cppy::incref( self->objref ) );
-    cppy::ptr obj( cppy::incref( PyWeakref_GET_OBJECT( objref.get() ) ) );
+    cppy::ptr obj( weakref_get_object( objref.get() ) );
+    if( !obj )
+    {
+        return 0;
+    }
     if( obj.is_none() )
     {
         Py_RETURN_NONE;
Index: python-enaml/enaml/src/weakmethod.cpp
===================================================================
--- python-enaml.orig/enaml/src/weakmethod.cpp
+++ python-enaml/enaml/src/weakmethod.cpp
@@ -9,6 +9,7 @@
 #include <sstream>
 #include <cppy/cppy.h>
 #include <structmember.h>  // Included to access offsetof
+#include "pyweakref_compat.h"
 
 
 namespace enaml
@@ -222,7 +223,11 @@ PyObject*
 WeakMethod_call( WeakMethod* self, PyObject* args, PyObject* kwargs )
 {
     cppy::ptr selfref( cppy::incref( self->selfref ) );
-    cppy::ptr mself( cppy::incref( PyWeakref_GET_OBJECT( selfref.get() ) ) );
+    cppy::ptr mself( weakref_get_object( selfref.get() ) );
+    if( !mself )
+    {
+        return 0;
+    }
     if( mself.is_none() )
     {
         Py_RETURN_NONE;
Index: python-enaml/enaml/src/pyweakref_compat.h
===================================================================
--- /dev/null
+++ python-enaml/enaml/src/pyweakref_compat.h
@@ -0,0 +1,32 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2025, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file LICENSE, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+#include <cppy/cppy.h>
+
+
+namespace enaml
+{
+
+
+// PyWeakref_GET_OBJECT was removed in Python 3.15; use PyWeakref_GetRef there.
+static inline PyObject*
+weakref_get_object( PyObject* ref )
+{
+#if PY_VERSION_HEX >= 0x030d0000
+    PyObject* obj;
+    if( PyWeakref_GetRef( ref, &obj ) < 0 )
+        return 0;
+    return obj ? obj : cppy::incref( Py_None );
+#else
+    return cppy::incref( PyWeakref_GET_OBJECT( ref ) );
+#endif
+}
+
+
+} // namespace enaml
Index: python-enaml/enaml/compat.py
===================================================================
--- python-enaml.orig/enaml/compat.py
+++ python-enaml/enaml/compat.py
@@ -20,6 +20,8 @@ PY313 = sys.version_info >= (3, 13)
 
 PY314 = sys.version_info >= (3, 14)
 
+PY315 = sys.version_info >= (3, 15)
+
 # Functions used to update the co_filename slot of a code object
 # Available in Python 3.5+ (tested up to 3.8)
 from _imp import _fix_co_filename
Index: python-enaml/enaml/core/code_generator.py
===================================================================
--- python-enaml.orig/enaml/core/code_generator.py
+++ python-enaml/enaml/core/code_generator.py
@@ -10,8 +10,9 @@ from contextlib import contextmanager
 
 import bytecode as bc
 from atom.api import Atom, Bool, Int, List, Str
+from bytecode.instr import CommonConstant
 
-from ..compat import PY310, PY311, PY312, PY313, PY314
+from ..compat import PY310, PY311, PY312, PY313, PY314, PY315
 
 
 class _ReturnNoneIdentifier(ast.NodeVisitor):
@@ -567,8 +568,15 @@ class CodeGenerator(Atom):
                     (rc := (block[-1].name == "RETURN_CONST" and block[-1].arg is None))
                     or (
                         block[-1].name == "RETURN_VALUE"
-                        and block[-2].name == "LOAD_CONST"
-                        and block[-2].arg is None
+                        and (
+                            (block[-2].name == "LOAD_CONST" and block[-2].arg is None)
+                            # Python 3.15 loads None via LOAD_COMMON_CONSTANT instead
+                            or (
+                                PY315
+                                and block[-2].name == "LOAD_COMMON_CONSTANT"
+                                and block[-2].arg == CommonConstant.CONSTANT_NONE
+                            )
+                        )
                         and block[-1].lineno not in _inspector.lines
                     )
                 ):
Index: python-enaml/enaml/core/import_hooks.py
===================================================================
--- python-enaml.orig/enaml/core/import_hooks.py
+++ python-enaml/enaml/core/import_hooks.py
@@ -136,6 +136,11 @@ class AbstractEnamlImporter(object, meta
         if code is None:
             code, _ = self.get_code()
 
+        # Python 3.15 stopped setting __cached__ from spec.cached (GH-65961).
+        spec = module.__spec__
+        if spec is not None and spec.cached is not None:
+            module.__cached__ = spec.cached
+
         # Even though the import hook is already installed, this is a
         # safety net to avoid potentially hard to find bugs if code has
         # manually installed and removed a hook. The contract here is
Index: python-enaml/enaml/core/parser/enaml.gram
===================================================================
--- python-enaml.orig/enaml/core/parser/enaml.gram
+++ python-enaml/enaml/core/parser/enaml.gram
@@ -597,14 +597,22 @@ import_stmt[ast.Import]:
 # Import statements
 # -----------------
 
-import_name[ast.Import]: 'import' a=dotted_as_names { ast.Import(names=a, LOCATIONS) }
+import_name[ast.Import]: 'import' a=dotted_as_names {
+    ast.Import(names=a, is_lazy=0, LOCATIONS)
+    if sys.version_info >= (3, 15) else
+    ast.Import(names=a, LOCATIONS)
+}
 
 # note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
 import_from[ast.ImportFrom]:
     | 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
+        ast.ImportFrom(module=b, names=c, level=self.extract_import_level(a), is_lazy=0, LOCATIONS)
+        if sys.version_info >= (3, 15) else
         ast.ImportFrom(module=b, names=c, level=self.extract_import_level(a), LOCATIONS)
      }
     | 'from' a=('.' | '...')+ 'import' b=import_from_targets {
+        ast.ImportFrom(names=b, level=self.extract_import_level(a), is_lazy=0, LOCATIONS)
+        if sys.version_info >= (3, 15) else
         ast.ImportFrom(names=b, level=self.extract_import_level(a), LOCATIONS)
         if sys.version_info >= (3, 9) else
         ast.ImportFrom(module=None, names=b, level=self.extract_import_level(a), LOCATIONS)
Index: python-enaml/enaml/core/parser/enaml_parser.py
===================================================================
--- python-enaml.orig/enaml/core/parser/enaml_parser.py
+++ python-enaml/enaml/core/parser/enaml_parser.py
@@ -1561,7 +1561,7 @@ class EnamlParser(Parser):
         ):
             tok = self._tokenizer.get_last_non_whitespace_token()
             end_lineno, end_col_offset = tok.end
-            return ast . Import ( names = a , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset );
+            return ast . Import ( names = a , is_lazy = 0 , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset ) if sys . version_info >= ( 3 , 15 ) else ast . Import ( names = a , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset );
         self._reset(mark)
         return None;
 
@@ -1584,7 +1584,7 @@ class EnamlParser(Parser):
         ):
             tok = self._tokenizer.get_last_non_whitespace_token()
             end_lineno, end_col_offset = tok.end
-            return ast . ImportFrom ( module = b , names = c , level = self . extract_import_level ( a ) , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset );
+            return ast . ImportFrom ( module = b , names = c , level = self . extract_import_level ( a ) , is_lazy = 0 , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset ) if sys . version_info >= ( 3 , 15 ) else ast . ImportFrom ( module = b , names = c , level = self . extract_import_level ( a ) , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset );
         self._reset(mark)
         if (
             (self.expect('from'))
@@ -1597,7 +1597,7 @@ class EnamlParser(Parser):
         ):
             tok = self._tokenizer.get_last_non_whitespace_token()
             end_lineno, end_col_offset = tok.end
-            return ast . ImportFrom ( names = b , level = self . extract_import_level ( a ) , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset ) if sys . version_info >= ( 3 , 9 ) else ast . ImportFrom ( module = None , names = b , level = self . extract_import_level ( a ) , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset );
+            return ast . ImportFrom ( names = b , level = self . extract_import_level ( a ) , is_lazy = 0 , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset ) if sys . version_info >= ( 3 , 15 ) else ast . ImportFrom ( names = b , level = self . extract_import_level ( a ) , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset ) if sys . version_info >= ( 3 , 9 ) else ast . ImportFrom ( module = None , names = b , level = self . extract_import_level ( a ) , lineno=start_lineno, col_offset=start_col_offset, end_lineno=end_lineno, end_col_offset=end_col_offset );
         self._reset(mark)
         return None;
 

--- End Message ---
--- Begin Message ---
Source: python-enaml
Source-Version: 0.19.0-2
Done: Margarita Manterola <[email protected]>

We believe that the bug you reported is fixed in the latest version of
python-enaml, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to [email protected],
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Margarita Manterola <[email protected]> (supplier of updated python-enaml 
package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing [email protected])


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Tue, 20 Oct 2026 11:01:26 +0200
Source: python-enaml
Architecture: source
Version: 0.19.0-2
Distribution: unstable
Urgency: medium
Maintainer: Debian Python Team <[email protected]>
Changed-By: Margarita Manterola <[email protected]>
Closes: 1147454
Changes:
 python-enaml (0.19.0-2) unstable; urgency=medium
 .
   * Team upload.
   * Apply patch created by Maximiliano Curia to solve Python 3.15
     incompatibilities (Closes: #1147454)
   * Update Standards-Version to 4.7.4: drop Priority field from
     debian/control.
   * Remove deprecated lintian-overrides.
Checksums-Sha1:
 891559849620c1253583d5dab03074ccbf095eba 2856 python-enaml_0.19.0-2.dsc
 9f68c29cff7b55d18996764cbd8418e8c4a89d73 12672 
python-enaml_0.19.0-2.debian.tar.xz
 ddc7f225be8da80b55747967db7778ff9d1dc971 6910 
python-enaml_0.19.0-2_source.buildinfo
Checksums-Sha256:
 b2a48ec30d37413bed7475ade77cb4865afb87f06b2e244aa61c89a21c229bcf 2856 
python-enaml_0.19.0-2.dsc
 292891344059e30b8b35887328bafb2450db4f66f877f4af8b548c52d2ec441d 12672 
python-enaml_0.19.0-2.debian.tar.xz
 fbdf62c50a44c844e0bed706560fc8bf5dce0281b0b5165d128be53c43377e81 6910 
python-enaml_0.19.0-2_source.buildinfo
Files:
 1d0faac0e609b1b1abc2693c73401a70 2856 python optional python-enaml_0.19.0-2.dsc
 7e1ad77c48bba0a70a1ce819da6f9f47 12672 python optional 
python-enaml_0.19.0-2.debian.tar.xz
 255921b3467d885592fe57df51d2aff9 6910 python optional 
python-enaml_0.19.0-2_source.buildinfo

-----BEGIN PGP SIGNATURE-----

iQJFBAEBCgAvFiEEAMPhhOivEnEYVt/SgNCkL/LIUMoFAmrXLjcRHG1hcmdhQGRl
Ymlhbi5vcmcACgkQgNCkL/LIUMqeXg//WWM3JIeAj5TmxU/1knojbRI1qL2jUrPN
EgkKdQYXWwp8xqa4B1QegLRNkjA8EpqgDEzwvd9/BfKrvP22DwkoZ3Vi1WCqf/le
ZdXaDbSNHSqAGj8nHv5JM1gaJXN4HyrWbx97tdU4QHy2plCOvGJfg+4VjiQXTAGL
3/agiVk7JCt1XYo3sPvbo1lGuBsZB6w2qEsxntfLT81ygg8+cQ/55lXDUrDVd+VN
lERkruY2j+KNYRUrBOyMNFE3srUupQvcYMRtPm0pkmaL49CBxwhzW0RKssg4kKzT
ccruyYea0vsZGNxzTtfq8dm9Ns6Ie9vwwSoXEmJCSxwfs+NBus6KrOEBk9UtyYwW
/GW/kEgGj4RZ18n1bfVgdNXzXIGqHdUCJE6bEB2P02CSRgbBMTCda76133xNpPFf
EaqPtnjzLmM8ot/qoC7pCLys/l48w4eqD6LUhvwf0OEF85WTxVnVafBhnFRqUUmd
ZJyfbL2ORrVCGyQxwX4o1kjccPulBGFU5lgyFBCf3kHafcEGm1uJY/RFQTo5NKGV
x0Oiib4cHVuo/rtNE8hZx/1NqH1CSQMwVe8qeebZTn5QQaiCx2TfnDAoX4QtMbuh
1irczhKc+orKBMIPj/g+W3Y6Jljx7Jmw7z8aj1wOmwE1cZI9WH8HFhfy2YdkSw2u
oU1q2fxEEkY=
=w2jo
-----END PGP SIGNATURE-----

Attachment: pgpkVXR997Uqy.pgp
Description: PGP signature


--- End Message ---

Reply via email to