urwid 2.6.15__py3-none-any.whl → 3.0.0__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 (54) hide show
  1. urwid/__init__.py +1 -4
  2. urwid/canvas.py +27 -46
  3. urwid/command_map.py +6 -4
  4. urwid/container.py +1 -1
  5. urwid/decoration.py +1 -1
  6. urwid/display/_posix_raw_display.py +16 -4
  7. urwid/display/_raw_display_base.py +8 -5
  8. urwid/display/_win32_raw_display.py +16 -17
  9. urwid/display/common.py +26 -55
  10. urwid/display/curses.py +1 -1
  11. urwid/display/escape.py +15 -12
  12. urwid/display/lcd.py +4 -6
  13. urwid/display/web.py +7 -12
  14. urwid/event_loop/asyncio_loop.py +1 -2
  15. urwid/event_loop/main_loop.py +13 -18
  16. urwid/event_loop/tornado_loop.py +4 -5
  17. urwid/event_loop/trio_loop.py +1 -1
  18. urwid/font.py +13 -18
  19. urwid/signals.py +2 -1
  20. urwid/str_util.py +15 -18
  21. urwid/text_layout.py +6 -7
  22. urwid/util.py +7 -18
  23. urwid/version.py +9 -4
  24. urwid/vterm.py +18 -45
  25. urwid/widget/__init__.py +0 -6
  26. urwid/widget/attr_wrap.py +8 -10
  27. urwid/widget/bar_graph.py +3 -8
  28. urwid/widget/big_text.py +9 -7
  29. urwid/widget/box_adapter.py +4 -4
  30. urwid/widget/columns.py +52 -83
  31. urwid/widget/container.py +29 -75
  32. urwid/widget/edit.py +8 -8
  33. urwid/widget/filler.py +6 -6
  34. urwid/widget/frame.py +28 -37
  35. urwid/widget/grid_flow.py +25 -110
  36. urwid/widget/line_box.py +13 -0
  37. urwid/widget/listbox.py +12 -50
  38. urwid/widget/monitored_list.py +6 -4
  39. urwid/widget/overlay.py +4 -37
  40. urwid/widget/padding.py +11 -48
  41. urwid/widget/pile.py +179 -158
  42. urwid/widget/popup.py +2 -2
  43. urwid/widget/progress_bar.py +10 -11
  44. urwid/widget/scrollable.py +25 -33
  45. urwid/widget/treetools.py +27 -48
  46. urwid/widget/widget.py +7 -124
  47. urwid/widget/widget_decoration.py +4 -33
  48. urwid/wimp.py +1 -1
  49. {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info}/METADATA +18 -18
  50. urwid-3.0.0.dist-info/RECORD +74 -0
  51. {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info}/WHEEL +1 -1
  52. urwid-2.6.15.dist-info/RECORD +0 -74
  53. {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info/licenses}/COPYING +0 -0
  54. {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info}/top_level.txt +0 -0
urwid/widget/__init__.py CHANGED
@@ -41,9 +41,6 @@ from .solid_fill import SolidFill
41
41
  from .text import Text, TextError
42
42
  from .treetools import ParentNode, TreeListBox, TreeNode, TreeWalker, TreeWidget, TreeWidgetError
43
43
  from .widget import (
44
- BoxWidget,
45
- FixedWidget,
46
- FlowWidget,
47
44
  Widget,
48
45
  WidgetError,
49
46
  WidgetMeta,
@@ -87,7 +84,6 @@ __all__ = (
87
84
  "BigText",
88
85
  "BoxAdapter",
89
86
  "BoxAdapterError",
90
- "BoxWidget",
91
87
  "Button",
92
88
  "CheckBox",
93
89
  "CheckBoxError",
@@ -99,8 +95,6 @@ __all__ = (
99
95
  "EditError",
100
96
  "Filler",
101
97
  "FillerError",
102
- "FixedWidget",
103
- "FlowWidget",
104
98
  "Frame",
105
99
  "FrameError",
106
100
  "GraphVScale",
urwid/widget/attr_wrap.py CHANGED
@@ -47,8 +47,7 @@ class AttrWrap(AttrMap):
47
47
  # only include the focus_attr when it takes effect (not None)
48
48
  d = {**super()._repr_attrs(), "attr": self.attr}
49
49
  del d["attr_map"]
50
- if "focus_map" in d:
51
- del d["focus_map"]
50
+ d.pop("focus_map", None)
52
51
  if self.focus_attr is not None:
53
52
  d["focus_attr"] = self.focus_attr
54
53
  return d
@@ -57,8 +56,8 @@ class AttrWrap(AttrMap):
57
56
  def w(self) -> Widget:
58
57
  """backwards compatibility, widget used to be stored as w"""
59
58
  warnings.warn(
60
- "backwards compatibility, widget used to be stored as original_widget",
61
- PendingDeprecationWarning,
59
+ "backwards compatibility, widget used to be stored as original_widget. API will be removed in version 5.0.",
60
+ DeprecationWarning,
62
61
  stacklevel=2,
63
62
  )
64
63
  return self.original_widget
@@ -66,15 +65,15 @@ class AttrWrap(AttrMap):
66
65
  @w.setter
67
66
  def w(self, new_widget: Widget) -> None:
68
67
  warnings.warn(
69
- "backwards compatibility, widget used to be stored as original_widget",
70
- PendingDeprecationWarning,
68
+ "backwards compatibility, widget used to be stored as original_widget. API will be removed in version 5.0.",
69
+ DeprecationWarning,
71
70
  stacklevel=2,
72
71
  )
73
72
  self.original_widget = new_widget
74
73
 
75
74
  def get_w(self):
76
75
  warnings.warn(
77
- "backwards compatibility, widget used to be stored as original_widget",
76
+ "backwards compatibility, widget used to be stored as original_widget. API will be removed in version 4.0.",
78
77
  DeprecationWarning,
79
78
  stacklevel=2,
80
79
  )
@@ -82,7 +81,7 @@ class AttrWrap(AttrMap):
82
81
 
83
82
  def set_w(self, new_widget: Widget) -> None:
84
83
  warnings.warn(
85
- "backwards compatibility, widget used to be stored as original_widget",
84
+ "backwards compatibility, widget used to be stored as original_widget. API will be removed in version 4.0.",
86
85
  DeprecationWarning,
87
86
  stacklevel=2,
88
87
  )
@@ -105,8 +104,7 @@ class AttrWrap(AttrMap):
105
104
  attr = property(get_attr, set_attr)
106
105
 
107
106
  def get_focus_attr(self) -> Hashable | None:
108
- focus_map = self.focus_map
109
- if focus_map:
107
+ if focus_map := self.focus_map:
110
108
  return focus_map[None]
111
109
  return None
112
110
 
urwid/widget/bar_graph.py CHANGED
@@ -269,12 +269,7 @@ class BarGraph(Widget, metaclass=BarGraphMeta):
269
269
  ]
270
270
 
271
271
  # reverse the hlines to match screen ordering
272
- rhl = []
273
- for h in hlines:
274
- rh = float(top - h) * maxrow / top - shiftr
275
- if rh < 0:
276
- continue
277
- rhl.append(rh)
272
+ rhl = [rh for h in hlines if (rh := float(top - h) * maxrow / top - shiftr) >= 0]
278
273
 
279
274
  # build a list of rows that will have hlines
280
275
  hrows = []
@@ -410,7 +405,7 @@ class BarGraph(Widget, metaclass=BarGraphMeta):
410
405
  if len(bar_type) == 3:
411
406
  # vertical eighths
412
407
  fg, bg, k = bar_type
413
- a = self.satt[(fg, bg)]
408
+ a = self.satt[fg, bg]
414
409
  t = self.eighths[k] * width
415
410
  else:
416
411
  # horizontal lines
@@ -562,7 +557,7 @@ def calculate_bargraph_display(bardata, top: float, bar_widths: list[int], maxro
562
557
  la, ln = last[i]
563
558
 
564
559
  if i < len(last):
565
- o += [(la, ln)] + last[i + 1 :]
560
+ o += [(la, ln), *last[i + 1 :]]
566
561
  last = o
567
562
  y_count += 1
568
563
 
urwid/widget/big_text.py CHANGED
@@ -70,15 +70,17 @@ class BigText(Widget):
70
70
  a, ak = attrib[ai]
71
71
  ai += 1
72
72
  ak -= 1
73
- width = self.font.char_width(ch)
74
- if not width:
73
+
74
+ if width := self.font.char_width(ch):
75
+ c: TextCanvas | CompositeCanvas = self.font.render(ch)
76
+ if a is not None:
77
+ c = CompositeCanvas(c)
78
+ c.fill_attr(a)
79
+ o.append((c, None, False, width))
80
+
81
+ else:
75
82
  # ignore invalid characters
76
83
  continue
77
- c: TextCanvas | CompositeCanvas = self.font.render(ch)
78
- if a is not None:
79
- c = CompositeCanvas(c)
80
- c.fill_attr(a)
81
- o.append((c, None, False, width))
82
84
  if o:
83
85
  canv = CanvasJoin(o)
84
86
  else:
@@ -48,8 +48,8 @@ class BoxAdapter(WidgetDecoration[WrappedWidget]):
48
48
  @property
49
49
  def box_widget(self) -> WrappedWidget:
50
50
  warnings.warn(
51
- "original stored as original_widget, keep for compatibility",
52
- PendingDeprecationWarning,
51
+ "original stored as original_widget, keep for compatibility. API will be removed in version 5.0.",
52
+ DeprecationWarning,
53
53
  stacklevel=2,
54
54
  )
55
55
  return self.original_widget
@@ -57,8 +57,8 @@ class BoxAdapter(WidgetDecoration[WrappedWidget]):
57
57
  @box_widget.setter
58
58
  def box_widget(self, widget: WrappedWidget) -> None:
59
59
  warnings.warn(
60
- "original stored as original_widget, keep for compatibility",
61
- PendingDeprecationWarning,
60
+ "original stored as original_widget, keep for compatibility. API will be removed in version 5.0.",
61
+ DeprecationWarning,
62
62
  stacklevel=2,
63
63
  )
64
64
  self.original_widget = widget
urwid/widget/columns.py CHANGED
@@ -121,7 +121,8 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
121
121
  flow_fixed = _ContainerElementSizingFlag.FLOW | _ContainerElementSizingFlag.FIXED
122
122
  given_box = _ContainerElementSizingFlag.BOX | _ContainerElementSizingFlag.WH_GIVEN
123
123
 
124
- flags: set[_ContainerElementSizingFlag] = set()
124
+ # This is a set of _ContainerElementSizingFlag ORed together.
125
+ flags: set[int] = set()
125
126
 
126
127
  for idx, (widget, (size_kind, _size_weight, is_box)) in enumerate(self.contents):
127
128
  w_sizing = widget.sizing()
@@ -190,7 +191,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
190
191
  if not supported:
191
192
  warnings.warn(
192
193
  f"Columns widget contents flags not allow to determine supported render kind:\n"
193
- f"{', '.join(sorted(flag.log_string for flag in flags))}\n"
194
+ f"{', '.join(sorted(_ContainerElementSizingFlag.log_string(flag) for flag in flags))}\n"
194
195
  f"Using fallback hardcoded BOX|FLOW sizing kind.",
195
196
  ColumnsWarning,
196
197
  stacklevel=3,
@@ -372,8 +373,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
372
373
  standard container property :attr:`contents`.
373
374
  """
374
375
  warnings.warn(
375
- "only for backwards compatibility. You should use the new standard container `contents`",
376
- PendingDeprecationWarning,
376
+ "only for backwards compatibility. You should use the new standard container `contents`."
377
+ "API will be removed in version 5.0.",
378
+ DeprecationWarning,
377
379
  stacklevel=2,
378
380
  )
379
381
  ml = MonitoredList(w for w, t in self.contents)
@@ -387,8 +389,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
387
389
  @widget_list.setter
388
390
  def widget_list(self, widgets):
389
391
  warnings.warn(
390
- "only for backwards compatibility. You should use the new standard container `contents`",
391
- PendingDeprecationWarning,
392
+ "only for backwards compatibility. You should use the new standard container `contents`."
393
+ "API will be removed in version 5.0.",
394
+ DeprecationWarning,
392
395
  stacklevel=2,
393
396
  )
394
397
  focus_position = self.focus_position
@@ -400,7 +403,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
400
403
  chain(self.contents, repeat((None, (WHSettings.WEIGHT, 1, False)))),
401
404
  )
402
405
  ]
403
- if focus_position < len(widgets): # pylint: disable=consider-using-max-builtin # pylint bug
406
+ if focus_position < len(widgets):
404
407
  self.focus_position = focus_position
405
408
 
406
409
  @property
@@ -412,8 +415,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
412
415
  """
413
416
  warnings.warn(
414
417
  "for backwards compatibility only."
415
- "You should use the new standard container property .contents to modify Pile contents.",
416
- PendingDeprecationWarning,
418
+ "You should use the new standard container property .contents to modify Pile contents."
419
+ "API will be removed in version 5.0.",
420
+ DeprecationWarning,
417
421
  stacklevel=2,
418
422
  )
419
423
  ml = MonitoredList(
@@ -432,8 +436,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
432
436
  def column_types(self, column_types):
433
437
  warnings.warn(
434
438
  "for backwards compatibility only."
435
- "You should use the new standard container property .contents to modify Pile contents.",
436
- PendingDeprecationWarning,
439
+ "You should use the new standard container property .contents to modify Pile contents."
440
+ "API will be removed in version 5.0.",
441
+ DeprecationWarning,
437
442
  stacklevel=2,
438
443
  )
439
444
  focus_position = self.focus_position
@@ -441,7 +446,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
441
446
  (w, ({Sizing.FIXED: WHSettings.GIVEN, Sizing.FLOW: WHSettings.PACK}.get(new_t, new_t), new_n, b))
442
447
  for ((new_t, new_n), (w, (t, n, b))) in zip(column_types, self.contents)
443
448
  ]
444
- if focus_position < len(column_types): # pylint: disable=consider-using-max-builtin # pylint bug
449
+ if focus_position < len(column_types):
445
450
  self.focus_position = focus_position
446
451
 
447
452
  @property
@@ -454,8 +459,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
454
459
  standard container property :attr:`contents`.
455
460
  """
456
461
  warnings.warn(
457
- "only for backwards compatibility.You should use the new standard container property `contents`",
458
- PendingDeprecationWarning,
462
+ "only for backwards compatibility.You should use the new standard container property `contents`."
463
+ "API will be removed in version 5.0.",
464
+ DeprecationWarning,
459
465
  stacklevel=2,
460
466
  )
461
467
  ml = MonitoredList(i for i, (w, (t, n, b)) in enumerate(self.contents) if b)
@@ -469,8 +475,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
469
475
  @box_columns.setter
470
476
  def box_columns(self, box_columns):
471
477
  warnings.warn(
472
- "only for backwards compatibility.You should use the new standard container property `contents`",
473
- PendingDeprecationWarning,
478
+ "only for backwards compatibility.You should use the new standard container property `contents`."
479
+ "API will be removed in version 5.0.",
480
+ DeprecationWarning,
474
481
  stacklevel=2,
475
482
  )
476
483
  box_columns = set(box_columns)
@@ -482,7 +489,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
482
489
  .. deprecated:: 1.0 Read values from :attr:`contents` instead.
483
490
  """
484
491
  warnings.warn(
485
- ".has_flow_type is deprecated, read values from .contents instead.",
492
+ ".has_flow_type is deprecated, read values from .contents instead. API will be removed in version 4.0.",
486
493
  DeprecationWarning,
487
494
  stacklevel=2,
488
495
  )
@@ -491,7 +498,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
491
498
  @has_flow_type.setter
492
499
  def has_flow_type(self, value):
493
500
  warnings.warn(
494
- ".has_flow_type is deprecated, read values from .contents instead.",
501
+ ".has_flow_type is deprecated, read values from .contents instead. API will be removed in version 4.0.",
495
502
  DeprecationWarning,
496
503
  stacklevel=2,
497
504
  )
@@ -582,8 +589,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
582
589
  standard container property :attr:`focus_position` to set the focus.
583
590
  """
584
591
  warnings.warn(
585
- "only for backwards compatibility.You may also use the new standard container property `focus_position`",
586
- PendingDeprecationWarning,
592
+ "only for backwards compatibility.You may also use the new standard container property `focus_position`."
593
+ "API will be removed in version 5.0.",
594
+ DeprecationWarning,
587
595
  stacklevel=2,
588
596
  )
589
597
  self.focus_position = num
@@ -596,8 +604,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
596
604
  standard container property :attr:`focus_position` to get the focus.
597
605
  """
598
606
  warnings.warn(
599
- "only for backwards compatibility.You may also use the new standard container property `focus_position`",
600
- PendingDeprecationWarning,
607
+ "only for backwards compatibility.You may also use the new standard container property `focus_position`."
608
+ "API will be removed in version 5.0.",
609
+ DeprecationWarning,
601
610
  stacklevel=2,
602
611
  )
603
612
  return self.focus_position
@@ -612,8 +621,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
612
621
  :param item: widget or integer index"""
613
622
  warnings.warn(
614
623
  "only for backwards compatibility."
615
- "You may also use the new standard container property `focus_position` to get the focus.",
616
- PendingDeprecationWarning,
624
+ "You may also use the new standard container property `focus_position` to get the focus."
625
+ "API will be removed in version 5.0.",
626
+ DeprecationWarning,
617
627
  stacklevel=2,
618
628
  )
619
629
  if isinstance(item, int):
@@ -638,17 +648,6 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
638
648
  return None
639
649
  return self.contents[self.focus_position][0]
640
650
 
641
- def _get_focus(self) -> Widget:
642
- warnings.warn(
643
- f"method `{self.__class__.__name__}._get_focus` is deprecated, "
644
- f"please use `{self.__class__.__name__}.focus` property",
645
- DeprecationWarning,
646
- stacklevel=3,
647
- )
648
- if not self.contents:
649
- return None
650
- return self.contents[self.focus_position][0]
651
-
652
651
  def get_focus(self):
653
652
  """
654
653
  Return the widget in focus, for backwards compatibility.
@@ -658,8 +657,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
658
657
  """
659
658
  warnings.warn(
660
659
  "only for backwards compatibility."
661
- "You may also use the new standard container property `focus` to get the focus.",
662
- PendingDeprecationWarning,
660
+ "You may also use the new standard container property `focus` to get the focus."
661
+ "API will be removed in version 5.0.",
662
+ DeprecationWarning,
663
663
  stacklevel=2,
664
664
  )
665
665
  if not self.contents:
@@ -692,38 +692,6 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
692
692
  ) from exc
693
693
  self.contents.focus = position
694
694
 
695
- def _get_focus_position(self) -> int | None:
696
- warnings.warn(
697
- f"method `{self.__class__.__name__}._get_focus_position` is deprecated, "
698
- f"please use `{self.__class__.__name__}.focus_position` property",
699
- DeprecationWarning,
700
- stacklevel=3,
701
- )
702
- if not self.contents:
703
- raise IndexError("No focus_position, Columns is empty")
704
- return self.contents.focus
705
-
706
- def _set_focus_position(self, position: int) -> None:
707
- """
708
- Set the widget in focus.
709
-
710
- position -- index of child widget to be made focus
711
- """
712
- warnings.warn(
713
- f"method `{self.__class__.__name__}._set_focus_position` is deprecated, "
714
- f"please use `{self.__class__.__name__}.focus_position` property",
715
- DeprecationWarning,
716
- stacklevel=3,
717
- )
718
- try:
719
- if position < 0 or position >= len(self.contents):
720
- raise IndexError(f"No Columns child widget at position {position}")
721
- except TypeError as exc:
722
- raise IndexError(f"No Columns child widget at position {position}").with_traceback(
723
- exc.__traceback__
724
- ) from exc
725
- self.contents.focus = position
726
-
727
695
  @property
728
696
  def focus_col(self):
729
697
  """
@@ -735,8 +703,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
735
703
  """
736
704
  warnings.warn(
737
705
  "only for backwards compatibility."
738
- "You may also use the new standard container property `focus_position` to get the focus.",
739
- PendingDeprecationWarning,
706
+ "You may also use the new standard container property `focus_position` to get the focus."
707
+ "API will be removed in version 5.0.",
708
+ DeprecationWarning,
740
709
  stacklevel=2,
741
710
  )
742
711
  return self.focus_position
@@ -745,8 +714,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
745
714
  def focus_col(self, new_position) -> None:
746
715
  warnings.warn(
747
716
  "only for backwards compatibility."
748
- "You may also use the new standard container property `focus_position` to get the focus.",
749
- PendingDeprecationWarning,
717
+ "You may also use the new standard container property `focus_position` to get the focus."
718
+ "API will be removed in version 5.0.",
719
+ DeprecationWarning,
750
720
  stacklevel=2,
751
721
  )
752
722
  self.focus_position = new_position
@@ -1032,7 +1002,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
1032
1002
 
1033
1003
  if not data:
1034
1004
  if size:
1035
- return SolidCanvas(" ", size[0], (size[1:] + (1,))[0])
1005
+ return SolidCanvas(" ", size[0], (*size[1:], 1)[0])
1036
1006
  raise ColumnsError("No data to render")
1037
1007
 
1038
1008
  canvas = CanvasJoin(data)
@@ -1053,13 +1023,12 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
1053
1023
  if len(widths) <= self.focus_position:
1054
1024
  return None
1055
1025
 
1056
- coords = w.get_cursor_coords(size_args[self.focus_position])
1057
- if coords is None:
1058
- return None
1026
+ if (coords := w.get_cursor_coords(size_args[self.focus_position])) is not None:
1027
+ x, y = coords
1028
+ x += sum(self.dividechars + wc for wc in widths[: self.focus_position] if wc > 0)
1029
+ return x, y
1059
1030
 
1060
- x, y = coords
1061
- x += sum(self.dividechars + wc for wc in widths[: self.focus_position] if wc > 0)
1062
- return x, y
1031
+ return None
1063
1032
 
1064
1033
  def move_cursor_to_coords(
1065
1034
  self,
@@ -1103,8 +1072,8 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
1103
1072
  move_x = min(max(0, col - x), end - x - 1)
1104
1073
  else:
1105
1074
  move_x = col
1106
- rval = w.move_cursor_to_coords(size_args[i], move_x, row)
1107
- if rval is False:
1075
+
1076
+ if w.move_cursor_to_coords(size_args[i], move_x, row) is False:
1108
1077
  return False
1109
1078
 
1110
1079
  self.focus_position = i
@@ -1176,7 +1145,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
1176
1145
  col += sum(widths[: self.focus_position])
1177
1146
  return col
1178
1147
 
1179
- def rows(self, size: tuple[int] | tuple[int, int], focus: bool = False) -> int:
1148
+ def rows(self, size: tuple[int], focus: bool = False) -> int:
1180
1149
  """
1181
1150
  Return the number of rows required by the columns.
1182
1151
  This only makes sense if :attr:`widget_list` contains flow widgets.
urwid/widget/container.py CHANGED
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  import abc
4
4
  import enum
5
5
  import typing
6
- import warnings
7
6
 
8
7
  from .constants import Sizing, WHSettings
9
8
 
@@ -13,39 +12,45 @@ if typing.TYPE_CHECKING:
13
12
  from .widget import Widget
14
13
 
15
14
 
16
- class _ContainerElementSizingFlag(enum.IntFlag):
17
- NONE = 0
18
- BOX = enum.auto()
19
- FLOW = enum.auto()
20
- FIXED = enum.auto()
21
- WH_WEIGHT = enum.auto()
22
- WH_PACK = enum.auto()
23
- WH_GIVEN = enum.auto()
24
-
25
- @property
26
- def reverse_flag(self) -> tuple[frozenset[Sizing], WHSettings | None]:
15
+ # Ideally, we would like to use an IntFlag coupled with enum.auto().
16
+ # However, doing many bitwise operations (which happens when nesting too many
17
+ # widgets ...) on IntFlag is orders of magnitude slower than doing the same
18
+ # operations on IntEnum.
19
+ class _ContainerElementSizingFlag(enum.IntEnum):
20
+ # fmt: off
21
+ NONE = 0b000000
22
+ BOX = 0b000001
23
+ FLOW = 0b000010
24
+ FIXED = 0b000100
25
+ WH_WEIGHT = 0b001000
26
+ WH_PACK = 0b010000
27
+ WH_GIVEN = 0b100000
28
+ # fmt: on
29
+
30
+ @staticmethod
31
+ def reverse_flag(bitfield: int) -> tuple[frozenset[Sizing], WHSettings | None]:
27
32
  """Get flag in public API format."""
28
33
  sizing: set[Sizing] = set()
29
34
 
30
- if self & self.BOX:
35
+ if bitfield & _ContainerElementSizingFlag.BOX:
31
36
  sizing.add(Sizing.BOX)
32
- if self & self.FLOW:
37
+ if bitfield & _ContainerElementSizingFlag.FLOW:
33
38
  sizing.add(Sizing.FLOW)
34
- if self & self.FIXED:
39
+ if bitfield & _ContainerElementSizingFlag.FIXED:
35
40
  sizing.add(Sizing.FIXED)
36
41
 
37
- if self & self.WH_WEIGHT:
42
+ if bitfield & _ContainerElementSizingFlag.WH_WEIGHT:
38
43
  return frozenset(sizing), WHSettings.WEIGHT
39
- if self & self.WH_PACK:
44
+ if bitfield & _ContainerElementSizingFlag.WH_PACK:
40
45
  return frozenset(sizing), WHSettings.PACK
41
- if self & self.WH_GIVEN:
46
+ if bitfield & _ContainerElementSizingFlag.WH_GIVEN:
42
47
  return frozenset(sizing), WHSettings.GIVEN
43
48
  return frozenset(sizing), None
44
49
 
45
- @property
46
- def log_string(self) -> str:
50
+ @staticmethod
51
+ def log_string(bitfield: int) -> str:
47
52
  """Get desctiprion in public API format."""
48
- sizing, render = self.reverse_flag
53
+ sizing, render = _ContainerElementSizingFlag.reverse_flag(bitfield)
49
54
  render_string = f" {render.upper()}" if render else ""
50
55
  return "|".join(sorted(mode.upper() for mode in sizing)) + render_string
51
56
 
@@ -115,12 +120,11 @@ class WidgetContainerMixin:
115
120
  """
116
121
  out = []
117
122
  w = self
118
- while True:
119
- w = w.base_widget.focus
120
- if w is None:
121
- return out
123
+ while (w := w.base_widget.focus) is not None:
122
124
  out.append(w)
123
125
 
126
+ return out
127
+
124
128
  @property
125
129
  @abc.abstractmethod
126
130
  def focus(self) -> Widget:
@@ -130,15 +134,6 @@ class WidgetContainerMixin:
130
134
  always returns ``None``, indicating that this widget has no children.
131
135
  """
132
136
 
133
- def _get_focus(self) -> Widget:
134
- warnings.warn(
135
- f"method `{self.__class__.__name__}._get_focus` is deprecated, "
136
- f"please use `{self.__class__.__name__}.focus` property",
137
- DeprecationWarning,
138
- stacklevel=3,
139
- )
140
- return self.focus
141
-
142
137
 
143
138
  class WidgetContainerListContentsMixin:
144
139
  """
@@ -172,24 +167,6 @@ class WidgetContainerListContentsMixin:
172
167
  def contents(self, new_contents: list[tuple[Widget, typing.Any]]) -> None:
173
168
  """The contents of container as a list of (widget, options)"""
174
169
 
175
- def _get_contents(self) -> list[tuple[Widget, typing.Any]]:
176
- warnings.warn(
177
- f"method `{self.__class__.__name__}._get_contents` is deprecated, "
178
- f"please use `{self.__class__.__name__}.contents` property",
179
- DeprecationWarning,
180
- stacklevel=2,
181
- )
182
- return self.contents
183
-
184
- def _set_contents(self, c: list[tuple[Widget, typing.Any]]) -> None:
185
- warnings.warn(
186
- f"method `{self.__class__.__name__}._set_contents` is deprecated, "
187
- f"please use `{self.__class__.__name__}.contents` property",
188
- DeprecationWarning,
189
- stacklevel=2,
190
- )
191
- self.contents = c
192
-
193
170
  @property
194
171
  @abc.abstractmethod
195
172
  def focus_position(self) -> int | None:
@@ -202,26 +179,3 @@ class WidgetContainerListContentsMixin:
202
179
  """
203
180
  index of child widget in focus.
204
181
  """
205
-
206
- def _get_focus_position(self) -> int | None:
207
- warnings.warn(
208
- f"method `{self.__class__.__name__}._get_focus_position` is deprecated, "
209
- f"please use `{self.__class__.__name__}.focus_position` property",
210
- DeprecationWarning,
211
- stacklevel=3,
212
- )
213
- return self.focus_position
214
-
215
- def _set_focus_position(self, position: int) -> None:
216
- """
217
- Set the widget in focus.
218
-
219
- position -- index of child widget to be made focus
220
- """
221
- warnings.warn(
222
- f"method `{self.__class__.__name__}._set_focus_position` is deprecated, "
223
- f"please use `{self.__class__.__name__}.focus_position` property",
224
- DeprecationWarning,
225
- stacklevel=3,
226
- )
227
- self.focus_position = position
urwid/widget/edit.py CHANGED
@@ -595,7 +595,7 @@ class Edit(Text):
595
595
  >>> c.cursor
596
596
  (5, 0)
597
597
  """
598
- self._shift_view_to_cursor = bool(focus) # noqa: FURB123,RUF100
598
+ self._shift_view_to_cursor = bool(focus)
599
599
 
600
600
  canv: TextCanvas | CompositeCanvas = super().render(size, focus)
601
601
  if focus:
@@ -698,15 +698,15 @@ class IntEdit(Edit):
698
698
  >>> print(e.edit_text)
699
699
  2
700
700
  """
701
- unhandled = super().keypress(size, key)
701
+ if unhandled := super().keypress(size, key):
702
+ return unhandled
702
703
 
703
- if not unhandled:
704
- # trim leading zeros
705
- while self.edit_pos > 0 and self.edit_text[:1] == "0":
706
- self.set_edit_pos(self.edit_pos - 1)
707
- self.set_edit_text(self.edit_text[1:])
704
+ # trim leading zeros
705
+ while self.edit_pos > 0 and self.edit_text[:1] == "0":
706
+ self.set_edit_pos(self.edit_pos - 1)
707
+ self.set_edit_text(self.edit_text[1:])
708
708
 
709
- return unhandled
709
+ return None
710
710
 
711
711
  def value(self) -> int:
712
712
  """