urwid 2.6.5__tar.gz → 2.6.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.
Potentially problematic release.
This version of urwid might be problematic. Click here for more details.
- {urwid-2.6.5 → urwid-2.6.7}/PKG-INFO +1 -1
- {urwid-2.6.5 → urwid-2.6.7}/pyproject.toml +4 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_columns.py +82 -3
- urwid-2.6.7/tests/test_main_loop.py +117 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/main_loop.py +20 -25
- {urwid-2.6.5 → urwid-2.6.7}/urwid/version.py +2 -2
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/columns.py +70 -26
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/frame.py +17 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/grid_flow.py +39 -4
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/overlay.py +62 -2
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/padding.py +10 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/pile.py +45 -14
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/widget.py +1 -1
- {urwid-2.6.5 → urwid-2.6.7}/urwid.egg-info/PKG-INFO +1 -1
- {urwid-2.6.5 → urwid-2.6.7}/urwid.egg-info/SOURCES.txt +1 -0
- {urwid-2.6.5 → urwid-2.6.7}/.coveralls.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.devcontainer/dev.dockerfile +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.devcontainer/devcontainer.json +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.dockerignore +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/CODE_OF_CONDUCT.md +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/ISSUE_TEMPLATE/docs.md +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/dependabot.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/labeler.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/release.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/workflows/documentation.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/workflows/isolated_static_check.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/workflows/labels.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/workflows/pythonpackage.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.github/workflows/yamllint.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.gitignore +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.pre-commit-config.yaml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/.yamllint.yml +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/COPYING +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/MANIFEST.in +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/README.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/black-requirements.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/classifiers.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/Makefile +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/changelog.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/conf.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/bigtext.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/bigtext.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/bigtext1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/bigtext2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/bigtext3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/browse.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/browse.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/browse1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/browse2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/edit.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/edit.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/edit1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/edit2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/edit_text.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/graph.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/graph.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/graph1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/graph2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/index.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/palette_test.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/palette_test.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/palette_test1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/palette_test2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/pop_up.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/pop_up.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/pop_up1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/pop_up2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/real_browse.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/real_edit.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/subproc.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/subproc.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/subproc1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/subproc2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/subproc2.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/tour.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/tour.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/tour1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/examples/tour2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/index.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/bright_combinations.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/bright_combinations.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/bright_combinations1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/canvascache.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/displayattributes.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/displaymodules.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/encodings.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/display_modules.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/introduction.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/urwid_widgets.svgz +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/urwid_widgets_1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/urwid_widgets_1.xcf +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/urwid_widgets_2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/urwid_widgets_2.xcf +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/images/widget_layout.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/index.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/mainloop.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/overview.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/safe_combinations.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/safe_combinations.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/safe_combinations1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/textlayout.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/userinput.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/wanat.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/wanat_multi.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/wcur1.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/wcur2.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/widgets.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/wmod.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/manual/wsel.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/attrspec.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/canvas.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/command_map.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/constants.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/deprecated.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/display_modules.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/exceptions.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/global_settings.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/index.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/list_walkers.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/main_loop.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/meta.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/signals.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/text_layout.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/reference/widget.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tools/compile_pngs.sh +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tools/screenshots.sh +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tools/static/.placeholder +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tools/templates/indexcontent.html +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tools/templates/indexsidebar.html +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tools/templates/localtoc.html +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/adventure.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/adventure.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/adventure1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/adventure2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/adventure3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/adventure4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/cmenu.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/cmenu.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/cmenu1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/cmenu2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/cmenu3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/cmenu4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/highcolors.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/highcolors.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/highcolors1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/hmenu.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/hmenu.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/hmenu1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/hmenu2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/hmenu3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/hmenu4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/index.rst +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/input5.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/menu25.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/minimal.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/minimal.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/minimal1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/multiple.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/multiple.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/multiple1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/multiple2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/multiple3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/multiple4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/qa.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/qa.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/qa1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/qa2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/qa3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/sig.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/sig.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/sig1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/sig2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/sig3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/sig4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/smenu.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/smenu.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/smenu1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/smenu2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/smenu3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/urwid_attr.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/urwid_attr.py.xdotool +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/urwid_attr1.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/urwid_attr2.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/urwid_attr3.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/tutorial/urwid_attr4.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/docs/urwid-logo.png +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/asyncio_socket_server.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/bigtext.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/browse.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/calc.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/dialog.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/edit.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/fib.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/graph.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/input_test.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/lcd_cf635.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/palette_test.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/pop_up.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/subproc.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/subproc2.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/terminal.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/tour.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/treesample.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/twisted_serve_ssh.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/examples/twisted_serve_ssh.tac +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/isort-requirements.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/pylint-requirements.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/requirements.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/ruff-requirements.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/setup.cfg +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/setup.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/test_requirements.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/__init__.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_canvas.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_container.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_doctests.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_escapes.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_event_loops.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_filler.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_floatedit.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_font.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_frame.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_graphics.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_grid_flow.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_line_box.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_listbox.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_moved_imports.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_overlay.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_padding.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_pile.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_raw_display.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_scrollable.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_signals.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_str_util.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_text_layout.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_tree.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_util.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_vterm.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/test_widget.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tests/util.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/tox.ini +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/__init__.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/canvas.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/command_map.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/container.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/decoration.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/__init__.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/_posix_raw_display.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/_raw_display_base.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/_web.css +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/_web.js +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/_win32.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/_win32_raw_display.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/common.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/curses.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/escape.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/html_fragment.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/lcd.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/raw.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/display/web.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/__init__.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/abstract_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/asyncio_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/glib_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/select_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/tornado_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/trio_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/twisted_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/event_loop/zmq_loop.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/font.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/graphics.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/numedit.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/signals.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/split_repr.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/str_util.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/text_layout.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/util.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/vterm.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/__init__.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/attr_map.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/attr_wrap.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/bar_graph.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/big_text.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/box_adapter.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/constants.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/container.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/divider.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/edit.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/filler.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/line_box.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/listbox.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/monitored_list.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/popup.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/progress_bar.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/scrollable.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/solid_fill.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/text.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/treetools.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/widget_decoration.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/widget/wimp.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid/wimp.py +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid.egg-info/dependency_links.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid.egg-info/not-zip-safe +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid.egg-info/requires.txt +0 -0
- {urwid-2.6.5 → urwid-2.6.7}/urwid.egg-info/top_level.txt +0 -0
|
@@ -90,6 +90,10 @@ exclude_lines = [
|
|
|
90
90
|
|
|
91
91
|
# Don't complain about missing debug-only code:
|
|
92
92
|
"def __repr__",
|
|
93
|
+
"def __rich_repr__",
|
|
94
|
+
# own repr construct magic
|
|
95
|
+
"def _repr_words",
|
|
96
|
+
"def _repr_attrs",
|
|
93
97
|
|
|
94
98
|
# Don't complain if tests don't hit defensive assertion code:
|
|
95
99
|
"raise NotImplementedError",
|
|
@@ -80,13 +80,40 @@ class ColumnsTest(unittest.TestCase):
|
|
|
80
80
|
|
|
81
81
|
with self.subTest("FIXED only"):
|
|
82
82
|
widget = urwid.Columns(((urwid.PACK, fixed_only),))
|
|
83
|
-
self.assertEqual(frozenset((urwid.FIXED
|
|
83
|
+
self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
|
|
84
84
|
cols, rows = 3, 3
|
|
85
85
|
self.assertEqual((cols, rows), widget.pack(()))
|
|
86
86
|
canvas = widget.render(())
|
|
87
87
|
self.assertEqual(cols, canvas.cols())
|
|
88
88
|
self.assertEqual(rows, canvas.rows())
|
|
89
89
|
|
|
90
|
+
with self.subTest("FIXED only use FLOW methods - drop & replace by solid"):
|
|
91
|
+
widget = urwid.Columns(((urwid.PACK, fixed_only),))
|
|
92
|
+
self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
|
|
93
|
+
cols, rows = 2, 1
|
|
94
|
+
self.assertEqual((cols, rows), widget.pack((cols,)))
|
|
95
|
+
canvas = widget.render((cols,))
|
|
96
|
+
self.assertEqual(cols, canvas.cols())
|
|
97
|
+
self.assertEqual(rows, canvas.rows())
|
|
98
|
+
self.assertEqual(" ", str(canvas))
|
|
99
|
+
|
|
100
|
+
with self.subTest("FIXED only use FLOW methods - add empty space"):
|
|
101
|
+
widget = urwid.Columns(((urwid.PACK, fixed_only),))
|
|
102
|
+
self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
|
|
103
|
+
cols, rows = 5, 3
|
|
104
|
+
self.assertEqual((cols, rows), widget.pack((cols,)))
|
|
105
|
+
canvas = widget.render((cols,))
|
|
106
|
+
self.assertEqual(cols, canvas.cols())
|
|
107
|
+
self.assertEqual(rows, canvas.rows())
|
|
108
|
+
self.assertEqual(
|
|
109
|
+
(
|
|
110
|
+
"┌─┐ ",
|
|
111
|
+
"│ │ ",
|
|
112
|
+
"└─┘ ",
|
|
113
|
+
),
|
|
114
|
+
canvas.decoded_text,
|
|
115
|
+
)
|
|
116
|
+
|
|
90
117
|
with self.subTest("GIVEN BOX + FLOW/FIXED, but other widgets do not support box"):
|
|
91
118
|
widget = urwid.Columns((flow_fixed, (3, box_only)), box_columns=(1,))
|
|
92
119
|
self.assertEqual(frozenset((urwid.FLOW, urwid.FIXED)), widget.sizing())
|
|
@@ -153,8 +180,7 @@ class ColumnsTest(unittest.TestCase):
|
|
|
153
180
|
)
|
|
154
181
|
|
|
155
182
|
cols, rows = 30, 1
|
|
156
|
-
|
|
157
|
-
widget.pack((cols,))
|
|
183
|
+
self.assertEqual((cols, rows), widget.pack((cols,)))
|
|
158
184
|
|
|
159
185
|
canvas = widget.render((cols,))
|
|
160
186
|
self.assertEqual(rows, canvas.rows())
|
|
@@ -241,6 +267,59 @@ class ColumnsTest(unittest.TestCase):
|
|
|
241
267
|
str(ctx.warnings[0].message),
|
|
242
268
|
)
|
|
243
269
|
|
|
270
|
+
def test_pack_render_skip_widget(self):
|
|
271
|
+
widget = urwid.Columns(((0, urwid.Text("Ignore\nme")), (urwid.Text("Count"))))
|
|
272
|
+
cols, rows = 5, 1
|
|
273
|
+
self.assertEqual((cols, rows), widget.pack(()))
|
|
274
|
+
self.assertEqual((cols, rows), widget.pack((cols,)))
|
|
275
|
+
self.assertEqual("Count", str(widget.render(())))
|
|
276
|
+
self.assertEqual("Count", str(widget.render((cols,))))
|
|
277
|
+
|
|
278
|
+
def test_pack_flow_with_fixed_item(self):
|
|
279
|
+
widget = urwid.Columns(
|
|
280
|
+
(
|
|
281
|
+
(urwid.PACK, urwid.BigText("3", urwid.Thin3x3Font())),
|
|
282
|
+
(urwid.Text("Multi\nline\ntext\n???")),
|
|
283
|
+
),
|
|
284
|
+
dividechars=1,
|
|
285
|
+
)
|
|
286
|
+
with self.subTest("Skip"):
|
|
287
|
+
self.assertEqual(3, widget.rows((3,)))
|
|
288
|
+
self.assertEqual((3, 3), widget.pack((3,)))
|
|
289
|
+
self.assertEqual(
|
|
290
|
+
(
|
|
291
|
+
"┌─┐",
|
|
292
|
+
" ─┤",
|
|
293
|
+
"└─┘",
|
|
294
|
+
),
|
|
295
|
+
widget.render((3,)).decoded_text,
|
|
296
|
+
)
|
|
297
|
+
with self.subTest("Fit all"):
|
|
298
|
+
self.assertEqual(4, widget.rows((9,)))
|
|
299
|
+
self.assertEqual((9, 4), widget.pack((9,)))
|
|
300
|
+
self.assertEqual(
|
|
301
|
+
(
|
|
302
|
+
"┌─┐ Multi",
|
|
303
|
+
" ─┤ line ",
|
|
304
|
+
"└─┘ text ",
|
|
305
|
+
" ??? ",
|
|
306
|
+
),
|
|
307
|
+
widget.render((9,)).decoded_text,
|
|
308
|
+
)
|
|
309
|
+
with self.subTest("Use SolidCanvas instead"):
|
|
310
|
+
self.assertEqual(1, widget.rows((2,)))
|
|
311
|
+
self.assertEqual((2, 1), widget.pack((2,)))
|
|
312
|
+
self.assertEqual((" ",), widget.render((2,)).decoded_text)
|
|
313
|
+
|
|
314
|
+
def test_pack_render_empty_widget(self):
|
|
315
|
+
widget = urwid.Columns(())
|
|
316
|
+
self.assertEqual(frozenset((urwid.FLOW, urwid.BOX)), widget.sizing())
|
|
317
|
+
cols, rows = 10, 1
|
|
318
|
+
self.assertEqual((cols, rows), widget.pack((cols,)))
|
|
319
|
+
canvas = widget.render((cols,))
|
|
320
|
+
self.assertEqual(rows, canvas.rows())
|
|
321
|
+
self.assertEqual((" ",), canvas.decoded_text)
|
|
322
|
+
|
|
244
323
|
def test_not_a_widget(self):
|
|
245
324
|
class NotAWidget:
|
|
246
325
|
__slots__ = ("name", "symbol")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import concurrent.futures
|
|
4
|
+
import os
|
|
5
|
+
import socket
|
|
6
|
+
import sys
|
|
7
|
+
import threading
|
|
8
|
+
import typing
|
|
9
|
+
import unittest.mock
|
|
10
|
+
|
|
11
|
+
import urwid
|
|
12
|
+
|
|
13
|
+
if typing.TYPE_CHECKING:
|
|
14
|
+
from types import TracebackType
|
|
15
|
+
|
|
16
|
+
IS_WINDOWS = sys.platform == "win32"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ClosingTemporaryFilesPair(typing.ContextManager[typing.Tuple[typing.TextIO, typing.TextIO]]):
|
|
20
|
+
"""File pair context manager that closes temporary files on exit.
|
|
21
|
+
|
|
22
|
+
Since `sys.stdout` is TextIO, tests have to use compatible api for the proper behavior imitation.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__slots__ = ("rd_s", "wr_s", "rd_f", "wr_f")
|
|
26
|
+
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self.rd_s: socket.socket | None = None
|
|
29
|
+
self.wr_s: socket.socket | None = None
|
|
30
|
+
self.rd_f: typing.TextIO | None = None
|
|
31
|
+
self.wr_f: typing.TextIO | None = None
|
|
32
|
+
|
|
33
|
+
def __enter__(self) -> tuple[typing.TextIO, typing.TextIO]:
|
|
34
|
+
self.rd_s, self.wr_s = socket.socketpair()
|
|
35
|
+
self.rd_f = os.fdopen(self.rd_s.fileno(), "r", encoding="utf-8", closefd=False)
|
|
36
|
+
self.wr_f = os.fdopen(self.wr_s.fileno(), "w", encoding="utf-8", closefd=False)
|
|
37
|
+
return self.rd_f, self.wr_f
|
|
38
|
+
|
|
39
|
+
def __exit__(
|
|
40
|
+
self,
|
|
41
|
+
exc_type: type[BaseException] | None,
|
|
42
|
+
exc_val: BaseException | None,
|
|
43
|
+
exc_tb: TracebackType | None,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Close everything explicit without waiting for garbage collected."""
|
|
46
|
+
if self.rd_f is not None and not self.rd_f.closed:
|
|
47
|
+
self.rd_f.close()
|
|
48
|
+
if self.rd_s is not None:
|
|
49
|
+
self.rd_s.close()
|
|
50
|
+
if self.wr_f is not None and not self.wr_f.closed:
|
|
51
|
+
self.wr_f.close()
|
|
52
|
+
if self.wr_s is not None:
|
|
53
|
+
self.wr_s.close()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def stop_screen_cb(*_args, **_kwargs) -> typing.NoReturn:
|
|
57
|
+
raise urwid.ExitMainLoop
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class TestMainLoop(unittest.TestCase):
|
|
61
|
+
@unittest.skipIf(IS_WINDOWS, "selectors for pipe are not supported on Windows")
|
|
62
|
+
def test_watch_pipe(self):
|
|
63
|
+
"""Test watching pipe is stopped on explicit False only."""
|
|
64
|
+
evt = threading.Event() # We need thread synchronization
|
|
65
|
+
outcome: list[bytes] = []
|
|
66
|
+
|
|
67
|
+
def pipe_cb(data: bytes) -> typing.Any:
|
|
68
|
+
outcome.append(data)
|
|
69
|
+
|
|
70
|
+
if not evt.is_set():
|
|
71
|
+
evt.set()
|
|
72
|
+
|
|
73
|
+
if data == b"false":
|
|
74
|
+
return False
|
|
75
|
+
if data == b"true":
|
|
76
|
+
return True
|
|
77
|
+
if data == b"null":
|
|
78
|
+
return None
|
|
79
|
+
return object()
|
|
80
|
+
|
|
81
|
+
def pipe_writer(fd: int) -> None:
|
|
82
|
+
os.write(fd, b"something")
|
|
83
|
+
if evt.wait(0.1):
|
|
84
|
+
evt.clear()
|
|
85
|
+
os.write(fd, b"true")
|
|
86
|
+
if evt.wait(0.1):
|
|
87
|
+
evt.clear()
|
|
88
|
+
os.write(fd, b"null")
|
|
89
|
+
if evt.wait(0.1):
|
|
90
|
+
evt.clear()
|
|
91
|
+
os.write(fd, b"false")
|
|
92
|
+
|
|
93
|
+
with ClosingTemporaryFilesPair() as (
|
|
94
|
+
rd_r,
|
|
95
|
+
wr_r,
|
|
96
|
+
), ClosingTemporaryFilesPair() as (
|
|
97
|
+
rd_w,
|
|
98
|
+
wr_w,
|
|
99
|
+
), concurrent.futures.ThreadPoolExecutor(
|
|
100
|
+
max_workers=1,
|
|
101
|
+
) as executor, unittest.mock.patch(
|
|
102
|
+
"subprocess.Popen", # we want to be sure that nothing outside is called
|
|
103
|
+
autospec=True,
|
|
104
|
+
):
|
|
105
|
+
evl = urwid.MainLoop(
|
|
106
|
+
urwid.SolidFill(),
|
|
107
|
+
screen=urwid.display.raw.Screen(input=rd_r, output=wr_w), # We need screen which support mocked IO
|
|
108
|
+
handle_mouse=False, # Less external calls - better
|
|
109
|
+
)
|
|
110
|
+
evl.set_alarm_in(1, stop_screen_cb)
|
|
111
|
+
pipe_fd = evl.watch_pipe(pipe_cb)
|
|
112
|
+
executor.submit(pipe_writer, pipe_fd)
|
|
113
|
+
|
|
114
|
+
evl.run()
|
|
115
|
+
self.assertEqual([b"something", b"true", b"null", b"false"], outcome)
|
|
116
|
+
not_removed = evl.remove_watch_pipe(pipe_fd)
|
|
117
|
+
self.assertFalse(not_removed)
|
|
@@ -190,7 +190,7 @@ class MainLoop:
|
|
|
190
190
|
else:
|
|
191
191
|
self._topmost_widget = self._widget
|
|
192
192
|
|
|
193
|
-
def _set_pop_ups(self, pop_ups) -> None:
|
|
193
|
+
def _set_pop_ups(self, pop_ups: bool) -> None:
|
|
194
194
|
warnings.warn(
|
|
195
195
|
f"method `{self.__class__.__name__}._set_pop_ups` is deprecated, "
|
|
196
196
|
f"please use `{self.__class__.__name__}.pop_ups` property",
|
|
@@ -214,7 +214,7 @@ class MainLoop:
|
|
|
214
214
|
"""
|
|
215
215
|
self.logger.debug(f"Setting alarm in {sec!r} seconds with callback {callback!r}")
|
|
216
216
|
|
|
217
|
-
def cb():
|
|
217
|
+
def cb() -> None:
|
|
218
218
|
callback(self, user_data)
|
|
219
219
|
|
|
220
220
|
return self.event_loop.alarm(sec, cb)
|
|
@@ -236,7 +236,7 @@ class MainLoop:
|
|
|
236
236
|
sec = tm - time.time()
|
|
237
237
|
self.logger.debug(f"Setting alarm in {sec!r} seconds with callback {callback!r}")
|
|
238
238
|
|
|
239
|
-
def cb():
|
|
239
|
+
def cb() -> None:
|
|
240
240
|
callback(self, user_data)
|
|
241
241
|
|
|
242
242
|
return self.event_loop.alarm(sec, cb)
|
|
@@ -250,33 +250,28 @@ class MainLoop:
|
|
|
250
250
|
|
|
251
251
|
if not IS_WINDOWS:
|
|
252
252
|
|
|
253
|
-
def watch_pipe(self, callback: Callable[[bytes], bool]) -> int:
|
|
253
|
+
def watch_pipe(self, callback: Callable[[bytes], bool | None]) -> int:
|
|
254
254
|
"""
|
|
255
255
|
Create a pipe for use by a subprocess or thread to trigger a callback
|
|
256
256
|
in the process/thread running the main loop.
|
|
257
257
|
|
|
258
|
-
:param callback: function taking one parameter to call from within
|
|
259
|
-
the process/thread running the main loop
|
|
258
|
+
:param callback: function taking one parameter to call from within the process/thread running the main loop
|
|
260
259
|
:type callback: callable
|
|
261
260
|
|
|
262
|
-
This method returns a file descriptor attached to the write end of a
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
data read from the pipe.
|
|
261
|
+
This method returns a file descriptor attached to the write end of a pipe.
|
|
262
|
+
The read end of the pipe is added to the list of files :attr:`event_loop` is watching.
|
|
263
|
+
When data is written to the pipe the callback function will be called
|
|
264
|
+
and passed a single value containing data read from the pipe.
|
|
267
265
|
|
|
268
|
-
This method may be used any time you want to update widgets from
|
|
269
|
-
another thread or subprocess.
|
|
266
|
+
This method may be used any time you want to update widgets from another thread or subprocess.
|
|
270
267
|
|
|
271
|
-
Data may be written to the returned file descriptor with
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
complete value of data passed in.
|
|
268
|
+
Data may be written to the returned file descriptor with ``os.write(fd, data)``.
|
|
269
|
+
Ensure that data is less than 512 bytes (or 4K on Linux)
|
|
270
|
+
so that the callback will be triggered just once with the complete value of data passed in.
|
|
275
271
|
|
|
276
|
-
If the callback returns ``False`` then the watch will be removed from
|
|
277
|
-
|
|
278
|
-
are responsible for closing the write end of the pipe with
|
|
279
|
-
``os.close(fd)``.
|
|
272
|
+
If the callback returns ``False`` then the watch will be removed from :attr:`event_loop`
|
|
273
|
+
and the read end of the pipe will be closed.
|
|
274
|
+
You are responsible for closing the write end of the pipe with ``os.close(fd)``.
|
|
280
275
|
"""
|
|
281
276
|
import fcntl
|
|
282
277
|
|
|
@@ -286,7 +281,7 @@ class MainLoop:
|
|
|
286
281
|
|
|
287
282
|
def cb() -> None:
|
|
288
283
|
data = os.read(pipe_rd, PIPE_BUFFER_READ_SIZE)
|
|
289
|
-
if
|
|
284
|
+
if callback(data) is False:
|
|
290
285
|
self.event_loop.remove_watch_file(watch_handle)
|
|
291
286
|
os.close(pipe_rd)
|
|
292
287
|
|
|
@@ -296,9 +291,9 @@ class MainLoop:
|
|
|
296
291
|
|
|
297
292
|
def remove_watch_pipe(self, write_fd: int) -> bool:
|
|
298
293
|
"""
|
|
299
|
-
Close the read end of the pipe and remove the watch created by
|
|
300
|
-
|
|
301
|
-
the pipe.
|
|
294
|
+
Close the read end of the pipe and remove the watch created by :meth:`watch_pipe`.
|
|
295
|
+
|
|
296
|
+
..note:: You are responsible for closing the write end of the pipe.
|
|
302
297
|
|
|
303
298
|
Returns ``True`` if the watch pipe exists, ``False`` otherwise
|
|
304
299
|
"""
|
|
@@ -7,6 +7,7 @@ from itertools import chain, repeat
|
|
|
7
7
|
import urwid
|
|
8
8
|
from urwid.canvas import Canvas, CanvasJoin, CompositeCanvas, SolidCanvas
|
|
9
9
|
from urwid.command_map import Command
|
|
10
|
+
from urwid.split_repr import remove_defaults
|
|
10
11
|
from urwid.util import is_mouse_press
|
|
11
12
|
|
|
12
13
|
from .constants import Align, Sizing, WHSettings
|
|
@@ -15,7 +16,7 @@ from .monitored_list import MonitoredFocusList, MonitoredList
|
|
|
15
16
|
from .widget import Widget, WidgetError, WidgetWarning
|
|
16
17
|
|
|
17
18
|
if typing.TYPE_CHECKING:
|
|
18
|
-
from collections.abc import Iterable, Sequence
|
|
19
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
19
20
|
|
|
20
21
|
from typing_extensions import Literal
|
|
21
22
|
|
|
@@ -66,43 +67,43 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
66
67
|
|
|
67
68
|
# BOX-only widget
|
|
68
69
|
>>> Columns((SolidFill("#"),))
|
|
69
|
-
<Columns box widget
|
|
70
|
+
<Columns box widget (1 item)>
|
|
70
71
|
|
|
71
72
|
# BOX-only widget with "get height from max"
|
|
72
73
|
>>> Columns((SolidFill("#"),), box_columns=(0,))
|
|
73
|
-
<Columns box widget
|
|
74
|
+
<Columns box widget (1 item)>
|
|
74
75
|
|
|
75
76
|
# FLOW-only
|
|
76
77
|
>>> Columns((Edit(),))
|
|
77
|
-
<Columns selectable flow widget
|
|
78
|
+
<Columns selectable flow widget (1 item)>
|
|
78
79
|
|
|
79
80
|
# FLOW allowed by "box_columns"
|
|
80
81
|
>>> Columns((Edit(), SolidFill("#")), box_columns=(1,))
|
|
81
|
-
<Columns selectable flow widget
|
|
82
|
+
<Columns selectable flow widget (2 items) focus_column=0>
|
|
82
83
|
|
|
83
84
|
# FLOW/FIXED
|
|
84
85
|
>>> Columns((Text("T"),))
|
|
85
|
-
<Columns fixed/flow widget
|
|
86
|
+
<Columns fixed/flow widget (1 item)>
|
|
86
87
|
|
|
87
88
|
# GIVEN BOX only -> BOX only
|
|
88
89
|
>>> Columns(((5, SolidFill("#")),), box_columns=(0,))
|
|
89
|
-
<Columns box widget
|
|
90
|
+
<Columns box widget (1 item)>
|
|
90
91
|
|
|
91
92
|
# No FLOW - BOX only
|
|
92
93
|
>>> Columns(((5, SolidFill("#")), SolidFill("*")), box_columns=(0, 1))
|
|
93
|
-
<Columns box widget
|
|
94
|
+
<Columns box widget (2 items) focus_column=0>
|
|
94
95
|
|
|
95
|
-
# FIXED only -> FIXED
|
|
96
|
+
# FIXED only -> FIXED (and FLOW via drop/expand)
|
|
96
97
|
>>> Columns(((WHSettings.PACK, BigText("1", font)),))
|
|
97
|
-
<Columns fixed widget
|
|
98
|
+
<Columns fixed/flow widget (1 item)>
|
|
98
99
|
|
|
99
100
|
# Invalid sizing combination -> use fallback settings (and produce warning)
|
|
100
101
|
>>> Columns(((WHSettings.PACK, SolidFill("#")),))
|
|
101
|
-
<Columns box/flow widget
|
|
102
|
+
<Columns box/flow widget (1 item)>
|
|
102
103
|
|
|
103
104
|
# Special case: empty columns widget sizing is impossible to calculate
|
|
104
105
|
>>> Columns(())
|
|
105
|
-
<Columns box/flow widget
|
|
106
|
+
<Columns box/flow widget ()>
|
|
106
107
|
"""
|
|
107
108
|
if not self.contents:
|
|
108
109
|
return frozenset((urwid.BOX, urwid.FLOW))
|
|
@@ -183,6 +184,7 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
183
184
|
supported.add(Sizing.FLOW)
|
|
184
185
|
|
|
185
186
|
if has_fixed and not block_fixed:
|
|
187
|
+
supported.add(Sizing.FLOW)
|
|
186
188
|
supported.add(Sizing.FIXED)
|
|
187
189
|
|
|
188
190
|
if not supported:
|
|
@@ -289,10 +291,50 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
289
291
|
|
|
290
292
|
def _repr_words(self) -> list[str]:
|
|
291
293
|
if len(self.contents) > 1:
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
contents_string = f"({len(self.contents)} items)"
|
|
295
|
+
elif self.contents:
|
|
296
|
+
contents_string = "(1 item)"
|
|
297
|
+
else:
|
|
298
|
+
contents_string = "()"
|
|
299
|
+
return [*super()._repr_words(), contents_string]
|
|
300
|
+
|
|
301
|
+
def _repr_attrs(self) -> dict[str, typing.Any]:
|
|
302
|
+
attrs = {
|
|
303
|
+
**super()._repr_attrs(),
|
|
304
|
+
"dividechars": self.dividechars,
|
|
305
|
+
"focus_column": self.focus_position if len(self._contents) > 1 else None,
|
|
306
|
+
"min_width": self.min_width,
|
|
307
|
+
}
|
|
308
|
+
return remove_defaults(attrs, Columns.__init__)
|
|
309
|
+
|
|
310
|
+
def __rich_repr__(self) -> Iterator[tuple[str | None, typing.Any] | typing.Any]:
|
|
311
|
+
widget_list: list[
|
|
312
|
+
Widget
|
|
313
|
+
| tuple[Literal[WHSettings.PACK] | int, Widget]
|
|
314
|
+
| tuple[Literal[WHSettings.WEIGHT], int | float, Widget]
|
|
315
|
+
] = []
|
|
316
|
+
box_columns: list[int] = []
|
|
317
|
+
for idx, (w_instance, (sizing, amount, is_box)) in enumerate(self._contents):
|
|
318
|
+
if sizing == WHSettings.GIVEN:
|
|
319
|
+
widget_list.append((amount, w_instance))
|
|
320
|
+
elif sizing == WHSettings.PACK:
|
|
321
|
+
widget_list.append((WHSettings.PACK, w_instance))
|
|
322
|
+
elif amount == 1:
|
|
323
|
+
widget_list.append(w_instance)
|
|
324
|
+
else:
|
|
325
|
+
widget_list.append((WHSettings.WEIGHT, amount, w_instance))
|
|
326
|
+
|
|
327
|
+
if is_box:
|
|
328
|
+
box_columns.append(idx)
|
|
329
|
+
|
|
330
|
+
yield "widget_list", widget_list
|
|
331
|
+
yield "dividechars", self.dividechars
|
|
332
|
+
yield "focus_column", self.focus_position if self._contents else None
|
|
333
|
+
yield "min_width", self.min_width
|
|
334
|
+
yield "box_columns", box_columns
|
|
335
|
+
|
|
336
|
+
def __len__(self) -> int:
|
|
337
|
+
return len(self._contents)
|
|
296
338
|
|
|
297
339
|
def _contents_modified(self) -> None:
|
|
298
340
|
"""
|
|
@@ -904,11 +946,17 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
904
946
|
box.append(i)
|
|
905
947
|
|
|
906
948
|
elif Sizing.FLOW in w_sizing:
|
|
907
|
-
|
|
949
|
+
if width > 0:
|
|
950
|
+
heights[i] = widget.rows((width,), focus and i == self.focus_position)
|
|
951
|
+
else:
|
|
952
|
+
heights[i] = 0
|
|
908
953
|
w_h_args[i] = (width,)
|
|
909
954
|
|
|
910
955
|
elif size_kind == WHSettings.PACK:
|
|
911
|
-
|
|
956
|
+
if width > 0:
|
|
957
|
+
heights[i] = widget.pack((), focus and i == self.focus_position)[1]
|
|
958
|
+
else:
|
|
959
|
+
heights[i] = 0
|
|
912
960
|
w_h_args[i] = ()
|
|
913
961
|
|
|
914
962
|
else:
|
|
@@ -1135,14 +1183,10 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin):
|
|
|
1135
1183
|
|
|
1136
1184
|
see :meth:`Widget.rows` for details
|
|
1137
1185
|
"""
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
if b or mc <= 0:
|
|
1143
|
-
continue
|
|
1144
|
-
rows = max(rows, w.rows((mc,), focus=focus and self.focus_position == i))
|
|
1145
|
-
return rows
|
|
1186
|
+
_, heights, _ = self.get_column_sizes(size, focus)
|
|
1187
|
+
if heights:
|
|
1188
|
+
return max(1, *heights)
|
|
1189
|
+
return 1
|
|
1146
1190
|
|
|
1147
1191
|
def keypress(
|
|
1148
1192
|
self,
|
|
@@ -4,6 +4,7 @@ import typing
|
|
|
4
4
|
import warnings
|
|
5
5
|
|
|
6
6
|
from urwid.canvas import CanvasCombine, CompositeCanvas
|
|
7
|
+
from urwid.split_repr import remove_defaults
|
|
7
8
|
from urwid.util import is_mouse_press
|
|
8
9
|
|
|
9
10
|
from .constants import Sizing, VAlign
|
|
@@ -89,6 +90,22 @@ class Frame(Widget, WidgetContainerMixin, typing.Generic[BodyWidget, HeaderWidge
|
|
|
89
90
|
_check_widget_subclass(body)
|
|
90
91
|
_check_widget_subclass(footer)
|
|
91
92
|
|
|
93
|
+
def _repr_attrs(self) -> dict[str, typing.Any]:
|
|
94
|
+
attrs = {
|
|
95
|
+
**super()._repr_attrs(),
|
|
96
|
+
"body": self._body,
|
|
97
|
+
"header": self._header,
|
|
98
|
+
"footer": self._footer,
|
|
99
|
+
"focus_part": self.focus_part,
|
|
100
|
+
}
|
|
101
|
+
return remove_defaults(attrs, Frame.__init__)
|
|
102
|
+
|
|
103
|
+
def __rich_repr__(self) -> Iterator[tuple[str | None, typing.Any] | typing.Any]:
|
|
104
|
+
yield "body", self._body
|
|
105
|
+
yield "header", self._header
|
|
106
|
+
yield "footer", self._footer
|
|
107
|
+
yield "focus_part", self.focus_part
|
|
108
|
+
|
|
92
109
|
@property
|
|
93
110
|
def header(self) -> HeaderWidget:
|
|
94
111
|
return self._header
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
import warnings
|
|
5
5
|
|
|
6
|
+
from urwid.split_repr import remove_defaults
|
|
7
|
+
|
|
6
8
|
from .columns import Columns
|
|
7
9
|
from .constants import Align, Sizing, WHSettings
|
|
8
10
|
from .container import WidgetContainerListContentsMixin, WidgetContainerMixin
|
|
@@ -13,7 +15,7 @@ from .pile import Pile
|
|
|
13
15
|
from .widget import Widget, WidgetError, WidgetWarning, WidgetWrap
|
|
14
16
|
|
|
15
17
|
if typing.TYPE_CHECKING:
|
|
16
|
-
from collections.abc import Iterable, Sequence
|
|
18
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
17
19
|
|
|
18
20
|
from typing_extensions import Literal
|
|
19
21
|
|
|
@@ -78,12 +80,45 @@ class GridFlow(WidgetWrap[Pile], WidgetContainerMixin, WidgetContainerListConten
|
|
|
78
80
|
self._cache_maxcol = self._get_maxcol(())
|
|
79
81
|
super().__init__(self.generate_display_widget((self._cache_maxcol,)))
|
|
80
82
|
|
|
83
|
+
def _repr_words(self) -> list[str]:
|
|
84
|
+
if len(self.contents) > 1:
|
|
85
|
+
contents_string = f"({len(self.contents)} items)"
|
|
86
|
+
elif self.contents:
|
|
87
|
+
contents_string = "(1 item)"
|
|
88
|
+
else:
|
|
89
|
+
contents_string = "()"
|
|
90
|
+
return [*super()._repr_words(), contents_string]
|
|
91
|
+
|
|
92
|
+
def _repr_attrs(self) -> dict[str, typing.Any]:
|
|
93
|
+
attrs = {
|
|
94
|
+
**super()._repr_attrs(),
|
|
95
|
+
"cell_width": self.cell_width,
|
|
96
|
+
"h_sep": self.h_sep,
|
|
97
|
+
"v_sep": self.v_sep,
|
|
98
|
+
"align": self.align,
|
|
99
|
+
"focus": self.focus_position if len(self._contents) > 1 else None,
|
|
100
|
+
}
|
|
101
|
+
return remove_defaults(attrs, GridFlow.__init__)
|
|
102
|
+
|
|
103
|
+
def __rich_repr__(self) -> Iterator[tuple[str | None, typing.Any] | typing.Any]:
|
|
104
|
+
yield "cells", [widget for widget, _ in self.contents]
|
|
105
|
+
yield "cell_width", self.cell_width
|
|
106
|
+
yield "h_sep", self.h_sep
|
|
107
|
+
yield "v_sep", self.v_sep
|
|
108
|
+
yield "align", self.align
|
|
109
|
+
yield "focus", self.focus_position
|
|
110
|
+
|
|
111
|
+
def __len__(self) -> int:
|
|
112
|
+
return len(self._contents)
|
|
113
|
+
|
|
81
114
|
def _invalidate(self) -> None:
|
|
82
115
|
self._cache_maxcol = None
|
|
83
116
|
super()._invalidate()
|
|
84
117
|
|
|
85
118
|
def _contents_modified(
|
|
86
|
-
self,
|
|
119
|
+
self,
|
|
120
|
+
_slc: tuple[int, int, int],
|
|
121
|
+
new_items: Iterable[tuple[Widget, tuple[Literal["given", WHSettings.GIVEN], int]]],
|
|
87
122
|
) -> None:
|
|
88
123
|
for item in new_items:
|
|
89
124
|
try:
|
|
@@ -258,7 +293,7 @@ class GridFlow(WidgetWrap[Pile], WidgetContainerMixin, WidgetContainerListConten
|
|
|
258
293
|
return None
|
|
259
294
|
return self.contents[self.focus_position][0]
|
|
260
295
|
|
|
261
|
-
def _get_focus(self) -> Widget:
|
|
296
|
+
def _get_focus(self) -> Widget | None:
|
|
262
297
|
warnings.warn(
|
|
263
298
|
f"method `{self.__class__.__name__}._get_focus` is deprecated, "
|
|
264
299
|
f"please use `{self.__class__.__name__}.focus` property",
|
|
@@ -446,7 +481,7 @@ class GridFlow(WidgetWrap[Pile], WidgetContainerMixin, WidgetContainerListConten
|
|
|
446
481
|
|
|
447
482
|
# Use width == maxcol in case of maxcol < width amount
|
|
448
483
|
# Columns will use empty widget in case of GIVEN width > maxcol
|
|
449
|
-
c.contents.append((w, c.options(WHSettings.GIVEN, width_amount
|
|
484
|
+
c.contents.append((w, c.options(WHSettings.GIVEN, min(width_amount, maxcol))))
|
|
450
485
|
if (i == self.focus_position) or (not column_focused and w.selectable()):
|
|
451
486
|
c.focus_position = len(c.contents) - 1
|
|
452
487
|
column_focused = True
|