urwid 4.0.3__tar.gz → 4.0.5__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 (317) hide show
  1. {urwid-4.0.3 → urwid-4.0.5}/PKG-INFO +1 -1
  2. {urwid-4.0.3 → urwid-4.0.5}/docs/changelog.rst +49 -0
  3. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/bigtext.py +1 -1
  4. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/graph.py +40 -25
  5. {urwid-4.0.3 → urwid-4.0.5/docs}/examples/pop_up.py +3 -3
  6. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/real_browse.py +7 -7
  7. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/real_edit.py +4 -4
  8. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/tour.py +3 -3
  9. {urwid-4.0.3 → urwid-4.0.5}/examples/bigtext.py +1 -1
  10. {urwid-4.0.3 → urwid-4.0.5}/examples/browse.py +7 -7
  11. {urwid-4.0.3 → urwid-4.0.5}/examples/calc.py +40 -29
  12. {urwid-4.0.3 → urwid-4.0.5}/examples/edit.py +4 -4
  13. {urwid-4.0.3 → urwid-4.0.5}/examples/fib.py +2 -2
  14. {urwid-4.0.3 → urwid-4.0.5}/examples/graph.py +40 -25
  15. {urwid-4.0.3 → urwid-4.0.5}/examples/input_test.py +2 -2
  16. {urwid-4.0.3/docs → urwid-4.0.5}/examples/pop_up.py +3 -3
  17. {urwid-4.0.3 → urwid-4.0.5}/examples/terminal.py +3 -3
  18. {urwid-4.0.3 → urwid-4.0.5}/examples/tour.py +3 -3
  19. {urwid-4.0.3 → urwid-4.0.5}/examples/treesample.py +15 -8
  20. urwid-4.0.5/pylint-requirements.txt +1 -0
  21. {urwid-4.0.3 → urwid-4.0.5}/pyproject.toml +7 -1
  22. urwid-4.0.5/ruff-requirements.txt +1 -0
  23. {urwid-4.0.3 → urwid-4.0.5}/tests/test_scrollable.py +66 -0
  24. {urwid-4.0.3 → urwid-4.0.5}/tests/test_signals.py +24 -0
  25. {urwid-4.0.3 → urwid-4.0.5}/tests/test_tree.py +2 -2
  26. {urwid-4.0.3 → urwid-4.0.5}/tests/test_vterm.py +145 -35
  27. {urwid-4.0.3 → urwid-4.0.5}/tests/test_widget.py +52 -0
  28. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/_posix_raw_display.py +1 -1
  29. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/_raw_display_base.py +2 -4
  30. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/common.py +2 -3
  31. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/web.py +1 -1
  32. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/main_loop.py +8 -4
  33. {urwid-4.0.3 → urwid-4.0.5}/urwid/signals.py +1 -1
  34. {urwid-4.0.3 → urwid-4.0.5}/urwid/split_repr.py +1 -1
  35. {urwid-4.0.3 → urwid-4.0.5}/urwid/util.py +13 -8
  36. {urwid-4.0.3 → urwid-4.0.5}/urwid/version.py +3 -3
  37. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/attr_map.py +6 -2
  38. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/big_text.py +0 -1
  39. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/box_adapter.py +5 -2
  40. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/columns.py +39 -30
  41. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/container.py +8 -2
  42. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/edit.py +110 -48
  43. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/filler.py +10 -5
  44. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/frame.py +26 -22
  45. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/line_box.py +8 -5
  46. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/listbox.py +8 -7
  47. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/monitored_list.py +8 -3
  48. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/padding.py +84 -26
  49. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/pile.py +4 -3
  50. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/popup.py +6 -2
  51. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/scrollable.py +82 -15
  52. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/treetools.py +32 -19
  53. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/widget.py +1 -1
  54. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/widget_decoration.py +11 -6
  55. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/PKG-INFO +1 -1
  56. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/scm_file_list.json +265 -265
  57. urwid-4.0.5/urwid.egg-info/scm_version.json +8 -0
  58. urwid-4.0.3/pylint-requirements.txt +0 -1
  59. urwid-4.0.3/ruff-requirements.txt +0 -1
  60. urwid-4.0.3/urwid.egg-info/scm_version.json +0 -8
  61. {urwid-4.0.3 → urwid-4.0.5}/.coveralls.yml +0 -0
  62. {urwid-4.0.3 → urwid-4.0.5}/.devcontainer/dev.dockerfile +0 -0
  63. {urwid-4.0.3 → urwid-4.0.5}/.devcontainer/devcontainer.json +0 -0
  64. {urwid-4.0.3 → urwid-4.0.5}/.dockerignore +0 -0
  65. {urwid-4.0.3 → urwid-4.0.5}/.editorconfig +0 -0
  66. {urwid-4.0.3 → urwid-4.0.5}/.github/CODE_OF_CONDUCT.md +0 -0
  67. {urwid-4.0.3 → urwid-4.0.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  68. {urwid-4.0.3 → urwid-4.0.5}/.github/ISSUE_TEMPLATE/docs.md +0 -0
  69. {urwid-4.0.3 → urwid-4.0.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  70. {urwid-4.0.3 → urwid-4.0.5}/.github/ISSUE_TEMPLATE/question.md +0 -0
  71. {urwid-4.0.3 → urwid-4.0.5}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  72. {urwid-4.0.3 → urwid-4.0.5}/.github/dependabot.yml +0 -0
  73. {urwid-4.0.3 → urwid-4.0.5}/.github/labeler.yml +0 -0
  74. {urwid-4.0.3 → urwid-4.0.5}/.github/release.yml +0 -0
  75. {urwid-4.0.3 → urwid-4.0.5}/.github/workflows/documentation.yml +0 -0
  76. {urwid-4.0.3 → urwid-4.0.5}/.github/workflows/isolated_static_check.yml +0 -0
  77. {urwid-4.0.3 → urwid-4.0.5}/.github/workflows/labels.yml +0 -0
  78. {urwid-4.0.3 → urwid-4.0.5}/.github/workflows/pythonpackage.yml +0 -0
  79. {urwid-4.0.3 → urwid-4.0.5}/.github/workflows/yamllint.yml +0 -0
  80. {urwid-4.0.3 → urwid-4.0.5}/.gitignore +0 -0
  81. {urwid-4.0.3 → urwid-4.0.5}/.pre-commit-config.yaml +0 -0
  82. {urwid-4.0.3 → urwid-4.0.5}/.yamllint.yml +0 -0
  83. {urwid-4.0.3 → urwid-4.0.5}/COPYING +0 -0
  84. {urwid-4.0.3 → urwid-4.0.5}/MANIFEST.in +0 -0
  85. {urwid-4.0.3 → urwid-4.0.5}/README.rst +0 -0
  86. {urwid-4.0.3 → urwid-4.0.5}/SECURITY.md +0 -0
  87. {urwid-4.0.3 → urwid-4.0.5}/classifiers.txt +0 -0
  88. {urwid-4.0.3 → urwid-4.0.5}/docs/Makefile +0 -0
  89. {urwid-4.0.3 → urwid-4.0.5}/docs/conf.py +0 -0
  90. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/bigtext.py.xdotool +0 -0
  91. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/bigtext1.png +0 -0
  92. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/bigtext2.png +0 -0
  93. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/bigtext3.png +0 -0
  94. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/browse.py +0 -0
  95. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/browse.py.xdotool +0 -0
  96. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/browse1.png +0 -0
  97. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/browse2.png +0 -0
  98. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/edit.py +0 -0
  99. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/edit.py.xdotool +0 -0
  100. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/edit1.png +0 -0
  101. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/edit2.png +0 -0
  102. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/edit_text.txt +0 -0
  103. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/graph.py.xdotool +0 -0
  104. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/graph1.png +0 -0
  105. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/graph2.png +0 -0
  106. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/index.rst +0 -0
  107. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/palette_test.py +0 -0
  108. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/palette_test.py.xdotool +0 -0
  109. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/palette_test1.png +0 -0
  110. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/palette_test2.png +0 -0
  111. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/pop_up.py.xdotool +0 -0
  112. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/pop_up1.png +0 -0
  113. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/pop_up2.png +0 -0
  114. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/subproc.py +0 -0
  115. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/subproc.py.xdotool +0 -0
  116. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/subproc1.png +0 -0
  117. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/subproc2.png +0 -0
  118. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/subproc2.py +0 -0
  119. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/tour.py.xdotool +0 -0
  120. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/tour1.png +0 -0
  121. {urwid-4.0.3 → urwid-4.0.5}/docs/examples/tour2.png +0 -0
  122. {urwid-4.0.3 → urwid-4.0.5}/docs/index.rst +0 -0
  123. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/bright_combinations.py +0 -0
  124. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/bright_combinations.py.xdotool +0 -0
  125. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/bright_combinations1.png +0 -0
  126. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/canvascache.rst +0 -0
  127. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/displayattributes.rst +0 -0
  128. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/displaymodules.rst +0 -0
  129. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/encodings.rst +0 -0
  130. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/display_modules.png +0 -0
  131. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/introduction.png +0 -0
  132. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/urwid_widgets.svgz +0 -0
  133. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/urwid_widgets_1.png +0 -0
  134. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/urwid_widgets_1.xcf +0 -0
  135. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/urwid_widgets_2.png +0 -0
  136. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/urwid_widgets_2.xcf +0 -0
  137. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/images/widget_layout.png +0 -0
  138. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/index.rst +0 -0
  139. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/mainloop.rst +0 -0
  140. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/overview.rst +0 -0
  141. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/safe_combinations.py +0 -0
  142. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/safe_combinations.py.xdotool +0 -0
  143. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/safe_combinations1.png +0 -0
  144. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/textlayout.rst +0 -0
  145. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/userinput.rst +0 -0
  146. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/wanat.py +0 -0
  147. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/wanat_multi.py +0 -0
  148. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/wcur1.py +0 -0
  149. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/wcur2.py +0 -0
  150. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/widgets.rst +0 -0
  151. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/wmod.py +0 -0
  152. {urwid-4.0.3 → urwid-4.0.5}/docs/manual/wsel.py +0 -0
  153. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/attrspec.rst +0 -0
  154. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/canvas.rst +0 -0
  155. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/command_map.rst +0 -0
  156. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/constants.rst +0 -0
  157. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/deprecated.rst +0 -0
  158. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/display_modules.rst +0 -0
  159. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/exceptions.rst +0 -0
  160. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/global_settings.rst +0 -0
  161. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/index.rst +0 -0
  162. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/list_walkers.rst +0 -0
  163. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/main_loop.rst +0 -0
  164. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/meta.rst +0 -0
  165. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/signals.rst +0 -0
  166. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/text_layout.rst +0 -0
  167. {urwid-4.0.3 → urwid-4.0.5}/docs/reference/widget.rst +0 -0
  168. {urwid-4.0.3 → urwid-4.0.5}/docs/tools/compile_pngs.sh +0 -0
  169. {urwid-4.0.3 → urwid-4.0.5}/docs/tools/screenshots.sh +0 -0
  170. {urwid-4.0.3 → urwid-4.0.5}/docs/tools/static/.placeholder +0 -0
  171. {urwid-4.0.3 → urwid-4.0.5}/docs/tools/templates/indexcontent.html +0 -0
  172. {urwid-4.0.3 → urwid-4.0.5}/docs/tools/templates/indexsidebar.html +0 -0
  173. {urwid-4.0.3 → urwid-4.0.5}/docs/tools/templates/localtoc.html +0 -0
  174. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/adventure.py +0 -0
  175. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/adventure.py.xdotool +0 -0
  176. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/adventure1.png +0 -0
  177. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/adventure2.png +0 -0
  178. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/adventure3.png +0 -0
  179. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/adventure4.png +0 -0
  180. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/cmenu.py +0 -0
  181. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/cmenu.py.xdotool +0 -0
  182. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/cmenu1.png +0 -0
  183. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/cmenu2.png +0 -0
  184. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/cmenu3.png +0 -0
  185. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/cmenu4.png +0 -0
  186. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/highcolors.py +0 -0
  187. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/highcolors.py.xdotool +0 -0
  188. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/highcolors1.png +0 -0
  189. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/hmenu.py +0 -0
  190. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/hmenu.py.xdotool +0 -0
  191. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/hmenu1.png +0 -0
  192. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/hmenu2.png +0 -0
  193. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/hmenu3.png +0 -0
  194. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/hmenu4.png +0 -0
  195. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/index.rst +0 -0
  196. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input.py +0 -0
  197. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input.py.xdotool +0 -0
  198. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input1.png +0 -0
  199. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input2.png +0 -0
  200. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input3.png +0 -0
  201. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input4.png +0 -0
  202. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/input5.png +0 -0
  203. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/menu25.png +0 -0
  204. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/minimal.py +0 -0
  205. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/minimal.py.xdotool +0 -0
  206. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/minimal1.png +0 -0
  207. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/multiple.py +0 -0
  208. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/multiple.py.xdotool +0 -0
  209. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/multiple1.png +0 -0
  210. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/multiple2.png +0 -0
  211. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/multiple3.png +0 -0
  212. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/multiple4.png +0 -0
  213. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/qa.py +0 -0
  214. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/qa.py.xdotool +0 -0
  215. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/qa1.png +0 -0
  216. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/qa2.png +0 -0
  217. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/qa3.png +0 -0
  218. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/sig.py +0 -0
  219. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/sig.py.xdotool +0 -0
  220. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/sig1.png +0 -0
  221. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/sig2.png +0 -0
  222. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/sig3.png +0 -0
  223. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/sig4.png +0 -0
  224. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/smenu.py +0 -0
  225. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/smenu.py.xdotool +0 -0
  226. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/smenu1.png +0 -0
  227. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/smenu2.png +0 -0
  228. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/smenu3.png +0 -0
  229. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/urwid_attr.py +0 -0
  230. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/urwid_attr.py.xdotool +0 -0
  231. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/urwid_attr1.png +0 -0
  232. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/urwid_attr2.png +0 -0
  233. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/urwid_attr3.png +0 -0
  234. {urwid-4.0.3 → urwid-4.0.5}/docs/tutorial/urwid_attr4.png +0 -0
  235. {urwid-4.0.3 → urwid-4.0.5}/docs/urwid-logo.png +0 -0
  236. {urwid-4.0.3 → urwid-4.0.5}/examples/asyncio_socket_server.py +0 -0
  237. {urwid-4.0.3 → urwid-4.0.5}/examples/dialog.py +0 -0
  238. {urwid-4.0.3 → urwid-4.0.5}/examples/lcd_cf635.py +0 -0
  239. {urwid-4.0.3 → urwid-4.0.5}/examples/palette_test.py +0 -0
  240. {urwid-4.0.3 → urwid-4.0.5}/examples/subproc.py +0 -0
  241. {urwid-4.0.3 → urwid-4.0.5}/examples/subproc2.py +0 -0
  242. {urwid-4.0.3 → urwid-4.0.5}/examples/twisted_serve_ssh.py +0 -0
  243. {urwid-4.0.3 → urwid-4.0.5}/examples/twisted_serve_ssh.tac +0 -0
  244. {urwid-4.0.3 → urwid-4.0.5}/requirements.txt +0 -0
  245. {urwid-4.0.3 → urwid-4.0.5}/setup.cfg +0 -0
  246. {urwid-4.0.3 → urwid-4.0.5}/test_requirements.txt +0 -0
  247. {urwid-4.0.3 → urwid-4.0.5}/tests/__init__.py +0 -0
  248. {urwid-4.0.3 → urwid-4.0.5}/tests/test_canvas.py +0 -0
  249. {urwid-4.0.3 → urwid-4.0.5}/tests/test_columns.py +0 -0
  250. {urwid-4.0.3 → urwid-4.0.5}/tests/test_container.py +0 -0
  251. {urwid-4.0.3 → urwid-4.0.5}/tests/test_doctests.py +0 -0
  252. {urwid-4.0.3 → urwid-4.0.5}/tests/test_escapes.py +0 -0
  253. {urwid-4.0.3 → urwid-4.0.5}/tests/test_event_loops.py +0 -0
  254. {urwid-4.0.3 → urwid-4.0.5}/tests/test_filler.py +0 -0
  255. {urwid-4.0.3 → urwid-4.0.5}/tests/test_floatedit.py +0 -0
  256. {urwid-4.0.3 → urwid-4.0.5}/tests/test_font.py +0 -0
  257. {urwid-4.0.3 → urwid-4.0.5}/tests/test_frame.py +0 -0
  258. {urwid-4.0.3 → urwid-4.0.5}/tests/test_grapheme_clusters.py +0 -0
  259. {urwid-4.0.3 → urwid-4.0.5}/tests/test_graphics.py +0 -0
  260. {urwid-4.0.3 → urwid-4.0.5}/tests/test_grid_flow.py +0 -0
  261. {urwid-4.0.3 → urwid-4.0.5}/tests/test_line_box.py +0 -0
  262. {urwid-4.0.3 → urwid-4.0.5}/tests/test_listbox.py +0 -0
  263. {urwid-4.0.3 → urwid-4.0.5}/tests/test_main_loop.py +0 -0
  264. {urwid-4.0.3 → urwid-4.0.5}/tests/test_overlay.py +0 -0
  265. {urwid-4.0.3 → urwid-4.0.5}/tests/test_padding.py +0 -0
  266. {urwid-4.0.3 → urwid-4.0.5}/tests/test_pile.py +0 -0
  267. {urwid-4.0.3 → urwid-4.0.5}/tests/test_raw_display.py +0 -0
  268. {urwid-4.0.3 → urwid-4.0.5}/tests/test_str_util.py +0 -0
  269. {urwid-4.0.3 → urwid-4.0.5}/tests/test_text_layout.py +0 -0
  270. {urwid-4.0.3 → urwid-4.0.5}/tests/test_util.py +0 -0
  271. {urwid-4.0.3 → urwid-4.0.5}/tests/util.py +0 -0
  272. {urwid-4.0.3 → urwid-4.0.5}/tox.ini +0 -0
  273. {urwid-4.0.3 → urwid-4.0.5}/urwid/__init__.py +0 -0
  274. {urwid-4.0.3 → urwid-4.0.5}/urwid/canvas.py +0 -0
  275. {urwid-4.0.3 → urwid-4.0.5}/urwid/command_map.py +0 -0
  276. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/__init__.py +0 -0
  277. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/_web.css +0 -0
  278. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/_web.js +0 -0
  279. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/_win32.py +0 -0
  280. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/_win32_raw_display.py +0 -0
  281. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/curses.py +0 -0
  282. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/escape.py +0 -0
  283. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/html_fragment.py +0 -0
  284. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/lcd.py +0 -0
  285. {urwid-4.0.3 → urwid-4.0.5}/urwid/display/raw.py +0 -0
  286. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/__init__.py +0 -0
  287. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/abstract_loop.py +0 -0
  288. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/asyncio_loop.py +0 -0
  289. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/glib_loop.py +0 -0
  290. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/select_loop.py +0 -0
  291. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/tornado_loop.py +0 -0
  292. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/trio_loop.py +0 -0
  293. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/twisted_loop.py +0 -0
  294. {urwid-4.0.3 → urwid-4.0.5}/urwid/event_loop/zmq_loop.py +0 -0
  295. {urwid-4.0.3 → urwid-4.0.5}/urwid/font.py +0 -0
  296. {urwid-4.0.3 → urwid-4.0.5}/urwid/graphics.py +0 -0
  297. {urwid-4.0.3 → urwid-4.0.5}/urwid/numedit.py +0 -0
  298. {urwid-4.0.3 → urwid-4.0.5}/urwid/py.typed +0 -0
  299. {urwid-4.0.3 → urwid-4.0.5}/urwid/str_util.py +0 -0
  300. {urwid-4.0.3 → urwid-4.0.5}/urwid/text_layout.py +0 -0
  301. {urwid-4.0.3 → urwid-4.0.5}/urwid/vterm.py +0 -0
  302. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/__init__.py +0 -0
  303. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/attr_wrap.py +0 -0
  304. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/bar_graph.py +0 -0
  305. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/constants.py +0 -0
  306. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/divider.py +0 -0
  307. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/grid_flow.py +0 -0
  308. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/overlay.py +0 -0
  309. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/progress_bar.py +0 -0
  310. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/solid_fill.py +0 -0
  311. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/text.py +0 -0
  312. {urwid-4.0.3 → urwid-4.0.5}/urwid/widget/wimp.py +0 -0
  313. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/SOURCES.txt +0 -0
  314. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/dependency_links.txt +0 -0
  315. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/not-zip-safe +0 -0
  316. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/requires.txt +0 -0
  317. {urwid-4.0.3 → urwid-4.0.5}/urwid.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: urwid
3
- Version: 4.0.3
3
+ Version: 4.0.5
4
4
  Summary: A full-featured console (xterm et al.) user interface library
5
5
  Author-email: Ian Ward <ian@excess.org>
6
6
  License-Expression: LGPL-2.1-only
@@ -2,6 +2,55 @@
2
2
  Changelog
3
3
  ---------
4
4
 
5
+ Urwid 4.0.5
6
+ ===========
7
+
8
+ 2026-07-20
9
+
10
+ New features 🗹
11
+ +++++++++++++++
12
+ * Copy signal handlers before emission by @Sanjays2402 in https://github.com/urwid/urwid/pull/1187
13
+ * Implement `_scrollbar_layout` and left click handling for `Scrollable` by @penguinolog in https://github.com/urwid/urwid/pull/1192
14
+ Bug fixes 🕷
15
+ ++++++++++++
16
+ * Fix rle_product for zero-len elements by @penguinolog in https://github.com/urwid/urwid/pull/1191
17
+ Documentation 🕮
18
+ ++++++++++++++++
19
+ * typing: fix `Filler` typing annotations by @penguinolog in https://github.com/urwid/urwid/pull/1183
20
+ * typing: extend widget_decoration module typing coverage by @penguinolog in https://github.com/urwid/urwid/pull/1184
21
+ * Typing: annotate and fix attr_map by @penguinolog in https://github.com/urwid/urwid/pull/1186
22
+ Refactoring 🛠
23
+ ++++++++++++++
24
+ * Migrate `Edit` widget to use `WidgetWrap` as base class and update methods by @penguinolog in https://github.com/urwid/urwid/pull/1180
25
+
26
+ New Contributors
27
+ ++++++++++++++++
28
+ * @Sanjays2402 made their first contribution in https://github.com/urwid/urwid/pull/1187
29
+
30
+ **Full Changelog**: https://github.com/urwid/urwid/compare/4.0.4...4.0.5
31
+
32
+ Urwid 4.0.4
33
+ ===========
34
+
35
+ 2026-07-13
36
+
37
+ New features 🗹
38
+ +++++++++++++++
39
+ * urwid.Colmns: re-calculate column_widths only if pack widgets changed by @penguinolog in https://github.com/urwid/urwid/pull/1178
40
+ Bug fixes 🕷
41
+ ++++++++++++
42
+ * Fix IndexError in decompose_tagmarkup when a nested sublist is empty by @gaoflow in https://github.com/urwid/urwid/pull/1172
43
+ Documentation 🕮
44
+ ++++++++++++++++
45
+ * Typing: partially annotate examples and fix annotations by @penguinolog in https://github.com/urwid/urwid/pull/1173
46
+ * urwid.WidgetContainerMixin: return use protocol base class by @penguinolog in https://github.com/urwid/urwid/pull/1181
47
+
48
+ New Contributors
49
+ ++++++++++++++++
50
+ * @gaoflow made their first contribution in https://github.com/urwid/urwid/pull/1172
51
+
52
+ **Full Changelog**: https://github.com/urwid/urwid/compare/4.0.3...4.0.4
53
+
5
54
  Urwid 4.0.3
6
55
  ===========
7
56
 
@@ -48,7 +48,7 @@ class SwitchingPadding(urwid.Padding[_Wrapped]):
48
48
 
49
49
 
50
50
  class BigTextDisplay:
51
- palette: typing.ClassVar[list[tuple[str, str, str, ...]]] = [
51
+ palette: typing.ClassVar[list[tuple[str, str, str] | tuple[str, str, str, str]]] = [
52
52
  ("body", "black", "light gray", "standout"),
53
53
  ("header", "white", "dark red", "bold"),
54
54
  ("button normal", "light gray", "dark blue", "standout"),
@@ -33,6 +33,9 @@ import typing
33
33
 
34
34
  import urwid
35
35
 
36
+ if typing.TYPE_CHECKING:
37
+ from collections.abc import Callable
38
+
36
39
  UPDATE_INTERVAL = 0.2
37
40
 
38
41
 
@@ -52,7 +55,7 @@ class GraphModel:
52
55
 
53
56
  data_max_value = 100
54
57
 
55
- def __init__(self):
58
+ def __init__(self) -> None:
56
59
  data = [
57
60
  ("Saw", list(range(0, 100, 2)) * 2),
58
61
  ("Square", [0] * 30 + [100] * 30),
@@ -66,13 +69,13 @@ class GraphModel:
66
69
  self.modes.append(m)
67
70
  self.data[m] = d
68
71
 
69
- def get_modes(self):
72
+ def get_modes(self) -> list[str]:
70
73
  return self.modes
71
74
 
72
- def set_mode(self, m) -> None:
75
+ def set_mode(self, m: str) -> None:
73
76
  self.current_mode = m
74
77
 
75
- def get_data(self, offset, r):
78
+ def get_data(self, offset: int, r):
76
79
  """
77
80
  Return the data in [offset:offset+r], the maximum value
78
81
  for items returned, and the offset at which the data
@@ -95,7 +98,7 @@ class GraphView(urwid.WidgetWrap):
95
98
  graph display.
96
99
  """
97
100
 
98
- palette: typing.ClassVar[tuple[str, str, str, ...]] = [
101
+ palette: typing.ClassVar[list[tuple[str, str, str] | tuple[str, str, str, str]]] = [
99
102
  ("body", "black", "light gray", "standout"),
100
103
  ("header", "white", "dark red", "bold"),
101
104
  ("screen edge", "light blue", "dark cyan"),
@@ -118,7 +121,7 @@ class GraphView(urwid.WidgetWrap):
118
121
  graph_num_bars = 5
119
122
  graph_offset_per_second = 5
120
123
 
121
- def __init__(self, controller):
124
+ def __init__(self, controller) -> None:
122
125
  self.controller = controller
123
126
  self.started = True
124
127
  self.start_time = None
@@ -126,7 +129,7 @@ class GraphView(urwid.WidgetWrap):
126
129
  self.last_offset = None
127
130
  super().__init__(self.main_window())
128
131
 
129
- def get_offset_now(self):
132
+ def get_offset_now(self) -> int:
130
133
  if self.start_time is None:
131
134
  return 0
132
135
  if not self.started:
@@ -134,7 +137,7 @@ class GraphView(urwid.WidgetWrap):
134
137
  tdelta = time.time() - self.start_time
135
138
  return int(self.offset + (tdelta * self.graph_offset_per_second))
136
139
 
137
- def update_graph(self, force_update=False):
140
+ def update_graph(self, force_update: bool = False) -> bool:
138
141
  o = self.get_offset_now()
139
142
  if o == self.last_offset and not force_update:
140
143
  return False
@@ -164,32 +167,32 @@ class GraphView(urwid.WidgetWrap):
164
167
  self.animate_progress.current = prog
165
168
  return True
166
169
 
167
- def on_animate_button(self, button):
170
+ def on_animate_button(self, button: urwid.AttrMap[urwid.Button]) -> None:
168
171
  """Toggle started state and button text."""
169
172
  if self.started: # stop animation
170
- button.base_widget.set_label("Start")
173
+ button.set_label("Start")
171
174
  self.offset = self.get_offset_now()
172
175
  self.started = False
173
176
  self.controller.stop_animation()
174
177
  else:
175
- button.base_widget.set_label("Stop")
178
+ button.set_label("Stop")
176
179
  self.started = True
177
180
  self.start_time = time.time()
178
181
  self.controller.animate_graph()
179
182
 
180
- def on_reset_button(self, w):
183
+ def on_reset_button(self, w: urwid.Button) -> None:
181
184
  self.offset = 0
182
185
  self.start_time = time.time()
183
186
  self.update_graph(True)
184
187
 
185
- def on_mode_button(self, button, state):
188
+ def on_mode_button(self, button: urwid.RadioButton, state: bool) -> None:
186
189
  """Notify the controller of a new mode setting."""
187
190
  if state:
188
191
  # The new mode is the label of the button
189
192
  self.controller.set_mode(button.get_label())
190
193
  self.last_offset = None
191
194
 
192
- def on_mode_change(self, m):
195
+ def on_mode_change(self, m: str) -> None:
193
196
  """Handle external mode change by updating radio buttons."""
194
197
  for rb in self.mode_buttons:
195
198
  if rb.base_widget.label == m:
@@ -197,7 +200,7 @@ class GraphView(urwid.WidgetWrap):
197
200
  break
198
201
  self.last_offset = None
199
202
 
200
- def on_unicode_checkbox(self, w, state):
203
+ def on_unicode_checkbox(self, w: urwid.CheckBox, state: bool) -> None:
201
204
  self.graph = self.bar_graph(state)
202
205
  self.graph_wrap._w = self.graph
203
206
  self.animate_progress = self.progress_bar(state)
@@ -235,30 +238,42 @@ class GraphView(urwid.WidgetWrap):
235
238
  )
236
239
  return w
237
240
 
238
- def bar_graph(self, smooth=False):
241
+ def bar_graph(self, smooth: bool = False) -> urwid.BarGraph:
239
242
  satt = None
240
243
  if smooth:
241
244
  satt = {(1, 0): "bg 1 smooth", (2, 0): "bg 2 smooth"}
242
245
  w = urwid.BarGraph(["bg background", "bg 1", "bg 2"], satt=satt)
243
246
  return w
244
247
 
245
- def button(self, t, fn):
248
+ def button(
249
+ self,
250
+ t: str,
251
+ fn: Callable[[urwid.Button], None],
252
+ ) -> urwid.AttrMap[urwid.Button]:
246
253
  w = urwid.Button(t, fn)
247
254
  w = urwid.AttrMap(w, "button normal", "button select")
248
255
  return w
249
256
 
250
- def radio_button(self, g, label, fn):
257
+ def radio_button(
258
+ self,
259
+ g: list[urwid.RadioButton],
260
+ label: str,
261
+ fn: Callable[[urwid.RadioButton, bool], None],
262
+ ) -> urwid.AttrMap[urwid.RadioButton]:
251
263
  w = urwid.RadioButton(g, label, False, on_state_change=fn)
252
264
  w = urwid.AttrMap(w, "button normal", "button select")
253
265
  return w
254
266
 
255
- def progress_bar(self, smooth=False):
256
- if smooth:
257
- return urwid.ProgressBar("pg normal", "pg complete", 0, 1, "pg smooth")
258
-
259
- return urwid.ProgressBar("pg normal", "pg complete", 0, 1)
267
+ def progress_bar(self, smooth: bool = False) -> urwid.ProgressBar:
268
+ return urwid.ProgressBar(
269
+ "pg normal",
270
+ "pg complete",
271
+ 0,
272
+ 1,
273
+ "pg smooth" if smooth else None,
274
+ )
260
275
 
261
- def exit_program(self, w):
276
+ def exit_program(self, w) -> typing.NoReturn:
262
277
  raise urwid.ExitMainLoop()
263
278
 
264
279
  def graph_controls(self):
@@ -271,7 +286,7 @@ class GraphView(urwid.WidgetWrap):
271
286
  self.mode_buttons.append(rb)
272
287
  # setup animate button
273
288
  self.animate_button = self.button("", self.on_animate_button)
274
- self.on_animate_button(self.animate_button)
289
+ self.on_animate_button(self.animate_button.original_widget)
275
290
  self.offset = 0
276
291
  self.animate_progress = self.progress_bar()
277
292
  animate_controls = urwid.GridFlow(
@@ -7,12 +7,12 @@ import typing
7
7
  import urwid
8
8
 
9
9
 
10
- class PopUpDialog(urwid.WidgetWrap):
10
+ class PopUpDialog(urwid.WidgetWrap[urwid.AttrMap[urwid.Filler[urwid.Pile]]]):
11
11
  """A dialog that appears with nothing but a close button"""
12
12
 
13
13
  signals: typing.ClassVar[list[str]] = ["close"]
14
14
 
15
- def __init__(self):
15
+ def __init__(self) -> None:
16
16
  close_button = urwid.Button("that's pretty cool")
17
17
  urwid.connect_signal(close_button, "click", lambda button: self._emit("close"))
18
18
  pile = urwid.Pile(
@@ -24,7 +24,7 @@ class PopUpDialog(urwid.WidgetWrap):
24
24
  super().__init__(urwid.AttrMap(urwid.Filler(pile), "popbg"))
25
25
 
26
26
 
27
- class ThingWithAPopUp(urwid.PopUpLauncher):
27
+ class ThingWithAPopUp(urwid.PopUpLauncher[urwid.Button]):
28
28
  def __init__(self) -> None:
29
29
  super().__init__(urwid.Button("click-me"))
30
30
  urwid.connect_signal(self.original_widget, "click", lambda button: self.open_pop_up())
@@ -178,9 +178,9 @@ class DirectoryNode(urwid.ParentNode):
178
178
  parent.set_child_node(self.get_key(), self)
179
179
  return parent
180
180
 
181
- def load_child_keys(self):
182
- dirs = []
183
- files = []
181
+ def load_child_keys(self) -> list[str] | list[None]:
182
+ dirs: list[str] = []
183
+ files: list[str] = []
184
184
  try:
185
185
  path = self.get_value()
186
186
  # separate dirs and files
@@ -207,7 +207,7 @@ class DirectoryNode(urwid.ParentNode):
207
207
  keys = [None]
208
208
  return keys
209
209
 
210
- def load_child_node(self, key) -> EmptyNode | DirectoryNode | FileNode:
210
+ def load_child_node(self, key: Hashable) -> EmptyNode | DirectoryNode | FileNode:
211
211
  """Return either a FileNode or DirectoryNode"""
212
212
  index = self.get_child_index(key)
213
213
  if key is None:
@@ -225,11 +225,11 @@ class DirectoryNode(urwid.ParentNode):
225
225
 
226
226
 
227
227
  class DirectoryBrowser:
228
- palette: typing.ClassVar[list[tuple[str, str, str, ...]]] = [
228
+ palette: typing.ClassVar[list[tuple[str, ...] | tuple[str, str, str, str]]] = [
229
229
  ("body", "black", "light gray"),
230
- ("flagged", "black", "dark green", ("bold", "underline")),
230
+ ("flagged", "black", "dark green", "bold,underline"),
231
231
  ("focus", "light gray", "dark blue", "standout"),
232
- ("flagged focus", "yellow", "dark cyan", ("bold", "standout", "underline")),
232
+ ("flagged focus", "yellow", "dark cyan", "bold,standout,underline"),
233
233
  ("head", "yellow", "black", "standout"),
234
234
  ("foot", "light gray", "black"),
235
235
  ("key", "light cyan", "black", "underline"),
@@ -51,10 +51,10 @@ class LineWalker(urwid.ListWalker):
51
51
  if self.file is not None:
52
52
  self.file.close()
53
53
 
54
- def get_focus(self):
54
+ def get_focus(self) -> tuple[urwid.Edit, int] | tuple[None, None]:
55
55
  return self._get_at_pos(self.focus)
56
56
 
57
- def set_focus(self, focus) -> None:
57
+ def set_focus(self, focus: int) -> None:
58
58
  self.focus = focus
59
59
  self._modified()
60
60
 
@@ -145,7 +145,7 @@ class LineWalker(urwid.ListWalker):
145
145
 
146
146
 
147
147
  class EditDisplay:
148
- palette: typing.ClassVar[list[tuple[str, str, str, ...]]] = [
148
+ palette: typing.ClassVar[list[tuple[str, str, str] | tuple[str, str, str, str]]] = [
149
149
  ("body", "default", "default"),
150
150
  ("foot", "dark cyan", "dark blue", "bold"),
151
151
  ("key", "light cyan", "dark blue", "underline"),
@@ -231,7 +231,7 @@ class EditDisplay:
231
231
  prefix = "\n"
232
232
 
233
233
 
234
- def re_tab(s) -> str:
234
+ def re_tab(s: str) -> str:
235
235
  """Return a tabbed string from an expanded one."""
236
236
  line = []
237
237
  p = 0
@@ -159,7 +159,7 @@ def main():
159
159
  " widget is used to keep the instructions at the top of the screen.",
160
160
  ]
161
161
 
162
- def button_press(button):
162
+ def button_press(button: urwid.Button) -> None:
163
163
  frame.footer = urwid.AttrMap(urwid.Text(["Pressed: ", button.get_label()]), "header")
164
164
 
165
165
  radio_button_group = []
@@ -355,11 +355,11 @@ def main():
355
355
  ("body", "black", "light gray", "standout"),
356
356
  ("reverse", "light gray", "black"),
357
357
  ("header", "white", "dark red", "bold"),
358
- ("important", "dark blue", "light gray", ("standout", "underline")),
358
+ ("important", "dark blue", "light gray", "standout,underline"),
359
359
  ("editfc", "white", "dark blue", "bold"),
360
360
  ("editbx", "light gray", "dark blue"),
361
361
  ("editcp", "black", "light gray", "standout"),
362
- ("bright", "dark gray", "light gray", ("bold", "standout")),
362
+ ("bright", "dark gray", "light gray", "bold,standout"),
363
363
  ("buttn", "black", "dark cyan"),
364
364
  ("buttnf", "white", "dark blue", "bold"),
365
365
  ]
@@ -48,7 +48,7 @@ class SwitchingPadding(urwid.Padding[_Wrapped]):
48
48
 
49
49
 
50
50
  class BigTextDisplay:
51
- palette: typing.ClassVar[list[tuple[str, str, str, ...]]] = [
51
+ palette: typing.ClassVar[list[tuple[str, str, str] | tuple[str, str, str, str]]] = [
52
52
  ("body", "black", "light gray", "standout"),
53
53
  ("header", "white", "dark red", "bold"),
54
54
  ("button normal", "light gray", "dark blue", "standout"),
@@ -178,9 +178,9 @@ class DirectoryNode(urwid.ParentNode):
178
178
  parent.set_child_node(self.get_key(), self)
179
179
  return parent
180
180
 
181
- def load_child_keys(self):
182
- dirs = []
183
- files = []
181
+ def load_child_keys(self) -> list[str] | list[None]:
182
+ dirs: list[str] = []
183
+ files: list[str] = []
184
184
  try:
185
185
  path = self.get_value()
186
186
  # separate dirs and files
@@ -207,7 +207,7 @@ class DirectoryNode(urwid.ParentNode):
207
207
  keys = [None]
208
208
  return keys
209
209
 
210
- def load_child_node(self, key) -> EmptyNode | DirectoryNode | FileNode:
210
+ def load_child_node(self, key: Hashable) -> EmptyNode | DirectoryNode | FileNode:
211
211
  """Return either a FileNode or DirectoryNode"""
212
212
  index = self.get_child_index(key)
213
213
  if key is None:
@@ -225,11 +225,11 @@ class DirectoryNode(urwid.ParentNode):
225
225
 
226
226
 
227
227
  class DirectoryBrowser:
228
- palette: typing.ClassVar[list[tuple[str, str, str, ...]]] = [
228
+ palette: typing.ClassVar[list[tuple[str, ...] | tuple[str, str, str, str]]] = [
229
229
  ("body", "black", "light gray"),
230
- ("flagged", "black", "dark green", ("bold", "underline")),
230
+ ("flagged", "black", "dark green", "bold,underline"),
231
231
  ("focus", "light gray", "dark blue", "standout"),
232
- ("flagged focus", "yellow", "dark cyan", ("bold", "standout", "underline")),
232
+ ("flagged focus", "yellow", "dark cyan", "bold,standout,underline"),
233
233
  ("head", "yellow", "black", "standout"),
234
234
  ("foot", "light gray", "black"),
235
235
  ("key", "light cyan", "black", "underline"),
@@ -40,7 +40,7 @@ import typing
40
40
  import urwid
41
41
 
42
42
  if typing.TYPE_CHECKING:
43
- from collections.abc import Hashable
43
+ from collections.abc import Hashable, Iterable
44
44
 
45
45
  # use appropriate Screen class
46
46
  if urwid.display.web.is_web_request():
@@ -99,7 +99,7 @@ class CalcEvent(Exception):
99
99
  def __init__(self, message: str | tuple[Hashable, str] | list[str | tuple[Hashable, str]]) -> None:
100
100
  self.message = message
101
101
 
102
- def widget(self):
102
+ def widget(self) -> urwid.AttrMap[urwid.Text]:
103
103
  """Return a widget containing event information"""
104
104
  text = urwid.Text(self.message, urwid.CENTER)
105
105
  return urwid.AttrMap(text, self.attr)
@@ -110,7 +110,7 @@ class ColumnDeleteEvent(CalcEvent):
110
110
 
111
111
  attr = "confirm"
112
112
 
113
- def __init__(self, letter: str, from_parent=0) -> None:
113
+ def __init__(self, letter: str, from_parent: int = 0) -> None:
114
114
  super().__init__(["Press ", ("key", "BACKSPACE"), " again to confirm column removal."])
115
115
  self.letter = letter
116
116
 
@@ -120,14 +120,14 @@ class UpdateParentEvent(Exception):
120
120
 
121
121
 
122
122
  class Cell:
123
- def __init__(self, op) -> None:
123
+ def __init__(self, op: str | None) -> None:
124
124
  self.op = op
125
125
  self.is_top = op is None
126
126
  self.child = None
127
127
  self.setup_edit()
128
128
  self.result = urwid.Text("", layout=CALC_LAYOUT)
129
129
 
130
- def show_result(self, next_cell) -> bool:
130
+ def show_result(self, next_cell: Cell | None) -> bool:
131
131
  """Return whether this widget should display its result.
132
132
 
133
133
  next_cell -- the cell following self or None"""
@@ -192,7 +192,7 @@ class Cell:
192
192
  class ParentEdit(urwid.Edit):
193
193
  """Edit widget modified to link to a child column"""
194
194
 
195
- def __init__(self, op, letter: str) -> None:
195
+ def __init__(self, op: str | None, letter: str) -> None:
196
196
  """Use the operator and letter of the child column as caption
197
197
 
198
198
  op -- operator or None
@@ -226,20 +226,23 @@ class ParentEdit(urwid.Edit):
226
226
 
227
227
 
228
228
  class CellWalker(urwid.ListWalker):
229
- def __init__(self, content):
229
+ def __init__(self, content: Iterable[Cell]) -> None:
230
230
  self.content = urwid.MonitoredList(content)
231
- self.content.modified = self._modified
231
+ self.content.set_modified_callback(self._modified)
232
232
  self.focus = (0, 0)
233
233
  # everyone can share the same divider widget
234
234
  self.div = urwid.Divider("-")
235
235
 
236
- def get_cell(self, i):
236
+ def get_cell(self, i: int) -> Cell | None:
237
237
  if i < 0 or i >= len(self.content):
238
238
  return None
239
239
 
240
240
  return self.content[i]
241
241
 
242
- def _get_at_pos(self, pos):
242
+ def _get_at_pos(
243
+ self,
244
+ pos: tuple[int, int],
245
+ ) -> tuple[urwid.Divider | urwid.AttrMap[urwid.IntEdit] | urwid.Text, tuple[int, int]] | tuple[None, None]:
243
246
  i, sub = pos
244
247
  assert sub in {0, 1, 2} # noqa: S101 # for examples "assert" is acceptable
245
248
  if i < 0 or i >= len(self.content):
@@ -252,13 +255,18 @@ class CellWalker(urwid.ListWalker):
252
255
 
253
256
  return self.content[i].result, pos
254
257
 
255
- def get_focus(self):
258
+ def get_focus(
259
+ self,
260
+ ) -> tuple[urwid.Divider | urwid.AttrMap[urwid.IntEdit] | urwid.Text, tuple[int, int]] | tuple[None, None]:
256
261
  return self._get_at_pos(self.focus)
257
262
 
258
- def set_focus(self, focus) -> None:
263
+ def set_focus(self, focus: tuple[int, int]) -> None:
259
264
  self.focus = focus
260
265
 
261
- def get_next(self, position):
266
+ def get_next(
267
+ self,
268
+ position: tuple[int, int],
269
+ ) -> tuple[urwid.Divider | urwid.AttrMap[urwid.IntEdit] | urwid.Text, tuple[int, int]] | tuple[None, None]:
262
270
  i, sub = position
263
271
  assert sub in {0, 1, 2} # noqa: S101 # for examples "assert" is acceptable
264
272
  if sub == 0:
@@ -272,7 +280,10 @@ class CellWalker(urwid.ListWalker):
272
280
 
273
281
  return self._get_at_pos((i + 1, 0))
274
282
 
275
- def get_prev(self, position):
283
+ def get_prev(
284
+ self,
285
+ position: tuple[int, int],
286
+ ) -> tuple[urwid.Divider | urwid.AttrMap[urwid.IntEdit] | urwid.Text, tuple[int, int]] | tuple[None, None]:
276
287
  i, sub = position
277
288
  assert sub in {0, 1, 2} # noqa: S101 # for examples "assert" is acceptable
278
289
  if sub == 0:
@@ -289,7 +300,7 @@ class CellWalker(urwid.ListWalker):
289
300
  return self._get_at_pos((i, 1))
290
301
 
291
302
 
292
- class CellColumn(urwid.WidgetWrap):
303
+ class CellColumn(urwid.WidgetWrap[urwid.Frame[urwid.WidgetWrap[urwid.Text], urwid.ListBox, None]]):
293
304
  def __init__(self, letter: str) -> None:
294
305
  self.walker = CellWalker([Cell(None)])
295
306
  self.content = self.walker.content
@@ -304,7 +315,7 @@ class CellColumn(urwid.WidgetWrap):
304
315
  header = urwid.AttrMap(urwid.Text(["Column ", ("key", letter)], layout=CALC_LAYOUT), "colhead")
305
316
  self.frame = urwid.Frame(self.listbox, header)
306
317
 
307
- def keypress(self, size, key: str) -> str | None:
318
+ def keypress(self, size: tuple[int, int], key: str) -> str | None:
308
319
  key = self.frame.keypress(size, key)
309
320
  if key is None:
310
321
  changed = self.update_results()
@@ -387,7 +398,7 @@ class CellColumn(urwid.WidgetWrap):
387
398
  return None
388
399
  return key
389
400
 
390
- def move_focus_next(self, size) -> None:
401
+ def move_focus_next(self, size: tuple[int, int]) -> None:
391
402
  _f, (i, _sub) = self.walker.get_focus()
392
403
  assert i < len(self.content) - 1 # noqa: S101 # for examples "assert" is acceptable
393
404
 
@@ -396,7 +407,7 @@ class CellColumn(urwid.WidgetWrap):
396
407
  self.frame.keypress(size, "down")
397
408
  _nf, (ni, _nsub) = self.walker.get_focus()
398
409
 
399
- def move_focus_prev(self, size) -> None:
410
+ def move_focus_prev(self, size: tuple[int, int]) -> None:
400
411
  _f, (i, _sub) = self.walker.get_focus()
401
412
  assert i > 0 # noqa: S101 # for examples "assert" is acceptable
402
413
 
@@ -442,7 +453,7 @@ class CellColumn(urwid.WidgetWrap):
442
453
 
443
454
  return True
444
455
 
445
- def create_child(self, letter):
456
+ def create_child(self, letter: str) -> tuple[Cell, CellColumn] | tuple[None, None]:
446
457
  """Return (parent cell,child column) or None,None on failure."""
447
458
  _f, (i, sub) = self.walker.get_focus()
448
459
  if sub != 0:
@@ -479,7 +490,7 @@ class CellColumn(urwid.WidgetWrap):
479
490
 
480
491
  return "".join(lines)
481
492
 
482
- def get_result(self):
493
+ def get_result(self) -> int | None:
483
494
  """Return the result of the last cell in the column."""
484
495
 
485
496
  return self.content[-1].get_result()
@@ -541,7 +552,7 @@ class HelpColumn(urwid.Widget):
541
552
  self.body = urwid.AttrMap(self.listbox, "help")
542
553
  self.frame = urwid.Frame(self.body, header=self.head)
543
554
 
544
- def render(self, size, focus: bool = False) -> urwid.Canvas:
555
+ def render(self, size: tuple[int, int], focus: bool = False) -> urwid.Canvas:
545
556
  maxcol, maxrow = size
546
557
  head_rows = self.head.rows((maxcol,))
547
558
  if "bottom" in self.listbox.ends_visible((maxcol, maxrow - head_rows)):
@@ -551,17 +562,17 @@ class HelpColumn(urwid.Widget):
551
562
 
552
563
  return self.frame.render((maxcol, maxrow), focus)
553
564
 
554
- def keypress(self, size, key: str) -> str | None:
565
+ def keypress(self, size: tuple[int, int], key: str) -> str | None:
555
566
  return self.frame.keypress(size, key)
556
567
 
557
568
 
558
569
  class CalcDisplay:
559
- palette: typing.ClassVar[list[tuple[str, str, str, ...]]] = [
570
+ palette: typing.ClassVar[list[tuple[str, str, str] | tuple[str, str, str, str]]] = [
560
571
  ("body", "white", "dark blue"),
561
572
  ("edit", "yellow", "dark blue"),
562
573
  ("editfocus", "yellow", "dark cyan", "bold"),
563
- ("key", "dark cyan", "light gray", ("standout", "underline")),
564
- ("title", "white", "light gray", ("bold", "standout")),
574
+ ("key", "dark cyan", "light gray", "standout,underline"),
575
+ ("title", "white", "light gray", "bold,standout"),
565
576
  ("help", "black", "light gray", "standout"),
566
577
  ("helpnote", "dark green", "light gray"),
567
578
  ("colhead", "black", "light gray", "standout"),
@@ -586,7 +597,7 @@ class CalcDisplay:
586
597
  print(expression)
587
598
  print("Result:", result)
588
599
 
589
- def input_filter(self, data, raw_input):
600
+ def input_filter(self, data: list[str | tuple[str, int, int, int]], raw_input: list[int]) -> list[str]:
590
601
  if "q" in data or "Q" in data:
591
602
  raise urwid.ExitMainLoop()
592
603
 
@@ -604,7 +615,7 @@ class CalcDisplay:
604
615
  # remove all input from further processing by MainLoop
605
616
  return []
606
617
 
607
- def wrap_keypress(self, key: str) -> None:
618
+ def wrap_keypress(self, key: str | tuple[str, int, int, int]) -> None:
608
619
  """Handle confirmation and throw event on bad input."""
609
620
 
610
621
  try:
@@ -633,7 +644,7 @@ class CalcDisplay:
633
644
  if key not in EDIT_KEYS and key not in MOVEMENT_KEYS:
634
645
  raise CalcEvent(E_invalid_key % key.upper())
635
646
 
636
- def keypress(self, key: str) -> str | None:
647
+ def keypress(self, key: str | tuple[str, int, int, int]) -> str | None:
637
648
  """Handle a keystroke."""
638
649
 
639
650
  self.loop.process_input([key])
@@ -774,7 +785,7 @@ class CalcNumLayout(urwid.TextLayout):
774
785
  the last line for the cursor.
775
786
  """
776
787
 
777
- def layout(self, text, width: int, align, wrap):
788
+ def layout(self, text: str | bytes, width: int, align: typing.Any, wrap: typing.Any):
778
789
  """
779
790
  Return layout structure for calculator number display.
780
791
  """