genshi: FTBFS against python 3.15rc1

Maximiliano Curia <[email protected]>
Newsgroups gmane.linux.debian.devel.python
Message-ID <[email protected]>
Package: src:genshi
Version: 0.7.10-2 
User: [email protected]
Usertags: python3.15
Tags: patch

Hi!

While rebuilding the python related packages against the Python 3.15rc1
version we found that genshi fails to build from source [1]. 

While looking for the fix, I found an unapplied PR upstream that tackles
the problem [2].

I've applied the PR fix in the sandbox [3] to be able to build the
packages that depend on genshi, 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/4283826/
[2]: https://github.com/edgewall/genshi/pull/93
[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 /\/\ /\ >< `/
solve-ast-deprecation.patch (text/x-diff, 7 KB)
From 0bcd1eeefaa58d49441ad1d82d0852c049154811 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Krier?= <[email protected]>
Date: Mon, 12 May 2025 00:28:42 +0200
Subject: [PATCH 1/4] Fix deprecation warning when creating AST node without
 required fields

Python 3.13 added the warning which will become an error in Python 3.15
(see https://github.com/python/cpython/pull/105880)
---
 genshi/template/astutil.py | 16 +++++++++++++++-
 genshi/template/eval.py    | 11 +++++------
 pytest.ini                 |  3 +++
 3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
index c841aeb..b53b573 100644
--- a/genshi/template/astutil.py
+++ b/genshi/template/astutil.py
@@ -802,7 +802,7 @@ def visit(self, node):
         return visitor(node)
 
     def _clone(self, node):
-        clone = node.__class__()
+        clone = construct_ast_class(node.__class__)
         for name in getattr(clone, '_attributes', ()):
             try:
                 setattr(clone, name, getattr(node, name))
@@ -887,3 +887,17 @@ def _clone(self, node):
     visit_Index = _clone
 
     del _clone
+
+
+def construct_ast_class(cls):
+    kwargs = {}
+    for name, typ in cls.__annotations__.items():
+        if typ is str:
+            kwargs[name] = 'foo'
+        elif typ is int:
+            kwargs[name] = 42
+        elif typ is object:
+            kwargs[name] = b'foo'
+        elif isinstance(typ, type) and issubclass(typ, _ast.AST):
+            kwargs[name] = construct_ast_class(typ)
+    return cls(**kwargs)
diff --git a/genshi/template/eval.py b/genshi/template/eval.py
index 82bddf3..4197597 100644
--- a/genshi/template/eval.py
+++ b/genshi/template/eval.py
@@ -18,7 +18,8 @@
 
 from genshi.compat import builtins, exec_, string_types, text_type
 from genshi.core import Markup
-from genshi.template.astutil import ASTTransformer, ASTCodeGenerator, parse
+from genshi.template.astutil import (
+    ASTTransformer, ASTCodeGenerator, parse, construct_ast_class)
 from genshi.template.base import TemplateRuntimeError
 from genshi.util import flatten
 
@@ -59,11 +60,9 @@ def __init__(self, source, filename=None, lineno=-1, lookup='strict',
                 'Expected string or AST node, but got %r' % source
             self.source = '?'
             if self.mode == 'eval':
-                node = _ast.Expression()
-                node.body = source
+                node = _ast.Expression(body=source)
             else:
-                node = _ast.Module()
-                node.body = [source]
+                node = _ast.Module(body=[source])
 
         self.ast = node
         self.code = _compile(node, self.source, mode=self.mode,
@@ -454,7 +453,7 @@ def _compile(node, source=None, mode='eval', filename=None, lineno=-1,
 
 
 def _new(class_, *args, **kwargs):
-    ret = class_()
+    ret = construct_ast_class(class_)
     for attr, value in zip(ret._fields, args):
         if attr in kwargs:
             raise ValueError('Field set both in args and kwargs')
diff --git a/pytest.ini b/pytest.ini
index 980658e..b05daa7 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,3 +1,6 @@
 [pytest]
 addopts = --doctest-modules
 doctest_optionflags = NORMALIZE_WHITESPACE ALLOW_UNICODE
+filterwarnings =
+    error
+    ignore:pkg_resources

From 01c8b3219a79fea139bf8ac717c8b06ca02aa2de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Krier?= <[email protected]>
Date: Mon, 12 May 2025 00:45:46 +0200
Subject: [PATCH 2/4] Simplify configuration of github workflows tests

---
 .github/workflows/tests.yml | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index d0ce1c6..59e157e 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -9,15 +9,7 @@ jobs:
 
     strategy:
       matrix:
-        python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "3.12", "pypy3.9"]
-        pytest-extra-options: ["--strict-config"]
-        include:
-          - python-version: "pypy2.7"
-            pytest-extra-options: ""
-          - python-version: "pypy3.11"
-            pytest-extra-options: ""
-          - python-version: "3.13.0-beta.2"
-            pytest-extra-options: "--strict-config -W ignore::DeprecationWarning"
+        python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "pypy3.9"]
       fail-fast: false
 
     steps:
@@ -37,12 +29,8 @@ jobs:
 
       - name: Run test suite
         run: |
-          pytest -Werror --strict-markers --verbosity=1 --color=yes ${{ matrix.pytest-extra-options }} genshi
+          pytest --strict-markers --verbosity=1 --color=yes genshi
           # Above flags are:
-          #  -Werror
-          #     treat warnings as errors
-          #  --strict-config
-          #     error out if the configuration file is not parseable
           #  --strict-markers
           #     error out if a marker is used but not defined in the
           #     configuration file

From 09fd95760e231d4f487c7378b11215e5c5d184c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Krier?= <[email protected]>
Date: Mon, 12 May 2025 00:49:35 +0200
Subject: [PATCH 3/4] Use ast Node annotations to construct if available

---
 genshi/template/astutil.py | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/genshi/template/astutil.py b/genshi/template/astutil.py
index b53b573..510d3a8 100644
--- a/genshi/template/astutil.py
+++ b/genshi/template/astutil.py
@@ -891,13 +891,14 @@ def _clone(self, node):
 
 def construct_ast_class(cls):
     kwargs = {}
-    for name, typ in cls.__annotations__.items():
-        if typ is str:
-            kwargs[name] = 'foo'
-        elif typ is int:
-            kwargs[name] = 42
-        elif typ is object:
-            kwargs[name] = b'foo'
-        elif isinstance(typ, type) and issubclass(typ, _ast.AST):
-            kwargs[name] = construct_ast_class(typ)
+    if hasattr(cls, '__annotations__'):
+        for name, typ in cls.__annotations__.items():
+            if typ is str:
+                kwargs[name] = 'foo'
+            elif typ is int:
+                kwargs[name] = 42
+            elif typ is object:
+                kwargs[name] = b'foo'
+            elif isinstance(typ, type) and issubclass(typ, _ast.AST):
+                kwargs[name] = construct_ast_class(typ)
     return cls(**kwargs)

From 76055327af17c5fc6c4bc5365407175276ff6a04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Krier?= <[email protected]>
Date: Mon, 12 May 2025 00:50:13 +0200
Subject: [PATCH 4/4] Remove 3.6 and 3.7 from github workflows tests

---
 .github/workflows/tests.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 59e157e..448fff8 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -9,7 +9,7 @@ jobs:
 
     strategy:
       matrix:
-        python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "pypy3.9"]
+        python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "pypy3.9"]
       fail-fast: false
 
     steps:
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.