urwid 2.6.4__py3-none-any.whl → 2.6.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of urwid might be problematic. Click here for more details.

Files changed (46) hide show
  1. urwid/__init__.py +46 -33
  2. urwid/canvas.py +4 -6
  3. urwid/display/_posix_raw_display.py +3 -4
  4. urwid/display/_raw_display_base.py +4 -5
  5. urwid/display/_win32_raw_display.py +1 -2
  6. urwid/display/curses.py +1 -1
  7. urwid/display/html_fragment.py +1 -1
  8. urwid/event_loop/__init__.py +5 -5
  9. urwid/event_loop/main_loop.py +26 -21
  10. urwid/event_loop/zmq_loop.py +2 -2
  11. urwid/numedit.py +5 -1
  12. urwid/signals.py +1 -1
  13. urwid/str_util.py +1 -2
  14. urwid/text_layout.py +8 -4
  15. urwid/version.py +2 -2
  16. urwid/vterm.py +10 -10
  17. urwid/widget/__init__.py +19 -1
  18. urwid/widget/bar_graph.py +8 -4
  19. urwid/widget/big_text.py +14 -4
  20. urwid/widget/box_adapter.py +11 -3
  21. urwid/widget/columns.py +104 -34
  22. urwid/widget/constants.py +43 -76
  23. urwid/widget/container.py +2 -2
  24. urwid/widget/divider.py +5 -1
  25. urwid/widget/edit.py +20 -14
  26. urwid/widget/filler.py +11 -4
  27. urwid/widget/frame.py +91 -28
  28. urwid/widget/grid_flow.py +66 -15
  29. urwid/{listbox.py → widget/listbox.py} +27 -23
  30. urwid/{monitored_list.py → widget/monitored_list.py} +2 -0
  31. urwid/widget/overlay.py +99 -14
  32. urwid/widget/padding.py +16 -3
  33. urwid/widget/pile.py +57 -13
  34. urwid/widget/progress_bar.py +5 -1
  35. urwid/widget/scrollable.py +28 -9
  36. urwid/widget/solid_fill.py +5 -1
  37. urwid/widget/text.py +11 -3
  38. urwid/{treetools.py → widget/treetools.py} +35 -18
  39. urwid/widget/widget.py +17 -9
  40. urwid/widget/wimp.py +8 -4
  41. {urwid-2.6.4.dist-info → urwid-2.6.6.dist-info}/METADATA +1 -1
  42. urwid-2.6.6.dist-info/RECORD +74 -0
  43. urwid-2.6.4.dist-info/RECORD +0 -74
  44. {urwid-2.6.4.dist-info → urwid-2.6.6.dist-info}/COPYING +0 -0
  45. {urwid-2.6.4.dist-info → urwid-2.6.6.dist-info}/WHEEL +0 -0
  46. {urwid-2.6.4.dist-info → urwid-2.6.6.dist-info}/top_level.txt +0 -0
urwid/__init__.py CHANGED
@@ -53,32 +53,6 @@ from urwid.command_map import (
53
53
  CommandMap,
54
54
  command_map,
55
55
  )
56
- from urwid.display import (
57
- BLACK,
58
- BROWN,
59
- DARK_BLUE,
60
- DARK_CYAN,
61
- DARK_GRAY,
62
- DARK_GREEN,
63
- DARK_MAGENTA,
64
- DARK_RED,
65
- DEFAULT,
66
- LIGHT_BLUE,
67
- LIGHT_CYAN,
68
- LIGHT_GRAY,
69
- LIGHT_GREEN,
70
- LIGHT_MAGENTA,
71
- LIGHT_RED,
72
- UPDATE_PALETTE_ENTRY,
73
- WHITE,
74
- YELLOW,
75
- AttrSpec,
76
- AttrSpecError,
77
- BaseScreen,
78
- RealTerminal,
79
- ScreenError,
80
- )
81
- from urwid.event_loop import AsyncioEventLoop, EventLoop, ExitMainLoop, MainLoop, SelectEventLoop
82
56
  from urwid.font import (
83
57
  Font,
84
58
  FontRegistry,
@@ -93,8 +67,6 @@ from urwid.font import (
93
67
  Thin6x6Font,
94
68
  get_all_fonts,
95
69
  )
96
- from urwid.listbox import ListBox, ListBoxError, ListWalker, ListWalkerError, SimpleFocusListWalker, SimpleListWalker
97
- from urwid.monitored_list import MonitoredFocusList, MonitoredList
98
70
  from urwid.signals import (
99
71
  MetaSignals,
100
72
  Signals,
@@ -121,7 +93,35 @@ from urwid.util import (
121
93
  )
122
94
  from urwid.version import version as __version__
123
95
  from urwid.version import version_tuple as __version_tuple__
124
- from urwid.widget import (
96
+
97
+ from . import display, event_loop, widget
98
+ from .display import (
99
+ BLACK,
100
+ BROWN,
101
+ DARK_BLUE,
102
+ DARK_CYAN,
103
+ DARK_GRAY,
104
+ DARK_GREEN,
105
+ DARK_MAGENTA,
106
+ DARK_RED,
107
+ DEFAULT,
108
+ LIGHT_BLUE,
109
+ LIGHT_CYAN,
110
+ LIGHT_GRAY,
111
+ LIGHT_GREEN,
112
+ LIGHT_MAGENTA,
113
+ LIGHT_RED,
114
+ UPDATE_PALETTE_ENTRY,
115
+ WHITE,
116
+ YELLOW,
117
+ AttrSpec,
118
+ AttrSpecError,
119
+ BaseScreen,
120
+ RealTerminal,
121
+ ScreenError,
122
+ )
123
+ from .event_loop import AsyncioEventLoop, EventLoop, ExitMainLoop, MainLoop, SelectEventLoop
124
+ from .widget import (
125
125
  ANY,
126
126
  BOTTOM,
127
127
  BOX,
@@ -170,10 +170,17 @@ from urwid.widget import (
170
170
  GridFlowError,
171
171
  IntEdit,
172
172
  LineBox,
173
+ ListBox,
174
+ ListBoxError,
175
+ ListWalker,
176
+ ListWalkerError,
177
+ MonitoredFocusList,
178
+ MonitoredList,
173
179
  Overlay,
174
180
  OverlayError,
175
181
  Padding,
176
182
  PaddingError,
183
+ ParentNode,
177
184
  Pile,
178
185
  PileError,
179
186
  PopUpLauncher,
@@ -183,10 +190,17 @@ from urwid.widget import (
183
190
  Scrollable,
184
191
  ScrollBar,
185
192
  SelectableIcon,
193
+ SimpleFocusListWalker,
194
+ SimpleListWalker,
186
195
  Sizing,
187
196
  SolidFill,
188
197
  Text,
189
198
  TextError,
199
+ TreeListBox,
200
+ TreeNode,
201
+ TreeWalker,
202
+ TreeWidget,
203
+ TreeWidgetError,
190
204
  VAlign,
191
205
  WHSettings,
192
206
  Widget,
@@ -204,10 +218,6 @@ from urwid.widget import (
204
218
  scale_bar_values,
205
219
  )
206
220
 
207
- from . import display, event_loop, widget
208
-
209
- from .treetools import ParentNode, TreeListBox, TreeNode, TreeWalker, TreeWidget, TreeWidgetError # isort: skip
210
-
211
221
  # Optional event loops with external dependencies
212
222
 
213
223
  try:
@@ -252,6 +262,9 @@ _moved_warn: dict[str, str] = {
252
262
  "lcd_display": "urwid.display.lcd",
253
263
  "html_fragment": "urwid.display.html_fragment",
254
264
  "web_display": "urwid.display.web",
265
+ "monitored_list": "urwid.widget.monitored_list",
266
+ "listbox": "urwid.widget.listbox",
267
+ "treetools": "urwid.widget.treetools",
255
268
  }
256
269
  # Backward compatible lazy load without any warnings
257
270
  # Before DeprecationWarning need to start PendingDeprecationWarning process.
urwid/canvas.py CHANGED
@@ -216,7 +216,7 @@ class Canvas:
216
216
  def __init__(self) -> None:
217
217
  """Base Canvas class"""
218
218
  self._widget_info = None
219
- self.coords: dict[str, tuple[int, int, tuple[Widget, int, int]]] = {}
219
+ self.coords: dict[str, tuple[int, int, tuple[Widget, int, int]] | tuple[int, int, None]] = {}
220
220
  self.shortcuts: dict[str, str] = {}
221
221
 
222
222
  def finalize(
@@ -580,7 +580,7 @@ class SolidCanvas(Canvas):
580
580
  A canvas filled completely with a single character.
581
581
  """
582
582
 
583
- def __init__(self, fill_char: str, cols: int, rows: int) -> None:
583
+ def __init__(self, fill_char: str | bytes, cols: int, rows: int) -> None:
584
584
  super().__init__()
585
585
  end, col = calc_text_pos(fill_char, 0, len(fill_char), 1)
586
586
  if col != 1:
@@ -726,8 +726,7 @@ class CompositeCanvas(Canvas):
726
726
  Return the differences between other and this canvas.
727
727
  """
728
728
  if not hasattr(other, "shards"):
729
- for row in self.content():
730
- yield row
729
+ yield from self.content()
731
730
  return
732
731
 
733
732
  shard_tail = []
@@ -1275,8 +1274,7 @@ def CanvasJoin(canvas_info: Iterable[tuple[Canvas, typing.Any, bool, int]]) -> C
1275
1274
  pad_right = cols - canv.cols()
1276
1275
  if focus:
1277
1276
  focus_item = n
1278
- if rows > maxrow:
1279
- maxrow = rows
1277
+ maxrow = max(maxrow, rows)
1280
1278
  l2.append((canv, pos, pad_right, rows))
1281
1279
 
1282
1280
  shard_lists = []
@@ -43,7 +43,6 @@ from . import _raw_display_base, escape
43
43
  from .common import INPUT_DESCRIPTORS_CHANGED
44
44
 
45
45
  if typing.TYPE_CHECKING:
46
- import io
47
46
  import socket
48
47
  from collections.abc import Callable
49
48
  from types import FrameType
@@ -54,8 +53,8 @@ if typing.TYPE_CHECKING:
54
53
  class Screen(_raw_display_base.Screen):
55
54
  def __init__(
56
55
  self,
57
- input: io.TextIOBase = sys.stdin, # noqa: A002 # pylint: disable=redefined-builtin
58
- output: io.TextIOBase = sys.stdout,
56
+ input: typing.TextIO = sys.stdin, # noqa: A002 # pylint: disable=redefined-builtin
57
+ output: typing.TextIO = sys.stdout,
59
58
  bracketed_paste_mode=False,
60
59
  ) -> None:
61
60
  """Initialize a screen that directly prints escape codes to an output
@@ -223,7 +222,7 @@ class Screen(_raw_display_base.Screen):
223
222
 
224
223
  super()._stop()
225
224
 
226
- def get_input_descriptors(self) -> list[socket.socket | io.IOBase | typing.IO | int]:
225
+ def get_input_descriptors(self) -> list[socket.socket | typing.IO | int]:
227
226
  """
228
227
  Return a list of integer file descriptors that should be
229
228
  polled in external event loops to check for user input.
@@ -41,7 +41,6 @@ from . import escape
41
41
  from .common import UNPRINTABLE_TRANS_TABLE, UPDATE_PALETTE_ENTRY, AttrSpec, BaseScreen, RealTerminal
42
42
 
43
43
  if typing.TYPE_CHECKING:
44
- import io
45
44
  from collections.abc import Callable, Iterable
46
45
  from types import FrameType
47
46
 
@@ -54,7 +53,7 @@ IS_WSL = (sys.platform == "linux") and ("wsl" in platform.platform().lower())
54
53
 
55
54
 
56
55
  class Screen(BaseScreen, RealTerminal):
57
- def __init__(self, input: io.IOBase, output: io.IOBase): # noqa: A002 # pylint: disable=redefined-builtin
56
+ def __init__(self, input: typing.IO, output: typing.IO) -> None: # noqa: A002 # pylint: disable=redefined-builtin
58
57
  """Initialize a screen that directly prints escape codes to an output
59
58
  terminal.
60
59
  """
@@ -116,7 +115,7 @@ class Screen(BaseScreen, RealTerminal):
116
115
  self.screen_buf = None
117
116
 
118
117
  @property
119
- def _term_input_io(self) -> io.IOBase | None:
118
+ def _term_input_io(self) -> typing.IO | None:
120
119
  if hasattr(self._term_input_file, "fileno"):
121
120
  return self._term_input_file
122
121
  return None
@@ -310,7 +309,7 @@ class Screen(BaseScreen, RealTerminal):
310
309
  return keys, raw
311
310
  return keys
312
311
 
313
- def get_input_descriptors(self) -> list[socket.socket | io.IOBase | typing.IO | int]:
312
+ def get_input_descriptors(self) -> list[socket.socket | typing.IO | int]:
314
313
  """
315
314
  Return a list of integer file descriptors that should be
316
315
  polled in external event loops to check for user input.
@@ -323,7 +322,7 @@ class Screen(BaseScreen, RealTerminal):
323
322
  if not self._started:
324
323
  return []
325
324
 
326
- fd_list = [self._resize_pipe_rd]
325
+ fd_list: list[socket.socket | typing.IO | int] = [self._resize_pipe_rd]
327
326
  input_io = self._term_input_io
328
327
  if input_io is not None:
329
328
  fd_list.append(input_io)
@@ -41,7 +41,6 @@ from . import _raw_display_base, _win32, escape
41
41
  from .common import INPUT_DESCRIPTORS_CHANGED
42
42
 
43
43
  if typing.TYPE_CHECKING:
44
- import io
45
44
  from collections.abc import Callable
46
45
 
47
46
  from urwid.event_loop import EventLoop
@@ -53,7 +52,7 @@ class Screen(_raw_display_base.Screen):
53
52
  def __init__(
54
53
  self,
55
54
  input: socket.socket | None = None, # noqa: A002 # pylint: disable=redefined-builtin
56
- output: io.TextIOBase = sys.stdout,
55
+ output: typing.TextIO = sys.stdout,
57
56
  ) -> None:
58
57
  """Initialize a screen that directly prints escape codes to an output
59
58
  terminal.
urwid/display/curses.py CHANGED
@@ -103,7 +103,7 @@ _curses_colours = { # pylint: disable=consider-using-namedtuple-or-dataclass #
103
103
 
104
104
 
105
105
  class Screen(BaseScreen, RealTerminal):
106
- def __init__(self):
106
+ def __init__(self) -> None:
107
107
  super().__init__()
108
108
  self.curses_pairs = [(None, None)] # Can't be sure what pair 0 will default to
109
109
  self.palette = {}
@@ -53,7 +53,7 @@ class HtmlGenerator(BaseScreen):
53
53
  # class variables
54
54
  fragments: typing.ClassVar[list[str]] = []
55
55
  sizes: typing.ClassVar[list[tuple[int, int]]] = []
56
- keys: typing.ClassVar[list[list[str] | tuple[list[str], list[int]]]] = []
56
+ keys: typing.ClassVar[list[list[str]]] = []
57
57
  started = True
58
58
 
59
59
  def __init__(self) -> None:
@@ -20,28 +20,28 @@ __all__ = (
20
20
  try:
21
21
  from .twisted_loop import TwistedEventLoop
22
22
 
23
- __all__ += ("TwistedEventLoop",)
23
+ __all__ += ("TwistedEventLoop",) # type: ignore[assignment]
24
24
  except ImportError:
25
25
  pass
26
26
 
27
27
  try:
28
28
  from .tornado_loop import TornadoEventLoop
29
29
 
30
- __all__ += ("TornadoEventLoop",)
30
+ __all__ += ("TornadoEventLoop",) # type: ignore[assignment]
31
31
  except ImportError:
32
32
  pass
33
33
 
34
34
  try:
35
35
  from .glib_loop import GLibEventLoop
36
36
 
37
- __all__ += ("GLibEventLoop",)
37
+ __all__ += ("GLibEventLoop",) # type: ignore[assignment]
38
38
  except ImportError:
39
39
  pass
40
40
 
41
41
  try:
42
42
  from .trio_loop import TrioEventLoop
43
43
 
44
- __all__ += ("TrioEventLoop",)
44
+ __all__ += ("TrioEventLoop",) # type: ignore[assignment]
45
45
  except ImportError:
46
46
  pass
47
47
 
@@ -50,6 +50,6 @@ if sys.platform != "win32":
50
50
  try:
51
51
  from .zmq_loop import ZMQEventLoop
52
52
 
53
- __all__ += ("ZMQEventLoop",)
53
+ __all__ += ("ZMQEventLoop",) # type: ignore[assignment]
54
54
  except ImportError:
55
55
  pass
@@ -562,36 +562,41 @@ class MainLoop:
562
562
 
563
563
  something_handled = False
564
564
 
565
- for k in keys:
566
- if k == "window resize":
565
+ for key in keys:
566
+ if key == "window resize":
567
567
  continue
568
568
 
569
- if isinstance(k, str):
569
+ if isinstance(key, str):
570
570
  if self._topmost_widget.selectable():
571
- k = self._topmost_widget.keypress(self.screen_size, k) # noqa: PLW2901
572
-
573
- elif isinstance(k, tuple):
574
- if is_mouse_event(k):
575
- event, button, col, row = k
576
- if hasattr(self._topmost_widget, "mouse_event") and self._topmost_widget.mouse_event(
577
- self.screen_size,
578
- event,
579
- button,
580
- col,
581
- row,
582
- focus=True,
583
- ):
584
- k = None # noqa: PLW2901
571
+ handled_key = self._topmost_widget.keypress(self.screen_size, key)
572
+ if not handled_key:
573
+ something_handled = True
574
+ continue
575
+
576
+ key = handled_key # noqa: PLW2901
577
+
578
+ elif is_mouse_event(key):
579
+ event, button, col, row = key
580
+ if hasattr(self._topmost_widget, "mouse_event") and self._topmost_widget.mouse_event(
581
+ self.screen_size,
582
+ event,
583
+ button,
584
+ col,
585
+ row,
586
+ focus=True,
587
+ ):
588
+ something_handled = True
589
+ continue
585
590
 
586
591
  else:
587
- raise TypeError(f"{k!r} is not str | tuple[str, int, int, int]")
592
+ raise TypeError(f"{key!r} is not str | tuple[str, int, int, int]")
588
593
 
589
- if k:
590
- if command_map[k] == Command.REDRAW_SCREEN:
594
+ if key:
595
+ if command_map[key] == Command.REDRAW_SCREEN:
591
596
  self.screen.clear()
592
597
  something_handled = True
593
598
  else:
594
- something_handled |= bool(self.unhandled_input(k))
599
+ something_handled |= bool(self.unhandled_input(key))
595
600
  else:
596
601
  something_handled = True
597
602
 
@@ -62,11 +62,11 @@ class ZMQEventLoop(EventLoop):
62
62
 
63
63
  _alarm_break = count()
64
64
 
65
- def __init__(self):
65
+ def __init__(self) -> None:
66
66
  super().__init__()
67
67
  self.logger = logging.getLogger(__name__).getChild(self.__class__.__name__)
68
68
  self._did_something = True
69
- self._alarms = []
69
+ self._alarms: list[tuple[float, int, Callable[[], typing.Any]]] = []
70
70
  self._poller = zmq.Poller()
71
71
  self._queue_callbacks: dict[int, Callable[[], typing.Any]] = {}
72
72
  self._idle_handle = 0
urwid/numedit.py CHANGED
@@ -79,7 +79,11 @@ class NumEdit(Edit):
79
79
  return self._allow_negative and ch == "-" and self.edit_pos == 0 and "-" not in self.edit_text
80
80
  return False
81
81
 
82
- def keypress(self, size: tuple[int], key: str) -> str | None:
82
+ def keypress(
83
+ self,
84
+ size: tuple[int], # type: ignore[override]
85
+ key: str,
86
+ ) -> str | None:
83
87
  """
84
88
  Handle editing keystrokes. Remove leading zeros.
85
89
 
urwid/signals.py CHANGED
@@ -65,7 +65,7 @@ class Key:
65
65
  class Signals:
66
66
  _signal_attr = "_urwid_signals" # attribute to attach to signal senders
67
67
 
68
- def __init__(self):
68
+ def __init__(self) -> None:
69
69
  self._supported = {}
70
70
 
71
71
  def register(self, sig_cls, signals: Container[Hashable]) -> None:
urwid/str_util.py CHANGED
@@ -29,7 +29,6 @@ import wcwidth
29
29
  if typing.TYPE_CHECKING:
30
30
  from typing_extensions import Literal
31
31
 
32
- UNICODE_VERSION = "15.1.0" # Use explicit version
33
32
  SAFE_ASCII_RE = re.compile("^[ -~]*$")
34
33
  SAFE_ASCII_BYTES_RE = re.compile(b"^[ -~]*$")
35
34
 
@@ -37,7 +36,7 @@ _byte_encoding: Literal["utf8", "narrow", "wide"] = "narrow"
37
36
 
38
37
 
39
38
  def get_char_width(char: str) -> Literal[0, 1, 2]:
40
- width = wcwidth.wcwidth(char, UNICODE_VERSION)
39
+ width = wcwidth.wcwidth(char)
41
40
  if width < 0:
42
41
  return 0
43
42
  return width
urwid/text_layout.py CHANGED
@@ -94,7 +94,7 @@ class CanNotDisplayText(Exception):
94
94
 
95
95
 
96
96
  class StandardTextLayout(TextLayout):
97
- def __init__(self): # , tab_stops=(), tab_stop_every=8):
97
+ def __init__(self) -> None: # , tab_stops=(), tab_stop_every=8):
98
98
  pass
99
99
  # """
100
100
  # tab_stops -- list of screen column indexes for tab stops
@@ -181,7 +181,7 @@ class StandardTextLayout(TextLayout):
181
181
  """Calculate text segments for cases of a text trimmed (wrap is clip or ellipsis)."""
182
182
  segments = []
183
183
 
184
- nl = "\n" if isinstance(text, str) else b"\n"
184
+ nl: str | bytes = "\n" if isinstance(text, str) else b"\n"
185
185
  encoding = get_encoding()
186
186
  ellipsis_string = get_ellipsis_string(encoding)
187
187
  ellipsis_width = _get_width(ellipsis_string)
@@ -508,7 +508,11 @@ def trim_line(
508
508
  return result
509
509
 
510
510
 
511
- def calc_line_pos(text: str | bytes, line_layout, pref_col: Literal["left", "right"] | int):
511
+ def calc_line_pos(
512
+ text: str | bytes,
513
+ line_layout,
514
+ pref_col: Literal["left", "right", Align.LEFT, Align.RIGHT] | int,
515
+ ):
512
516
  """
513
517
  Calculate the closest linear position to pref_col given a
514
518
  line layout structure. Returns None if no position found.
@@ -566,7 +570,7 @@ def calc_line_pos(text: str | bytes, line_layout, pref_col: Literal["left", "rig
566
570
  def calc_pos(
567
571
  text: str | bytes,
568
572
  layout: list[list[tuple[int, int, int | bytes] | tuple[int, int | None]]],
569
- pref_col: Literal["left", "right"] | int,
573
+ pref_col: Literal["left", "right", Align.LEFT, Align.RIGHT] | int,
570
574
  row: int,
571
575
  ) -> int:
572
576
  """
urwid/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '2.6.4'
16
- __version_tuple__ = version_tuple = (2, 6, 4)
15
+ __version__ = version = '2.6.6'
16
+ __version_tuple__ = version_tuple = (2, 6, 6)
urwid/vterm.py CHANGED
@@ -721,7 +721,7 @@ class TermCanvas(Canvas):
721
721
  x, y = self.term_cursor
722
722
 
723
723
  if isinstance(char, int):
724
- char = chr(char)
724
+ char = char.to_bytes(1, "little")
725
725
 
726
726
  dc = self.modes.display_ctrl
727
727
 
@@ -986,14 +986,14 @@ class TermCanvas(Canvas):
986
986
  chars = 1
987
987
 
988
988
  if char is None:
989
- char = self.empty_char()
989
+ char_spec = self.empty_char()
990
990
  else:
991
- char = (self.attrspec, self.charset.current, char)
991
+ char_spec = (self.attrspec, self.charset.current, char)
992
992
 
993
993
  x, y = position
994
994
 
995
995
  while chars > 0:
996
- self.term[y].insert(x, char)
996
+ self.term[y].insert(x, char_spec)
997
997
  self.term[y].pop()
998
998
  chars -= 1
999
999
 
@@ -1187,19 +1187,19 @@ class TermCanvas(Canvas):
1187
1187
  return _color_desc_256(color)
1188
1188
  return _BASIC_COLORS[color]
1189
1189
 
1190
- fg = _defaulter(fg, colors)
1191
- bg = _defaulter(bg, colors)
1190
+ decoded_fg = _defaulter(fg, colors)
1191
+ decoded_bg = _defaulter(bg, colors)
1192
1192
 
1193
1193
  if attributes:
1194
- fg = ",".join((fg, *list(attributes)))
1194
+ decoded_fg = ",".join((decoded_fg, *list(attributes)))
1195
1195
 
1196
- if fg == bg == "default":
1196
+ if decoded_fg == decoded_bg == "default":
1197
1197
  return None
1198
1198
 
1199
1199
  if colors:
1200
- return AttrSpec(fg, bg, colors=colors)
1200
+ return AttrSpec(decoded_fg, decoded_bg, colors=colors)
1201
1201
 
1202
- return AttrSpec(fg, bg)
1202
+ return AttrSpec(decoded_fg, decoded_bg)
1203
1203
 
1204
1204
  def csi_set_attr(self, attrs: Sequence[int]) -> None:
1205
1205
  """
urwid/widget/__init__.py CHANGED
@@ -27,8 +27,10 @@ from .divider import Divider
27
27
  from .edit import Edit, EditError, IntEdit
28
28
  from .filler import Filler, FillerError, calculate_top_bottom_filler
29
29
  from .frame import Frame, FrameError
30
- from .grid_flow import GridFlow, GridFlowError
30
+ from .grid_flow import GridFlow, GridFlowError, GridFlowWarning
31
31
  from .line_box import LineBox
32
+ from .listbox import ListBox, ListBoxError, ListWalker, ListWalkerError, SimpleFocusListWalker, SimpleListWalker
33
+ from .monitored_list import MonitoredFocusList, MonitoredList
32
34
  from .overlay import Overlay, OverlayError, OverlayWarning
33
35
  from .padding import Padding, PaddingError, PaddingWarning, calculate_left_right_padding
34
36
  from .pile import Pile, PileError, PileWarning
@@ -37,6 +39,7 @@ from .progress_bar import ProgressBar
37
39
  from .scrollable import Scrollable, ScrollableError, ScrollBar
38
40
  from .solid_fill import SolidFill
39
41
  from .text import Text, TextError
42
+ from .treetools import ParentNode, TreeListBox, TreeNode, TreeWalker, TreeWidget, TreeWidgetError
40
43
  from .widget import (
41
44
  BoxWidget,
42
45
  FixedWidget,
@@ -58,6 +61,8 @@ from .wimp import Button, CheckBox, CheckBoxError, RadioButton, SelectableIcon
58
61
  __all__ = (
59
62
  "ANY",
60
63
  "BOTTOM",
64
+ "MonitoredList",
65
+ "MonitoredFocusList",
61
66
  "BOX",
62
67
  "CENTER",
63
68
  "CLIP",
@@ -67,6 +72,7 @@ __all__ = (
67
72
  "GIVEN",
68
73
  "LEFT",
69
74
  "MIDDLE",
75
+ "GridFlowWarning",
70
76
  "PACK",
71
77
  "RELATIVE",
72
78
  "RELATIVE_100",
@@ -85,8 +91,20 @@ __all__ = (
85
91
  "BoxAdapter",
86
92
  "BoxAdapterError",
87
93
  "BoxWidget",
94
+ "ListWalkerError",
95
+ "ListWalker",
96
+ "SimpleListWalker",
97
+ "SimpleFocusListWalker",
98
+ "ListBoxError",
99
+ "ListBox",
88
100
  "Button",
89
101
  "CheckBox",
102
+ "TreeWidgetError",
103
+ "TreeWidget",
104
+ "TreeNode",
105
+ "ParentNode",
106
+ "TreeWalker",
107
+ "TreeListBox",
90
108
  "CheckBoxError",
91
109
  "Columns",
92
110
  "ColumnsError",
urwid/widget/bar_graph.py CHANGED
@@ -611,7 +611,11 @@ class GraphVScale(Widget):
611
611
  """
612
612
  return False
613
613
 
614
- def render(self, size: tuple[int, int], focus: bool = False) -> SolidCanvas | CompositeCanvas:
614
+ def render(
615
+ self,
616
+ size: tuple[int, int],
617
+ focus: bool = False,
618
+ ) -> SolidCanvas | CompositeCanvas:
615
619
  """
616
620
  Render GraphVScale.
617
621
  """
@@ -636,10 +640,10 @@ class GraphVScale(Widget):
636
640
  if not combinelist:
637
641
  return SolidCanvas(" ", size[0], size[1])
638
642
 
639
- c = CanvasCombine(combinelist)
643
+ canvas = CanvasCombine(combinelist)
640
644
  if maxrow - rows:
641
- c.pad_trim_top_bottom(0, maxrow - rows)
642
- return c
645
+ canvas.pad_trim_top_bottom(0, maxrow - rows)
646
+ return canvas
643
647
 
644
648
 
645
649
  def scale_bar_values(bar, top: float, maxrow: int) -> list[int]:
urwid/widget/big_text.py CHANGED
@@ -9,6 +9,8 @@ from .constants import Sizing
9
9
  from .widget import Widget, fixed_size
10
10
 
11
11
  if typing.TYPE_CHECKING:
12
+ from collections.abc import Hashable
13
+
12
14
  from urwid import Font
13
15
 
14
16
 
@@ -41,16 +43,24 @@ class BigText(Widget):
41
43
  self.font = font
42
44
  self._invalidate()
43
45
 
44
- def pack(self, size: tuple[()] | None = None, focus: bool = False) -> tuple[int, int]:
46
+ def pack(
47
+ self,
48
+ size: tuple[()] | None = (), # type: ignore[override]
49
+ focus: bool = False,
50
+ ) -> tuple[int, int]:
45
51
  rows = self.font.height
46
52
  cols = 0
47
53
  for c in self.text:
48
54
  cols += self.font.char_width(c)
49
55
  return cols, rows
50
56
 
51
- def render(self, size: tuple[()], focus: bool = False) -> CompositeCanvas:
57
+ def render(
58
+ self,
59
+ size: tuple[()], # type: ignore[override]
60
+ focus: bool = False,
61
+ ) -> CompositeCanvas:
52
62
  fixed_size(size) # complain if parameter is wrong
53
- a = None
63
+ a: Hashable | None = None
54
64
  ai = ak = 0
55
65
  o = []
56
66
  rows = self.font.height
@@ -64,7 +74,7 @@ class BigText(Widget):
64
74
  if not width:
65
75
  # ignore invalid characters
66
76
  continue
67
- c = self.font.render(ch)
77
+ c: TextCanvas | CompositeCanvas = self.font.render(ch)
68
78
  if a is not None:
69
79
  c = CompositeCanvas(c)
70
80
  c.fill_attr(a)