Your message dated Fri, 23 Jan 2026 11:45:37 +0000
with message-id <[email protected]>
and subject line Re: Bug#1125310: textual: FTBFS with rich 13.9.4-1.1
has caused the Debian Bug report #1125310,
regarding textual: FTBFS with rich 13.9.4-1.1
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.)
--
1125310: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1125310
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Source: textual
Version: 2.1.2-1
Severity: serious
Tags: ftbfs, patch
rich 13.9.4-1.1 causes one test failure in textual:
__________________________________ test_demo ___________________________________
async def test_demo():
"""Test the demo runs."""
# Test he demo can at least run.
# This exists mainly to catch screw-ups that might effect only certain
Python versions.
app = DemoApp()
> async with app.run_test() as pilot:
^^^^^^^^^^^^^^
tests/test_demo.py:9:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.13/contextlib.py:221: in __aexit__
await anext(self.gen)
/usr/lib/python3/dist-packages/textual/app.py:1991: in run_test
raise self._exception
/usr/lib/python3/dist-packages/textual/message_pump.py:609: in
_process_messages_loop
await self._dispatch_message(message)
/usr/lib/python3/dist-packages/textual/message_pump.py:673: in _dispatch_message
await self.on_event(message)
/usr/lib/python3/dist-packages/textual/message_pump.py:754: in on_event
await self._on_message(event)
/usr/lib/python3/dist-packages/textual/message_pump.py:775: in _on_message
await invoke(method, message)
/usr/lib/python3/dist-packages/textual/_callback.py:93: in invoke
return await _invoke(callback, *params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/_callback.py:53: in _invoke
result = callback(*params[:parameter_count])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/screen.py:1335: in _on_screen_resume
self._refresh_layout(size)
/usr/lib/python3/dist-packages/textual/screen.py:1255: in _refresh_layout
self._compositor_refresh()
/usr/lib/python3/dist-packages/textual/screen.py:1091: in _compositor_refresh
update = self._compositor.render_update(
/usr/lib/python3/dist-packages/textual/_compositor.py:1082: in render_update
return self.render_full_update(simplify=simplify)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/_compositor.py:1118: in
render_full_update
chops = self._render_chops(crop, lambda y: True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/_compositor.py:1188: in _render_chops
for region, clip, strips in renders:
^^^^^^^
/usr/lib/python3/dist-packages/textual/_compositor.py:1037: in _get_renders
widget.render_lines(
/usr/lib/python3/dist-packages/textual/widget.py:3919: in render_lines
strips = self._styles_cache.render_widget(self, crop)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/_styles_cache.py:127: in render_widget
strips = self.render(
/usr/lib/python3/dist-packages/textual/_styles_cache.py:230: in render
strip = render_line(
/usr/lib/python3/dist-packages/textual/_styles_cache.py:449: in render_line
line = render_content_line(y - gutter.top)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/widget.py:3902: in render_line
self._render_content()
/usr/lib/python3/dist-packages/textual/widget.py:3888: in _render_content
strips = Visual.to_strips(self, visual, width, height, self.visual_style)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/visual.py:199: in to_strips
strips = visual.render_strips(
/usr/lib/python3/dist-packages/textual/content.py:520: in render_strips
strip_lines = [Strip(*line.to_strip(style)) for line in lines]
^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/content.py:1376: in to_strip
_Segment(text, (style + text_style).rich_style_with_offset(x, y))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/textual/style.py:365: in rich_style_with_offset
meta={**self.meta, "offset": (x, y)},
^^^^^^^^^
/usr/lib/python3.13/functools.py:1025: in __get__
val = self.func(instance)
^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <[ValueError('bad marshal data (unknown type code)') raised in repr()]
Style object at 0x7fa0743a8050>
@cached_property
def meta(self) -> Mapping[str, Any]:
"""Get meta information (can not be changed after construction)."""
> return {} if self._meta is None else loads(self._meta)
^^^^^^^^^^^^^^^^^
E ValueError: bad marshal data (unknown type code)
/usr/lib/python3/dist-packages/textual/style.py:396: ValueError
This was my NMU, so I'm sorry for not spotting the problem in advance; I
thought the rich changes were small enough to avoid compatibility issues
in textual and missed the fact that they switched from marshal to pickle
for style meta information. However, I don't think the compatibility
breakage could really have been avoided anyway: the change that caused
this was part of upstream changes to support Python 3.14, and when I
experimented locally I also couldn't find a way to get marshal.dumps to
do the right thing on Python 3.14 so I can absolutely see why they
switched to pickle instead.
The corresponding upstream fix to textual is in a commit unhelpfully
labelled just "optimization"
(https://github.com/Textualize/textual/pull/6169); as far as I can see
upstream failed to label either side of this as affecting compatibility
between rich and textual. I think the only sensible way forward is to
cherry-pick the relevant part of the textual change as well, add a
Depends to textual for the new rich, and add a Breaks on old textual
versions to rich.
https://salsa.debian.org/morph/textual/-/merge_requests/1 has the
necessary changes to textual, and I've attached a debdiff here too. The
change to rich would then just be adding "Breaks: python3-textual (<<
2.1.2-1.1~)".
Thanks,
--
Colin Watson (he/him) [[email protected]]
diff -Nru textual-2.1.2/debian/changelog textual-2.1.2/debian/changelog
--- textual-2.1.2/debian/changelog 2025-03-16 21:27:22.000000000 +0000
+++ textual-2.1.2/debian/changelog 2026-01-12 11:18:59.000000000 +0000
@@ -1,3 +1,10 @@
+textual (2.1.2-1.1) UNRELEASED; urgency=medium
+
+ * Non-maintainer upload.
+ * Use pickle for style meta information to match rich 13.9.4-1.1.
+
+ -- Colin Watson <[email protected]> Mon, 12 Jan 2026 11:18:59 +0000
+
textual (2.1.2-1) unstable; urgency=medium
* New upstream release
diff -Nru textual-2.1.2/debian/control textual-2.1.2/debian/control
--- textual-2.1.2/debian/control 2025-03-16 21:27:22.000000000 +0000
+++ textual-2.1.2/debian/control 2026-01-12 11:18:59.000000000 +0000
@@ -12,7 +12,7 @@
python3-pytest (>= 6.2.3) <!nocheck>,
python3-pytest-asyncio <!nocheck>,
python3-pytest-xdist <!nocheck>,
- python3-rich (>= 10.7.0) <!nocheck>,
+ python3-rich (>= 13.9.4-1.1~) <!nocheck>,
python3-syrupy <!nocheck>,
python3-typing-extensions <!nocheck>,
Standards-Version: 4.6.2
diff -Nru textual-2.1.2/debian/patches/pickle-style-meta.patch
textual-2.1.2/debian/patches/pickle-style-meta.patch
--- textual-2.1.2/debian/patches/pickle-style-meta.patch 1970-01-01
01:00:00.000000000 +0100
+++ textual-2.1.2/debian/patches/pickle-style-meta.patch 2026-01-12
11:18:59.000000000 +0000
@@ -0,0 +1,25 @@
+From: Colin Watson <[email protected]>
+Date: Mon, 12 Jan 2026 11:18:22 +0000
+Subject: Use pickle for style meta information
+
+Backported from https://github.com/Textualize/textual/pull/6169; needed
+to match rich 14.2.0 / 13.9.4-1.1.
+
+Last-Update: 2026-01-12
+---
+ src/textual/style.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/textual/style.py b/src/textual/style.py
+index c96c9b7..7df24da 100644
+--- a/src/textual/style.py
++++ b/src/textual/style.py
+@@ -9,7 +9,7 @@ from __future__ import annotations
+
+ from dataclasses import dataclass
+ from functools import cached_property, lru_cache
+-from marshal import dumps, loads
++from pickle import dumps, loads
+ from typing import TYPE_CHECKING, Any, Iterable, Mapping
+
+ import rich.repr
diff -Nru textual-2.1.2/debian/patches/series
textual-2.1.2/debian/patches/series
--- textual-2.1.2/debian/patches/series 1970-01-01 01:00:00.000000000 +0100
+++ textual-2.1.2/debian/patches/series 2026-01-12 11:18:29.000000000 +0000
@@ -0,0 +1 @@
+pickle-style-meta.patch
--- End Message ---
--- Begin Message ---
Source: textual
Source-Version: 2.1.2-1.1
textual (2.1.2-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Use pickle for style meta information to match rich 13.9.4-1.1 (closes:
#1125310).
-- Colin Watson <[email protected]> Mon, 19 Jan 2026 11:09:00 +0000
--
Colin Watson (he/him) [[email protected]]
--- End Message ---