urwid 4.0.6__tar.gz → 4.0.7__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.
- {urwid-4.0.6/urwid.egg-info → urwid-4.0.7}/PKG-INFO +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/docs/changelog.rst +17 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/graph.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/real_browse.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/real_edit.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/examples/browse.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/examples/calc.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/examples/edit.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/examples/fib.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/examples/graph.py +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/examples/treesample.py +2 -2
- {urwid-4.0.6 → urwid-4.0.7}/pyproject.toml +8 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/web.py +32 -11
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/main_loop.py +67 -20
- {urwid-4.0.6 → urwid-4.0.7}/urwid/signals.py +19 -8
- {urwid-4.0.6 → urwid-4.0.7}/urwid/version.py +3 -3
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/constants.py +19 -7
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/filler.py +7 -2
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/listbox.py +89 -67
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/monitored_list.py +10 -9
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/overlay.py +15 -6
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/scrollable.py +23 -20
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/treetools.py +25 -22
- {urwid-4.0.6 → urwid-4.0.7/urwid.egg-info}/PKG-INFO +1 -1
- {urwid-4.0.6 → urwid-4.0.7}/urwid.egg-info/scm_file_list.json +238 -238
- urwid-4.0.7/urwid.egg-info/scm_version.json +8 -0
- urwid-4.0.6/urwid.egg-info/scm_version.json +0 -8
- {urwid-4.0.6 → urwid-4.0.7}/.coveralls.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.devcontainer/dev.dockerfile +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.devcontainer/devcontainer.json +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.dockerignore +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.editorconfig +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/CODE_OF_CONDUCT.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/ISSUE_TEMPLATE/docs.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/dependabot.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/labeler.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/release.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/workflows/documentation.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/workflows/isolated_static_check.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/workflows/labels.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/workflows/pythonpackage.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.github/workflows/yamllint.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.gitignore +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.pre-commit-config.yaml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/.yamllint.yml +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/COPYING +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/MANIFEST.in +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/README.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/SECURITY.md +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/classifiers.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/Makefile +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/conf.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/bigtext.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/bigtext.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/bigtext1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/bigtext2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/bigtext3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/browse.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/browse.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/browse1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/browse2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/edit.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/edit.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/edit1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/edit2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/edit_text.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/graph.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/graph1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/graph2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/index.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/palette_test.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/palette_test.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/palette_test1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/palette_test2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/pop_up.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/pop_up.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/pop_up1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/pop_up2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/subproc.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/subproc.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/subproc1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/subproc2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/subproc2.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/tour.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/tour.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/tour1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/examples/tour2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/index.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/bright_combinations.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/bright_combinations.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/bright_combinations1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/canvascache.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/displayattributes.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/displaymodules.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/encodings.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/display_modules.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/introduction.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/urwid_widgets.svgz +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/urwid_widgets_1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/urwid_widgets_1.xcf +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/urwid_widgets_2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/urwid_widgets_2.xcf +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/images/widget_layout.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/index.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/mainloop.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/overview.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/safe_combinations.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/safe_combinations.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/safe_combinations1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/textlayout.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/userinput.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/wanat.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/wanat_multi.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/wcur1.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/wcur2.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/widgets.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/wmod.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/manual/wsel.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/attrspec.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/canvas.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/command_map.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/constants.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/deprecated.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/display_modules.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/exceptions.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/global_settings.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/index.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/list_walkers.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/main_loop.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/meta.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/signals.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/text_layout.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/reference/widget.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tools/compile_pngs.sh +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tools/screenshots.sh +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tools/static/.placeholder +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tools/templates/indexcontent.html +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tools/templates/indexsidebar.html +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tools/templates/localtoc.html +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/adventure.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/adventure.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/adventure1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/adventure2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/adventure3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/adventure4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/cmenu.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/cmenu.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/cmenu1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/cmenu2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/cmenu3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/cmenu4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/highcolors.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/highcolors.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/highcolors1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/hmenu.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/hmenu.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/hmenu1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/hmenu2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/hmenu3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/hmenu4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/index.rst +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/input5.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/menu25.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/minimal.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/minimal.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/minimal1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/multiple.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/multiple.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/multiple1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/multiple2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/multiple3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/multiple4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/qa.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/qa.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/qa1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/qa2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/qa3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/sig.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/sig.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/sig1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/sig2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/sig3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/sig4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/smenu.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/smenu.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/smenu1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/smenu2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/smenu3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/urwid_attr.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/urwid_attr.py.xdotool +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/urwid_attr1.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/urwid_attr2.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/urwid_attr3.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/tutorial/urwid_attr4.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/docs/urwid-logo.png +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/asyncio_socket_server.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/bigtext.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/dialog.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/input_test.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/lcd_cf635.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/palette_test.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/pop_up.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/subproc.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/subproc2.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/terminal.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/tour.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/twisted_serve_ssh.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/examples/twisted_serve_ssh.tac +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/pylint-requirements.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/requirements.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/ruff-requirements.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/setup.cfg +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/test_requirements.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/__init__.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_canvas.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_columns.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_container.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_doctests.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_escapes.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_event_loops.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_filler.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_floatedit.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_font.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_frame.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_grapheme_clusters.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_graphics.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_grid_flow.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_line_box.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_listbox.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_main_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_overlay.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_padding.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_pile.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_raw_display.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_scrollable.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_signals.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_str_util.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_text_layout.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_tree.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_util.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_vterm.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/test_widget.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tests/util.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/tox.ini +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/__init__.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/canvas.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/command_map.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/__init__.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/_posix_raw_display.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/_raw_display_base.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/_web.css +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/_web.js +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/_win32.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/_win32_raw_display.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/common.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/curses.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/escape.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/html_fragment.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/lcd.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/display/raw.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/__init__.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/abstract_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/asyncio_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/glib_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/select_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/tornado_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/trio_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/twisted_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/event_loop/zmq_loop.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/font.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/graphics.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/numedit.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/py.typed +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/split_repr.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/str_util.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/text_layout.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/util.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/vterm.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/__init__.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/attr_map.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/attr_wrap.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/bar_graph.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/big_text.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/box_adapter.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/columns.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/container.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/divider.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/edit.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/frame.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/grid_flow.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/line_box.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/padding.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/pile.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/popup.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/progress_bar.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/solid_fill.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/text.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/widget.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/widget_decoration.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid/widget/wimp.py +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid.egg-info/SOURCES.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid.egg-info/dependency_links.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid.egg-info/not-zip-safe +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid.egg-info/requires.txt +0 -0
- {urwid-4.0.6 → urwid-4.0.7}/urwid.egg-info/top_level.txt +0 -0
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
---------
|
|
4
4
|
|
|
5
|
+
Urwid 4.0.7
|
|
6
|
+
===========
|
|
7
|
+
|
|
8
|
+
2026-07-24
|
|
9
|
+
|
|
10
|
+
Bug fixes 🕷
|
|
11
|
+
++++++++++++
|
|
12
|
+
* Fix encoding handling by web display by @penguinolog in https://github.com/urwid/urwid/pull/1201
|
|
13
|
+
Documentation 🕮
|
|
14
|
+
++++++++++++++++
|
|
15
|
+
* Typing: annotate `MainLoop` and `signals` by @penguinolog in https://github.com/urwid/urwid/pull/1199
|
|
16
|
+
* Typing: fix `ListBox` expected widget API by @penguinolog in https://github.com/urwid/urwid/pull/1200
|
|
17
|
+
* Typing: partial annotation for `treetools` by @penguinolog in https://github.com/urwid/urwid/pull/1197
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
**Full Changelog**: https://github.com/urwid/urwid/compare/4.0.6...4.0.7
|
|
21
|
+
|
|
5
22
|
Urwid 4.0.6
|
|
6
23
|
===========
|
|
7
24
|
|
|
@@ -276,7 +276,7 @@ class GraphView(urwid.WidgetWrap):
|
|
|
276
276
|
def exit_program(self, w) -> typing.NoReturn:
|
|
277
277
|
raise urwid.ExitMainLoop()
|
|
278
278
|
|
|
279
|
-
def graph_controls(self):
|
|
279
|
+
def graph_controls(self) -> urwid.ListBox[int]:
|
|
280
280
|
modes = self.controller.get_modes()
|
|
281
281
|
# setup mode radio buttons
|
|
282
282
|
self.mode_buttons = []
|
|
@@ -132,7 +132,7 @@ class DirectoryWidget(FlagFileWidget):
|
|
|
132
132
|
return node.get_key()
|
|
133
133
|
|
|
134
134
|
|
|
135
|
-
class FileNode(urwid.TreeNode):
|
|
135
|
+
class FileNode(urwid.TreeNode[str]):
|
|
136
136
|
"""Metadata storage for individual files"""
|
|
137
137
|
|
|
138
138
|
def __init__(self, path: str, parent: urwid.ParentNode | None = None) -> None:
|
|
@@ -132,7 +132,7 @@ class DirectoryWidget(FlagFileWidget):
|
|
|
132
132
|
return node.get_key()
|
|
133
133
|
|
|
134
134
|
|
|
135
|
-
class FileNode(urwid.TreeNode):
|
|
135
|
+
class FileNode(urwid.TreeNode[str]):
|
|
136
136
|
"""Metadata storage for individual files"""
|
|
137
137
|
|
|
138
138
|
def __init__(self, path: str, parent: urwid.ParentNode | None = None) -> None:
|
|
@@ -225,7 +225,7 @@ class ParentEdit(urwid.Edit):
|
|
|
225
225
|
return key
|
|
226
226
|
|
|
227
227
|
|
|
228
|
-
class CellWalker(urwid.ListWalker):
|
|
228
|
+
class CellWalker(urwid.ListWalker[tuple[int, int], urwid.Divider | urwid.AttrMap[urwid.IntEdit] | urwid.Text]):
|
|
229
229
|
def __init__(self, content: Iterable[Cell]) -> None:
|
|
230
230
|
self.content = urwid.MonitoredList(content)
|
|
231
231
|
self.content.set_modified_callback(self._modified)
|
|
@@ -37,7 +37,7 @@ if typing.TYPE_CHECKING:
|
|
|
37
37
|
from typing_extensions import Literal
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
class FibonacciWalker(urwid.ListWalker):
|
|
40
|
+
class FibonacciWalker(urwid.ListWalker[tuple[int, int], urwid.Text]):
|
|
41
41
|
"""ListWalker-compatible class for browsing fibonacci set.
|
|
42
42
|
|
|
43
43
|
positions returned are (value at position-1, value at position) tuples.
|
|
@@ -276,7 +276,7 @@ class GraphView(urwid.WidgetWrap):
|
|
|
276
276
|
def exit_program(self, w) -> typing.NoReturn:
|
|
277
277
|
raise urwid.ExitMainLoop()
|
|
278
278
|
|
|
279
|
-
def graph_controls(self):
|
|
279
|
+
def graph_controls(self) -> urwid.ListBox[int]:
|
|
280
280
|
modes = self.controller.get_modes()
|
|
281
281
|
# setup mode radio buttons
|
|
282
282
|
self.mode_buttons = []
|
|
@@ -55,14 +55,14 @@ class ExampleTreeWidget(urwid.TreeWidget):
|
|
|
55
55
|
return self.get_node().get_value()["name"]
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
class ExampleNode(urwid.TreeNode):
|
|
58
|
+
class ExampleNode(urwid.TreeNode[str | None]):
|
|
59
59
|
"""Data storage object for leaf nodes"""
|
|
60
60
|
|
|
61
61
|
def load_widget(self) -> ExampleTreeWidget:
|
|
62
62
|
return ExampleTreeWidget(self)
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
class ExampleParentNode(urwid.ParentNode):
|
|
65
|
+
class ExampleParentNode(urwid.ParentNode[SampleTree]):
|
|
66
66
|
"""Data storage object for interior/parent nodes"""
|
|
67
67
|
|
|
68
68
|
def load_widget(self) -> ExampleTreeWidget:
|
|
@@ -289,6 +289,14 @@ disable_error_code = [
|
|
|
289
289
|
"union-attr", # chacking for started state before each operation if too expensive
|
|
290
290
|
]
|
|
291
291
|
[[tool.mypy.overrides]]
|
|
292
|
+
module = "urwid.widget.constants"
|
|
293
|
+
disable_error_code = [
|
|
294
|
+
# False positive: plain-string `Literal`s (e.g. "relative") are reported as overlapping
|
|
295
|
+
# sibling `str`-based enums (`Align`/`VAlign`) in the size/alignment overloads, even though
|
|
296
|
+
# the underlying values are disjoint. The public API must accept both string and enum forms.
|
|
297
|
+
"overload-overlap",
|
|
298
|
+
]
|
|
299
|
+
[[tool.mypy.overrides]]
|
|
292
300
|
module = [ "gi.*", "serial.*", "trio.*" ]
|
|
293
301
|
ignore_missing_imports = true
|
|
294
302
|
|
|
@@ -38,6 +38,7 @@ import sys
|
|
|
38
38
|
import tempfile
|
|
39
39
|
import typing
|
|
40
40
|
from contextlib import suppress
|
|
41
|
+
from email.message import Message
|
|
41
42
|
|
|
42
43
|
from urwid.str_util import calc_text_pos, calc_width, move_next_char
|
|
43
44
|
from urwid.util import StoppingContext, get_encoding
|
|
@@ -264,7 +265,7 @@ class Screen(BaseScreen):
|
|
|
264
265
|
self._started = False
|
|
265
266
|
|
|
266
267
|
def set_input_timeouts(self, *args: typing.Any) -> None:
|
|
267
|
-
|
|
268
|
+
"""Not supported for web display."""
|
|
268
269
|
|
|
269
270
|
def _close_connection(self) -> None:
|
|
270
271
|
if self.update_method == "polling child":
|
|
@@ -501,6 +502,12 @@ def is_web_request() -> bool:
|
|
|
501
502
|
return "REQUEST_METHOD" in os.environ
|
|
502
503
|
|
|
503
504
|
|
|
505
|
+
def _request_charset() -> str:
|
|
506
|
+
content_type = Message()
|
|
507
|
+
content_type["content-type"] = os.environ.get("CONTENT_TYPE", "")
|
|
508
|
+
return content_type.get_content_charset() or "utf-8"
|
|
509
|
+
|
|
510
|
+
|
|
504
511
|
def handle_short_request() -> bool:
|
|
505
512
|
"""
|
|
506
513
|
Handle short requests such as passing keystrokes to the application
|
|
@@ -541,16 +548,23 @@ def handle_short_request() -> bool:
|
|
|
541
548
|
|
|
542
549
|
if os.environ.get("HTTP_X_URWID_METHOD", None) == "polling":
|
|
543
550
|
# this is a screen update request
|
|
544
|
-
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
545
551
|
try:
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
552
|
+
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
|
|
553
|
+
s.connect(os.path.join(_prefs.pipe_dir, f"urwid_{urwid_id}.update"))
|
|
554
|
+
chunks = []
|
|
555
|
+
while data := s.recv(BUF_SZ):
|
|
556
|
+
chunks.append(data)
|
|
551
557
|
except OSError:
|
|
552
558
|
sys.stdout.write("Status: 404 Not Found\r\n\r\n")
|
|
553
559
|
return True
|
|
560
|
+
|
|
561
|
+
try:
|
|
562
|
+
decoded = b"".join(chunks).decode("utf-8")
|
|
563
|
+
except UnicodeDecodeError:
|
|
564
|
+
sys.stdout.write("Status: 502 Bad Gateway\r\n\r\n")
|
|
565
|
+
return True
|
|
566
|
+
|
|
567
|
+
sys.stdout.write(f"Content-type: text/plain; charset=utf-8\r\n\r\n{decoded}")
|
|
554
568
|
return True
|
|
555
569
|
|
|
556
570
|
# this is a keyboard input request
|
|
@@ -560,10 +574,17 @@ def handle_short_request() -> bool:
|
|
|
560
574
|
sys.stdout.write("Status: 404 Not Found\r\n\r\n")
|
|
561
575
|
return True
|
|
562
576
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
577
|
+
try:
|
|
578
|
+
try:
|
|
579
|
+
keydata = sys.stdin.read(MAX_READ)
|
|
580
|
+
encoded_keydata = keydata.encode(_request_charset())
|
|
581
|
+
except (LookupError, UnicodeError):
|
|
582
|
+
sys.stdout.write("Status: 400 Bad Request\r\n\r\n")
|
|
583
|
+
return True
|
|
584
|
+
os.write(fd, encoded_keydata)
|
|
585
|
+
finally:
|
|
586
|
+
with suppress(OSError):
|
|
587
|
+
os.close(fd)
|
|
567
588
|
sys.stdout.write("Content-type: text/plain\r\n\r\n")
|
|
568
589
|
|
|
569
590
|
return True
|
|
@@ -42,7 +42,7 @@ from .select_loop import SelectEventLoop
|
|
|
42
42
|
if typing.TYPE_CHECKING:
|
|
43
43
|
from collections.abc import Callable, Iterable
|
|
44
44
|
|
|
45
|
-
from typing_extensions import Self
|
|
45
|
+
from typing_extensions import Literal, Self
|
|
46
46
|
|
|
47
47
|
from urwid.display import BaseScreen
|
|
48
48
|
from urwid.widget import AbstractWidget
|
|
@@ -51,6 +51,37 @@ if typing.TYPE_CHECKING:
|
|
|
51
51
|
|
|
52
52
|
_T = typing.TypeVar("_T")
|
|
53
53
|
|
|
54
|
+
class _ExternalLoopScreen(typing.Protocol):
|
|
55
|
+
"""Screen able to drive an external event loop (e.g. raw_display / curses screens).
|
|
56
|
+
|
|
57
|
+
These members are not part of :class:`BaseScreen`;
|
|
58
|
+
:class:`MainLoop` only uses them after guarding with ``hasattr``
|
|
59
|
+
(or after :meth:`MainLoop.start` raised :exc:`CantUseExternalLoop`),
|
|
60
|
+
so accessing them through this protocol via ``cast`` is safe.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
signal_handler_setter: Callable[..., typing.Any]
|
|
64
|
+
|
|
65
|
+
def hook_event_loop(
|
|
66
|
+
self,
|
|
67
|
+
event_loop: EventLoop,
|
|
68
|
+
callback: Callable[[list[str | tuple[str, int, int, int]], list[int]], typing.Any],
|
|
69
|
+
) -> None: ...
|
|
70
|
+
|
|
71
|
+
def unhook_event_loop(self, event_loop: EventLoop) -> None: ...
|
|
72
|
+
|
|
73
|
+
def get_input(self, raw_keys: Literal[True]) -> tuple[list[str | tuple[str, int, int, int]], list[int]]: ...
|
|
74
|
+
|
|
75
|
+
def set_input_timeouts(self, max_wait: float | None = ...) -> None: ...
|
|
76
|
+
|
|
77
|
+
class _EventLoopWithAlarmsStore(typing.Protocol):
|
|
78
|
+
"""Event loop that supports alarms storage (like :class:`SelectEventLoop`).
|
|
79
|
+
|
|
80
|
+
Not all event loops support alarms storage.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
_alarms: list[tuple[float, int, Callable[[], typing.Any]]]
|
|
84
|
+
|
|
54
85
|
|
|
55
86
|
IS_WINDOWS = sys.platform == "win32"
|
|
56
87
|
PIPE_BUFFER_READ_SIZE = 4096 # can expect this much on Linux, so try for that
|
|
@@ -116,7 +147,9 @@ class MainLoop:
|
|
|
116
147
|
] = (),
|
|
117
148
|
screen: BaseScreen | None = None,
|
|
118
149
|
handle_mouse: bool = True,
|
|
119
|
-
input_filter:
|
|
150
|
+
input_filter: (
|
|
151
|
+
Callable[[list[str | tuple[str, int, int, int]], list[int]], list[str | tuple[str, int, int, int]]] | None
|
|
152
|
+
) = None,
|
|
120
153
|
unhandled_input: Callable[[str | tuple[str, int, int, int]], bool | None] | None = None,
|
|
121
154
|
event_loop: EventLoop | None = None,
|
|
122
155
|
pop_ups: bool = False,
|
|
@@ -149,7 +182,7 @@ class MainLoop:
|
|
|
149
182
|
if hasattr(self.screen, "signal_handler_setter"):
|
|
150
183
|
# Tell the screen what function it must use to set
|
|
151
184
|
# signal handlers
|
|
152
|
-
self.screen.signal_handler_setter = self.event_loop.set_signal_handler
|
|
185
|
+
typing.cast("_ExternalLoopScreen", self.screen).signal_handler_setter = self.event_loop.set_signal_handler
|
|
153
186
|
|
|
154
187
|
self._watch_pipes: dict[int, tuple[Callable[[], typing.Any], int]] = {}
|
|
155
188
|
|
|
@@ -164,7 +197,7 @@ class MainLoop:
|
|
|
164
197
|
@widget.setter
|
|
165
198
|
def widget(self, widget: AbstractWidget) -> None:
|
|
166
199
|
self._widget = widget
|
|
167
|
-
if self.pop_ups:
|
|
200
|
+
if self.pop_ups and hasattr(self._topmost_widget, "original_widget"):
|
|
168
201
|
self._topmost_widget.original_widget = self._widget
|
|
169
202
|
else:
|
|
170
203
|
self._topmost_widget = self._widget
|
|
@@ -181,7 +214,12 @@ class MainLoop:
|
|
|
181
214
|
else:
|
|
182
215
|
self._topmost_widget = self._widget
|
|
183
216
|
|
|
184
|
-
def set_alarm_in(
|
|
217
|
+
def set_alarm_in(
|
|
218
|
+
self,
|
|
219
|
+
sec: float,
|
|
220
|
+
callback: Callable[[Self, _T | None], typing.Any],
|
|
221
|
+
user_data: _T | None = None,
|
|
222
|
+
) -> typing.Any:
|
|
185
223
|
"""
|
|
186
224
|
Schedule an alarm in *sec* seconds that will call *callback* from the
|
|
187
225
|
within the :meth:`run` method.
|
|
@@ -201,7 +239,12 @@ class MainLoop:
|
|
|
201
239
|
|
|
202
240
|
return self.event_loop.alarm(sec, cb)
|
|
203
241
|
|
|
204
|
-
def set_alarm_at(
|
|
242
|
+
def set_alarm_at(
|
|
243
|
+
self,
|
|
244
|
+
tm: float,
|
|
245
|
+
callback: Callable[[Self, _T | None], typing.Any],
|
|
246
|
+
user_data: _T | None = None,
|
|
247
|
+
) -> typing.Any:
|
|
205
248
|
"""
|
|
206
249
|
Schedule an alarm at *tm* time that will call *callback* from the
|
|
207
250
|
within the :meth:`run` function. Returns a handle that may be passed to
|
|
@@ -223,7 +266,7 @@ class MainLoop:
|
|
|
223
266
|
|
|
224
267
|
return self.event_loop.alarm(sec, cb)
|
|
225
268
|
|
|
226
|
-
def remove_alarm(self, handle) -> bool:
|
|
269
|
+
def remove_alarm(self, handle: typing.Any) -> bool:
|
|
227
270
|
"""
|
|
228
271
|
Remove an alarm. Return ``True`` if *handle* was found, ``False``
|
|
229
272
|
otherwise.
|
|
@@ -289,7 +332,7 @@ class MainLoop:
|
|
|
289
332
|
os.close(pipe_rd)
|
|
290
333
|
return True
|
|
291
334
|
|
|
292
|
-
def watch_file(self, fd: int, callback: Callable[[], typing.Any]):
|
|
335
|
+
def watch_file(self, fd: int, callback: Callable[[], typing.Any]) -> typing.Any:
|
|
293
336
|
"""
|
|
294
337
|
Call *callback* when *fd* has some data to read. No parameters are
|
|
295
338
|
passed to callback.
|
|
@@ -299,7 +342,7 @@ class MainLoop:
|
|
|
299
342
|
self.logger.debug(f"Setting watch file descriptor {fd!r} with {callback!r}")
|
|
300
343
|
return self.event_loop.watch_file(fd, callback)
|
|
301
344
|
|
|
302
|
-
def remove_watch_file(self, handle) -> bool:
|
|
345
|
+
def remove_watch_file(self, handle: typing.Any) -> bool:
|
|
303
346
|
"""
|
|
304
347
|
Remove a watch file. Returns ``True`` if the watch file
|
|
305
348
|
exists, ``False`` otherwise.
|
|
@@ -399,13 +442,14 @@ class MainLoop:
|
|
|
399
442
|
self.event_loop.remove_enter_idle(self.idle_handle)
|
|
400
443
|
del self.idle_handle
|
|
401
444
|
signals.disconnect_signal(self.screen, INPUT_DESCRIPTORS_CHANGED, self._reset_input_descriptors)
|
|
402
|
-
self.screen.unhook_event_loop(self.event_loop)
|
|
445
|
+
typing.cast("_ExternalLoopScreen", self.screen).unhook_event_loop(self.event_loop)
|
|
403
446
|
|
|
404
447
|
self.screen.stop()
|
|
405
448
|
|
|
406
449
|
def _reset_input_descriptors(self) -> None:
|
|
407
|
-
|
|
408
|
-
|
|
450
|
+
screen = typing.cast("_ExternalLoopScreen", self.screen)
|
|
451
|
+
screen.unhook_event_loop(self.event_loop)
|
|
452
|
+
screen.hook_event_loop(self.event_loop, self._update)
|
|
409
453
|
|
|
410
454
|
def _run(self) -> None:
|
|
411
455
|
try:
|
|
@@ -456,23 +500,26 @@ class MainLoop:
|
|
|
456
500
|
# pylint: disable=protected-access # special case for alarms handling
|
|
457
501
|
self.logger.debug(f"Starting screen {self.screen!r} event loop")
|
|
458
502
|
|
|
459
|
-
|
|
503
|
+
screen = typing.cast("_ExternalLoopScreen", self.screen)
|
|
504
|
+
event_loop = typing.cast("_EventLoopWithAlarmsStore", self.event_loop)
|
|
505
|
+
|
|
506
|
+
next_alarm: tuple[float, int, Callable[[], typing.Any]] | None = None
|
|
460
507
|
|
|
461
508
|
while True:
|
|
462
509
|
self.draw_screen()
|
|
463
510
|
|
|
464
|
-
if not next_alarm and
|
|
465
|
-
next_alarm = heapq.heappop(
|
|
511
|
+
if not next_alarm and event_loop._alarms:
|
|
512
|
+
next_alarm = heapq.heappop(event_loop._alarms)
|
|
466
513
|
|
|
467
514
|
keys: list[str | tuple[str, int, int, int]] = []
|
|
468
515
|
raw: list[int] = []
|
|
469
516
|
while not keys:
|
|
470
517
|
if next_alarm:
|
|
471
518
|
sec = max(0.0, next_alarm[0] - time.time())
|
|
472
|
-
|
|
519
|
+
screen.set_input_timeouts(sec)
|
|
473
520
|
else:
|
|
474
|
-
|
|
475
|
-
keys, raw =
|
|
521
|
+
screen.set_input_timeouts(None)
|
|
522
|
+
keys, raw = screen.get_input(True)
|
|
476
523
|
if not keys and next_alarm and next_alarm[0] - time.time() <= 0:
|
|
477
524
|
break
|
|
478
525
|
|
|
@@ -485,8 +532,8 @@ class MainLoop:
|
|
|
485
532
|
_tm, _tie_break, callback = next_alarm
|
|
486
533
|
callback()
|
|
487
534
|
|
|
488
|
-
if
|
|
489
|
-
next_alarm = heapq.heappop(
|
|
535
|
+
if event_loop._alarms:
|
|
536
|
+
next_alarm = heapq.heappop(event_loop._alarms)
|
|
490
537
|
else:
|
|
491
538
|
next_alarm = None
|
|
492
539
|
|
|
@@ -55,7 +55,7 @@ class MetaSignals(abc.ABCMeta):
|
|
|
55
55
|
def setdefaultattr(obj: typing.Any, name: str, value: _T) -> _T:
|
|
56
56
|
# like dict.setdefault() for object attributes
|
|
57
57
|
if hasattr(obj, name):
|
|
58
|
-
return getattr(obj, name)
|
|
58
|
+
return getattr(obj, name)
|
|
59
59
|
setattr(obj, name, value)
|
|
60
60
|
return value
|
|
61
61
|
|
|
@@ -69,6 +69,15 @@ class Key:
|
|
|
69
69
|
__slots__ = ()
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
if typing.TYPE_CHECKING:
|
|
73
|
+
# ``weak_args`` (converted to weakrefs) and ``user_args`` as prepared by ``_prepare_user_args``.
|
|
74
|
+
_UserArgs = tuple[Collection[weakref.ReferenceType], Collection[typing.Any]]
|
|
75
|
+
# A single connected handler: (key, callback, deprecated user_arg, prepared args).
|
|
76
|
+
_SignalHandler = tuple[Key, Callable[..., typing.Any], typing.Any, _UserArgs]
|
|
77
|
+
# Per-sender storage attached to ``obj`` under ``Signals._signal_attr``.
|
|
78
|
+
_SignalStore = dict[Hashable, list[_SignalHandler]]
|
|
79
|
+
|
|
80
|
+
|
|
72
81
|
class Signals:
|
|
73
82
|
_signal_attr = "_urwid_signals" # attribute to attach to signal senders
|
|
74
83
|
|
|
@@ -89,7 +98,7 @@ class Signals:
|
|
|
89
98
|
|
|
90
99
|
def connect(
|
|
91
100
|
self,
|
|
92
|
-
obj,
|
|
101
|
+
obj: typing.Any,
|
|
93
102
|
name: Hashable,
|
|
94
103
|
callback: Callable[..., typing.Any],
|
|
95
104
|
user_arg: typing.Any = None,
|
|
@@ -180,7 +189,8 @@ class Signals:
|
|
|
180
189
|
# Just generate an arbitrary (but unique) key
|
|
181
190
|
key = Key()
|
|
182
191
|
|
|
183
|
-
|
|
192
|
+
signals: _SignalStore = setdefaultattr(obj, self._signal_attr, {})
|
|
193
|
+
handlers = signals.setdefault(name, [])
|
|
184
194
|
|
|
185
195
|
# Remove the signal handler when any of the weakref'd arguments
|
|
186
196
|
# are garbage collected. Note that this means that the handlers
|
|
@@ -216,7 +226,7 @@ class Signals:
|
|
|
216
226
|
|
|
217
227
|
def disconnect(
|
|
218
228
|
self,
|
|
219
|
-
obj,
|
|
229
|
+
obj: typing.Any,
|
|
220
230
|
name: Hashable,
|
|
221
231
|
callback: Callable[..., typing.Any],
|
|
222
232
|
user_arg: typing.Any = None,
|
|
@@ -242,7 +252,7 @@ class Signals:
|
|
|
242
252
|
If the callback is not connected or already disconnected, this
|
|
243
253
|
function will simply do nothing.
|
|
244
254
|
"""
|
|
245
|
-
signals = setdefaultattr(obj, self._signal_attr, {})
|
|
255
|
+
signals: _SignalStore = setdefaultattr(obj, self._signal_attr, {})
|
|
246
256
|
if name not in signals:
|
|
247
257
|
return None
|
|
248
258
|
|
|
@@ -258,7 +268,7 @@ class Signals:
|
|
|
258
268
|
return self.disconnect_by_key(obj, name, h[0])
|
|
259
269
|
return None
|
|
260
270
|
|
|
261
|
-
def disconnect_by_key(self, obj, name: Hashable, key: Key) -> None:
|
|
271
|
+
def disconnect_by_key(self, obj: typing.Any, name: Hashable, key: Key) -> None:
|
|
262
272
|
"""
|
|
263
273
|
:param obj: the object to disconnect the signal from
|
|
264
274
|
:type obj: object
|
|
@@ -275,10 +285,11 @@ class Signals:
|
|
|
275
285
|
If the callback is not connected or already disconnected, this
|
|
276
286
|
function will simply do nothing.
|
|
277
287
|
"""
|
|
278
|
-
|
|
288
|
+
signals: _SignalStore = setdefaultattr(obj, self._signal_attr, {})
|
|
289
|
+
handlers = signals.get(name, [])
|
|
279
290
|
handlers[:] = [h for h in handlers if h[0] is not key]
|
|
280
291
|
|
|
281
|
-
def emit(self, obj, name: Hashable, *args: typing.Any) -> bool:
|
|
292
|
+
def emit(self, obj: typing.Any, name: Hashable, *args: typing.Any) -> bool:
|
|
282
293
|
"""
|
|
283
294
|
:param obj: the object sending a signal
|
|
284
295
|
:type obj: object
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '4.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (4, 0,
|
|
21
|
+
__version__ = version = '4.0.7'
|
|
22
|
+
__version_tuple__ = version_tuple = (4, 0, 7)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g7c32ae3ff'
|
|
@@ -246,14 +246,17 @@ def normalize_width(
|
|
|
246
246
|
if width doesn't match a valid alignment.
|
|
247
247
|
"""
|
|
248
248
|
if width in {WHSettings.CLIP, WHSettings.PACK}:
|
|
249
|
-
return (WHSettings(width), None)
|
|
249
|
+
return (typing.cast("Literal[WHSettings.CLIP, WHSettings.PACK]", WHSettings(width)), None)
|
|
250
250
|
|
|
251
251
|
if isinstance(width, int):
|
|
252
252
|
return (WHSettings.GIVEN, width)
|
|
253
253
|
|
|
254
254
|
if isinstance(width, tuple) and len(width) == 2 and width[0] in {WHSettings.RELATIVE, WHSettings.WEIGHT}:
|
|
255
255
|
width_type, width_amount = width
|
|
256
|
-
return (
|
|
256
|
+
return typing.cast(
|
|
257
|
+
"tuple[Literal[WHSettings.RELATIVE], int] | tuple[Literal[WHSettings.WEIGHT], int | float]",
|
|
258
|
+
(WHSettings(width_type), width_amount),
|
|
259
|
+
)
|
|
257
260
|
|
|
258
261
|
raise err(
|
|
259
262
|
f"width value {width!r} is not one of"
|
|
@@ -310,7 +313,7 @@ def simplify_width(
|
|
|
310
313
|
Inverse of normalize_width.
|
|
311
314
|
"""
|
|
312
315
|
if width_type in {WHSettings.CLIP, WHSettings.PACK}:
|
|
313
|
-
return WHSettings(width_type)
|
|
316
|
+
return typing.cast("Literal[WHSettings.CLIP, WHSettings.PACK]", WHSettings(width_type))
|
|
314
317
|
|
|
315
318
|
if not isinstance(width_amount, int):
|
|
316
319
|
raise TypeError(width_amount)
|
|
@@ -318,7 +321,10 @@ def simplify_width(
|
|
|
318
321
|
if width_type == WHSettings.GIVEN:
|
|
319
322
|
return width_amount
|
|
320
323
|
|
|
321
|
-
return (
|
|
324
|
+
return typing.cast(
|
|
325
|
+
"tuple[Literal[WHSettings.RELATIVE], int] | tuple[Literal[WHSettings.WEIGHT], int | float]",
|
|
326
|
+
(WHSettings(width_type), width_amount),
|
|
327
|
+
)
|
|
322
328
|
|
|
323
329
|
|
|
324
330
|
@typing.overload
|
|
@@ -373,7 +379,10 @@ def normalize_height(
|
|
|
373
379
|
return (WHSettings.PACK, None)
|
|
374
380
|
|
|
375
381
|
if isinstance(height, tuple) and len(height) == 2 and height[0] in {WHSettings.RELATIVE, WHSettings.WEIGHT}:
|
|
376
|
-
return (
|
|
382
|
+
return typing.cast(
|
|
383
|
+
"tuple[Literal[WHSettings.RELATIVE], int] | tuple[Literal[WHSettings.WEIGHT], int | float]",
|
|
384
|
+
(WHSettings(height[0]), height[1]),
|
|
385
|
+
)
|
|
377
386
|
|
|
378
387
|
if isinstance(height, int):
|
|
379
388
|
return (WHSettings.GIVEN, height)
|
|
@@ -444,7 +453,7 @@ def simplify_height(
|
|
|
444
453
|
Inverse of normalize_height.
|
|
445
454
|
"""
|
|
446
455
|
if height_type in {WHSettings.FLOW, WHSettings.PACK}:
|
|
447
|
-
return WHSettings(height_type)
|
|
456
|
+
return typing.cast("Literal[WHSettings.FLOW, WHSettings.PACK]", WHSettings(height_type))
|
|
448
457
|
|
|
449
458
|
if not isinstance(height_amount, int):
|
|
450
459
|
raise TypeError(height_amount)
|
|
@@ -452,7 +461,10 @@ def simplify_height(
|
|
|
452
461
|
if height_type == WHSettings.GIVEN:
|
|
453
462
|
return height_amount
|
|
454
463
|
|
|
455
|
-
return (
|
|
464
|
+
return typing.cast(
|
|
465
|
+
"tuple[Literal[WHSettings.RELATIVE], int] | tuple[Literal[WHSettings.WEIGHT], int | float]",
|
|
466
|
+
(WHSettings(height_type), height_amount),
|
|
467
|
+
)
|
|
456
468
|
|
|
457
469
|
|
|
458
470
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -342,7 +342,7 @@ class Filler(WidgetDecoration[WrappedWidget]):
|
|
|
342
342
|
def calculate_top_bottom_filler(
|
|
343
343
|
maxrow: int,
|
|
344
344
|
valign_type: Literal["top", "middle", "bottom", "relative", WHSettings.RELATIVE] | VAlign,
|
|
345
|
-
valign_amount: int,
|
|
345
|
+
valign_amount: int | None,
|
|
346
346
|
height_type: Literal["given", "relative", "clip", WHSettings.GIVEN, WHSettings.RELATIVE, WHSettings.CLIP],
|
|
347
347
|
height_amount: int,
|
|
348
348
|
min_height: int | None,
|
|
@@ -380,6 +380,9 @@ def calculate_top_bottom_filler(
|
|
|
380
380
|
>>> ctbf(20, "relative", 30, "relative", 60, 14, 0, 0)
|
|
381
381
|
(2, 4)
|
|
382
382
|
"""
|
|
383
|
+
if valign_type == WHSettings.RELATIVE and valign_amount is None:
|
|
384
|
+
raise TypeError("valign_amount must be specified when valign_type is relative")
|
|
385
|
+
|
|
383
386
|
if height_type == WHSettings.RELATIVE:
|
|
384
387
|
maxheight = max(maxrow - top - bottom, 0)
|
|
385
388
|
height = int_scale(height_amount, 101, maxheight + 1)
|
|
@@ -388,7 +391,9 @@ def calculate_top_bottom_filler(
|
|
|
388
391
|
else:
|
|
389
392
|
height = height_amount
|
|
390
393
|
|
|
391
|
-
valign = {VAlign.TOP: 0, VAlign.MIDDLE: 50, VAlign.BOTTOM: 100}.get(
|
|
394
|
+
valign: int = {VAlign.TOP: 0, VAlign.MIDDLE: 50, VAlign.BOTTOM: 100}.get( # type: ignore[assignment]
|
|
395
|
+
valign_type, valign_amount
|
|
396
|
+
) # relative + None already filtered above
|
|
392
397
|
|
|
393
398
|
# add the remainder of top/bottom to the filler
|
|
394
399
|
filler = maxrow - height - top - bottom
|