Package: urwid
Version: 2.6.4-1
Severity: normal
Tags: patch
User: [email protected]
Usertags: origin-ubuntu noble ubuntu-patch
Dear Maintainer,
With the version of urwid 2.6.4-1 currently in trixie, the following
code fails with an exception:
```python
from urwid import Pile
Pile([
("pack", Pile([])),
]).render((10,))
```
File "/usr/lib/python3/dist-packages/urwid/widget/widget.py", line 112, in
cached_render
canv = fn(self, size, focus=focus)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/urwid/widget/pile.py", line 822, in
render
_widths, heights, size_args = self.get_rows_sizes(size, focus)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/urwid/widget/pile.py", line 730, in
get_rows_sizes
heights.append(w.pack(w_h_arg, item_focus)[1])
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/urwid/widget/pile.py", line 744, in pack
return super().pack(size, focus)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/urwid/widget/widget.py", line 401, in
pack
raise WidgetError(f"Cannot pack (maxcol,) size, this is not a flow widget:
{self!r}")
urwid.widget.widget.WidgetError: Cannot pack (maxcol,) size, this is not a flow
widget: <Pile widget>
The same code used to work with urwid 2.1.2-4 in bookworm.
I applied a fix from upstream [1] that was included in urwid 2.6.5. I
think the proper way forward would be to take a more recent upstream
version of urwid. That said, we are in feature freeze downstream in
Ubuntu so I skipped the refactoring bits.
In Ubuntu, the attached patch was applied to achieve the following:
* Apply upstream patch to fix a crash when rendering an empty Pile or an
empty Columns as a flow widget. (LP: #2058388)
+ d/patches/fix-crash-empty-pile.patch
Thanks for considering the patch.
-- System Information:
Debian Release: trixie/sid
APT prefers noble
APT policy: (500, 'noble'), (100, 'noble-proposed')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 6.8.0-11-generic (SMP w/8 CPU threads; PREEMPT)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
[1]
https://github.com/urwid/urwid/commit/83c278b53de431a9b41d7ddadf5f318914246593
diff -Nru urwid-2.6.4/debian/patches/fix-crash-empty-pile.patch
urwid-2.6.4/debian/patches/fix-crash-empty-pile.patch
--- urwid-2.6.4/debian/patches/fix-crash-empty-pile.patch 1970-01-01
01:00:00.000000000 +0100
+++ urwid-2.6.4/debian/patches/fix-crash-empty-pile.patch 2024-03-19
14:23:31.000000000 +0100
@@ -0,0 +1,158 @@
+Description: Fix crash when rendering empty Pile or Columns as a flow widget
+ Special case: in case of `Columns`/`Pile` empty - use fallback sizing (#843)
+ .
+ * Extend `repr` to provide brief info about contents
+ .
+Author: Aleksei Stepanov <[email protected]>
+Origin: upstream,
https://github.com/urwid/urwid/commit/83c278b53de431a9b41d7ddadf5f318914246593
+Bug-Ubuntu: https://launchpad.net/bugs/2058388
+Last-Update: 2024-03-19
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+diff --git a/urwid/widget/columns.py b/urwid/widget/columns.py
+index e3fa134..5a3421f 100644
+--- a/urwid/widget/columns.py
++++ b/urwid/widget/columns.py
+@@ -66,40 +66,47 @@ class Columns(Widget, WidgetContainerMixin,
WidgetContainerListContentsMixin):
+
+ # BOX-only widget
+ >>> Columns((SolidFill("#"),))
+- <Columns box widget>
++ <Columns box widget with 1 item>
+
+ # BOX-only widget with "get height from max"
+ >>> Columns((SolidFill("#"),), box_columns=(0,))
+- <Columns box widget>
++ <Columns box widget with 1 item>
+
+ # FLOW-only
+ >>> Columns((Edit(),))
+- <Columns selectable flow widget>
++ <Columns selectable flow widget with 1 item>
+
+ # FLOW allowed by "box_columns"
+ >>> Columns((Edit(), SolidFill("#")), box_columns=(1,))
+- <Columns selectable flow widget>
++ <Columns selectable flow widget with 2 items>
+
+ # FLOW/FIXED
+ >>> Columns((Text("T"),))
+- <Columns fixed/flow widget>
++ <Columns fixed/flow widget with 1 item>
+
+ # GIVEN BOX only -> BOX only
+ >>> Columns(((5, SolidFill("#")),), box_columns=(0,))
+- <Columns box widget>
++ <Columns box widget with 1 item>
+
+ # No FLOW - BOX only
+ >>> Columns(((5, SolidFill("#")), SolidFill("*")), box_columns=(0, 1))
+- <Columns box widget>
++ <Columns box widget with 2 items>
+
+ # FIXED only -> FIXED
+ >>> Columns(((WHSettings.PACK, BigText("1", font)),))
+- <Columns fixed widget>
++ <Columns fixed widget with 1 item>
+
+ # Invalid sizing combination -> use fallback settings (and produce
warning)
+ >>> Columns(((WHSettings.PACK, SolidFill("#")),))
+- <Columns box/flow widget>
++ <Columns box/flow widget with 1 item>
++
++ # Special case: empty columns widget sizing is impossible to calculate
++ >>> Columns(())
++ <Columns box/flow widget without contents>
+ """
++ if not self.contents:
++ return frozenset((urwid.BOX, urwid.FLOW))
++
+ strict_box = False
+ has_flow = False
+
+@@ -280,6 +287,13 @@ class Columns(Widget, WidgetContainerMixin,
WidgetContainerListContentsMixin):
+ self.min_width = min_width
+ self._cache_maxcol = None
+
++ def _repr_words(self) -> list[str]:
++ if len(self.contents) > 1:
++ return [*super()._repr_words(), f"with {len(self.contents)}
items"]
++ if self.contents:
++ return [*super()._repr_words(), "with 1 item"]
++ return [*super()._repr_words(), "without contents"]
++
+ def _contents_modified(self) -> None:
+ """
+ Recalculate whether this widget should be selectable whenever the
+diff --git a/urwid/widget/pile.py b/urwid/widget/pile.py
+index 2ee27fb..a1fc37f 100644
+--- a/urwid/widget/pile.py
++++ b/urwid/widget/pile.py
+@@ -58,36 +58,42 @@ class Pile(Widget, WidgetContainerMixin,
WidgetContainerListContentsMixin):
+
+ # BOX-only widget
+ >>> Pile((SolidFill("#"),))
+- <Pile box widget>
++ <Pile box widget with 1 item>
+
+ # GIVEN BOX -> BOX/FLOW
+ >>> Pile(((10, SolidFill("#")),))
+- <Pile box/flow widget>
++ <Pile box/flow widget with 1 item>
+
+ # FLOW-only
+ >>> Pile((ProgressBar(None, None),))
+- <Pile flow widget>
++ <Pile flow widget with 1 item>
+
+ # FIXED -> FIXED
+ >>> Pile(((WHSettings.PACK, BigText("0", font)),))
+- <Pile fixed widget>
++ <Pile fixed widget with 1 item>
+
+ # FLOW/FIXED -> FLOW/FIXED
+ >>> Pile(((WHSettings.PACK, Text("text")),))
+- <Pile fixed/flow widget>
++ <Pile fixed/flow widget with 1 item>
+
+ # FLOW + FIXED widgets -> FLOW/FIXED
+ >>> Pile((ProgressBar(None, None), (WHSettings.PACK, BigText("0",
font))))
+- <Pile fixed/flow widget>
++ <Pile fixed/flow widget with 2 items>
+
+ # GIVEN BOX + FIXED widgets -> BOX/FLOW/FIXED (GIVEN BOX allows
overriding its height & allows any width)
+ >>> Pile(((10, SolidFill("#")), (WHSettings.PACK, BigText("0",
font))))
+- <Pile widget>
++ <Pile widget with 2 items>
+
+ # Invalid sizing combination -> use fallback settings (and produce
warning)
+ >>> Pile(((WHSettings.WEIGHT, 1, BigText("0", font)),))
+- <Pile box/flow widget>
++ <Pile box/flow widget with 1 item>
++
++ # Special case: empty pile widget sizing is impossible to calculate
++ >>> Pile(())
++ <Pile box/flow widget without contents>
+ """
++ if not self.contents:
++ return frozenset((Sizing.BOX, Sizing.FLOW))
+ strict_box = False
+ has_flow = False
+
+@@ -225,6 +231,13 @@ class Pile(Widget, WidgetContainerMixin,
WidgetContainerListContentsMixin):
+
+ self.pref_col = 0
+
++ def _repr_words(self) -> list[str]:
++ if len(self.contents) > 1:
++ return [*super()._repr_words(), f"with {len(self.contents)}
items"]
++ if self.contents:
++ return [*super()._repr_words(), "with 1 item"]
++ return [*super()._repr_words(), "without contents"]
++
+ def _contents_modified(self) -> None:
+ """Recalculate whether this widget should be selectable whenever the
contents has been changed."""
+ self._selectable = any(w.selectable() for w, o in self.contents)
+--
+2.43.0
+
diff -Nru urwid-2.6.4/debian/patches/series urwid-2.6.4/debian/patches/series
--- urwid-2.6.4/debian/patches/series 2024-02-24 20:58:30.000000000 +0100
+++ urwid-2.6.4/debian/patches/series 2024-03-19 14:23:31.000000000 +0100
@@ -1,2 +1,3 @@
no-sphinx-changelog.diff
#version-module.diff
+fix-crash-empty-pile.patch