urwid 2.6.4__tar.gz → 2.6.6__tar.gz

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.
Files changed (316) hide show
  1. {urwid-2.6.4 → urwid-2.6.6}/.pre-commit-config.yaml +2 -2
  2. {urwid-2.6.4 → urwid-2.6.6}/PKG-INFO +1 -1
  3. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/bigtext.py +21 -9
  4. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/real_browse.py +3 -1
  5. {urwid-2.6.4 → urwid-2.6.6}/examples/bigtext.py +21 -9
  6. {urwid-2.6.4 → urwid-2.6.6}/examples/browse.py +3 -1
  7. urwid-2.6.6/pylint-requirements.txt +1 -0
  8. {urwid-2.6.4 → urwid-2.6.6}/pyproject.toml +4 -0
  9. {urwid-2.6.4 → urwid-2.6.6}/tests/test_columns.py +82 -3
  10. {urwid-2.6.4 → urwid-2.6.6}/tests/test_doctests.py +1 -1
  11. {urwid-2.6.4 → urwid-2.6.6}/tests/test_grid_flow.py +53 -0
  12. urwid-2.6.6/tests/test_tree.py +273 -0
  13. {urwid-2.6.4 → urwid-2.6.6}/urwid/__init__.py +46 -33
  14. {urwid-2.6.4 → urwid-2.6.6}/urwid/canvas.py +4 -6
  15. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/_posix_raw_display.py +3 -4
  16. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/_raw_display_base.py +4 -5
  17. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/_win32_raw_display.py +1 -2
  18. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/curses.py +1 -1
  19. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/html_fragment.py +1 -1
  20. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/__init__.py +5 -5
  21. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/main_loop.py +26 -21
  22. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/zmq_loop.py +2 -2
  23. {urwid-2.6.4 → urwid-2.6.6}/urwid/numedit.py +5 -1
  24. {urwid-2.6.4 → urwid-2.6.6}/urwid/signals.py +1 -1
  25. {urwid-2.6.4 → urwid-2.6.6}/urwid/str_util.py +1 -2
  26. {urwid-2.6.4 → urwid-2.6.6}/urwid/text_layout.py +8 -4
  27. {urwid-2.6.4 → urwid-2.6.6}/urwid/version.py +2 -2
  28. {urwid-2.6.4 → urwid-2.6.6}/urwid/vterm.py +10 -10
  29. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/__init__.py +19 -1
  30. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/bar_graph.py +8 -4
  31. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/big_text.py +14 -4
  32. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/box_adapter.py +11 -3
  33. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/columns.py +104 -34
  34. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/constants.py +43 -76
  35. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/container.py +2 -2
  36. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/divider.py +5 -1
  37. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/edit.py +20 -14
  38. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/filler.py +11 -4
  39. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/frame.py +91 -28
  40. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/grid_flow.py +66 -15
  41. {urwid-2.6.4/urwid → urwid-2.6.6/urwid/widget}/listbox.py +27 -23
  42. {urwid-2.6.4/urwid → urwid-2.6.6/urwid/widget}/monitored_list.py +2 -0
  43. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/overlay.py +99 -14
  44. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/padding.py +16 -3
  45. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/pile.py +57 -13
  46. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/progress_bar.py +5 -1
  47. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/scrollable.py +28 -9
  48. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/solid_fill.py +5 -1
  49. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/text.py +11 -3
  50. {urwid-2.6.4/urwid → urwid-2.6.6/urwid/widget}/treetools.py +35 -18
  51. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/widget.py +17 -9
  52. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/wimp.py +8 -4
  53. {urwid-2.6.4 → urwid-2.6.6}/urwid.egg-info/PKG-INFO +1 -1
  54. {urwid-2.6.4 → urwid-2.6.6}/urwid.egg-info/SOURCES.txt +3 -3
  55. urwid-2.6.4/pylint-requirements.txt +0 -1
  56. urwid-2.6.4/tests/test_tree.py +0 -102
  57. {urwid-2.6.4 → urwid-2.6.6}/.coveralls.yml +0 -0
  58. {urwid-2.6.4 → urwid-2.6.6}/.devcontainer/dev.dockerfile +0 -0
  59. {urwid-2.6.4 → urwid-2.6.6}/.devcontainer/devcontainer.json +0 -0
  60. {urwid-2.6.4 → urwid-2.6.6}/.dockerignore +0 -0
  61. {urwid-2.6.4 → urwid-2.6.6}/.github/CODE_OF_CONDUCT.md +0 -0
  62. {urwid-2.6.4 → urwid-2.6.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  63. {urwid-2.6.4 → urwid-2.6.6}/.github/ISSUE_TEMPLATE/docs.md +0 -0
  64. {urwid-2.6.4 → urwid-2.6.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  65. {urwid-2.6.4 → urwid-2.6.6}/.github/ISSUE_TEMPLATE/question.md +0 -0
  66. {urwid-2.6.4 → urwid-2.6.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  67. {urwid-2.6.4 → urwid-2.6.6}/.github/dependabot.yml +0 -0
  68. {urwid-2.6.4 → urwid-2.6.6}/.github/labeler.yml +0 -0
  69. {urwid-2.6.4 → urwid-2.6.6}/.github/release.yml +0 -0
  70. {urwid-2.6.4 → urwid-2.6.6}/.github/workflows/documentation.yml +0 -0
  71. {urwid-2.6.4 → urwid-2.6.6}/.github/workflows/isolated_static_check.yml +0 -0
  72. {urwid-2.6.4 → urwid-2.6.6}/.github/workflows/labels.yml +0 -0
  73. {urwid-2.6.4 → urwid-2.6.6}/.github/workflows/pythonpackage.yml +0 -0
  74. {urwid-2.6.4 → urwid-2.6.6}/.github/workflows/yamllint.yml +0 -0
  75. {urwid-2.6.4 → urwid-2.6.6}/.gitignore +0 -0
  76. {urwid-2.6.4 → urwid-2.6.6}/.yamllint.yml +0 -0
  77. {urwid-2.6.4 → urwid-2.6.6}/COPYING +0 -0
  78. {urwid-2.6.4 → urwid-2.6.6}/MANIFEST.in +0 -0
  79. {urwid-2.6.4 → urwid-2.6.6}/README.rst +0 -0
  80. {urwid-2.6.4 → urwid-2.6.6}/black-requirements.txt +0 -0
  81. {urwid-2.6.4 → urwid-2.6.6}/classifiers.txt +0 -0
  82. {urwid-2.6.4 → urwid-2.6.6}/docs/Makefile +0 -0
  83. {urwid-2.6.4 → urwid-2.6.6}/docs/changelog.rst +0 -0
  84. {urwid-2.6.4 → urwid-2.6.6}/docs/conf.py +0 -0
  85. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/bigtext.py.xdotool +0 -0
  86. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/bigtext1.png +0 -0
  87. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/bigtext2.png +0 -0
  88. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/bigtext3.png +0 -0
  89. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/browse.py +0 -0
  90. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/browse.py.xdotool +0 -0
  91. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/browse1.png +0 -0
  92. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/browse2.png +0 -0
  93. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/edit.py +0 -0
  94. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/edit.py.xdotool +0 -0
  95. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/edit1.png +0 -0
  96. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/edit2.png +0 -0
  97. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/edit_text.txt +0 -0
  98. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/graph.py +0 -0
  99. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/graph.py.xdotool +0 -0
  100. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/graph1.png +0 -0
  101. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/graph2.png +0 -0
  102. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/index.rst +0 -0
  103. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/palette_test.py +0 -0
  104. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/palette_test.py.xdotool +0 -0
  105. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/palette_test1.png +0 -0
  106. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/palette_test2.png +0 -0
  107. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/pop_up.py +0 -0
  108. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/pop_up.py.xdotool +0 -0
  109. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/pop_up1.png +0 -0
  110. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/pop_up2.png +0 -0
  111. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/real_edit.py +0 -0
  112. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/subproc.py +0 -0
  113. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/subproc.py.xdotool +0 -0
  114. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/subproc1.png +0 -0
  115. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/subproc2.png +0 -0
  116. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/subproc2.py +0 -0
  117. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/tour.py +0 -0
  118. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/tour.py.xdotool +0 -0
  119. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/tour1.png +0 -0
  120. {urwid-2.6.4 → urwid-2.6.6}/docs/examples/tour2.png +0 -0
  121. {urwid-2.6.4 → urwid-2.6.6}/docs/index.rst +0 -0
  122. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/bright_combinations.py +0 -0
  123. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/bright_combinations.py.xdotool +0 -0
  124. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/bright_combinations1.png +0 -0
  125. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/canvascache.rst +0 -0
  126. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/displayattributes.rst +0 -0
  127. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/displaymodules.rst +0 -0
  128. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/encodings.rst +0 -0
  129. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/display_modules.png +0 -0
  130. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/introduction.png +0 -0
  131. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/urwid_widgets.svgz +0 -0
  132. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/urwid_widgets_1.png +0 -0
  133. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/urwid_widgets_1.xcf +0 -0
  134. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/urwid_widgets_2.png +0 -0
  135. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/urwid_widgets_2.xcf +0 -0
  136. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/images/widget_layout.png +0 -0
  137. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/index.rst +0 -0
  138. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/mainloop.rst +0 -0
  139. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/overview.rst +0 -0
  140. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/safe_combinations.py +0 -0
  141. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/safe_combinations.py.xdotool +0 -0
  142. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/safe_combinations1.png +0 -0
  143. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/textlayout.rst +0 -0
  144. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/userinput.rst +0 -0
  145. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/wanat.py +0 -0
  146. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/wanat_multi.py +0 -0
  147. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/wcur1.py +0 -0
  148. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/wcur2.py +0 -0
  149. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/widgets.rst +0 -0
  150. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/wmod.py +0 -0
  151. {urwid-2.6.4 → urwid-2.6.6}/docs/manual/wsel.py +0 -0
  152. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/attrspec.rst +0 -0
  153. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/canvas.rst +0 -0
  154. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/command_map.rst +0 -0
  155. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/constants.rst +0 -0
  156. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/deprecated.rst +0 -0
  157. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/display_modules.rst +0 -0
  158. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/exceptions.rst +0 -0
  159. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/global_settings.rst +0 -0
  160. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/index.rst +0 -0
  161. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/list_walkers.rst +0 -0
  162. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/main_loop.rst +0 -0
  163. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/meta.rst +0 -0
  164. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/signals.rst +0 -0
  165. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/text_layout.rst +0 -0
  166. {urwid-2.6.4 → urwid-2.6.6}/docs/reference/widget.rst +0 -0
  167. {urwid-2.6.4 → urwid-2.6.6}/docs/tools/compile_pngs.sh +0 -0
  168. {urwid-2.6.4 → urwid-2.6.6}/docs/tools/screenshots.sh +0 -0
  169. {urwid-2.6.4 → urwid-2.6.6}/docs/tools/static/.placeholder +0 -0
  170. {urwid-2.6.4 → urwid-2.6.6}/docs/tools/templates/indexcontent.html +0 -0
  171. {urwid-2.6.4 → urwid-2.6.6}/docs/tools/templates/indexsidebar.html +0 -0
  172. {urwid-2.6.4 → urwid-2.6.6}/docs/tools/templates/localtoc.html +0 -0
  173. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/adventure.py +0 -0
  174. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/adventure.py.xdotool +0 -0
  175. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/adventure1.png +0 -0
  176. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/adventure2.png +0 -0
  177. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/adventure3.png +0 -0
  178. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/adventure4.png +0 -0
  179. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/cmenu.py +0 -0
  180. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/cmenu.py.xdotool +0 -0
  181. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/cmenu1.png +0 -0
  182. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/cmenu2.png +0 -0
  183. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/cmenu3.png +0 -0
  184. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/cmenu4.png +0 -0
  185. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/highcolors.py +0 -0
  186. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/highcolors.py.xdotool +0 -0
  187. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/highcolors1.png +0 -0
  188. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/hmenu.py +0 -0
  189. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/hmenu.py.xdotool +0 -0
  190. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/hmenu1.png +0 -0
  191. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/hmenu2.png +0 -0
  192. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/hmenu3.png +0 -0
  193. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/hmenu4.png +0 -0
  194. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/index.rst +0 -0
  195. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input.py +0 -0
  196. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input.py.xdotool +0 -0
  197. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input1.png +0 -0
  198. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input2.png +0 -0
  199. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input3.png +0 -0
  200. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input4.png +0 -0
  201. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/input5.png +0 -0
  202. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/menu25.png +0 -0
  203. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/minimal.py +0 -0
  204. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/minimal.py.xdotool +0 -0
  205. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/minimal1.png +0 -0
  206. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/multiple.py +0 -0
  207. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/multiple.py.xdotool +0 -0
  208. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/multiple1.png +0 -0
  209. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/multiple2.png +0 -0
  210. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/multiple3.png +0 -0
  211. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/multiple4.png +0 -0
  212. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/qa.py +0 -0
  213. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/qa.py.xdotool +0 -0
  214. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/qa1.png +0 -0
  215. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/qa2.png +0 -0
  216. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/qa3.png +0 -0
  217. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/sig.py +0 -0
  218. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/sig.py.xdotool +0 -0
  219. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/sig1.png +0 -0
  220. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/sig2.png +0 -0
  221. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/sig3.png +0 -0
  222. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/sig4.png +0 -0
  223. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/smenu.py +0 -0
  224. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/smenu.py.xdotool +0 -0
  225. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/smenu1.png +0 -0
  226. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/smenu2.png +0 -0
  227. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/smenu3.png +0 -0
  228. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/urwid_attr.py +0 -0
  229. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/urwid_attr.py.xdotool +0 -0
  230. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/urwid_attr1.png +0 -0
  231. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/urwid_attr2.png +0 -0
  232. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/urwid_attr3.png +0 -0
  233. {urwid-2.6.4 → urwid-2.6.6}/docs/tutorial/urwid_attr4.png +0 -0
  234. {urwid-2.6.4 → urwid-2.6.6}/docs/urwid-logo.png +0 -0
  235. {urwid-2.6.4 → urwid-2.6.6}/examples/asyncio_socket_server.py +0 -0
  236. {urwid-2.6.4 → urwid-2.6.6}/examples/calc.py +0 -0
  237. {urwid-2.6.4 → urwid-2.6.6}/examples/dialog.py +0 -0
  238. {urwid-2.6.4 → urwid-2.6.6}/examples/edit.py +0 -0
  239. {urwid-2.6.4 → urwid-2.6.6}/examples/fib.py +0 -0
  240. {urwid-2.6.4 → urwid-2.6.6}/examples/graph.py +0 -0
  241. {urwid-2.6.4 → urwid-2.6.6}/examples/input_test.py +0 -0
  242. {urwid-2.6.4 → urwid-2.6.6}/examples/lcd_cf635.py +0 -0
  243. {urwid-2.6.4 → urwid-2.6.6}/examples/palette_test.py +0 -0
  244. {urwid-2.6.4 → urwid-2.6.6}/examples/pop_up.py +0 -0
  245. {urwid-2.6.4 → urwid-2.6.6}/examples/subproc.py +0 -0
  246. {urwid-2.6.4 → urwid-2.6.6}/examples/subproc2.py +0 -0
  247. {urwid-2.6.4 → urwid-2.6.6}/examples/terminal.py +0 -0
  248. {urwid-2.6.4 → urwid-2.6.6}/examples/tour.py +0 -0
  249. {urwid-2.6.4 → urwid-2.6.6}/examples/treesample.py +0 -0
  250. {urwid-2.6.4 → urwid-2.6.6}/examples/twisted_serve_ssh.py +0 -0
  251. {urwid-2.6.4 → urwid-2.6.6}/examples/twisted_serve_ssh.tac +0 -0
  252. {urwid-2.6.4 → urwid-2.6.6}/isort-requirements.txt +0 -0
  253. {urwid-2.6.4 → urwid-2.6.6}/requirements.txt +0 -0
  254. {urwid-2.6.4 → urwid-2.6.6}/ruff-requirements.txt +0 -0
  255. {urwid-2.6.4 → urwid-2.6.6}/setup.cfg +0 -0
  256. {urwid-2.6.4 → urwid-2.6.6}/setup.py +0 -0
  257. {urwid-2.6.4 → urwid-2.6.6}/test_requirements.txt +0 -0
  258. {urwid-2.6.4 → urwid-2.6.6}/tests/__init__.py +0 -0
  259. {urwid-2.6.4 → urwid-2.6.6}/tests/test_canvas.py +0 -0
  260. {urwid-2.6.4 → urwid-2.6.6}/tests/test_container.py +0 -0
  261. {urwid-2.6.4 → urwid-2.6.6}/tests/test_escapes.py +0 -0
  262. {urwid-2.6.4 → urwid-2.6.6}/tests/test_event_loops.py +0 -0
  263. {urwid-2.6.4 → urwid-2.6.6}/tests/test_filler.py +0 -0
  264. {urwid-2.6.4 → urwid-2.6.6}/tests/test_floatedit.py +0 -0
  265. {urwid-2.6.4 → urwid-2.6.6}/tests/test_font.py +0 -0
  266. {urwid-2.6.4 → urwid-2.6.6}/tests/test_frame.py +0 -0
  267. {urwid-2.6.4 → urwid-2.6.6}/tests/test_graphics.py +0 -0
  268. {urwid-2.6.4 → urwid-2.6.6}/tests/test_line_box.py +0 -0
  269. {urwid-2.6.4 → urwid-2.6.6}/tests/test_listbox.py +0 -0
  270. {urwid-2.6.4 → urwid-2.6.6}/tests/test_moved_imports.py +0 -0
  271. {urwid-2.6.4 → urwid-2.6.6}/tests/test_overlay.py +0 -0
  272. {urwid-2.6.4 → urwid-2.6.6}/tests/test_padding.py +0 -0
  273. {urwid-2.6.4 → urwid-2.6.6}/tests/test_pile.py +0 -0
  274. {urwid-2.6.4 → urwid-2.6.6}/tests/test_raw_display.py +0 -0
  275. {urwid-2.6.4 → urwid-2.6.6}/tests/test_scrollable.py +0 -0
  276. {urwid-2.6.4 → urwid-2.6.6}/tests/test_signals.py +0 -0
  277. {urwid-2.6.4 → urwid-2.6.6}/tests/test_str_util.py +0 -0
  278. {urwid-2.6.4 → urwid-2.6.6}/tests/test_text_layout.py +0 -0
  279. {urwid-2.6.4 → urwid-2.6.6}/tests/test_util.py +0 -0
  280. {urwid-2.6.4 → urwid-2.6.6}/tests/test_vterm.py +0 -0
  281. {urwid-2.6.4 → urwid-2.6.6}/tests/test_widget.py +0 -0
  282. {urwid-2.6.4 → urwid-2.6.6}/tests/util.py +0 -0
  283. {urwid-2.6.4 → urwid-2.6.6}/tox.ini +0 -0
  284. {urwid-2.6.4 → urwid-2.6.6}/urwid/command_map.py +0 -0
  285. {urwid-2.6.4 → urwid-2.6.6}/urwid/container.py +0 -0
  286. {urwid-2.6.4 → urwid-2.6.6}/urwid/decoration.py +0 -0
  287. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/__init__.py +0 -0
  288. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/_web.css +0 -0
  289. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/_web.js +0 -0
  290. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/_win32.py +0 -0
  291. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/common.py +0 -0
  292. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/escape.py +0 -0
  293. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/lcd.py +0 -0
  294. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/raw.py +0 -0
  295. {urwid-2.6.4 → urwid-2.6.6}/urwid/display/web.py +0 -0
  296. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/abstract_loop.py +0 -0
  297. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/asyncio_loop.py +0 -0
  298. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/glib_loop.py +0 -0
  299. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/select_loop.py +0 -0
  300. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/tornado_loop.py +0 -0
  301. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/trio_loop.py +0 -0
  302. {urwid-2.6.4 → urwid-2.6.6}/urwid/event_loop/twisted_loop.py +0 -0
  303. {urwid-2.6.4 → urwid-2.6.6}/urwid/font.py +0 -0
  304. {urwid-2.6.4 → urwid-2.6.6}/urwid/graphics.py +0 -0
  305. {urwid-2.6.4 → urwid-2.6.6}/urwid/split_repr.py +0 -0
  306. {urwid-2.6.4 → urwid-2.6.6}/urwid/util.py +0 -0
  307. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/attr_map.py +0 -0
  308. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/attr_wrap.py +0 -0
  309. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/line_box.py +0 -0
  310. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/popup.py +0 -0
  311. {urwid-2.6.4 → urwid-2.6.6}/urwid/widget/widget_decoration.py +0 -0
  312. {urwid-2.6.4 → urwid-2.6.6}/urwid/wimp.py +0 -0
  313. {urwid-2.6.4 → urwid-2.6.6}/urwid.egg-info/dependency_links.txt +0 -0
  314. {urwid-2.6.4 → urwid-2.6.6}/urwid.egg-info/not-zip-safe +0 -0
  315. {urwid-2.6.4 → urwid-2.6.6}/urwid.egg-info/requires.txt +0 -0
  316. {urwid-2.6.4 → urwid-2.6.6}/urwid.egg-info/top_level.txt +0 -0
@@ -26,13 +26,13 @@ repos:
26
26
 
27
27
  - repo: https://github.com/astral-sh/ruff-pre-commit
28
28
  # Ruff version.
29
- rev: v0.2.1
29
+ rev: v0.2.2
30
30
  hooks:
31
31
  - id: ruff
32
32
  args: [ --fix, --exit-non-zero-on-fix ]
33
33
 
34
34
  - repo: https://github.com/adrienverge/yamllint.git
35
- rev: v1.35.0
35
+ rev: v1.35.1
36
36
  hooks:
37
37
  - id: yamllint
38
38
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: urwid
3
- Version: 2.6.4
3
+ Version: 2.6.6
4
4
  Summary: A full-featured console (xterm et al.) user interface library
5
5
  Home-page: https://urwid.org/
6
6
  Author-email: Ian Ward <ian@excess.org>
@@ -34,7 +34,10 @@ if typing.TYPE_CHECKING:
34
34
  from collections.abc import Callable
35
35
 
36
36
 
37
- class SwitchingPadding(urwid.Padding):
37
+ _Wrapped = typing.TypeVar("_Wrapped")
38
+
39
+
40
+ class SwitchingPadding(urwid.Padding[_Wrapped]):
38
41
  def padding_values(self, size, focus: bool) -> tuple[int, int]:
39
42
  maxcol = size[0]
40
43
  width, _height = self.original_widget.pack(size, focus=focus)
@@ -95,7 +98,10 @@ class BigTextDisplay:
95
98
  def edit_change_event(self, widget, text: str) -> None:
96
99
  self.bigtext.set_text(text)
97
100
 
98
- def setup_view(self):
101
+ def setup_view(self) -> tuple[
102
+ urwid.Frame[urwid.AttrMap[urwid.ListBox], urwid.AttrMap[urwid.Text], None],
103
+ urwid.Overlay[urwid.BigText, urwid.Frame[urwid.AttrMap[urwid.ListBox], urwid.AttrMap[urwid.Text], None]],
104
+ ]:
99
105
  fonts = urwid.get_all_fonts()
100
106
  # setup mode radio buttons
101
107
  self.font_buttons = []
@@ -143,17 +149,23 @@ class BigTextDisplay:
143
149
  col = urwid.Columns([(16, chars), fonts], 3, focus_column=1)
144
150
  bt = urwid.Pile([bt, edit], focus_item=1)
145
151
  lines = [bt, urwid.Divider(), col]
146
- w = urwid.ListBox(urwid.SimpleListWalker(lines))
152
+ listbox = urwid.ListBox(urwid.SimpleListWalker(lines))
147
153
 
148
154
  # Frame
149
- w = urwid.AttrMap(w, "body")
150
- hdr = urwid.Text("Urwid BigText example program - F8 exits.")
151
- hdr = urwid.AttrMap(hdr, "header")
152
- w = urwid.Frame(header=hdr, body=w)
155
+ w = urwid.Frame(
156
+ body=urwid.AttrMap(listbox, "body"),
157
+ header=urwid.AttrMap(urwid.Text("Urwid BigText example program - F8 exits."), "header"),
158
+ )
153
159
 
154
160
  # Exit message
155
- exit_w = urwid.BigText(("exit", " Quit? "), exit_font)
156
- exit_w = urwid.Overlay(exit_w, w, urwid.CENTER, None, urwid.MIDDLE, None)
161
+ exit_w = urwid.Overlay(
162
+ urwid.BigText(("exit", " Quit? "), exit_font),
163
+ w,
164
+ urwid.CENTER,
165
+ None,
166
+ urwid.MIDDLE,
167
+ None,
168
+ )
157
169
  return w, exit_w
158
170
 
159
171
  def main(self):
@@ -274,7 +274,9 @@ class DirectoryBrowser:
274
274
  self.listbox.offset_rows = 1
275
275
  self.footer = urwid.AttrMap(urwid.Text(self.footer_text), "foot")
276
276
  self.view = urwid.Frame(
277
- urwid.AttrMap(self.listbox, "body"), header=urwid.AttrMap(self.header, "head"), footer=self.footer
277
+ urwid.AttrMap(self.listbox, "body"),
278
+ header=urwid.AttrMap(self.header, "head"),
279
+ footer=self.footer,
278
280
  )
279
281
 
280
282
  def main(self) -> None:
@@ -34,7 +34,10 @@ if typing.TYPE_CHECKING:
34
34
  from collections.abc import Callable
35
35
 
36
36
 
37
- class SwitchingPadding(urwid.Padding):
37
+ _Wrapped = typing.TypeVar("_Wrapped")
38
+
39
+
40
+ class SwitchingPadding(urwid.Padding[_Wrapped]):
38
41
  def padding_values(self, size, focus: bool) -> tuple[int, int]:
39
42
  maxcol = size[0]
40
43
  width, _height = self.original_widget.pack(size, focus=focus)
@@ -95,7 +98,10 @@ class BigTextDisplay:
95
98
  def edit_change_event(self, widget, text: str) -> None:
96
99
  self.bigtext.set_text(text)
97
100
 
98
- def setup_view(self):
101
+ def setup_view(self) -> tuple[
102
+ urwid.Frame[urwid.AttrMap[urwid.ListBox], urwid.AttrMap[urwid.Text], None],
103
+ urwid.Overlay[urwid.BigText, urwid.Frame[urwid.AttrMap[urwid.ListBox], urwid.AttrMap[urwid.Text], None]],
104
+ ]:
99
105
  fonts = urwid.get_all_fonts()
100
106
  # setup mode radio buttons
101
107
  self.font_buttons = []
@@ -143,17 +149,23 @@ class BigTextDisplay:
143
149
  col = urwid.Columns([(16, chars), fonts], 3, focus_column=1)
144
150
  bt = urwid.Pile([bt, edit], focus_item=1)
145
151
  lines = [bt, urwid.Divider(), col]
146
- w = urwid.ListBox(urwid.SimpleListWalker(lines))
152
+ listbox = urwid.ListBox(urwid.SimpleListWalker(lines))
147
153
 
148
154
  # Frame
149
- w = urwid.AttrMap(w, "body")
150
- hdr = urwid.Text("Urwid BigText example program - F8 exits.")
151
- hdr = urwid.AttrMap(hdr, "header")
152
- w = urwid.Frame(header=hdr, body=w)
155
+ w = urwid.Frame(
156
+ body=urwid.AttrMap(listbox, "body"),
157
+ header=urwid.AttrMap(urwid.Text("Urwid BigText example program - F8 exits."), "header"),
158
+ )
153
159
 
154
160
  # Exit message
155
- exit_w = urwid.BigText(("exit", " Quit? "), exit_font)
156
- exit_w = urwid.Overlay(exit_w, w, urwid.CENTER, None, urwid.MIDDLE, None)
161
+ exit_w = urwid.Overlay(
162
+ urwid.BigText(("exit", " Quit? "), exit_font),
163
+ w,
164
+ urwid.CENTER,
165
+ None,
166
+ urwid.MIDDLE,
167
+ None,
168
+ )
157
169
  return w, exit_w
158
170
 
159
171
  def main(self):
@@ -274,7 +274,9 @@ class DirectoryBrowser:
274
274
  self.listbox.offset_rows = 1
275
275
  self.footer = urwid.AttrMap(urwid.Text(self.footer_text), "foot")
276
276
  self.view = urwid.Frame(
277
- urwid.AttrMap(self.listbox, "body"), header=urwid.AttrMap(self.header, "head"), footer=self.footer
277
+ urwid.AttrMap(self.listbox, "body"),
278
+ header=urwid.AttrMap(self.header, "head"),
279
+ footer=self.footer,
278
280
  )
279
281
 
280
282
  def main(self) -> None:
@@ -0,0 +1 @@
1
+ pylint==3.1.0
@@ -90,6 +90,10 @@ exclude_lines = [
90
90
 
91
91
  # Don't complain about missing debug-only code:
92
92
  "def __repr__",
93
+ "def __rich_repr__",
94
+ # own repr construct magic
95
+ "def _repr_words",
96
+ "def _repr_attrs",
93
97
 
94
98
  # Don't complain if tests don't hit defensive assertion code:
95
99
  "raise NotImplementedError",
@@ -80,13 +80,40 @@ class ColumnsTest(unittest.TestCase):
80
80
 
81
81
  with self.subTest("FIXED only"):
82
82
  widget = urwid.Columns(((urwid.PACK, fixed_only),))
83
- self.assertEqual(frozenset((urwid.FIXED,)), widget.sizing())
83
+ self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
84
84
  cols, rows = 3, 3
85
85
  self.assertEqual((cols, rows), widget.pack(()))
86
86
  canvas = widget.render(())
87
87
  self.assertEqual(cols, canvas.cols())
88
88
  self.assertEqual(rows, canvas.rows())
89
89
 
90
+ with self.subTest("FIXED only use FLOW methods - drop & replace by solid"):
91
+ widget = urwid.Columns(((urwid.PACK, fixed_only),))
92
+ self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
93
+ cols, rows = 2, 1
94
+ self.assertEqual((cols, rows), widget.pack((cols,)))
95
+ canvas = widget.render((cols,))
96
+ self.assertEqual(cols, canvas.cols())
97
+ self.assertEqual(rows, canvas.rows())
98
+ self.assertEqual(" ", str(canvas))
99
+
100
+ with self.subTest("FIXED only use FLOW methods - add empty space"):
101
+ widget = urwid.Columns(((urwid.PACK, fixed_only),))
102
+ self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
103
+ cols, rows = 5, 3
104
+ self.assertEqual((cols, rows), widget.pack((cols,)))
105
+ canvas = widget.render((cols,))
106
+ self.assertEqual(cols, canvas.cols())
107
+ self.assertEqual(rows, canvas.rows())
108
+ self.assertEqual(
109
+ (
110
+ "┌─┐ ",
111
+ "│ │ ",
112
+ "└─┘ ",
113
+ ),
114
+ canvas.decoded_text,
115
+ )
116
+
90
117
  with self.subTest("GIVEN BOX + FLOW/FIXED, but other widgets do not support box"):
91
118
  widget = urwid.Columns((flow_fixed, (3, box_only)), box_columns=(1,))
92
119
  self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
@@ -153,8 +180,7 @@ class ColumnsTest(unittest.TestCase):
153
180
  )
154
181
 
155
182
  cols, rows = 30, 1
156
- with self.assertRaises(AttributeError):
157
- widget.pack((cols,))
183
+ self.assertEqual((cols, rows), widget.pack((cols,)))
158
184
 
159
185
  canvas = widget.render((cols,))
160
186
  self.assertEqual(rows, canvas.rows())
@@ -241,6 +267,59 @@ class ColumnsTest(unittest.TestCase):
241
267
  str(ctx.warnings[0].message),
242
268
  )
243
269
 
270
+ def test_pack_render_skip_widget(self):
271
+ widget = urwid.Columns(((0, urwid.Text("Ignore\nme")), (urwid.Text("Count"))))
272
+ cols, rows = 5, 1
273
+ self.assertEqual((cols, rows), widget.pack(()))
274
+ self.assertEqual((cols, rows), widget.pack((cols,)))
275
+ self.assertEqual("Count", str(widget.render(())))
276
+ self.assertEqual("Count", str(widget.render((cols,))))
277
+
278
+ def test_pack_flow_with_fixed_item(self):
279
+ widget = urwid.Columns(
280
+ (
281
+ (urwid.PACK, urwid.BigText("3", urwid.Thin3x3Font())),
282
+ (urwid.Text("Multi\nline\ntext\n???")),
283
+ ),
284
+ dividechars=1,
285
+ )
286
+ with self.subTest("Skip"):
287
+ self.assertEqual(3, widget.rows((3,)))
288
+ self.assertEqual((3, 3), widget.pack((3,)))
289
+ self.assertEqual(
290
+ (
291
+ "┌─┐",
292
+ " ─┤",
293
+ "└─┘",
294
+ ),
295
+ widget.render((3,)).decoded_text,
296
+ )
297
+ with self.subTest("Fit all"):
298
+ self.assertEqual(4, widget.rows((9,)))
299
+ self.assertEqual((9, 4), widget.pack((9,)))
300
+ self.assertEqual(
301
+ (
302
+ "┌─┐ Multi",
303
+ " ─┤ line ",
304
+ "└─┘ text ",
305
+ " ??? ",
306
+ ),
307
+ widget.render((9,)).decoded_text,
308
+ )
309
+ with self.subTest("Use SolidCanvas instead"):
310
+ self.assertEqual(1, widget.rows((2,)))
311
+ self.assertEqual((2, 1), widget.pack((2,)))
312
+ self.assertEqual((" ",), widget.render((2,)).decoded_text)
313
+
314
+ def test_pack_render_empty_widget(self):
315
+ widget = urwid.Columns(())
316
+ self.assertEqual(frozenset((urwid.FLOW, urwid.BOX)), widget.sizing())
317
+ cols, rows = 10, 1
318
+ self.assertEqual((cols, rows), widget.pack((cols,)))
319
+ canvas = widget.render((cols,))
320
+ self.assertEqual(rows, canvas.rows())
321
+ self.assertEqual((" ",), canvas.decoded_text)
322
+
244
323
  def test_not_a_widget(self):
245
324
  class NotAWidget:
246
325
  __slots__ = ("name", "symbol")
@@ -34,11 +34,11 @@ def load_tests(loader: unittest.TestLoader, tests: unittest.BaseTestSuite, ignor
34
34
  urwid.widget.widget,
35
35
  urwid.widget.widget_decoration,
36
36
  urwid.widget.wimp,
37
+ urwid.widget.monitored_list,
37
38
  urwid.display.common,
38
39
  urwid.display.raw,
39
40
  urwid.event_loop.main_loop,
40
41
  urwid.numedit,
41
- urwid.monitored_list,
42
42
  urwid.raw_display,
43
43
  urwid.font,
44
44
  "urwid.split_repr", # override function with same name
@@ -84,6 +84,59 @@ class GridFlowTest(unittest.TestCase):
84
84
  gf = urwid.GridFlow([], 5, 0, 0, "left")
85
85
  self.assertEqual(gf.cell_width, 5)
86
86
 
87
+ def test_not_fit(self):
88
+ """Test scenario with maxcol < cell_width (special case, warning will be produced)."""
89
+ widget = urwid.GridFlow(
90
+ [urwid.Button("first"), urwid.Button("second")],
91
+ 5,
92
+ 0,
93
+ 0,
94
+ "left",
95
+ )
96
+ size = (3,)
97
+ with self.assertWarns(urwid.widget.GridFlowWarning):
98
+ canvas = widget.render(size)
99
+
100
+ self.assertEqual(
101
+ ("< f", " i", " r", " s", " t", "< s", " e", " c", " o", " n", " d"),
102
+ canvas.decoded_text,
103
+ )
104
+
105
+ def test_multiline(self):
106
+ """Test widgets fit only with multiple lines"""
107
+ widget = urwid.GridFlow(
108
+ [urwid.Button("first"), urwid.Button("second")],
109
+ 10,
110
+ 0,
111
+ 0,
112
+ "left",
113
+ )
114
+ size = (10,)
115
+ canvas = widget.render(size)
116
+ self.assertEqual(
117
+ ("< first >", "< second >"),
118
+ canvas.decoded_text,
119
+ )
120
+
121
+ def test_multiline_2(self):
122
+ """Test widgets fit only with multiple lines"""
123
+ widget = urwid.GridFlow(
124
+ [urwid.Button("first"), urwid.Button("second"), urwid.Button("third"), urwid.Button("forth")],
125
+ 10,
126
+ 0,
127
+ 0,
128
+ "left",
129
+ )
130
+ size = (20,)
131
+ canvas = widget.render(size)
132
+ self.assertEqual(
133
+ (
134
+ "< first >< second >",
135
+ "< third >< forth >",
136
+ ),
137
+ canvas.decoded_text,
138
+ )
139
+
87
140
  def test_basics(self):
88
141
  repr(urwid.GridFlow([], 5, 0, 0, "left")) # should not fail
89
142
 
@@ -0,0 +1,273 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ import unittest
5
+ from typing import Collection
6
+
7
+ import urwid
8
+ from urwid import TreeNode
9
+
10
+ if typing.TYPE_CHECKING:
11
+ from collections.abc import Hashable, Iterable
12
+
13
+
14
+ class SelfRegisteringParent(urwid.ParentNode):
15
+ def __init__(
16
+ self,
17
+ value: str,
18
+ parent: SelfRegisteringParent | None = None,
19
+ key: Hashable = None,
20
+ depth: int | None = None,
21
+ children: Iterable[SelfRegisteringChild | SelfRegisteringParent] = (),
22
+ ) -> None:
23
+ super().__init__(value, parent, key, depth)
24
+ if parent:
25
+ parent.set_child_node(key, self)
26
+
27
+ self._child_keys = []
28
+ for child in children:
29
+ key = child.get_key()
30
+ self._children[key] = child
31
+ self._child_keys.append(key)
32
+ child.set_parent(self)
33
+
34
+ def load_child_keys(self) -> Collection[Hashable]:
35
+ return list(self._children)
36
+
37
+ def set_child_node(self, key: Hashable, node: TreeNode) -> None:
38
+ super().set_child_node(key, node)
39
+ self._child_keys = self.load_child_keys()
40
+
41
+ def set_parent(self, parent: SelfRegisteringParent) -> None:
42
+ self._parent = parent
43
+
44
+
45
+ class SelfRegisteringChild(urwid.TreeNode):
46
+ def __init__(
47
+ self,
48
+ value: str,
49
+ parent: SelfRegisteringParent | None = None,
50
+ key: Hashable | None = None,
51
+ depth: int | None = None,
52
+ ) -> None:
53
+ super().__init__(value, parent, key, depth)
54
+ if parent:
55
+ parent.set_child_node(key, self)
56
+
57
+ def set_parent(self, parent: SelfRegisteringParent) -> None:
58
+ self._parent = parent
59
+
60
+
61
+ class TestTree(unittest.TestCase):
62
+ def test_basic(self):
63
+ root = SelfRegisteringParent(
64
+ "root",
65
+ key="/",
66
+ children=(SelfRegisteringChild(f"child_{idx}", key=str(idx)) for idx in range(1, 4)),
67
+ )
68
+
69
+ widget = urwid.TreeListBox(urwid.TreeWalker(root))
70
+ size = (15, 5)
71
+ expanded = (
72
+ "- /: root ",
73
+ " 1: child_1 ",
74
+ " 2: child_2 ",
75
+ " 3: child_3 ",
76
+ " ",
77
+ )
78
+ collapsed = (
79
+ "+ /: root ",
80
+ *(" " * size[0] for _ in range(size[1] - 1)),
81
+ )
82
+ self.assertEqual(expanded, widget.render(size).decoded_text)
83
+ widget.keypress(size, "-")
84
+ self.assertEqual(collapsed, widget.render(size).decoded_text)
85
+ widget.keypress(size, "+")
86
+ self.assertEqual(expanded, widget.render(size).decoded_text)
87
+ widget.keypress(size, "down")
88
+ self.assertIs(root, widget.focus_position)
89
+ widget.keypress(size, "-")
90
+ self.assertEqual(collapsed, widget.render(size).decoded_text)
91
+ widget.keypress(size, "right")
92
+ self.assertEqual(expanded, widget.render(size).decoded_text)
93
+
94
+ def test_nested_behavior(self):
95
+ root = SelfRegisteringParent(
96
+ "root",
97
+ key="/",
98
+ children=(
99
+ SelfRegisteringParent(
100
+ f"nested_{idx}",
101
+ key=f"{idx}/",
102
+ children=(SelfRegisteringChild(f"child_{idx}{cidx}", key=str(cidx)) for cidx in range(1, 4)),
103
+ )
104
+ for idx in range(1, 4)
105
+ ),
106
+ )
107
+ widget = urwid.TreeListBox(urwid.TreeWalker(root))
108
+ size = (18, 13)
109
+ expanded = (
110
+ "- /: root ",
111
+ " - 1/: nested_1 ",
112
+ " 1: child_11 ",
113
+ " 2: child_12 ",
114
+ " 3: child_13 ",
115
+ " - 2/: nested_2 ",
116
+ " 1: child_21 ",
117
+ " 2: child_22 ",
118
+ " 3: child_23 ",
119
+ " - 3/: nested_3 ",
120
+ " 1: child_31 ",
121
+ " 2: child_32 ",
122
+ " 3: child_33 ",
123
+ )
124
+ collapsed = (
125
+ "+ /: root ",
126
+ *(" " * size[0] for _ in range(size[1] - 1)),
127
+ )
128
+ self.assertEqual(expanded, widget.render(size).decoded_text)
129
+ widget.keypress(size, "-")
130
+ self.assertEqual(collapsed, widget.render(size).decoded_text)
131
+ widget.keypress(size, "+")
132
+ self.assertEqual(expanded, widget.render(size).decoded_text)
133
+ widget.keypress(size, "down")
134
+ widget.keypress(size, "-")
135
+ self.assertEqual(
136
+ (
137
+ "- /: root ",
138
+ " + 1/: nested_1 ",
139
+ " - 2/: nested_2 ",
140
+ " 1: child_21 ",
141
+ " 2: child_22 ",
142
+ " 3: child_23 ",
143
+ " - 3/: nested_3 ",
144
+ " 1: child_31 ",
145
+ " 2: child_32 ",
146
+ " 3: child_33 ",
147
+ " ",
148
+ " ",
149
+ " ",
150
+ ),
151
+ widget.render(size).decoded_text,
152
+ )
153
+ widget.keypress(size, "right")
154
+ self.assertEqual(expanded, widget.render(size).decoded_text)
155
+ widget.keypress(size, "left")
156
+ widget.keypress(size, "-")
157
+ self.assertEqual(collapsed, widget.render(size).decoded_text)
158
+ widget.keypress(size, "+")
159
+ widget.keypress(size, "page down")
160
+ widget.keypress(size, "-")
161
+ self.assertEqual(
162
+ (
163
+ "- /: root ",
164
+ " - 1/: nested_1 ",
165
+ " 1: child_11 ",
166
+ " 2: child_12 ",
167
+ " 3: child_13 ",
168
+ " - 2/: nested_2 ",
169
+ " 1: child_21 ",
170
+ " 2: child_22 ",
171
+ " 3: child_23 ",
172
+ " + 3/: nested_3 ",
173
+ " ",
174
+ " ",
175
+ " ",
176
+ ),
177
+ widget.render(size).decoded_text,
178
+ )
179
+
180
+ def test_deep_nested_collapse_expand(self):
181
+ root = SelfRegisteringParent(
182
+ "root",
183
+ key="/",
184
+ children=(
185
+ SelfRegisteringParent(
186
+ f"nested_{top_idx}",
187
+ key=f"{top_idx}/",
188
+ children=(
189
+ SelfRegisteringParent(
190
+ f"nested_{top_idx}{first_idx}",
191
+ key=f"{first_idx}/",
192
+ children=(
193
+ SelfRegisteringChild(f"child_{top_idx}{first_idx}{last_idx}", key=str(last_idx))
194
+ for last_idx in range(1, 3)
195
+ ),
196
+ )
197
+ for first_idx in range(1, 3)
198
+ ),
199
+ )
200
+ for top_idx in range(1, 3)
201
+ ),
202
+ )
203
+ widget = urwid.TreeListBox(urwid.TreeWalker(root))
204
+ size = (21, 15)
205
+ expanded = (
206
+ "- /: root ",
207
+ " - 1/: nested_1 ",
208
+ " - 1/: nested_11",
209
+ " 1: child_111",
210
+ " 2: child_112",
211
+ " - 2/: nested_12",
212
+ " 1: child_121",
213
+ " 2: child_122",
214
+ " - 2/: nested_2 ",
215
+ " - 1/: nested_21",
216
+ " 1: child_211",
217
+ " 2: child_212",
218
+ " - 2/: nested_22",
219
+ " 1: child_221",
220
+ " 2: child_222",
221
+ )
222
+ collapsed = (
223
+ "+ /: root ",
224
+ *(" " * size[0] for _ in range(size[1] - 1)),
225
+ )
226
+ collapsed_last = (
227
+ "- /: root ",
228
+ " - 1/: nested_1 ",
229
+ " - 1/: nested_11",
230
+ " 1: child_111",
231
+ " 2: child_112",
232
+ " - 2/: nested_12",
233
+ " 1: child_121",
234
+ " 2: child_122",
235
+ " - 2/: nested_2 ",
236
+ " - 1/: nested_21",
237
+ " 1: child_211",
238
+ " 2: child_212",
239
+ " + 2/: nested_22",
240
+ " ",
241
+ " ",
242
+ )
243
+ self.assertEqual(expanded, widget.render(size).decoded_text)
244
+ widget.keypress(size, "page down")
245
+ widget.keypress(size, "-")
246
+ self.assertEqual(collapsed_last, widget.render(size).decoded_text)
247
+ widget.keypress(size, "left")
248
+ widget.keypress(size, "-")
249
+ self.assertEqual(
250
+ (
251
+ "- /: root ",
252
+ " - 1/: nested_1 ",
253
+ " - 1/: nested_11",
254
+ " 1: child_111",
255
+ " 2: child_112",
256
+ " - 2/: nested_12",
257
+ " 1: child_121",
258
+ " 2: child_122",
259
+ " + 2/: nested_2 ",
260
+ " ",
261
+ " ",
262
+ " ",
263
+ " ",
264
+ " ",
265
+ " ",
266
+ ),
267
+ widget.render(size).decoded_text,
268
+ )
269
+ widget.keypress(size, "right")
270
+ self.assertEqual(collapsed_last, widget.render(size).decoded_text)
271
+ widget.keypress(size, "home")
272
+ widget.keypress(size, "-")
273
+ self.assertEqual(collapsed, widget.render(size).decoded_text)