From c412cd5d335762e562acfad54fc36f5dd3706fc7 Mon Sep 17 00:00:00 2001 From: nocode Date: Sat, 13 Jun 2026 02:06:34 +0200 Subject: [PATCH] feat(Anaconda): Local Repo --- configs/baseline/profiledef.sh | 7 - pkgbuilds/python-meh/PKGBUILD | 29 + .../python-meh/pkg/python-meh/.BUILDINFO | 898 ++++++++++++++++++ pkgbuilds/python-meh/pkg/python-meh/.MTREE | Bin 0 -> 1320 bytes pkgbuilds/python-meh/pkg/python-meh/.PKGINFO | 16 + .../python3.14/site-packages/meh/__init__.py | 139 +++ .../meh/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 5344 bytes .../meh/__pycache__/dump.cpython-314.pyc | Bin 0 -> 22861 bytes .../meh/__pycache__/handler.cpython-314.pyc | Bin 0 -> 13927 bytes .../meh/__pycache__/network.cpython-314.pyc | Bin 0 -> 1068 bytes .../__pycache__/safe_string.cpython-314.pyc | Bin 0 -> 2555 bytes .../lib/python3.14/site-packages/meh/dump.py | 551 +++++++++++ .../python3.14/site-packages/meh/handler.py | 299 ++++++ .../python3.14/site-packages/meh/network.py | 45 + .../site-packages/meh/safe_string.py | 71 ++ .../site-packages/meh/ui/__init__.py | 181 ++++ .../ui/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 7634 bytes .../meh/ui/__pycache__/gui.cpython-314.pyc | Bin 0 -> 10773 bytes .../meh/ui/__pycache__/text.cpython-314.pyc | Bin 0 -> 12437 bytes .../python3.14/site-packages/meh/ui/gui.py | 177 ++++ .../python3.14/site-packages/meh/ui/text.py | 225 +++++ .../usr/share/licenses/python-meh/COPYING | 339 +++++++ .../share/python-meh/exception-dialog.glade | 248 +++++ .../python-meh-0.43-1-any.pkg.tar.zst | Bin 0 -> 64459 bytes pkgbuilds/python-meh/python-meh-0.43.tar.gz | Bin 0 -> 39764 bytes .../python-meh/src/python-meh-0.43.tar.gz | 1 + .../src/python-meh-r0.43-1/.gitignore | 14 + .../python-meh/src/python-meh-r0.43-1/COPYING | 339 +++++++ .../src/python-meh-r0.43-1/MANIFEST.in | 6 + .../src/python-meh-r0.43-1/Makefile | 101 ++ .../python-meh-r0.43-1/examples/meh_test.py | 38 + .../src/python-meh-r0.43-1/meh/__init__.py | 139 +++ .../src/python-meh-r0.43-1/meh/dump.py | 551 +++++++++++ .../src/python-meh-r0.43-1/meh/handler.py | 299 ++++++ .../src/python-meh-r0.43-1/meh/network.py | 45 + .../src/python-meh-r0.43-1/meh/safe_string.py | 71 ++ .../src/python-meh-r0.43-1/meh/ui/__init__.py | 181 ++++ .../src/python-meh-r0.43-1/meh/ui/gui.py | 177 ++++ .../src/python-meh-r0.43-1/meh/ui/text.py | 225 +++++ .../python-meh-r0.43-1/pixmaps/exception.png | Bin 0 -> 3920 bytes .../src/python-meh-r0.43-1/po/Makefile | 76 ++ .../src/python-meh-r0.43-1/po/python-meh.pot | 116 +++ .../src/python-meh-r0.43-1/python-meh.spec | 383 ++++++++ .../src/python-meh-r0.43-1/setup.py | 10 + .../src/python-meh-r0.43-1/tests/__init__.py | 0 .../python-meh-r0.43-1/tests/attrSkipList.py | 25 + .../src/python-meh-r0.43-1/tests/baseclass.py | 103 ++ .../src/python-meh-r0.43-1/tests/callbacks.py | 56 ++ .../python-meh-r0.43-1/tests/handle_binary.py | 41 + .../tests/handle_unicode.py | 55 ++ .../tests/pylint/runpylint.py | 19 + .../tests/safe_string_test.py | 44 + .../ui/exception-dialog.glade | 248 +++++ .../src/python-meh-r0.43-1/zanata.xml | 106 +++ pkgbuilds/python-simpleline/PKGBUILD | 27 + .../pkg/python-simpleline/.BUILDINFO | 898 ++++++++++++++++++ .../pkg/python-simpleline/.MTREE | Bin 0 -> 3233 bytes .../pkg/python-simpleline/.PKGINFO | 15 + .../site-packages/simpleline/__init__.py | 136 +++ .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 5462 bytes .../__pycache__/errors.cpython-314.pyc | Bin 0 -> 693 bytes .../global_configuration.cpython-314.pyc | Bin 0 -> 3946 bytes .../__pycache__/logging.cpython-314.pyc | Bin 0 -> 797 bytes .../site-packages/simpleline/errors.py | 31 + .../simpleline/event_loop/__init__.py | 264 +++++ .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 11671 bytes .../__pycache__/event_queue.cpython-314.pyc | Bin 0 -> 5808 bytes .../glib_event_loop.cpython-314.pyc | Bin 0 -> 10356 bytes .../__pycache__/main_loop.cpython-314.pyc | Bin 0 -> 10160 bytes .../__pycache__/signals.cpython-314.pyc | Bin 0 -> 4276 bytes .../ticket_machine.cpython-314.pyc | Bin 0 -> 2478 bytes .../simpleline/event_loop/event_queue.py | 153 +++ .../simpleline/event_loop/glib_event_loop.py | 230 +++++ .../simpleline/event_loop/main_loop.py | 247 +++++ .../simpleline/event_loop/signals.py | 110 +++ .../simpleline/event_loop/ticket_machine.py | 81 ++ .../simpleline/global_configuration.py | 112 +++ .../simpleline/input/__init__.py | 22 + .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 303 bytes .../__pycache__/input_handler.cpython-314.pyc | Bin 0 -> 12640 bytes .../input_threading.cpython-314.pyc | Bin 0 -> 10368 bytes .../simpleline/input/input_handler.py | 292 ++++++ .../simpleline/input/input_threading.py | 238 +++++ .../site-packages/simpleline/logging.py | 39 + .../simpleline/render/__init__.py | 31 + .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 751 bytes .../__pycache__/adv_widgets.cpython-314.pyc | Bin 0 -> 11804 bytes .../__pycache__/containers.cpython-314.pyc | Bin 0 -> 18941 bytes .../render/__pycache__/prompt.cpython-314.pyc | Bin 0 -> 5772 bytes .../screen_handler.cpython-314.pyc | Bin 0 -> 2101 bytes .../screen_scheduler.cpython-314.pyc | Bin 0 -> 14095 bytes .../__pycache__/screen_stack.cpython-314.pyc | Bin 0 -> 4532 bytes .../__pycache__/widgets.cpython-314.pyc | Bin 0 -> 19121 bytes .../simpleline/render/adv_widgets.py | 253 +++++ .../simpleline/render/containers.py | 475 +++++++++ .../site-packages/simpleline/render/prompt.py | 154 +++ .../simpleline/render/screen/__init__.py | 313 ++++++ .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 11639 bytes .../__pycache__/input_manager.cpython-314.pyc | Bin 0 -> 7602 bytes .../signal_handler.cpython-314.pyc | Bin 0 -> 3593 bytes .../simpleline/render/screen/input_manager.py | 203 ++++ .../render/screen/signal_handler.py | 94 ++ .../simpleline/render/screen_handler.py | 58 ++ .../simpleline/render/screen_scheduler.py | 311 ++++++ .../simpleline/render/screen_stack.py | 117 +++ .../simpleline/render/widgets.py | 495 ++++++++++ .../simpleline/utils/__init__.py | 94 ++ .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 2861 bytes .../utils/__pycache__/i18n.cpython-314.pyc | Bin 0 -> 1434 bytes .../site-packages/simpleline/utils/i18n.py | 61 ++ .../licenses/python-simpleline/LICENSE.md | 157 +++ .../python-simpleline-1.8-1-any.pkg.tar.zst | Bin 0 -> 106541 bytes .../python-simpleline-1.8.tar.gz | Bin 0 -> 84535 bytes .../src/python-simpleline-1.8.tar.gz | 1 + .../.github/workflows/validate.yml | 16 + .../.gitignore | 23 + .../.packit.yaml | 46 + .../.pylintrc | 504 ++++++++++ .../LICENSE.md | 157 +++ .../MANIFEST.in | 4 + .../python-simpleline-simpleline-1.8/Makefile | 154 +++ .../README.md | 48 + .../doc/Makefile | 20 + .../doc/api.rst | 22 + .../doc/api/adv_widgets.rst | 13 + .../doc/api/advanced_input.rst | 92 ++ .../doc/api/app.rst | 48 + .../doc/api/containers.rst | 47 + .../doc/api/errors.rst | 39 + .../doc/api/event_loops.rst | 92 ++ .../doc/api/prompt.rst | 23 + .../doc/api/screen.rst | 126 +++ .../doc/api/screen_handling.rst | 82 ++ .../doc/api/signals.rst | 22 + .../doc/api/widgets.rst | 44 + .../doc/conf.py | 214 +++++ .../doc/guide.rst | 176 ++++ .../doc/index.rst | 23 + .../doc/introduction.rst | 102 ++ .../doc/make.bat | 36 + .../examples/00_basic/00_basic.py | 60 ++ .../01_base_widgets/01_base_widgets.py | 75 ++ .../02_ignore_continue/02_ignore_continue.py | 78 ++ .../03_entry_counter/03_entry_counter.py | 89 ++ .../examples/04_help/04_help.py | 37 + .../examples/04_help/example_help.txt | 3 + .../examples/05_hub_spoke/05_hub_spoke.py | 202 ++++ .../examples/06_glib_loop/06_glib_loop.py | 62 ++ .../examples/07_divider/07_divider.py | 102 ++ .../examples/run_example.sh | 51 + .../po/Makefile | 86 ++ .../python-simpleline.spec | 408 ++++++++ .../python-simpleline-simpleline-1.8/setup.py | 43 + .../simpleline/__init__.py | 136 +++ .../simpleline/errors.py | 31 + .../simpleline/event_loop/__init__.py | 264 +++++ .../simpleline/event_loop/event_queue.py | 153 +++ .../simpleline/event_loop/glib_event_loop.py | 230 +++++ .../simpleline/event_loop/main_loop.py | 247 +++++ .../simpleline/event_loop/signals.py | 110 +++ .../simpleline/event_loop/ticket_machine.py | 81 ++ .../simpleline/global_configuration.py | 112 +++ .../simpleline/input/__init__.py | 22 + .../simpleline/input/input_handler.py | 292 ++++++ .../simpleline/input/input_threading.py | 238 +++++ .../simpleline/logging.py | 39 + .../simpleline/render/__init__.py | 31 + .../simpleline/render/adv_widgets.py | 253 +++++ .../simpleline/render/containers.py | 475 +++++++++ .../simpleline/render/prompt.py | 154 +++ .../simpleline/render/screen/__init__.py | 313 ++++++ .../simpleline/render/screen/input_manager.py | 203 ++++ .../render/screen/signal_handler.py | 94 ++ .../simpleline/render/screen_handler.py | 58 ++ .../simpleline/render/screen_scheduler.py | 311 ++++++ .../simpleline/render/screen_stack.py | 117 +++ .../simpleline/render/widgets.py | 495 ++++++++++ .../simpleline/utils/__init__.py | 94 ++ .../simpleline/utils/i18n.py | 61 ++ .../tests/units/__init__.py | 45 + .../tests/units/glib/__init__.py | 67 ++ .../tests/units/glib/event_loop_glib_test.py | 37 + .../units/glib/input_handler_glib_test.py | 38 + .../units/glib/render_screen_glib_test.py | 73 ++ .../units/glib/screen_scheduler_glib_test.py | 37 + .../tests/units/main/__init__.py | 0 .../tests/units/main/adv_widgets_test.py | 118 +++ .../tests/units/main/app_test.py | 120 +++ .../tests/units/main/containers_test.py | 394 ++++++++ .../tests/units/main/event_loop_test.py | 310 ++++++ .../tests/units/main/event_queue_test.py | 105 ++ .../units/main/global_configuration_test.py | 84 ++ .../tests/units/main/input_handler_test.py | 247 +++++ .../tests/units/main/prompt_test.py | 135 +++ .../tests/units/main/render_screen_test.py | 564 +++++++++++ .../tests/units/main/scheduler_test.py | 181 ++++ .../tests/units/main/screen_scheduler_test.py | 207 ++++ .../tests/units/main/screen_stack_test.py | 162 ++++ .../tests/units/main/signal_handler_test.py | 113 +++ .../tests/units/main/ticket_machine_test.py | 106 +++ .../tests/units/main/widgets_test.py | 335 +++++++ .../tests/units/run_test.sh | 9 + setup-aur.sh | 28 + 203 files changed, 23997 insertions(+), 7 deletions(-) create mode 100644 pkgbuilds/python-meh/PKGBUILD create mode 100644 pkgbuilds/python-meh/pkg/python-meh/.BUILDINFO create mode 100644 pkgbuilds/python-meh/pkg/python-meh/.MTREE create mode 100644 pkgbuilds/python-meh/pkg/python-meh/.PKGINFO create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__init__.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/dump.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/handler.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/network.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/safe_string.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/dump.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/handler.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/network.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/safe_string.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__init__.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/gui.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/text.cpython-314.pyc create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/gui.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/text.py create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/share/licenses/python-meh/COPYING create mode 100644 pkgbuilds/python-meh/pkg/python-meh/usr/share/python-meh/exception-dialog.glade create mode 100644 pkgbuilds/python-meh/python-meh-0.43-1-any.pkg.tar.zst create mode 100644 pkgbuilds/python-meh/python-meh-0.43.tar.gz create mode 120000 pkgbuilds/python-meh/src/python-meh-0.43.tar.gz create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/.gitignore create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/COPYING create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/MANIFEST.in create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/Makefile create mode 100755 pkgbuilds/python-meh/src/python-meh-r0.43-1/examples/meh_test.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/__init__.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/dump.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/handler.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/network.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/safe_string.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/__init__.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/gui.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/text.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/pixmaps/exception.png create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/po/Makefile create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/po/python-meh.pot create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/python-meh.spec create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/setup.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/__init__.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/attrSkipList.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/baseclass.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/callbacks.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_binary.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_unicode.py create mode 100755 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/pylint/runpylint.py create mode 100755 pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/safe_string_test.py create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/ui/exception-dialog.glade create mode 100644 pkgbuilds/python-meh/src/python-meh-r0.43-1/zanata.xml create mode 100644 pkgbuilds/python-simpleline/PKGBUILD create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/.BUILDINFO create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/.MTREE create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/.PKGINFO create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__init__.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/errors.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/global_configuration.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/logging.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/errors.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__init__.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/event_queue.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/glib_event_loop.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/main_loop.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/signals.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/ticket_machine.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/event_queue.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/glib_event_loop.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/main_loop.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/signals.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/ticket_machine.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/global_configuration.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__init__.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/input_handler.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/input_threading.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/input_handler.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/input_threading.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/logging.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__init__.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/adv_widgets.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/containers.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/prompt.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_handler.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_scheduler.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_stack.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/widgets.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/adv_widgets.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/containers.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/prompt.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__init__.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/input_manager.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/signal_handler.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/input_manager.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/signal_handler.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_handler.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_scheduler.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_stack.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/widgets.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__init__.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__pycache__/__init__.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__pycache__/i18n.cpython-314.pyc create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/i18n.py create mode 100644 pkgbuilds/python-simpleline/pkg/python-simpleline/usr/share/licenses/python-simpleline/LICENSE.md create mode 100644 pkgbuilds/python-simpleline/python-simpleline-1.8-1-any.pkg.tar.zst create mode 100644 pkgbuilds/python-simpleline/python-simpleline-1.8.tar.gz create mode 120000 pkgbuilds/python-simpleline/src/python-simpleline-1.8.tar.gz create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.github/workflows/validate.yml create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.gitignore create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.packit.yaml create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.pylintrc create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/LICENSE.md create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/MANIFEST.in create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/Makefile create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/README.md create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/Makefile create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/adv_widgets.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/advanced_input.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/app.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/containers.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/errors.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/event_loops.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/prompt.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen_handling.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/signals.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/widgets.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/conf.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/guide.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/index.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/introduction.rst create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/make.bat create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/00_basic/00_basic.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/01_base_widgets/01_base_widgets.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/02_ignore_continue/02_ignore_continue.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/03_entry_counter/03_entry_counter.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/04_help.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/example_help.txt create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/05_hub_spoke/05_hub_spoke.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/06_glib_loop/06_glib_loop.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/07_divider/07_divider.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/run_example.sh create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/po/Makefile create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/python-simpleline.spec create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/setup.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/errors.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/event_queue.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/glib_event_loop.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/main_loop.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/signals.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/ticket_machine.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/global_configuration.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_handler.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_threading.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/logging.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/adv_widgets.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/containers.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/prompt.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/input_manager.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/signal_handler.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_handler.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_scheduler.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_stack.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/widgets.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/i18n.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/event_loop_glib_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/input_handler_glib_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/render_screen_glib_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/screen_scheduler_glib_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/__init__.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/adv_widgets_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/app_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/containers_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_loop_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_queue_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/global_configuration_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/input_handler_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/prompt_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/render_screen_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/scheduler_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_scheduler_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_stack_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/signal_handler_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/ticket_machine_test.py create mode 100644 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/widgets_test.py create mode 100755 pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/run_test.sh diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 40290a8..f0ba624 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -26,11 +26,4 @@ file_permissions=( ["/usr/local/bin/choose-mirror"]="0:0:755" ["/usr/local/bin/Installation_guide"]="0:0:755" ["/usr/local/bin/livecd-sound"]="0:0:755" - ["/usr/local/bin/fws-pick-desktop"]="0:0:755" - ["/usr/bin/fws-installer"]="0:0:755" - ["/usr/local/bin/fws-desktop-init-common"]="0:0:755" - ["/usr/local/bin/fws-desktop-init-xfce"]="0:0:755" - ["/usr/local/bin/fws-desktop-init-kde"]="0:0:755" - ["/usr/local/bin/fws-desktop-init-gnome"]="0:0:755" - ["/usr/local/bin/fws-desktop-init-hyprland"]="0:0:755" ) diff --git a/pkgbuilds/python-meh/PKGBUILD b/pkgbuilds/python-meh/PKGBUILD new file mode 100644 index 0000000..7d565ed --- /dev/null +++ b/pkgbuilds/python-meh/PKGBUILD @@ -0,0 +1,29 @@ +# Maintainer: FWS +# Dépendance de l'installateur Anaconda (rhinstaller) — gestion d'exceptions. +# setup.py amont = distutils + `setup.py install` : tous deux supprimés +# (Python 3.12+, setuptools 80+). Le paquet étant du pur Python, on installe +# l'arborescence à la main plutôt que de patcher la chaîne distutils. +pkgname=python-meh +pkgver=0.43 +pkgrel=1 +pkgdesc="Python exception handling library (dépendance Anaconda)" +arch=('any') +url="https://github.com/rhinstaller/python-meh" +license=('GPL-2.0-or-later') +depends=('python' 'python-gobject' 'python-dbus' 'libreport') +_tag="r$pkgver-1" +source=("$pkgname-$pkgver.tar.gz::https://github.com/rhinstaller/python-meh/archive/refs/tags/$_tag.tar.gz") +sha256sums=('cd50301794ab68a064715f1ace960f6de07aea809aa85f73087d44573c98be52') +_srcdir="python-meh-$_tag" + +package() { + cd "$srcdir/$_srcdir" + local sitedir + sitedir=$(python -c 'import site; print(site.getsitepackages()[0])') + install -d "$pkgdir$sitedir" + cp -a meh "$pkgdir$sitedir/meh" + # -d : grave le chemin d'exécution réel dans les .pyc (pas le $pkgdir de build). + python -m compileall -q -d "$sitedir/meh" "$pkgdir$sitedir/meh" || true + install -Dm644 ui/exception-dialog.glade -t "$pkgdir/usr/share/python-meh/" + install -Dm644 COPYING "$pkgdir/usr/share/licenses/$pkgname/COPYING" +} diff --git a/pkgbuilds/python-meh/pkg/python-meh/.BUILDINFO b/pkgbuilds/python-meh/pkg/python-meh/.BUILDINFO new file mode 100644 index 0000000..ec09f92 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/.BUILDINFO @@ -0,0 +1,898 @@ +format = 2 +pkgname = python-meh +pkgbase = python-meh +pkgver = 0.43-1 +pkgarch = any +pkgbuild_sha256sum = 207bd70c0f151083b8194b40534aeed665c9af48e588230ad370757eb4368229 +packager = Unknown Packager +builddate = 1781307281 +builddir = /home/nocode/Files/FWS-ISO/pkgbuilds/python-meh +startdir = /home/nocode/Files/FWS-ISO/pkgbuilds/python-meh +buildtool = makepkg +buildtoolver = 7.1.0 +buildenv = !distcc +buildenv = color +buildenv = !ccache +buildenv = check +buildenv = !sign +options = strip +options = docs +options = !libtool +options = !staticlibs +options = emptydirs +options = zipman +options = purge +options = debug +options = lto +installed = aardvark-dns-1.17.1-1-x86_64 +installed = abseil-cpp-20260107.1-1-x86_64 +installed = accountsservice-26.13.3-1-x86_64 +installed = acl-2.3.2-2-x86_64 +installed = adwaita-cursors-50.0-1-any +installed = adwaita-fonts-50.0-1-any +installed = adwaita-icon-theme-50.0-1-any +installed = adwaita-icon-theme-legacy-46.2-3-any +installed = alsa-card-profiles-1:1.6.6-1-x86_64 +installed = alsa-lib-1.2.16-1-x86_64 +installed = alsa-plugins-1:1.2.12-5-x86_64 +installed = alsa-topology-conf-1.2.5.1-4-any +installed = alsa-ucm-conf-1.2.16-2-any +installed = aom-3.14.1-1-x86_64 +installed = appstream-1.1.2-1-x86_64 +installed = aquamarine-0.12.1-1-x86_64 +installed = arch-install-scripts-31-1-any +installed = archiso-88-1-any +installed = archlinux-keyring-20260420-1-any +installed = argon2-20190702-6-x86_64 +installed = at-spi2-core-2.60.4-1-x86_64 +installed = atkmm-2.28.5-2-x86_64 +installed = attr-2.5.2-2-x86_64 +installed = audit-4.1.4-2-x86_64 +installed = autoconf-2.73-1-any +installed = automake-1.18.1-1-any +installed = avahi-1:0.9rc4-1-x86_64 +installed = base-3-3-any +installed = base-devel-1-2-any +installed = bash-5.3.15-1-x86_64 +installed = bemoji-0.4.0-1-any +installed = binutils-2.46+r70+g155188ea10a7-1-x86_64 +installed = bison-3.8.2-8-x86_64 +installed = blas-3.12.1-2-x86_64 +installed = bluez-libs-5.86-6-x86_64 +installed = boost-libs-1.91.0-1-x86_64 +installed = brightnessctl-0.5.1-3-x86_64 +installed = brotli-1.2.0-1-x86_64 +installed = bubblewrap-0.11.2-1-x86_64 +installed = bzip2-1.0.8-6-x86_64 +installed = c-ares-1.34.6-1-x86_64 +installed = ca-certificates-20240618-1-any +installed = ca-certificates-mozilla-3.124-1-x86_64 +installed = ca-certificates-utils-20240618-1-any +installed = cabextract-1.11-2-x86_64 +installed = cairo-1.18.4-1-x86_64 +installed = cairomm-1.14.6-1-x86_64 +installed = cairomm-1.16-1.18.1-1-x86_64 +installed = catatonit-0.2.1-2-x86_64 +installed = cblas-3.12.1-2-x86_64 +installed = cliphist-1:0.7.0-2-x86_64 +installed = clucene-2.3.3.4-17-x86_64 +installed = cmake-4.3.3-1-x86_64 +installed = compiler-rt-22.1.6-1-x86_64 +installed = composefs-1.0.8-1-x86_64 +installed = conmon-1:2.2.1-1-x86_64 +installed = containers-common-1:0.67.1-3-any +installed = coreutils-9.11-1-x86_64 +installed = cpio-2.15-3-x86_64 +installed = cppdap-1.58.0-3-x86_64 +installed = cracklib-2.10.3-1-x86_64 +installed = criu-4.2-3-x86_64 +installed = crun-1.28-1-x86_64 +installed = cryptsetup-2.8.6-1-x86_64 +installed = curl-8.20.0-7-x86_64 +installed = dav1d-1.5.3-1-x86_64 +installed = db5.3-5.3.28-7-x86_64 +installed = dbus-1.16.2-1-x86_64 +installed = dbus-broker-37-3-x86_64 +installed = dbus-broker-units-37-3-x86_64 +installed = dbus-units-37-3-x86_64 +installed = dconf-0.49.0-1-x86_64 +installed = debugedit-5.3-1-x86_64 +installed = default-cursors-3-1-any +installed = desktop-file-utils-0.28-1-x86_64 +installed = device-mapper-2.03.41-1-x86_64 +installed = diffutils-3.12-2-x86_64 +installed = discord-1:1.0.142-1-x86_64 +installed = dkms-3.4.1-1-any +installed = dos2unix-7.5.6-1-x86_64 +installed = dosfstools-4.2-5-x86_64 +installed = double-conversion-3.4.0-1-x86_64 +installed = duktape-2.7.0-7-x86_64 +installed = e2fsprogs-1.47.4-1-x86_64 +installed = efibootmgr-18-4-x86_64 +installed = efivar-39-2-x86_64 +installed = egl-gbm-1.1.3-1-x86_64 +installed = egl-wayland-4:1.1.21-1-x86_64 +installed = egl-wayland2-1.0.1-1-x86_64 +installed = egl-x11-1.0.5-1-x86_64 +installed = eglexternalplatform-1.2.1-1-any +installed = electron41-41.7.2-1-x86_64 +installed = elfutils-0.195-1-x86_64 +installed = erofs-utils-1.9.1-1-x86_64 +installed = exo-4.20.0-2-x86_64 +installed = expat-2.8.1-1-x86_64 +installed = extra-cmake-modules-6.26.0-1-any +installed = fakeroot-1:1.37.2-1-x86_64 +installed = fcft-3.3.3-1-x86_64 +installed = ffmpeg-2:8.1.1-2-x86_64 +installed = fftw-3.3.11-1-x86_64 +installed = file-5.48-1-x86_64 +installed = filesystem-2025.10.12-1-any +installed = findutils-4.10.0-3-x86_64 +installed = firefox-151.0.4-1-x86_64 +installed = flac-1.5.0-1-x86_64 +installed = flatpak-1:1.18.0-1-x86_64 +installed = flex-2.6.4-6-x86_64 +installed = fmt-12.1.0-2-x86_64 +installed = fontconfig-2:2.18.1-1-x86_64 +installed = freerdp-2:3.26.0-1-x86_64 +installed = freetype2-2.14.3-1-x86_64 +installed = fribidi-1.0.16-2-x86_64 +installed = fuse-common-3.18.2-1-x86_64 +installed = fuse2-2.9.9-5-x86_64 +installed = fuse3-3.18.2-1-x86_64 +installed = fuzzel-1.14.1-1-x86_64 +installed = gawk-5.4.0-1-x86_64 +installed = gc-8.2.12-1-x86_64 +installed = gcc-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = gcc-libs-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = gcr-3.41.2-2-x86_64 +installed = gcr-4-4.4.0.1-1-x86_64 +installed = gdb-17.2-1-x86_64 +installed = gdb-common-17.2-1-x86_64 +installed = gdbm-1.26-2-x86_64 +installed = gdk-pixbuf2-2.44.6-2-x86_64 +installed = gettext-1.0-2-x86_64 +installed = giflib-6.1.3-1-x86_64 +installed = git-2.54.0-1-x86_64 +installed = glib-networking-1:2.80.1-1-x86_64 +installed = glib2-2.88.1-1-x86_64 +installed = glibc-2.43+r22+g8362e8ce10b2-2-x86_64 +installed = glibmm-2.66.8-2-x86_64 +installed = glibmm-2.68-2.88.0-2-x86_64 +installed = glslang-1:1.4.350.0-1-x86_64 +installed = glycin-2.1.1-1-x86_64 +installed = gmp-6.3.0-3-x86_64 +installed = gnome-themes-extra-1:3.28-1-any +installed = gnulib-l10n-20241231-1-any +installed = gnupg-2.4.9-1-x86_64 +installed = gnutls-3.8.13-2-x86_64 +installed = go-2:1.26.4-1-x86_64 +installed = gobject-introspection-1.86.0-2-x86_64 +installed = gobject-introspection-runtime-1.86.0-2-x86_64 +installed = gparted-1.8.1-2-x86_64 +installed = gperftools-2.18.1-1-x86_64 +installed = gpgme-2.1.0-1-x86_64 +installed = gpgmepp-2.1.0-1-x86_64 +installed = gpm-1.20.7.r38.ge82d1a6-6-x86_64 +installed = gpsd-3.27.5-1-x86_64 +installed = gptfdisk-1.0.10-2-x86_64 +installed = graphene-1.10.8-2-x86_64 +installed = graphite-1:1.3.15-1-x86_64 +installed = grep-3.12-2-x86_64 +installed = grim-1.5.0-2-x86_64 +installed = groff-1.24.1-1-x86_64 +installed = grub-2:2.14-1-x86_64 +installed = gsettings-desktop-schemas-50.1-1-any +installed = gsettings-system-schemas-50.1-1-any +installed = gsm-1.0.24-1-x86_64 +installed = gssdp-1.6.5-1-x86_64 +installed = gst-plugins-bad-libs-1.28.3-1-x86_64 +installed = gst-plugins-base-libs-1.28.3-1-x86_64 +installed = gstreamer-1.28.3-1-x86_64 +installed = gtest-1.17.0-2-x86_64 +installed = gtk-layer-shell-0.10.1-1-x86_64 +installed = gtk-update-icon-cache-1:4.22.4-1-x86_64 +installed = gtk3-1:3.24.52-1-x86_64 +installed = gtk4-1:4.22.4-1-x86_64 +installed = gtkmm-4.0-4.22.0-2-x86_64 +installed = gtkmm3-3.24.11-1-x86_64 +installed = guile-3.0.11-1-x86_64 +installed = gupnp-1:1.6.10-1-x86_64 +installed = gupnp-igd-1.6.0-2-x86_64 +installed = gzip-1.14-2-x86_64 +installed = harfbuzz-14.2.1-1-x86_64 +installed = harfbuzz-icu-14.2.1-1-x86_64 +installed = hicolor-icon-theme-0.18-1-any +installed = hidapi-0.15.0-1-x86_64 +installed = highway-1.4.0-1-x86_64 +installed = hunspell-1.7.3-1-x86_64 +installed = hwdata-0.408-1-any +installed = hwloc-2.13.0-1-x86_64 +installed = hyphen-2.8.9-1-x86_64 +installed = hyprcursor-0.1.13-6-x86_64 +installed = hyprgraphics-0.5.1-2-x86_64 +installed = hypridle-0.1.7-9-x86_64 +installed = hyprland-0.55.4-1-x86_64 +installed = hyprland-guiutils-0.2.1-6-x86_64 +installed = hyprland-qt-support-0.1.0-12-x86_64 +installed = hyprlang-0.6.8-4-x86_64 +installed = hyprlock-0.9.5-4-x86_64 +installed = hyprpaper-0.8.4-2-x86_64 +installed = hyprpicker-0.4.7-1-x86_64 +installed = hyprpolkitagent-0.1.3-7-x86_64 +installed = hyprshot-1.3.0-4-any +installed = hyprtoolkit-0.5.4-2-x86_64 +installed = hyprutils-0.13.1-1-x86_64 +installed = hyprwayland-scanner-0.4.6-1-x86_64 +installed = hyprwire-0.3.1-2-x86_64 +installed = iana-etc-20260530-1-any +installed = icu-78.3-1-x86_64 +installed = imagemagick-7.1.2.25-1-x86_64 +installed = iniparser-4.2.6-2-x86_64 +installed = iproute2-7.0.0-1-x86_64 +installed = iptables-1:1.8.13-1-x86_64 +installed = iputils-20250605-1-x86_64 +installed = iso-codes-4.20.1-1-any +installed = jack2-1.9.22-2-x86_64 +installed = jansson-2.15.0-1-x86_64 +installed = jbigkit-2.1-8-x86_64 +installed = jq-1.8.1-3-x86_64 +installed = json-c-0.18-2-x86_64 +installed = json-glib-1.10.8-1-x86_64 +installed = jsoncpp-1.9.6-3-x86_64 +installed = kbd-2.10.0-1-x86_64 +installed = kcoreaddons-6.26.0-1-x86_64 +installed = keyutils-1.6.3-4-x86_64 +installed = ki18n-6.26.0-1-x86_64 +installed = kitty-0.47.1-1-x86_64 +installed = kitty-shell-integration-0.47.1-1-x86_64 +installed = kitty-terminfo-0.47.1-1-x86_64 +installed = kmod-34.2-1-x86_64 +installed = kpmcore-26.04.2-1-x86_64 +installed = krb5-1.22.2-1-x86_64 +installed = kwidgetsaddons-6.26.0-1-x86_64 +installed = l-smash-2.14.5-4-x86_64 +installed = lame-3.101.r6531-1-x86_64 +installed = lapack-3.12.1-2-x86_64 +installed = lcms2-2.19.1-1-x86_64 +installed = leancrypto-1.7.2-1-x86_64 +installed = lib32-alsa-lib-1.2.16-1-x86_64 +installed = lib32-alsa-plugins-1.2.12-1-x86_64 +installed = lib32-brotli-1.1.0-1-x86_64 +installed = lib32-bzip2-1.0.8-4-x86_64 +installed = lib32-curl-8.20.0-7-x86_64 +installed = lib32-dbus-1.16.2-1-x86_64 +installed = lib32-e2fsprogs-1.47.4-1-x86_64 +installed = lib32-expat-2.8.1-1-x86_64 +installed = lib32-fontconfig-2:2.18.1-1-x86_64 +installed = lib32-freetype2-2.14.3-1-x86_64 +installed = lib32-gcc-libs-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = lib32-glib2-2.88.1-1-x86_64 +installed = lib32-glibc-2.43+r22+g8362e8ce10b2-2-x86_64 +installed = lib32-gmp-6.3.0-2-x86_64 +installed = lib32-gnutls-3.8.13-3-x86_64 +installed = lib32-icu-78.3-1-x86_64 +installed = lib32-json-c-0.18-2-x86_64 +installed = lib32-keyutils-1.6.3-4-x86_64 +installed = lib32-krb5-1.22.2-1-x86_64 +installed = lib32-libdrm-2.4.134-1-x86_64 +installed = lib32-libelf-0.195-1-x86_64 +installed = lib32-libffi-3.5.2-1-x86_64 +installed = lib32-libgcrypt-1.12.2-1-x86_64 +installed = lib32-libglvnd-1.7.0-1-x86_64 +installed = lib32-libgpg-error-1.61-1-x86_64 +installed = lib32-libidn2-2.3.8-1-x86_64 +installed = lib32-libldap-2.6.13-1-x86_64 +installed = lib32-libnghttp2-1.69.0-1-x86_64 +installed = lib32-libnghttp3-1.16.0-1-x86_64 +installed = lib32-libngtcp2-1.23.0-1-x86_64 +installed = lib32-libnm-1.56.1-1-x86_64 +installed = lib32-libpciaccess-0.19-1-x86_64 +installed = lib32-libpipewire-1:1.6.6-1-x86_64 +installed = lib32-libpng-1.6.58-1-x86_64 +installed = lib32-libpsl-0.21.5-1-x86_64 +installed = lib32-libssh2-1.11.1-1-x86_64 +installed = lib32-libtasn1-4.21.0-1-x86_64 +installed = lib32-libunistring-1.4.2-1-x86_64 +installed = lib32-libva-2.22.0-1-x86_64 +installed = lib32-libx11-1.8.13-1-x86_64 +installed = lib32-libxau-1.0.12-1-x86_64 +installed = lib32-libxcb-1.17.0-1-x86_64 +installed = lib32-libxcrypt-4.5.2-1-x86_64 +installed = lib32-libxcrypt-compat-4.5.2-1-x86_64 +installed = lib32-libxdmcp-1.1.5-1-x86_64 +installed = lib32-libxext-1.3.7-1-x86_64 +installed = lib32-libxfixes-6.0.1-2-x86_64 +installed = lib32-libxinerama-1.1.6-1-x86_64 +installed = lib32-libxml2-2.15.3-1-x86_64 +installed = lib32-libxshmfence-1.3.3-1-x86_64 +installed = lib32-libxss-1.2.5-1-x86_64 +installed = lib32-libxxf86vm-1.1.5-2-x86_64 +installed = lib32-llvm-libs-1:22.1.6-1-x86_64 +installed = lib32-lm_sensors-1:3.6.2-2-x86_64 +installed = lib32-mesa-1:26.1.2-1-x86_64 +installed = lib32-ncurses-6.6-2-x86_64 +installed = lib32-nettle-4.0-2-x86_64 +installed = lib32-nspr-4.39-1-x86_64 +installed = lib32-nss-3.124-1-x86_64 +installed = lib32-nvidia-utils-610.43.02-1-x86_64 +installed = lib32-openssl-1:3.6.3-1-x86_64 +installed = lib32-p11-kit-0.26.2-1-x86_64 +installed = lib32-pcre2-10.47-1-x86_64 +installed = lib32-pipewire-1:1.6.6-1-x86_64 +installed = lib32-spirv-tools-1:1.4.350.0-1-x86_64 +installed = lib32-sqlite-3.53.2-1-x86_64 +installed = lib32-systemd-260.2-1-x86_64 +installed = lib32-util-linux-2.42.1-1-x86_64 +installed = lib32-vulkan-icd-loader-1.4.350.0-1-x86_64 +installed = lib32-wayland-1.25.0-1-x86_64 +installed = lib32-xz-5.8.3-1-x86_64 +installed = lib32-zlib-1.3.2-1-x86_64 +installed = lib32-zstd-1.5.7-2-x86_64 +installed = libabw-0.1.4-1-x86_64 +installed = libadwaita-1:1.9.1-1-x86_64 +installed = libaio-0.3.113-4-x86_64 +installed = libappindicator-12.10.1-1-x86_64 +installed = libarchive-3.8.7-1-x86_64 +installed = libasan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libass-0.17.4-2-x86_64 +installed = libassuan-3.0.0-1-x86_64 +installed = libasyncns-1:0.8+r3+g68cd5af-3-x86_64 +installed = libatomic-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libatomic_ops-7.8.2-2-x86_64 +installed = libavc1394-0.5.4-7-x86_64 +installed = libavif-1.4.2-1-x86_64 +installed = libb2-0.98.1-3-x86_64 +installed = libblake3-1.8.4-1-x86_64 +installed = libbluray-1.4.1-1-x86_64 +installed = libbpf-1.7.0-1-x86_64 +installed = libbs2b-3.1.0-10-x86_64 +installed = libbsd-0.12.2-2-x86_64 +installed = libburn-1.5.8-1-x86_64 +installed = libcanberra-1:0.30+r2+gc0620e4-6-x86_64 +installed = libcap-2.78-1-x86_64 +installed = libcap-ng-0.9.3-1-x86_64 +installed = libcbor-0.14.0-1-x86_64 +installed = libcdio-2.3.0-1-x86_64 +installed = libcdio-paranoia-10.2+2.0.2-2-x86_64 +installed = libcdr-0.1.9-1-x86_64 +installed = libcloudproviders-0.4.0-1-x86_64 +installed = libcmis-0.6.3-1-x86_64 +installed = libcolord-1.4.8-1-x86_64 +installed = libcups-2:2.4.19-1-x86_64 +installed = libdaemon-0.14-6-x86_64 +installed = libdatrie-0.2.14-1-x86_64 +installed = libdbusmenu-glib-18.10.20180917-1-x86_64 +installed = libdbusmenu-gtk3-18.10.20180917-1-x86_64 +installed = libdecor-0.2.5-1-x86_64 +installed = libdeflate-1.25-1-x86_64 +installed = libdisplay-info-0.3.0-1-x86_64 +installed = libdovi-3.3.2-1-x86_64 +installed = libdrm-2.4.134-1-x86_64 +installed = libdvdnav-7.0.0-1-x86_64 +installed = libdvdread-7.0.1-1-x86_64 +installed = libe-book-0.1.3-20-x86_64 +installed = libebur128-1.2.6-2-x86_64 +installed = libedit-20260512_3.1-1-x86_64 +installed = libei-1.6.0-1-x86_64 +installed = libelf-0.195-1-x86_64 +installed = libepoxy-1.5.10-3-x86_64 +installed = libepubgen-0.1.1-6-x86_64 +installed = libetonyek-0.1.13-2-x86_64 +installed = libevdev-1.13.6-1-x86_64 +installed = libevent-2.1.12-5-x86_64 +installed = libexif-0.6.26-1-x86_64 +installed = libexttextcat-3.4.8-1-x86_64 +installed = libfdk-aac-2.0.3-2-x86_64 +installed = libffi-3.5.2-1-x86_64 +installed = libfido2-1.17.0-1-x86_64 +installed = libfontenc-1.1.9-1-x86_64 +installed = libfreeaptx-0.2.2-1-x86_64 +installed = libfreehand-0.1.3-1-x86_64 +installed = libfyaml-0.9.6-2-x86_64 +installed = libgcc-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libgcrypt-1.12.2-1-x86_64 +installed = libgfortran-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libgirepository-1.86.0-2-x86_64 +installed = libgit2-1:1.9.4-1-x86_64 +installed = libglvnd-1.7.0-3-x86_64 +installed = libgomp-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libgpg-error-1.61-1-x86_64 +installed = libgtop-2.41.3-2-x86_64 +installed = libgudev-238-3-x86_64 +installed = libice-1.1.2-1-x86_64 +installed = libidn2-2.3.8-1-x86_64 +installed = libiec61883-1.2.0-9-x86_64 +installed = libimobiledevice-1.4.0-2-x86_64 +installed = libimobiledevice-glue-1.3.2-1-x86_64 +installed = libinih-62-2-x86_64 +installed = libinput-1.31.3-1-x86_64 +installed = libisl-0.27-1-x86_64 +installed = libisoburn-1.5.8.2-1-x86_64 +installed = libisofs-1.5.8.2-1-x86_64 +installed = libixion-0.20.0-7-x86_64 +installed = libjpeg-turbo-3.1.4.1-1-x86_64 +installed = libjxl-0.11.2-2-x86_64 +installed = libksba-1.8.0-1-x86_64 +installed = liblangtag-0.6.8-1-x86_64 +installed = liblc3-1.1.3-2-x86_64 +installed = libldac-2.0.2.3-3-x86_64 +installed = libldap-2.6.13-1-x86_64 +installed = liblqr-0.4.3-1-x86_64 +installed = liblsan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libmakepkg-dropins-20-1-any +installed = libmalcontent-0.14.0-4-x86_64 +installed = libmd-1.2.0-1-x86_64 +installed = libmm-glib-1.24.2-1-x86_64 +installed = libmnl-1.0.5-2-x86_64 +installed = libmodplug-0.8.9.0-7-x86_64 +installed = libmpc-1.4.1-1-x86_64 +installed = libmpdclient-2.23-1-x86_64 +installed = libmspub-0.1.5-1-x86_64 +installed = libmwaw-0.3.22-4-x86_64 +installed = libmysofa-1.3.4-1-x86_64 +installed = libndp-1.9-1-x86_64 +installed = libnet-2:1.3-2-x86_64 +installed = libnetfilter_conntrack-1.1.1-1-x86_64 +installed = libnewt-0.52.25-2-x86_64 +installed = libnfnetlink-1.0.2-2-x86_64 +installed = libnftnl-1.3.1-1-x86_64 +installed = libnghttp2-1.69.0-1-x86_64 +installed = libnghttp3-1.16.0-1-x86_64 +installed = libngtcp2-1.23.0-1-x86_64 +installed = libnice-0.1.23-1-x86_64 +installed = libnl-3.12.0-1-x86_64 +installed = libnm-1.56.1-1-x86_64 +installed = libnma-1.10.6-3-x86_64 +installed = libnma-common-1.10.6-3-x86_64 +installed = libnotify-0.8.8-1-x86_64 +installed = libnsl-2.0.1-2-x86_64 +installed = libnumbertext-1.0.11-3-x86_64 +installed = libobjc-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libodfgen-0.1.8-5-x86_64 +installed = libogg-1.3.6-1-x86_64 +installed = libopenmpt-0.8.7-1-x86_64 +installed = libopenrazer-0.4.0-1-x86_64 +installed = liborcus-0.21.0-6-x86_64 +installed = libp11-kit-0.26.2-1-x86_64 +installed = libpagemaker-0.0.4-5-x86_64 +installed = libpcap-1.10.6-1-x86_64 +installed = libpciaccess-0.19-1-x86_64 +installed = libpgm-5.3.128-4-x86_64 +installed = libpipewire-1:1.6.6-1-x86_64 +installed = libplacebo-7.360.1-2-x86_64 +installed = libplist-2.7.0-3-x86_64 +installed = libpng-1.6.58-1-x86_64 +installed = libproxy-0.5.12-1-x86_64 +installed = libpsl-0.21.5-2-x86_64 +installed = libpulse-17.0+r98+gb096704c0-1-x86_64 +installed = libpwquality-1.4.5-7-x86_64 +installed = libquadmath-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libqxp-0.0.3-1-x86_64 +installed = libraqm-0.10.5-1-x86_64 +installed = libraw1394-2.1.2-4-x86_64 +installed = libreoffice-fresh-26.2.4-1-x86_64 +installed = librevenge-0.0.5-4-x86_64 +installed = librsvg-2:2.62.3-1-x86_64 +installed = librsync-1:2.3.4-2-x86_64 +installed = libsamplerate-0.2.2-3-x86_64 +installed = libsasl-2.1.28-5-x86_64 +installed = libseccomp-2.6.0-1-x86_64 +installed = libsecret-0.21.7-1-x86_64 +installed = libsigc++-2.12.2-1-x86_64 +installed = libsigc++-3.0-3.8.1-1-x86_64 +installed = libsixel-1.10.5-1-x86_64 +installed = libsm-1.2.6-1-x86_64 +installed = libsndfile-1.2.2-4-x86_64 +installed = libsodium-1.0.22-1-x86_64 +installed = libsoup3-3.6.6-2-x86_64 +installed = libsoxr-0.1.3-4-x86_64 +installed = libssh-0.12.0-1-x86_64 +installed = libssh2-1.11.1-1-x86_64 +installed = libstaroffice-0.0.7-5-x86_64 +installed = libstdc++-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libstemmer-3.1.1-1-x86_64 +installed = libsysprof-capture-50.0-2-x86_64 +installed = libtasn1-4.21.0-1-x86_64 +installed = libtatsu-1.0.5-1-x86_64 +installed = libteam-1.32-3-x86_64 +installed = libthai-0.1.30-1-x86_64 +installed = libtheora-1.2.0-1-x86_64 +installed = libtiff-4.7.1-2-x86_64 +installed = libtirpc-1.3.7-1-x86_64 +installed = libtommath-1.3.0-2-x86_64 +installed = libtool-2.6.1-1-x86_64 +installed = libtsan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libubsan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libunibreak-7.0-1-x86_64 +installed = libunistring-1.4.2-1-x86_64 +installed = libunwind-1.8.2-1-x86_64 +installed = liburing-2.14-1-x86_64 +installed = libusb-1.0.30-1-x86_64 +installed = libusbmuxd-2.1.1-2-x86_64 +installed = libutf8proc-2.11.3-1-x86_64 +installed = libuv-1.52.1-1-x86_64 +installed = libva-2.23.0-1-x86_64 +installed = libva-nvidia-driver-0.0.17-1-x86_64 +installed = libvdpau-1.5-4-x86_64 +installed = libverto-0.3.2-6-x86_64 +installed = libvisio-0.1.11-1-x86_64 +installed = libvorbis-1.3.7-4-x86_64 +installed = libvpl-2.16.0-2-x86_64 +installed = libvpx-1.16.0-3-x86_64 +installed = libwacom-2.19.0-1-x86_64 +installed = libwebp-1.6.0-2-x86_64 +installed = libwireplumber-0.5.14-1-x86_64 +installed = libwpd-0.10.3-6-x86_64 +installed = libwps-0.4.14-4-x86_64 +installed = libx11-1.8.13-1-x86_64 +installed = libxau-1.0.12-1-x86_64 +installed = libxcb-1.17.0-1-x86_64 +installed = libxcomposite-0.4.7-1-x86_64 +installed = libxcrypt-4.5.2-1-x86_64 +installed = libxcrypt-compat-4.5.2-1-x86_64 +installed = libxcursor-1.2.3-1-x86_64 +installed = libxcvt-0.1.3-1-x86_64 +installed = libxdamage-1.1.7-1-x86_64 +installed = libxdmcp-1.1.5-2-x86_64 +installed = libxext-1.3.7-1-x86_64 +installed = libxfce4ui-4.20.2-1-x86_64 +installed = libxfce4util-4.20.1-1-x86_64 +installed = libxfixes-6.0.2-1-x86_64 +installed = libxfont2-2.0.7-1-x86_64 +installed = libxft-2.3.9-1-x86_64 +installed = libxi-1.8.3-1-x86_64 +installed = libxinerama-1.1.6-1-x86_64 +installed = libxkbcommon-1.13.2-1-x86_64 +installed = libxkbcommon-x11-1.13.2-1-x86_64 +installed = libxkbfile-1.2.0-1-x86_64 +installed = libxml2-2.15.3-1-x86_64 +installed = libxml2-legacy-2.13.9-2-x86_64 +installed = libxmlb-0.3.27-1-x86_64 +installed = libxmp-4.7.0-1-x86_64 +installed = libxmu-1.3.1-1-x86_64 +installed = libxpresent-1.0.2-1-x86_64 +installed = libxrandr-1.5.5-1-x86_64 +installed = libxrender-0.9.12-1-x86_64 +installed = libxshmfence-1.3.3-1-x86_64 +installed = libxslt-1.1.45-2-x86_64 +installed = libxss-1.2.5-1-x86_64 +installed = libxt-1.3.1-1-x86_64 +installed = libxtst-1.2.5-1-x86_64 +installed = libxv-1.0.13-1-x86_64 +installed = libxxf86vm-1.1.7-1-x86_64 +installed = libyaml-0.2.5-3-x86_64 +installed = libyuv-r2426+464c51a03-1-x86_64 +installed = libzip-1.11.4-1-x86_64 +installed = libzmf-0.0.2-20-x86_64 +installed = licenses-20240728-1-any +installed = lilv-0.26.4-1-x86_64 +installed = linux-7.0.11.arch1-1-x86_64 +installed = linux-api-headers-7.0-1-x86_64 +installed = linux-firmware-20260519-1-any +installed = linux-firmware-amdgpu-20260519-1-any +installed = linux-firmware-atheros-20260519-1-any +installed = linux-firmware-broadcom-20260519-1-any +installed = linux-firmware-cirrus-20260519-1-any +installed = linux-firmware-intel-20260519-1-any +installed = linux-firmware-mediatek-20260519-1-any +installed = linux-firmware-nvidia-20260519-1-any +installed = linux-firmware-other-20260519-1-any +installed = linux-firmware-radeon-20260519-1-any +installed = linux-firmware-realtek-20260519-1-any +installed = linux-firmware-whence-20260519-1-any +installed = linux-headers-7.0.11.arch1-1-x86_64 +installed = lld-22.1.6-1-x86_64 +installed = llhttp-9.3.1-1-x86_64 +installed = llvm-libs-22.1.6-1-x86_64 +installed = lm_sensors-1:3.6.2-1-x86_64 +installed = lmdb-0.9.35-1-x86_64 +installed = lpsolve-5.5.2.14-1-x86_64 +installed = lsb-release-2.0.r55.a25a4fc-1-any +installed = lsof-4.99.6-1-x86_64 +installed = lua-5.5.0-2-x86_64 +installed = lua54-5.4.8-6-x86_64 +installed = luajit-2.1.1780076327+b925b3e-1-x86_64 +installed = lug-helper-1:4.13-1-any +installed = lv2-1.18.10-2-x86_64 +installed = lz4-1:1.10.0-2-x86_64 +installed = lzo-2.10-5-x86_64 +installed = m4-1.4.21-2-x86_64 +installed = mailcap-2.1.54-2-any +installed = make-4.4.1-3-x86_64 +installed = mako-1.11.0-1-x86_64 +installed = md4c-0.5.3-1-x86_64 +installed = mesa-1:26.1.2-1-x86_64 +installed = meson-1.11.1-3-any +installed = mingw-w64-binutils-2.46.0-1-x86_64 +installed = mingw-w64-crt-14.0.0-1-any +installed = mingw-w64-gcc-16.1.0-1-x86_64 +installed = mingw-w64-headers-14.0.0-1-any +installed = mingw-w64-winpthreads-14.0.0-1-any +installed = minizip-1:1.3.2-3-x86_64 +installed = mkinitcpio-41-4-any +installed = mkinitcpio-busybox-1.36.1-1-x86_64 +installed = mobile-broadband-provider-info-20251101-1-any +installed = mpdecimal-4.0.1-3-x86_64 +installed = mpfr-4.2.2-1-x86_64 +installed = mpg123-1.33.5-1-x86_64 +installed = mpv-1:0.41.0-3-x86_64 +installed = mpvpaper-1.8-1-x86_64 +installed = mtdev-1.1.7-1-x86_64 +installed = mtools-1:4.0.49-1-x86_64 +installed = mujs-1.3.9-1-x86_64 +installed = muparser-2.3.5-2-x86_64 +installed = nano-9.0-1-x86_64 +installed = ncurses-6.6-2-x86_64 +installed = neon-0.37.1-1-x86_64 +installed = netavark-1.17.2-2-x86_64 +installed = nettle-4.0-1-x86_64 +installed = network-manager-applet-1.36.0-2-x86_64 +installed = networkmanager-1.56.1-1-x86_64 +installed = nftables-1:1.1.6-3-x86_64 +installed = ninja-1.13.2-3-x86_64 +installed = nm-connection-editor-1.36.0-2-x86_64 +installed = noto-fonts-1:2026.06.01-1-any +installed = noto-fonts-cjk-20240730-1-any +installed = noto-fonts-emoji-1:2.051-1-any +installed = noto-fonts-extra-1:2026.06.01-1-any +installed = npth-1.8-1-x86_64 +installed = nspr-4.39-1-x86_64 +installed = nss-3.124-1-x86_64 +installed = nvidia-open-610.43.02-2-x86_64 +installed = nvidia-utils-610.43.02-2-x86_64 +installed = ocl-icd-2.3.4-1-x86_64 +installed = onetbb-2023.0.0-1-x86_64 +installed = oniguruma-6.9.10-1-x86_64 +installed = openal-1.25.2-1-x86_64 +installed = opencore-amr-0.1.6-2-x86_64 +installed = openjpeg2-2.5.4-1-x86_64 +installed = openrazer-daemon-3.12.2-2-any +installed = openrazer-driver-dkms-3.12.2-2-any +installed = openssh-10.3p1-1-x86_64 +installed = openssl-3.6.3-1-x86_64 +installed = opus-1.6.1-1-x86_64 +installed = opusfile-0.12-4-x86_64 +installed = orc-0.4.42-1-x86_64 +installed = os-prober-1.84-1-x86_64 +installed = ostree-2025.7-3-x86_64 +installed = p11-kit-0.26.2-1-x86_64 +installed = pacman-7.1.0.r9.g54d9411-2-x86_64 +installed = pacman-mirrorlist-20260610-1-any +installed = pahole-1:1.31-2-x86_64 +installed = pam-1.7.2-2-x86_64 +installed = pambase-20250719-1-any +installed = pango-1:1.57.1-1-x86_64 +installed = pangomm-2.46.4-3-x86_64 +installed = pangomm-2.48-2.56.1-2-x86_64 +installed = papirus-icon-theme-20250501-1-any +installed = parted-3.7-1-x86_64 +installed = paru-2.1.0-2-x86_64 +installed = paru-debug-2.1.0-2-x86_64 +installed = passt-2026_05_26.038c51e-1-x86_64 +installed = patch-2.8-1-x86_64 +installed = pavucontrol-1:6.2-1-x86_64 +installed = pciutils-3.15.0-1-x86_64 +installed = pcre-8.45-4-x86_64 +installed = pcre2-10.47-1-x86_64 +installed = pcsclite-2.5.1-1-x86_64 +installed = perl-5.42.2-1-x86_64 +installed = perl-error-0.17030-3-any +installed = perl-mailtools-2.22-3-any +installed = perl-timedate-2.35-1-any +installed = pinentry-1.3.2-2-x86_64 +installed = pipewire-1:1.6.6-1-x86_64 +installed = pipewire-audio-1:1.6.6-1-x86_64 +installed = pipewire-pulse-1:1.6.6-1-x86_64 +installed = pixman-0.46.4-1-x86_64 +installed = pkgconf-2.5.1-1-x86_64 +installed = playerctl-2.4.1-5-x86_64 +installed = podman-5.8.3-1-x86_64 +installed = podman-compose-1.6.0-1-any +installed = podman-desktop-1.27.2-2-x86_64 +installed = polkit-127-3-x86_64 +installed = polkit-qt6-0.201.1-1-x86_64 +installed = poppler-26.05.0-1-x86_64 +installed = popt-1.19-2-x86_64 +installed = portaudio-1:19.7.0-4-x86_64 +installed = portmidi-1:2.0.8-1-x86_64 +installed = pps-tools-1.0.3-2-x86_64 +installed = procps-ng-4.0.6-1-x86_64 +installed = protobuf-35.0-1-x86_64 +installed = protobuf-c-1.5.2-10-x86_64 +installed = psmisc-23.7-2-x86_64 +installed = pugixml-1.15-3-x86_64 +installed = python-3.14.5-1-x86_64 +installed = python-attrs-26.1.0-1-any +installed = python-autocommand-2.2.2-9-any +installed = python-cffi-2.0.0-2-x86_64 +installed = python-click-8.3.3-1-any +installed = python-cryptography-48.0.1-1-x86_64 +installed = python-daemonize-2.5.0-10-any +installed = python-dbus-1.4.0-2-x86_64 +installed = python-dotenv-1.2.2-1-any +installed = python-filelock-3.29.0-1-any +installed = python-gobject-3.56.3-1-x86_64 +installed = python-jaraco.collections-5.1.0-3-any +installed = python-jaraco.context-6.1.2-1-any +installed = python-jaraco.functools-4.1.0-3-any +installed = python-jaraco.text-4.0.0-4-any +installed = python-mako-1.3.11-1-any +installed = python-markdown-3.10.2-1-any +installed = python-markupsafe-3.0.3-1-x86_64 +installed = python-more-itertools-11.1.0-1-any +installed = python-numpy-2.4.6-1-x86_64 +installed = python-openrazer-3.12.2-2-any +installed = python-packaging-26.2-1-any +installed = python-pip-26.1.2-1-any +installed = python-pkg_resources-81.0.0-1-any +installed = python-platformdirs-4.10.0-1-any +installed = python-protobuf-35.0-1-x86_64 +installed = python-pycparser-3.00-1-any +installed = python-pygame-2.6.1-5-x86_64 +installed = python-pyudev-0.24.4-1-any +installed = python-setproctitle-1.3.7-2-x86_64 +installed = python-setuptools-1:82.0.1-1-any +installed = python-tqdm-4.68.1-1-any +installed = python-typing_extensions-4.15.0-3-any +installed = python-wheel-0.47.0-1-any +installed = python-yaml-6.0.3-2-x86_64 +installed = qt5-base-5.15.19+kde+r96-1-x86_64 +installed = qt5-declarative-5.15.19+kde+r23-1-x86_64 +installed = qt5-graphicaleffects-5.15.19-1-x86_64 +installed = qt5-quickcontrols2-5.15.19+kde+r5-1-x86_64 +installed = qt5-svg-5.15.19+kde+r5-1-x86_64 +installed = qt5-translations-5.15.19-1-any +installed = qt5-wayland-5.15.19+kde+r55-1-x86_64 +installed = qt6-5compat-6.11.1-1-x86_64 +installed = qt6-base-6.11.1-1-x86_64 +installed = qt6-declarative-6.11.1-3-x86_64 +installed = qt6-shadertools-6.11.1-1-x86_64 +installed = qt6-svg-6.11.1-1-x86_64 +installed = qt6-tools-6.11.1-1-x86_64 +installed = qt6-translations-6.11.1-1-any +installed = qt6-wayland-6.11.1-1-x86_64 +installed = raptor-2.0.16-9-x86_64 +installed = rasqal-1:0.9.33-9-x86_64 +installed = rav1e-0.8.1-2-x86_64 +installed = razergenie-1.3.0-1-x86_64 +installed = re2-2:2025.11.05-4-x86_64 +installed = readline-8.3.003-1-x86_64 +installed = redland-1:1.0.17-10-x86_64 +installed = reflector-2023-5-any +installed = resvg-0.47.0-2-x86_64 +installed = rhash-1.4.6-1-x86_64 +installed = rsync-3.4.4-1-x86_64 +installed = rtkit-0.14-1-x86_64 +installed = rubberband-4.0.0-2-x86_64 +installed = rustup-1.29.0-2-x86_64 +installed = sbc-2.2-1-x86_64 +installed = scdoc-1.11.4-1-x86_64 +installed = sdbus-cpp-2.3.1-1-x86_64 +installed = sddm-0.21.0-7-x86_64 +installed = sddm-catppuccin-git-r42.10831de-1-any +installed = sdl2-compat-2.32.70-1-x86_64 +installed = sdl2_image-2.8.12-1-x86_64 +installed = sdl2_mixer-2.8.2-1-x86_64 +installed = sdl2_ttf-2.24.0-2-x86_64 +installed = sdl3-3.4.10-1-x86_64 +installed = sdl3_ttf-3.2.2-3-x86_64 +installed = seatd-0.9.3-1-x86_64 +installed = sed-4.10-1-x86_64 +installed = serd-0.32.10-1-x86_64 +installed = shaderc-2026.2-1-x86_64 +installed = shadow-4.18.0-1-x86_64 +installed = shared-mime-info-2.4-3-x86_64 +installed = slang-2.3.3-4-x86_64 +installed = slurp-1.5.0-2-x86_64 +installed = smartmontools-7.5-1-x86_64 +installed = snappy-1.2.2-3-x86_64 +installed = sndio-1.10.0-1-x86_64 +installed = sord-0.16.22-1-x86_64 +installed = sound-theme-freedesktop-0.8-6-any +installed = source-highlight-3.1.9-18-x86_64 +installed = spandsp-0.0.6-7-x86_64 +installed = spdlog-1.17.0-2-x86_64 +installed = speex-1.2.1-2-x86_64 +installed = speexdsp-1.2.1-2-x86_64 +installed = spirv-tools-1:1.4.350.0-1-x86_64 +installed = sqlite-3.53.2-1-x86_64 +installed = squashfs-tools-4.7.5-1-x86_64 +installed = sratom-0.6.22-1-x86_64 +installed = srt-1.5.5-1-x86_64 +installed = startup-notification-0.12-9-x86_64 +installed = steam-1.0.0.85-7-x86_64 +installed = steam-devices-1.0.0.85-7-x86_64 +installed = sudo-1.9.17.p2-2-x86_64 +installed = svt-av1-4.1.0-1-x86_64 +installed = systemd-260.2-2-x86_64 +installed = systemd-libs-260.2-2-x86_64 +installed = systemd-sysvcompat-260.2-2-x86_64 +installed = tar-1.35-2-x86_64 +installed = tcl-8.6.16-1-x86_64 +installed = tdb-1.4.15-1-x86_64 +installed = texinfo-7.3-1-x86_64 +installed = thunar-4.20.8-3-x86_64 +installed = tinysparql-3.11.1-1-x86_64 +installed = tk-8.6.16-1-x86_64 +installed = tomlplusplus-3.4.0-2-x86_64 +installed = tpm2-tss-4.1.3-1-x86_64 +installed = tslib-1.24-1-x86_64 +installed = ttf-jetbrains-mono-nerd-3.4.0-2-any +installed = tzdata-2026b-1-x86_64 +installed = uchardet-0.0.8-4-x86_64 +installed = uefitool-debug-1:0.28.0-3-x86_64 +installed = unzip-6.0-23-x86_64 +installed = upower-1.91.2-1-x86_64 +installed = usbutils-019-1-x86_64 +installed = util-linux-2.42.1-1-x86_64 +installed = util-linux-libs-2.42.1-1-x86_64 +installed = v4l-utils-1.32.0-2-x86_64 +installed = vapoursynth-76-1-x86_64 +installed = vid.stab-1.1.1-2-x86_64 +installed = vim-9.2.0623-1-x86_64 +installed = vim-runtime-9.2.0623-1-x86_64 +installed = vmaf-3.1.0-1-x86_64 +installed = vmware-keymaps-1.0-3-any +installed = vmware-workstation-26H1-3-x86_64 +installed = vscodium-bin-1.121.03429-1-x86_64 +installed = vulkan-icd-loader-1.4.350.0-1-x86_64 +installed = vulkan-tools-1.4.350.0-1-x86_64 +installed = waybar-0.15.0-2-x86_64 +installed = wayland-1.25.0-1-x86_64 +installed = wayland-protocols-1.49-1-any +installed = webrtc-audio-processing-1-1.3-5-x86_64 +installed = which-2.25-1-x86_64 +installed = winboat-bin-0.9.0-1-x86_64 +installed = wine-staging-11.10-1-x86_64 +installed = wireplumber-0.5.14-1-x86_64 +installed = wl-clipboard-1:2.3.0-1-x86_64 +installed = wlogout-1.2.2-0-x86_64 +installed = woff2-font-awesome-7.2.0-1-any +installed = wpa_supplicant-2:2.11-5-x86_64 +installed = x264-3:0.165.r3222.b35605a-2-x86_64 +installed = x265-4.1-1-x86_64 +installed = xautomation-1.09-6-x86_64 +installed = xcb-proto-1.17.0-4-any +installed = xcb-util-0.4.1-2-x86_64 +installed = xcb-util-cursor-0.1.6-1-x86_64 +installed = xcb-util-errors-1.0.1-2-x86_64 +installed = xcb-util-image-0.4.1-3-x86_64 +installed = xcb-util-keysyms-0.4.1-5-x86_64 +installed = xcb-util-renderutil-0.3.10-2-x86_64 +installed = xcb-util-wm-0.4.2-2-x86_64 +installed = xdg-dbus-proxy-0.1.7-1-x86_64 +installed = xdg-desktop-portal-1.22.0-1-x86_64 +installed = xdg-desktop-portal-gtk-1.15.3-1-x86_64 +installed = xdg-desktop-portal-hyprland-1.3.12-2-x86_64 +installed = xdg-user-dirs-0.20-1-x86_64 +installed = xdg-utils-1.2.1-2-any +installed = xf86-input-libinput-1.5.0-1-x86_64 +installed = xfconf-4.20.0-2-x86_64 +installed = xkeyboard-config-2.47-1-any +installed = xmlsec-1.3.11-1-x86_64 +installed = xorg-fonts-encodings-1.1.0-2-any +installed = xorg-server-21.1.23-1-x86_64 +installed = xorg-server-common-21.1.23-1-x86_64 +installed = xorg-setxkbmap-1.3.5-1-x86_64 +installed = xorg-xauth-1.1.5-1-x86_64 +installed = xorg-xkbcomp-1.5.0-1-x86_64 +installed = xorg-xprop-1.2.8-1-x86_64 +installed = xorg-xrandr-1.5.4-1-x86_64 +installed = xorg-xwayland-24.1.12-1-x86_64 +installed = xorgproto-2025.1-1-any +installed = xvidcore-1.3.7-3-x86_64 +installed = xxhash-0.8.3-1-x86_64 +installed = xz-5.8.3-1-x86_64 +installed = yaml-cpp-0.9.0-1-x86_64 +installed = yay-12.6.0-1-x86_64 +installed = yay-debug-12.6.0-1-x86_64 +installed = zenity-4.2.2-1-x86_64 +installed = zeromq-4.3.5-3-x86_64 +installed = zimg-3.0.6-1-x86_64 +installed = zint-2.16.0-2-x86_64 +installed = zix-0.8.0-1-x86_64 +installed = zlib-1:1.3.2-3-x86_64 +installed = zlib-ng-2.3.3-1-x86_64 +installed = zstd-1.5.7-3-x86_64 +installed = zxing-cpp-3.0.2-1-x86_64 diff --git a/pkgbuilds/python-meh/pkg/python-meh/.MTREE b/pkgbuilds/python-meh/pkg/python-meh/.MTREE new file mode 100644 index 0000000000000000000000000000000000000000..6dcfa5f0b5dffdb1c1e2b77088f8820766cb002a GIT binary patch literal 1320 zcmV+@1=so?iwFP!000001GQJnZd*4H-RCO|bRCNv&hWADrY#x-E!u9n=*l36Gqw=h zF)SHv`t?0hnl=&~Asc|Vft2NGTl;m}07sXlk_1K@hhycOk=HZFW_XV5l zhxZFsH|w!z(dz!)_WJEzI*=}yME$*A8PO% zSi4uPE-%-2>+R*``Te_3wJj6#Vc%v!XNYogQXff)SebguL{#y3Gcm3`IEJIlE}B(F zC_IBzDPt}LHy>~BPXLRpG&)3PI!&mwMr{V{L~hb7GL>MOyG|J?+7RkBX3Nt?bk+cT zg#&S3itM`I%^Q0-1uoW<4#7p?npz9&qdH5F;$q%sZ>4M1CK|Ie>8X0xW0#s8N$EfGL?&s0i8Yqye?1mZN#b3Hzi% zgFMzemh<8Mop!yp%ge7zvwvUvALaD@BQH~A)IvX13`xiQ8?icJFanJ!app8;qL{V! zRBCcAC`&JOB`1B8Cd&cnDe16tf6j00fE9jGmngbDyVs z_L>Sy^C5i>0FO`;h2Nym69c+_3FHqXU5FaGMMtKnoU?^0845;}ytEWpD&{ORIN@!` zY&GSY?{i7t6`Vs6ViGDe91qTs3>i9TdsXkr~FEX@ppMVVJlT5ZG(? zVKdFnaY~AqBX+nvxa^?Smw^75)=P&(z@x*lrjbBi&CRS1)tw9}Qb+?dWCVc>B@56b z40$k~%|nEy#ekn& zS}(*=>VVx1i6zVE0bG6tzN^ReDSwBqAB{cgK&rtfxET@gkOrm3*)seS+{Q$~Gc!0_ zAU|ai6O7#^2~!f4XF%K9pW74IYDh=Z?cG}h!4%``yEIr4Jv0-dDyr4I)3BJjbAXi= zjV7Z>Mu1gN00Q%@w*D_(aQNnD+d;|c$PU7gP{0O5XTW##&9%V5$4IQT1i_>s28l%E zZD}#`&KqI(rH+u=VmmkjzMHDWB2~&!7(&iy1MSiQSpw;s*Il5T71mH7SXrTL-6Utk zCAAVwOA52L3Ug0tUkG|XZ%a`Vrz1mPDX`@zg^?kT=$!|SLatZ;KS$76d^K)XCi2#U~E~9AcbuVd. +# +# Author(s): Chris Lumens +# + +from collections import namedtuple + +# These constants represent the return values of buttons on the initial +# exception handling dialog - the dialog that first pops up when an +# exception is hit. +MAIN_RESPONSE_DEBUG = 0 +MAIN_RESPONSE_SAVE = 1 +MAIN_RESPONSE_QUIT = 2 +MAIN_RESPONSE_SHELL = 3 +MAIN_RESPONSE_NONE = 4 + +class ConfigError(Exception): + """Exception class for the configuration related errors.""" + + pass + +class Config(object): + """Hold configuration info useful throughout the exception handling + classes. This prevents having to pass a bunch of arguments to a + bunch of different functions. A Config instance must be created + before creating an ExceptionHandler instance. + """ + def __init__(self, *args, **kwargs): + """Create a new Config instance. Arguments may be passed in to + set any of the configuration values. Unknown arguments will + be ignored. Instance attributes: + + attrSkipList -- A list of strings. When handling a traceback, + any attributes found with the same name as an + element of this list will not be written to + the dump. This is to prevent writing potentially + sensitive information like passwords. The names + must be given without the leading name of the + object passed to handler.install(). For instance, + if handler.install() gets an Anaconda instance + with the name "anaconda" and you want to skip + anaconda.id.rootPassword, "id.rootPassword" should + be listed in attrSkipList. + fileList -- A list of files to find on the system and add + to the traceback dump. + localSkipList -- A list of strings. When handling a traceback, + any local variables found with their name containing + an element of this list will not be written to + the dump. This is subtely different from + attrSkipList. + callbackDict -- A dictionary having item names as keys and pairs + (function, attchmnt_only) as values. + @see register_callback + programName -- The name of the erroring program. + programVersion -- The version number of the erroring program. + Both programName and programVersion are used + throughout the exception handler, so must be + set. + programArch -- The architecture of the erroring program. + """ + self.attrSkipList = [] + self.fileList = [] + self.localSkipList = [] + self.callbackDict = dict() + self.programName = None + self.programVersion = None + self.programArch = None + + # Override the defaults set above with whatever's passed in as an + # argument. Unknown arguments get thrown away. + for (key, val) in kwargs.items(): + if key in self.__dict__: + self.__dict__[key] = val + + # Make sure required things are set. + if not self.programName: + raise ValueError("programName must be set.") + + if not self.programVersion: + raise ValueError("programVersion must be set.") + + def register_callback(self, item_name, callback, attchmnt_only=False, + override=False): + """ + Register new callback that will be called when data about the + crash is collected. The returned value will be included as the + 'item_name' item. + + :param item_name: name of the item storing the value returned by the + 'callback' function + :type item_name: string + :param callback: a function to be called + :type callback: a function of type: () -> string + :param attchmnt_only: whether the returned valued should be included only + as an attachment or also in the main '*-tb' file + (defaults to False) + :type attchmnt_only: bool + :param override: whether to override the previously registered callback + with the same item name or not (may raise exception) + :type override: bool + + :raise ConfigError: if callback with the 'item_name' has already been + registered and 'override' is not set to True + :return: None + + """ + + if item_name not in self.callbackDict or override: + self.callbackDict[item_name] = (callback, attchmnt_only) + else: + msg = "Callback with name '%s' already registered" % item_name + raise ConfigError(msg) + +# type, value and stack are items provided by Python for the exception handler +ExceptionInfo = namedtuple("ExceptionInfo", ["type", "value", "stack"]) + +# ExceptionInfo instance plus the object that should be dumped +DumpInfo = namedtuple("DumpInfo", ["exc_info", "object"]) + +# information about a package (as provided e.g. by rpm) +PackageInfo = namedtuple("PackageInfo", ["name", "version", "release", "epoch", + "arch"]) diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9da02fd1d345059e4aef8fca2723e717b9a3cbb GIT binary patch literal 5344 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 ALI3~& literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/handler.cpython-314.pyc b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/handler.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f75c7debb65d61e3df0b21c9b6610cf03b05e668 GIT binary patch literal 13927 zcmcIrYit`=cAnvLNRbltmTb!!*|H?Ydf2hou^l_{JCYv?O*>KzC>AJkBr&Eq+?kf-b%G#QuT7 z(eU9@p=SqA9UeV&_`q||=rt=Jp4vZjxU}J^{=>(Qmo_~4+`wsFIFz1B4J5~9-GBH( zR7z=aIZ3yJQJ&^BlLJ>Gba@N1Ic~&!%yA)GzL+oI<+vekyIBMB`B`sjMw^tAJyX(T z(5Aa5Bu$epXu2m6GmAl9=P#%`6qX#$u7DluC@S4*zO3vN`VJM7FZ^PG##g-_6KU<(6eUW z$s(Vol0g@0jr4+<;zMKvV}yfS&+$_)pS`EkPBM(!3r7_{r2{L<*c=x96{*G5Nm z`;Nh(n?IvPzxR5cclYEdbX7#+RE z>;9sL=tgh8&tN7AlS0{g{Ht}yzW5PHeq^&b8$TC#XYc`sjFHcpMbRRk9A;_x4^dbl zVjZT4LBK5WdftWI10_M~!P-F(HYZvLtd1#&qB>7lK%F=2L0%E|BKL(Wko&_vd388|ye3?&)k2Kx!ZldWT0M{#uzq7#MJ=j{c#X5H;DV6e9`TPNK5}eHBx^`O#vsq++fCb6T+=PP@I{sGJ-ZDfRS-`^E8iB7te* zN%0__$0v$u-LHuWDWYm@5>PauM5YEI-(J?;%&-JR5Y-JyiVBU)$W^58r{jtg>-9<( zk_SnA*?h_T`1JaDMv-0@Wd;0GP5w}IT*FJ828&iq2##5U6En^wp}q(e#xSTV`;WJD96 z8xXB^24QJc>h%sPEfAZaTX)bB=z_%<-9ZHCo>A#ST#L#vNq3-_)ZNIA#1j%LoW>Cp zbTDf*t82o=lWU|qU#_uv-tnrBX^s^Kh`Hs2m`SI=uIxk18OWQ+Cmq#4l5r2`jM|KSC7-;}=g} z9s0@8>UaLuj6Xn=FySJ$S^FqI^)ocJ4;gsQ-|$@b+-!Tj%yuB+K!R_%!$D08_!AO9 zWS8p)aOXqMhFkEG{lE!mzJau!Gw}D zLdb@tP?J?ET&?q-v@!B+T1NE$B@HX!U@RLI--C!c}Xh2rq&#IH%Ew6RY|hm zJ>^9G;gU++TJ^2mT5fn#cb@+o2YD{Ln+h`?TjV&A8zG&=l8cK0ORnQuxfbr&pL1NC zd(z&*#rYr~5%98vbqHQCP!|CvE8rDoK*p03BG8R8Bc@~={QxAxlTuPNfex%wSU1I; z;+jZMFxjcCfJufi+Kp*2mjNEdY2ZMHKmmz>+5jFIh)RlTU{Q85_^AD0zCEbo3m;)pVlo&uY|3^YgqdKv(C zT#=_3S;qS-7TOlaW`M2}FvupnWS{mjxSmLK1uev9@<^SO(}@^J)9_}n=n^v`FuQzS zQj~ZshJ_fL@ka6p7S!z4W>O##;1+i9xV)QI$Fcxp)1qSm2K$FH1z)5{&vM%71@eC zcPjSW^Hsgp|4RSD>C4YwdVa~b@sW#L(~@o8oN3;C(SEV=zTnFW%^9J2F}NhOKX7q% zO_%px+Iy`z+qNy!w(ZT+Z=ZSV%-!0jf!>8&>&B}uU3uw`f0z;0&DULg5upC^g-aK* zjk_|9yWRn62r{)b#z_{^p^#``_ySng1Q_A71?H7w^^_pFj9-wGFvI-DTe;-{P5UOJAm? zZz-_les$gD#!HPqZk|7o!%H4}`Pju14;)T^b1ty%qkw3=!bgGaU)-x*`-rpqn;*Kk z>gES-lzyWUhIy~Esh{WG=PUXH_V=rJmQ~qnY-z~zQ=KYdogSC$Jf-3HLSLWPQlKbr!VQ+kEJHG;t^b8djXh~-b~^+xU13gGI&KeS_1X?S!traplgHGM1%_t{OL}5&~gGQz@m=_#= zrnx!8(?nLM{#fZcSvab9PeKOE)u&J}A|Kb#UM1)L7jsBz6#f3G&`3r;(XH3Pq(6NR-FNjU(G_g0?bV3bW=ib@3znpE>To zYWOvS{6%{?*AX!dEc7k^DGF9}EyV-s=NXF%GlgwoJB$&BbziuaGv&MKC^A#nVJ!$5 zi^|4=nP1MxhpAx;JFSIFIff5zqgb0OasV4K?|fDOPUI<^NOWw)urak%S~FA-1lTxL z2$vURmc$#v-Ror%Yq~W_Zxy+FX&b=#hHb}`>}o&pY3v3?($Y#&WGK_nd|gcS0h>jY zcuJEMIJG0%WDt2=VOs?Hl$7IC8k?04R>FTV0^>v?+oNPWV7C$Bw0W?>*txgDi(UZb zUK5Ga218R*sicz$9HKPlj9~;B_6Tk}E%U*0&Ca?usXf|Q&#a?Q14`wm5i=7sX(~l@ z>h7s?D%}`}x1xwax=mJf*LaNZZ_sHRsxw$--8LT69rV^H$;PJ1gG^rcJxov*p)uX^pw zD`ysz#cg-}t@E~Apk{vd1EG1f>L*#ozi;^no1&oV%eknSaB;}llN6%UIrWpiTVNgL7t&jja!I^N3Mbvl{G6N75N7MkC z9;!X5F_X-TxP!*TrJ#RVR6rrsY(XaMfUh>m^2&_j%cfn1=%%5GPJ(Aj7@4Jxj-$K+ zLOp{AWmJ)A&%H&>>yW`(z}os=6J8M(>MpljYWYZLUA;txxZO9fPMPHJj&)!bZ@bW9JP(KC zv!oKNg@(WsMP9sEavbO}GKob*TMK~rTdgjO&dd%xr%GZc0xS@rwA2aoFf~Q)4(Lx3 zEGB+z#tBSK74W*`T@$3Z$X12!Nu~#Jd^%GK{4_d`0C)<9cLf161cnvp5#5QHVDubB zih*#FAmvBMRN9#^MvarTA2(%`gyjkN8|py*LI@IIc;)=qMbACKe=&j>Z?(A0@l|b) zINr12Q=uj&RJ>O8a@C@6wem{kM?&XnF{8tYsf3@f0Sf~4ZN#kL)h>4sQrtM~=*5v1 zc7@$f&?_S`p(K=3k_sNUumJJ%%-;VB@nb$Gk`iD*2I9dhQX=FV=_Rk$*Jzn@#JZp z@5A>NPS#PkN2g;DN9A|HSmpPS>0T&R)4tT5Av$w($8;pF6^kQ|E?A%|3dbp*{aq%Rjt<=ZZ>})ZhL3@?Ndut1M?2@ zF?e3~yjrnZFi9gZ!Mq8LHCLqREWu!cV+s-4=F>MvW(5rgy;w#B!#s4UX*#9szQyD@JC z&3odfShsJ^QG-Y2dz1-Wh3He8k`(rw<@2lS7@;sdOG6GzF3#F^{ub8T#a7F~5c|-H ziXq2Yt~el&a)x~=*KpWanc*>G4Z{9BzspluCM0I9LAWy1W>HhPmgkQ}tHsCit-eGq ztJsQ{w`4XHX0}S0Bk&bH+O2klD|%E@k8sU5r;Eu4cT6N-z*|8=)iSc$`@`p?JJh^GhIYc3woq{Px}t@$BtodvT~fa!jdAlnX}|@ z0@AvUi`yu4*~|VgaB>J-mwa*_&~rNc72^ zqyD*U^hkHX{i({y+2CpLb6id&WW=;45H(eqb0sE5(waO)-;^5R${BIiw%e;$ zSZ*26J?ms%kJ-S%2(WWZL^M-Yc8i--omX@xK30YA!(})~bs>UJ=4NKmgw9CaLorzv z@?ZglV3+Qok5qM6Iu%1`L>Zz+0V#PtuE(K+olxEzNWWhm^U*el8|-{8X+#lYd1u3^_(U=SN1CJMr_~>ck!^t2$f8z#8X%qdJZc(#+%WIT36-z;U-mD= zE>B*X%r^988v2%mExFp}%eyb_UVPzZ``y~Uc>!TYU*qEVQbl`iL&uHa^)k8TW$;4eW9g&q1@J8*{%DRw(h^Z^S!T@Fb%! z!zgU;y0Po}uI$F0nTCtmHp(tq{Dl@s%>`58oyb8B0#?!2<|>fS4R z@#MlCq3M3-<{LBDXR@7pmOA(RZS;2gdtL8#{oNEX-~^90FJ%N`KvV0rx&lofHtv}B zQJDF~D=*Hw5N1Y;-pAiKbL&jD=U}GiV76x<(=+f<&#{azIDaP7)V0|3z~=Pt{kUQM zk6&1@Q<%7G^Wv_%b(=o3b9IfMxw+os{DT13u;%iaOJ}n6olEtd^M@bUD*Vm&>YEog zU8{vdbg6#R%{qj|#SK@duS{oK`!cP4Z#wU`?pWy0HMTA__T)DAy|L@ouD^J4(RHV( z>;ASU-rn`ruAkxVru##*ZrbvB71z)Kzv^dBuA%F}dTxCOUT_w_G{~(NuTETLlflS@; z+e66aJy=JNpUm5=uqh*Kx)%RP*z(1rC%C#6xM%!(bL~6csr|5h&w?u(X!{`0_P=1X zfA4QT_kuFR>HEJA0ycm1r-7#5s0Xo;e$ib!SZ(`dYu&RIwqI`BUo*JF{Vz@dH@~W` z7~JOk)w+toUgxiRomAdY@vKnsYu%`D4eX2gIP&aMt*PQ z8OjI^DFlQRQXR?$$~IEgj*NZ$Y5t^vFo;4KK^8TMjQynHp{>rj=3zJQT>qJi3p8b# zdOmL2fh`c&IoJQt#XB4DxS}>wyYb`NZal8&ojdr@wbR+~P~!!s|6v`=yv{-XVUrgF zt#doYhc!ND*TeNbXWi%PPV>&K4>-!1OM(%ApC8!q#SZ%*hkb^_zP@2!>lET<${^9p z&W{k4{+Y6Wq-=pQ0`1HT!_FP{8w}+PJ!7v)k$Gc2idEs)LdNe%o>D%-Eqo4~O6-Mz z@cic;96!rvxtUKm?G)p_s3hZunrYM|< z2UGPxMtpj!x&%=g~ReDmggnQy@F^N0Y@H}>`3 z)@!ohrD=T#^)Pcx2&<_^;e@y5!6JY?i^M~$@5;_MY#oh;s{WC`c0dz{m=*avx`(B`b0 zw_JHwCgALz#j}?*p~)2smmEf3j5AGq6hfyFVCWe@nd$9jKM?^`5BpHFAkusyI58PNzn5sU-DrGo)UY zkVUGd5tXROn{XM6RJNEyFqJWH5OZHBY|z_k4cqEMbw;(8NyRh{@-&+^=e8IKp zH`AL>J_UAsLv`1Fuw%o&?*Cx#Mh16+@w&Vh3~#vKyEpqk&g}$ab@{i~U$4Cz-n}xg z>mB&f-ubh=>+ild@ZH<<&D(Pff*huSjzf{ff0%#$t3*6844;R?Bkkgskian7Vsr1> z+@iLdgP((!18;W=ju?W?4MAHUESlxo0(xk7u_gBuzQKS!AP7hOAhaE}f Y1`fiPw;^=U9^Z!GvE&oNb|>Th2eN|lRsaA1 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/safe_string.cpython-314.pyc b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/__pycache__/safe_string.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f74411f7b9dfe4e97d2db42e0f014e90e208cf70 GIT binary patch literal 2555 zcmb6bTTC2P^xT=9U0B#Ij{+@78M?A|X}i>v);2|23aHeUlIa#wLpvE}hB9`UUFY64 z&@bYTn3zZt6Co0*v56W@>}MPOvhg3g8g%SO6Z_M@ZD@RbdG0W?P#=ljWbQrp+;h+S zoI88B#iAkr96ivletoKP{%3^CL-L{Z*AbY5OQ4V;U~rMN!$lYgmFddBNTdvw0Y&I0 z8=Fh8uepqd0Lwxx&;aeAh)tk`E=t{89ULsIkOZWphkP^alC;i&VE8Oyy%RASDt8eW zQGf}TWF|I34pn6#MQ8#hDIyDx0*fdi&d!aT(PQ)g7xHCvuAqZF0O&dORoZ`ualWjWbm@*X?KkfK1j zn#|F3b3)Uvq|)-qq2WH|f;`Zd>63@f$!E_DWio>U>1b3J0uSL@fggIaV*LZe&cS&3 z=#p^cT>v8m@Dz;u{stH?NA#cKI11xIKENmmqSx)q3-$>ZuMEVDl1+{Q-825-VP$;{|S28&+BqWJnE^ zeIqIoV#F<&kP;qg3T|$$nNXR(^j~x5g7kO$TOorUu;7^33KmI49`a0bBdUsZrK(pu z{G680o;)?!pOMFgGB2GypTUy!&gCl|d@ zg`EHx`7+(6=38>vKb?U&sSRFk0jPvspg;l+iKrnNP6@6!WzM)_&M^=c(g)m-KBYO7 ztDcnI?ydrLy0X?pSAG^7hJ7&oY=tR#Y7&y-*qAMJjxhjm$ z45x@2!QPj}7L^j5YGmO?&{e8knD)KnY(u2O%hRdBsSiJjh3(l<0@87U{Mg<5NmEIL z{dmCJ4mwWGaYL`>EISo;L)6Spx>Al!nT{(u zCUc`6tfFC>Te|`ChD`ARnKF&wn7;v(XJIlaYbMT-lwm{xK ze6PNF`QXa2rDNCG=jU!VeD+GQ?ee-T0m#cC@a7VG-w`%6ivsh^LQ67kscr7+YszE^#%dU5Q#nvQ#ot;_n# zm8C16JYC#%xY+pIf>>(yh<|&$6SgNGLp1jMqbTe;L2fq`TaPb99|?Xq*F_Gj*0kSm zZCe>z8e8o+Tx@-AA^Kn|%VWjHo@?U$cpXaLiLCyhyd&PJ>gw--J3W2XgVo|URRrfx zVK`OcR;a42O`EFfMpYGG>Oz*o)vEehLCg9laaEnP9LlnmZQ40J#uPDfx~e)}7#esJ z(U_&HJTa_^0y8NR)vBuZD_~eU)6HyFRWYk$Tab8-*U5>Ei1GyVvQS2V@*ex!n;6JP zf+SV^x~)yBF9A;Lh~FSfMKE1wsViDGb0e>t4z+T&E75$`VooEc;@#Hc=. +# +# Author(s): Matt Wilson +# Erik Troan +# Chris Lumens +# +# pylint: disable=bare-except,broad-except + +import copy +import inspect +import os +import traceback +import sys +import codecs +import six +from meh import PackageInfo +from meh.safe_string import SafeStr + +# Python 2/3 compatibilty +try: + longtype = long # pylint: disable=undefined-variable +except NameError: + longtype = int + +try: + unitype = unicode # pylint: disable=undefined-variable +except NameError: + unitype = str + +class ExceptionDump(object): + """This class represents a traceback and contains several useful methods + for manipulating a traceback. In general, clients should not have to + use this class. It is mainly for internal use. + """ + def __init__(self, exc_info, config_obj): + """Create a new ExceptionDump instance. Instance attributes: + + :param exc_info: info about the exception provided by Python + :type exc_info: an instance of the meh.ExceptionInfo class + :param config_obj: configuration for python-meh + :type config_obj: an instance of the meh.Config class + """ + + if inspect.istraceback(exc_info.stack): + self.stack = inspect.getinnerframes(exc_info.stack) + else: + self.stack = exc_info.stack + + self.conf = config_obj + self.type = exc_info.type + self.value = exc_info.value + + self._dumpHash = {} + + @property + def desc(self): + # The description is a single line of text that should be used anywhere + # the bug needs to quickly be summarized. The most obvious example of + # this is when saving to bugzilla. We can populate the UI with this + # string so the user doesn't need to come up with one. + if self.type and self.value: + return traceback.format_exception_only(self.type, self.value)[0].strip() + else: + return "" + + def _get_environment_info(self): + """ + Returns dictionary containing these items for a bugreport header + + architecture + cmdline + component + executable + kernel + package + release + other involved packages + + :rtype: dict (string -> string) + """ + + RELEASE_NAME_FILE = "/etc/system-release" + + class RPMinfoError(Exception): + """Exception for errors in rpm queries""" + pass + + def get_python_opts(): + """ + Returns python's command line options + + :return: list of python's command line options + :rtype: list + + """ + + flags_to_opts = { + "debug": "-d", + "py3k_warning": "-3", + "division_new": "-Qnew", + "division_warning": "-Q", + "inspect": "-i", + "interactive": "-i", + "optimize": "-O", + "dont_write_bytecode": "-B", + "no_user_site": "-s", + "no_site": "-S", + "ignore_environment": "-E", + "tabcheck": "-t", + "verbose": "-v", + "unicode": "-u", + "bytes_warning": "-b", + "quiet": "-q", + } + + ret = set() + for flag in flags_to_opts.keys(): + if getattr(sys.flags, flag, None): + ret.add(flags_to_opts[flag]) + ret = list(ret) + return ret + + def get_package_and_component(file_=sys.argv[0]): + """ + Returns package and component names for file (by default for script itself). + + :param file_: filename + :type file_: string + :return: tuple containing package info and component name for the file + :rtype: (PackageInfo, str) + :raise RPMinfoError: if package and component for the file cannot be found + + """ + + import rpm + ts = rpm.TransactionSet() + mi = ts.dbMatch("basenames", file_) + try: + header = next(mi) + except StopIteration: + raise RPMinfoError("Cannot get package and component for file "+ + "{0}".format(file_)) + pkg_info = PackageInfo(header["name"].decode("utf-8"), header["version"].decode("utf-8"), + header["release"].decode("utf-8"), + u"%d" % header["epoch"] if header["epoch"] else u"0", + header["arch"].decode("utf-8")) + + # cuts the name from the NVR format: foo-blah-2.8.8-2.fc17.src.rpm + srpm_name = header["sourcerpm"].decode("utf-8") + name_end = len(srpm_name) + try: + name_end = srpm_name.rindex('-') + name_end = srpm_name[:name_end].rindex('-') + except ValueError: + # expected exception + pass + + component = srpm_name[:name_end] + + return (pkg_info, component) + + def get_release_version(): + """Returns release version (according to RELEASE_NAME_FILE)""" + try: + with open(RELEASE_NAME_FILE, "r") as file_: + return file_.readline().rstrip() + except IOError: + return "Cannot get release name." + + def get_other_packages(self): + """ + Returns a set of additional packages whose files appear in + traceback. + + :rtype: set + + """ + packages = set() + if not self.stack: + return packages + + for (_frame, fn, _lineno, _func, _ctx, _idx) in self.stack: + try: + pkg_info = get_package_and_component(fn)[0] + package = "{0.name}-{0.version}-{0.release}.{0.arch}".format( + pkg_info) + packages.add(package) + except RPMinfoError: + continue + + try: + pkg_info = get_package_and_component()[0] + package = "{0.name}-{0.version}-{0.release}.{0.arch}".format( + pkg_info) + packages.discard(package) + except RPMinfoError: + pass + return packages + + def get_environment_variables(): + """ + Returns a list of strings containing defined environment + variables and their values in the following format: + + VARIABLE=VALUE + + :rtype: list + + """ + + ret = list() + for (key, value) in os.environ.items(): + ret.append("{0}={1}".format(key, value)) + + return ret + + + #--begining of the method _get_environment_info-- + try: + pkg_info, component = get_package_and_component() + except RPMinfoError: + pkg_info = None + component = None + + other_packages = ", ".join(get_other_packages(self)) + + ret = dict() + ret["architecture"] = os.uname()[4] + ret["cmdline"] = "{0} {1} {2}".format(sys.executable, + " ".join(get_python_opts()), + " ".join(sys.argv)) + if component: + ret["component"] = component + ret["executable"] = sys.argv[0] + ret["kernel"] = os.uname()[2] + if pkg_info: + ret["pkg_info"] = pkg_info + ret["release"] = get_release_version() + if other_packages: + ret["other involved packages"] = other_packages + ret["environ"] = "\n".join(get_environment_variables()) + + return ret + + @property + def environment_info(self): + return self._get_environment_info() + + def __str__(self): + lst = self._format_stack() + + lst.insert(0, "%s %s exception report\n" % (self.conf.programName, self.conf.programVersion)) + lst.insert(1, "Traceback (most recent call last):\n") + + if self.type is not None and self.value is not None: + lst.extend(traceback.format_exception_only(self.type, self.value)) + + return "".join(lst) + + def _format_stack(self): + if not self.stack: + return [] + + frames = [] + for (_frame, fn, lineno, func, ctx, _idx) in self.stack: + if isinstance(ctx, list): + code = "".join(ctx) + else: + code = ctx + + frames.append((fn, lineno, func, code)) + + return traceback.format_list(frames) + + # Create a string representation of a class. This method will recursively + # handle all attributes of the base given class. + def _dumpClass(self, instance, level=0, parentkey="", skipList=None): + # This is horribly cheesy, and bound to require maintainence in the + # future. The problem is that anything subclassed from object fails + # the types.InstanceType test we used to have which means those + # objects never get dumped. However, most everything basic in + # python is derived from object so we can't just check for the super + # class. Any instances of the following types will just be printed + # out, and everything else will be assumed to be something that + # needs to be recursed on. + def __isSimpleType(instance): + return isinstance(instance, bool) or \ + isinstance(instance, complex) or \ + isinstance(instance, float) or \ + isinstance(instance, int) or \ + isinstance(instance, longtype) or \ + isinstance(instance, type(None)) or \ + isinstance(instance, bytes) or \ + isinstance(instance, str) or \ + isinstance(instance, unitype) or \ + not hasattr(instance, "__class__") or \ + not hasattr(instance, "__dict__") + + ret = SafeStr() + + if not skipList: + skipList = [] + + # protect from loops + try: + # Store the id(), not the instance name to protect against + # instances that cannot be hashed. + if not id(instance) in self._dumpHash: + self._dumpHash[id(instance)] = None + else: + ret += "Already dumped (%s instance)\n" % instance.__class__.__name__ + return ret + except TypeError: + ret += "Cannot dump object\n" + return ret + + if ("__str__" in instance.__class__.__dict__ or + "__repr__" in instance.__class__.__dict__): + try: + ret += "%s\n" % (instance,) + except: + ret += "\n" + + return ret + + ret += "%s instance, containing members:\n" %\ + (instance.__class__.__name__) + pad = ' ' * ((level) * 2) + + for key, value in instance.__dict__.items(): + if key.startswith("_%s__" % instance.__class__.__name__): + continue + + if parentkey != "": + curkey = parentkey + "." + key + else: + curkey = key + + # Don't dump objects that are in our skip list, though ones that are + # None are probably okay. + if eval("instance.%s is not None" % key) and \ + eval("id(instance.%s)" % key) in skipList: + ret += "%s%s: Skipped\n" % (pad, curkey) + continue + + if isinstance(value, list): + ret += "%s%s: [" % (pad, curkey) + first = 1 + for item in value: + if not first: + ret += ", " + else: + first = 0 + + if __isSimpleType(item): + ret += "%s" % (item,) + else: + ret += self._dumpClass(item, level + 1, skipList=skipList) + ret += "]\n" + elif isinstance(value, dict): + # append things one after another so that e.g. binary data is + # replaced by hexa values separately + ret += pad + ret += curkey + ret += ": {" + first = 1 + for k, v in value.items(): + if not first: + ret += ", " + else: + first = 0 + if isinstance(k, str) or isinstance(k, unitype): + ret += "'" + ret += k + ret += "': " + else: + ret += "%s: " % (k,) + + if __isSimpleType(v): + ret += "%s" % (v,) + else: + ret += self._dumpClass(v, level + 1, parentkey = curkey, skipList=skipList) + ret += "}\n" + elif __isSimpleType(value): + ret += "%s%s: " % (pad, curkey) + ret += value + ret += "\n" + else: + ret += "%s%s: " % (pad, curkey) + ret += self._dumpClass(value, level + 1, parentkey=curkey, skipList=skipList) + + return ret + + def dump(self, obj): + """Dump the local variables and all attributes of a given object. + The lists of files and attrs to ignore are all taken from a + Config object instance provided when the ExceptionDump class was + created. + + obj -- Any Python object. This object will have all its attributes + written out, except for those mentioned in the attrSkipList. + """ + idSkipList = [] + ret = SafeStr() + + # We need to augment the environment eval() will run in with the + # bindings that were local when the traceback happened so that the + # idSkipList can be populated. However since we're not allowed to + # modify the results of locals(), we'll have to make a copy first. + localVars = copy.copy(locals()) + if self.stack: + localVars.update(self.stack[-1][0].f_locals) + + # Catch attributes that do not exist at the time we do the exception dump + # and ignore them. + for k in self.conf.attrSkipList: + try: + eval("idSkipList.append(id(obj.%s))" % k, None, localVars) + except: + pass + + # Write local variables to the given file descriptor, ignoring any of + # the local skips. + if self.stack: + frame = self.stack[-1][0] + ret += "\nLocal variables in innermost frame:\n" + try: + for (key, value) in frame.f_locals.items(): + lowered_key = key.lower() + if any(item.lower() in lowered_key + for item in self.conf.localSkipList): + continue + + ret += "%s: %s\n" % (key, value) + except: + pass + + # And now dump the object's attributes. + try: + ret += "\n\n" + ret += self._dumpClass(obj, skipList=idSkipList) + except: + ret += "\nException occurred during state dump:\n" + ret += traceback.format_exc(None) + + # Filter out item names and callbacks that should appear + # only as attachments + items_callbacks = ((name, cb) for (name, (cb, attchmnt_only)) + in self.conf.callbackDict.items() + if not attchmnt_only) + + # And now add data returned by the registered callbacks + ret += "\nRegistered callbacks:\n" + for (item_name, callback) in items_callbacks: + try: + callback_ret = callback() + if callback_ret: + ret += "%s:\n%s\n" % (item_name, callback_ret) + except Exception as exc: + ret += "%s: Caused error: %s\n" % (item_name, exc) + + # And finally, write a bunch of files into the dump too. + for fname in self.conf.fileList: + try: + if six.PY2: + with codecs.open(fname, "r", "utf-8", "ignore") as fobj: + ret += "\n\n%s:\n" % (fname,) + for line in fobj: + ret += line.encode("utf-8") + else: + with open(fname, "rt", encoding="utf-8") as fobj: + ret += "\n\n%s:\n" % (fname,) + for line in fobj: + ret += line + except IOError: + pass + except: + ret += "\nException occurred during %s file copy:\n" % (fname,) + ret += traceback.format_exc(None) + + return ret + + @property + def hash(self): + """Create a hash for this traceback object. This is most suitable for + searching bug filing systems for duplicates. The hash is composed + of the basename of each file in the stack, the method names, and + the bit of code. Line numbers and the actual exception message + itself are left out. + """ + import hashlib + s = "" + + if self.stack: + for (file, _lineno, func, text) in [f[1:5] for f in self.stack]: + if isinstance(text, list): + text = "".join(text) + s += "%s %s %s\n" % (os.path.basename(file), func, text) + else: + s = "%s %s" % (self.type, self.value) + + return hashlib.sha256(s.encode("utf-8")).hexdigest() + + def traceback_and_object_dump(self, obj): + """ + Return the traceback and a text representation of an object. + + :param obj: Any Python object. This object will have all its attributes + written out, except for those mentioned in the attrSkipList. + + """ + + ret = SafeStr(str(self)) + ret += self.dump(obj) + + return ret + +class ReverseExceptionDump(ExceptionDump): + """This class provides an alternate representation of an exception. In + this representation, the traceback is printed with the most recent call + at the top of the stack, and the most generic call at the bottom. Note + that this order does not affect the hash at all. + """ + def __str__(self): + lst = self._format_stack() + lst.reverse() + + lst.insert(0, "%s %s exception report\n" % (self.conf.programName, self.conf.programVersion)) + lst.insert(1, "Traceback (most recent call first):\n") + + if self.type is not None and self.value is not None: + lst.extend(traceback.format_exception_only(self.type, self.value)) + + return "".join(lst) diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/handler.py b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/handler.py new file mode 100644 index 0000000..6ae0a5d --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/handler.py @@ -0,0 +1,299 @@ +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# +from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_SAVE, MAIN_RESPONSE_SHELL, MAIN_RESPONSE_QUIT, DumpInfo, ExceptionInfo +import bdb +import os +import sys +import report +import traceback +import subprocess + +import gettext +_ = lambda x: gettext.ldgettext("python-meh", x) + +class NoNetwork(Exception): + def __init__(self, msg=""): + Exception.__init__(self) + self.msg = msg + + def __str__(self): + return "No network is available" + +class ExceptionHandler(object): + def __init__(self, confObj, intfClass, exnClass): + """Create a new ExceptionHandler instance. Subclasses of this one may + be created, provided they are careful to provide all the methods + this one does. Instance attributes: + + conf -- A filled in Config instance. At least the programName + and programVersion are required. + exnClass -- An instance of ExceptionDump or a subclass of it. This + is required to know how to represent the Python + exception internally. + intfClass-- An instance of AbstractIntf. This is required to know + what UI classes to use. + """ + self.conf = confObj + self.exnClass = exnClass + self.intf = intfClass + + self._exitcode = 10 + self._exn = None + self.exnFile = None + self.exnText = "" + + def _setExitCode(self, code): + self._exitcode = code + + exitcode = property(lambda s: s._exitcode, + lambda s, v: s._setExitCode(v)) + + def _setExn(self, e): + self._exn = e + + exn = property(lambda s: s._exn, + lambda s, v: s._setExn(v)) + + def handleException(self, dump_info): + """This is the main exception handling entry point. When Python + gets an exception it doesn't know how to handle, this method will + be called. It then saves the traceback and displays the main + dialog asking the user what to do next. Once this method is + called, there's no good way to go back to what you were doing + before. + + All arguments are passed in from the handler created by calling + self.install(). This method should not usually be overridden by + a subclass. + + :type dump_info: an instance of the meh.DumpInfo class + + """ + + responseHash = { MAIN_RESPONSE_QUIT: self.runQuit, + MAIN_RESPONSE_DEBUG: self.runDebug, + MAIN_RESPONSE_SAVE: self.runSave, + MAIN_RESPONSE_SHELL: self.runShell, + } + + # Quit if we got an exception when running pdb. + if isinstance(dump_info.exc_info.value, bdb.BdbQuit): + sys.exit(self.exitcode) + + # Restore original exception handler. + sys.excepthook = sys.__excepthook__ + + self.preWriteHook(dump_info) + + # Save the exception to the filesystem first. + self.exn = self.exnClass(dump_info.exc_info, self.conf) + (fobj, self.exnFile) = self.openFile() + self.exnText = self.exn.traceback_and_object_dump(dump_info.object) + fobj.write(self.exnText) + fobj.close() + + self.postWriteHook(dump_info) + + # Run initial UI screen, asking whether to save/debug/quit. + while True: + win = self.intf.mainExceptionWindow(str(self.exn), self.exnText) + if not win: + self.runQuit(dump_info.exc_info) + + rc = win.run() + win.destroy() + + try: + responseHash[rc](dump_info.exc_info) + except KeyError: + # This happens if (for example) the user hits Escape instead + # of pressing a button. + continue + + win.destroy() + + def preWriteHook(self, dump_info): + """Subclasses may supply a function with this name that will be + called immediately before the traceback is written to disk in + order to have any sort of special pre-write processing that needs + to be done. + + :type dump_info: an instance of the meh.DumpInfo class + """ + pass + + def postWriteHook(self, dump_info): + """Subclasses may supply a function with this name that will be + called immediately after the traceback is written to disk, but + immediately before the UI is run. This is to provide a place for + any special handling to happen once there is a file on disk. + + :type dump_info: an instance of the meh.DumpInfo class + """ + pass + + def install(self, obj): + """Install ourselves as the top level exception handler with Python. + If this method is not called after an ExceptionHandler instance is + created, none of the rest of this code will ever be called. + + obj -- A Python object that may be dumped to a file when the + exception is saved. This should be something like the top + level object in a program. + """ + sys.excepthook = lambda ty, value, tb: \ + self.handleException(DumpInfo(ExceptionInfo(ty, value, tb), obj)) + + def openFile(self): + """Create a randomly named output file to write the exception dump to. + This requires a programName be set in the Config instance. The + return value is a (file descriptor, path) pair. The file must be + closed by the caller when writing is done. Subclasses should not + override this method unless they know what they're doing. + """ + import tempfile + (fd, path) = tempfile.mkstemp("", "%s-tb-" % self.conf.programName, "/tmp") + fo = os.fdopen(fd, "w") + return (fo, path) + + ### Methods called by the primary exception handling dialog. + + def runQuit(self, exc_info): + """This method is called when the "Exit" button is clicked. It may + be overridden by a subclass, but the basic behavior of eventually + quitting should be preserved. + + :type exc_info: an instance of the meh.ExceptionInfo class + """ + sys.exit(self.exitcode) + + def runDebug(self, exc_info): + """This method is called when the "Debug" button is clicked. It may + be overridden by a subclass if specialized behavior is required to + enter debug mode. + + :type exc_info: an instance of the meh.ExceptionInfo class + """ + + print("") + print(_("Use 'continue' command to quit the debugger and get back to " + "the main menu")) + import pdb + pdb.post_mortem(exc_info.stack) + #no need to quit here, let's just get back to the main dialog + + def runShell(self, exc_info): + """This method is called when user requests to run a shell. It may + be overridden by a subclass if specialized behavior is required to + run shell (e.g. TTY switching). + + :type exc_info: an instance of the meh.ExceptionInfo class + + """ + + print("") + print(_("Exit the shell to get back to the main menu")) + proc = subprocess.Popen(["bash", "--login"], shell=True, cwd="/") + proc.wait() + + def runSave(self, exc_info): + """This method is called when the "Save" button is clicked. It may + be overridden by a subclass, but that's going to be a lot of work. + + :type exc_info: an instance of the meh.ExceptionInfo class + """ + + params = dict() + params.update(self.exn.environment_info) + pkg_info = params.pop("pkg_info", None) + + #if rpmdb queries fail (anaconda), use self.conf.* values + if "component" not in params: + params["component"] = self.conf.programName + + if pkg_info: + params["pkg_name"] = pkg_info.name + params["pkg_version"] = pkg_info.version + params["pkg_release"] = pkg_info.release + params["pkg_epoch"] = pkg_info.epoch + params["pkg_arch"] = pkg_info.arch + params["package"] = "%s-%s-%s.%s" % (pkg_info.name, pkg_info.version, + pkg_info.release, pkg_info.arch) + else: + params["pkg_name"] = self.conf.programName + parts = self.conf.programVersion.rsplit("-", 1) + if len(parts) == 2: + version, release = parts + else: + version = parts[0] + # not given, make something up + release = "1" + params["pkg_version"] = version + params["pkg_release"] = release + # we don't support specifying epoch in the config object and only + # the anaconda which is not using epochs doesn't have the RPMdb to + # query + params["pkg_epoch"] = "0" + params["pkg_arch"] = self.conf.programArch + params["package"] = "{0.programName}-{0.programVersion}".format( + self.conf) + + params["hashmarkername"] = self.conf.programName + params["duphash"] = self.exn.hash + params["reason"] = self.exn.desc + params["description"] = "The following was filed automatically by %s:\n%s" \ + % (self.conf.programName, str(self.exn)) + + tb_item_name = "%s-tb" % self.conf.programName + params[tb_item_name] = self.exnText + + # save data generated by callbacks + for (item_name, (callback, _anc)) in self.conf.callbackDict.items(): + try: + ret = callback() + if ret: + params[item_name] = ret + except Exception as exc: # pylint: disable=broad-except + params[item_name] = "Caused error: %s" % exc + + for fpath in self.conf.fileList: + try: + with open(fpath, "r") as fobj: + # would be better to use the full path here, but libreport + # doesn't allow '/' characters in the item name + filename = os.path.basename(fpath) + if filename not in params: + params[filename] = fobj.read() + else: + params[filename+"_file"] = fobj.read() + except: # pylint: disable=bare-except + #skip files we cannot read + continue + + # tell ABRT some more things it requires + params["analyzer"] = "Python" + params["backtrace"] = "".join(traceback.format_exception(exc_info.type, + exc_info.value, + exc_info.stack)) + + signature = report.createPythonUnhandledExceptionSignature(**params) + + # We don't want to automatically quit here since the user may wish to + # save somewhere else, debug, etc. + self.intf.saveExceptionWindow(signature) diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/network.py b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/network.py new file mode 100644 index 0000000..ede2b8a --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/network.py @@ -0,0 +1,45 @@ +# +# network.py - network configuration install data +# +# Copyright (C) 2008, 2009 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): David Cantrell +# +import dbus + +# This code was taken from anaconda, and slightly adapted to not rely +# on isys. +NM_SERVICE = "org.freedesktop.NetworkManager" +NM_MANAGER_PATH = "/org/freedesktop/NetworkManager" + +NM_STATE_CONNECTED = 3 + +DBUS_PROPS_IFACE = "org.freedesktop.DBus.Properties" + +def hasActiveNetDev(): + """Does the system have an enabled network interface?""" + try: + bus = dbus.SystemBus() + nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH) + props = dbus.Interface(nm, DBUS_PROPS_IFACE) + state = props.Get(NM_SERVICE, "State") + + if int(state) == NM_STATE_CONNECTED: + return True + else: + return False + except dbus.DBusException: + return False diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/safe_string.py b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/safe_string.py new file mode 100644 index 0000000..714ce37 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/safe_string.py @@ -0,0 +1,71 @@ +# +# Copyright (C) 2013 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author: Vratislav Podzimek +# +# + +import sys +PY = int(sys.version.split('.')[0]) + +""" +This module provides a SafeStr class. + +@see: SafeStr + +""" + +class SafeStr(str): + """ + String class that has a modified __add__ method so that ascii strings, + binary data represented as a byte string and unicode objects can be + safely appended to it (not causing traceback). BINARY DATA IS OMITTED. + + """ + + def __add__(self, other): + + if PY > 2: + return SafeStr(str.__add__(self, str(other))) + + if not (isinstance(other, str) or isinstance(other, unicode)): # pylint: disable=undefined-variable + if hasattr(other, "__str__"): + other = other.__str__() + else: + other = "OMITTED OBJECT WITHOUT __str__ METHOD" + + if isinstance(other, unicode): # pylint: disable=undefined-variable + ret = SafeStr(str.__add__(self, other.encode("utf-8"))) + else: + try: + # try to decode which doesn't cause traceback for utf-8 encoded + # non-ascii string and ascii string + other.decode("utf-8") + ret = SafeStr(str.__add__(self, other)) + except UnicodeDecodeError: + # binary data, get the representation used by Python for + # non-ascii bytes + + # hex(255) returns "0xff", we want "\xff" + other_hexa = (hex(ord(char)) for char in other) + other_backslashed = (hex_num.replace("0x", "\\x") + for hex_num in other_hexa) + other_repr = "".join(other_backslashed) + + ret = SafeStr(str.__add__(self, other_repr)) + + return ret diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__init__.py b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__init__.py new file mode 100644 index 0000000..8c174e1 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__init__.py @@ -0,0 +1,181 @@ +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# + +class AbstractIntf(object): + """The base class for Interfaces. This is an abstract class. It + provides methods that create and run various kinds of windows. + We provide a basic level of graphical and text oriented interfaces + here, but it should be possible for things like anaconda to supply + their own much more complicated ones with little effort. + """ + def __init__(self, *args, **kwargs): + """Create a new AbstractInterface instance. This method need not + be overridden by subclasses. + """ + pass + + def enableNetwork(self, *args, **kwargs): + """Display and run a dialog that brings up the network, if it is + currently disabled. This method must be provided by all subclasses, + and should return False if unsuccessful. + """ + raise NotImplementedError + + def exitWindow(self, title, message, *args, **kwargs): + """Display and run a dialog that displays a message with the proper + buttons and images for quitting afterwards. This method must be + provided by all subclasses. + + title -- The window's title. + message -- The window's text. + """ + raise NotImplementedError + + def mainExceptionWindow(self, text, exnFile, *args, **kwargs): + """Create and return an instance of the initial execption handling + dialog. This method must be provided by all subclasses. + + text -- The short traceback (usually, just the stack trace). + exnFile -- A file containing the output of ExceptionDump.write(). + """ + raise NotImplementedError + + def messageWindow(self, title, message, *args, **kwargs): + """Display a generic informational message. This can be an error, + status update, and so forth. It must be provided by all subclasses. + + title -- The window's title. + message -- The window's text. + """ + raise NotImplementedError + + def saveExceptionWindow(self, exnFile, *args, **kwargs): + """Create and return an instance of the exception saving dialog. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractMainExceptionWindow(object): + """This abstract class describes the basic level of support required of + any interface that supplies a main exception window. The main exception + window is the initial dialog displayed by the exception handler that + provides the debug/save/quit options. + """ + def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs): + """Create a new MainExceptionWindow instance. This must handle + creating the dialog and populating it with widgets, but must not + run the dialog. A self.dialog attribute should be created that + refers to the dialog itself. + + shortTraceback -- The short traceback (usually, just the stack + trace). + longTraceback -- The long traceback (full traceback and the main + object dump). + """ + pass + + def destroy(self, *args, **kwargs): + """Destroy the current dialog. This method must be provided by all + subclasses. + """ + raise NotImplementedError + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up, but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractExitWindow(object): + """This abstract class describes the basic level of support required of + a basic message dialog that should be displayed before the program + exits. All interfaces must provide this class. + """ + def __init__(self, title, text, *args, **kwargs): + """Create a new ExitWindow instance. This must handle creating the + dialog and putting the text into it, but must not run the dialog. + This method must be provided by all subclasses. + + title -- The window's title. + text -- The window's text. + """ + pass + + def destroy(self, *args, **kwargs): + """Destroy the current dialog. This method must be provided by all + subclasses. + """ + raise NotImplementedError + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractMessageWindow(object): + """This abstract class describes the basic level of support required of + a basic message dialog. All interfaces must provide this class. + """ + def __init__(self, title, text, *args, **kwargs): + """Create a new MessageWindow instance. This must handle creating the + dialog and putting the text into it, but must not run the dialog. + This method must be provided by all subclasses. + + title -- The window's title. + text -- The window's text. + """ + pass + + def destroy(self, *args, **kwargs): + """Destroy the current dialog. This method must be provided by all + subclasses. + """ + raise NotImplementedError + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractSaveExceptionWindow(object): + """This abstract class describes the basic level of support required of + any interface that supplies an exception saving window. The exception + saving window is the dialog displayed if the user clicks "save" on the + initial dialog, and presents multiple options for how the traceback + should be saved. + """ + def __init__(self, *args, **kwargs): + """Create a new SaveExceptionWindow instance. This must handle + creating the dialog and populating it with widgets, but must not + run the dialog. A self.dialog attribute should be created that + refers to the dialog itself. + """ + pass + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39d97329a348642bc3e0a7c85641d7e1b8fda5c1 GIT binary patch literal 7634 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/gui.cpython-314.pyc b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/__pycache__/gui.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9cae43bf2add4b8327ca9cee6aaa326932509729 GIT binary patch literal 10773 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 E0g}j9&Hw-a literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/gui.py b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/gui.py new file mode 100644 index 0000000..b6920a3 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/gui.py @@ -0,0 +1,177 @@ +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# +from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_NONE, MAIN_RESPONSE_QUIT, MAIN_RESPONSE_SAVE +from meh.ui import AbstractIntf, AbstractSaveExceptionWindow, AbstractMainExceptionWindow, AbstractMessageWindow +import os +import sys +import report + +import gi +gi.require_version("Gtk", "3.0") + +from gi.repository import Gtk + +import gettext +_ = lambda x: gettext.ldgettext("python-meh", x) + +def find_glade_file(file): + path = os.environ.get("GLADEPATH", "./:ui/:/tmp/updates/:/tmp/updates/ui/:/usr/share/python-meh/") + for d in path.split(":"): + fn = d + file + if os.access(fn, os.R_OK): + return fn + raise RuntimeError("Unable to find glade file %s" % file) + +class GraphicalIntf(AbstractIntf): + def __init__(self, *args, **kwargs): + AbstractIntf.__init__(self, *args, **kwargs) + + def enableNetwork(self, *args, **kwargs): + """Should be provided by the inheriting class.""" + + return False + + def exitWindow(self, title, message, *args, **kwargs): + win = ExitWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def mainExceptionWindow(self, text, exnFile, *args, **kwargs): + win = MainExceptionWindow(text, exnFile, *args, **kwargs) + return win + + def messageWindow(self, title, message, *args, **kwargs): + win = MessageWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def saveExceptionWindow(self, signature, *args, **kwargs): + win = SaveExceptionWindow(signature) + win.run() + +class SaveExceptionWindow(AbstractSaveExceptionWindow): + def __init__(self, signature, *args, **kwargs): + AbstractSaveExceptionWindow.__init__(self, signature, *args, **kwargs) + self.signature = signature + + def run(self, *args, **kwargs): + # Don't need to check the return value of report since it will + # handle all the UI reporting for us. + report.report_problem_in_memory(self.signature, report.LIBREPORT_WAIT) + +class MainExceptionWindow(AbstractMainExceptionWindow): + def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs): + AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback, + *args, **kwargs) + + builder = Gtk.Builder() + builder.set_translation_domain("python-meh") + glade_file = find_glade_file("exception-dialog.glade") + builder.add_from_file(glade_file) + builder.connect_signals(self) + + self._main_window = builder.get_object("exceptionWindow") + + # this makes sure the Meh window remains active + # even if the exception has been triggered in a dialog + window_group = Gtk.WindowGroup() + window_group.add_window(self._main_window) + + self._traceback_buffer = builder.get_object("tracebackBuffer") + + self._traceback_buffer.set_text(longTraceback) + self._response = MAIN_RESPONSE_QUIT + + self._debug_button = builder.get_object("debugButton") + + allowDebug = kwargs.get("allowDebug", sys.stdout.isatty) + + if allowDebug and not allowDebug(): + self._debug_button.set_sensitive(False) + + @property + def main_window(self): + return self._main_window + + def destroy(self, *args, **kwargs): + self._main_window.destroy() + + def run(self, *args, **kwargs): + self._main_window.show_all() + # keep our window above dialogs + self._main_window.set_modal(True) + self._main_window.set_keep_above(True) + Gtk.main() + self.destroy() + return self._response + + def on_report_clicked(self, button): + # hide our window to not interfere with libreport window + self._main_window.hide() + self._response = MAIN_RESPONSE_SAVE + Gtk.main_quit() + + def on_quit_clicked(self, button): + self._response = MAIN_RESPONSE_QUIT + Gtk.main_quit() + + def on_debug_clicked(self, button): + self._response = MAIN_RESPONSE_DEBUG + Gtk.main_quit() + + def on_expander_activated(self, expander, *args): + if not expander.get_expanded(): + self._main_window.resize(600, 400) + else: + #resize the window back to the default size when expander is + #minimized + self._main_window.resize(600, 1) + + def on_main_window_deleted(self, *args): + self._response = MAIN_RESPONSE_NONE + self.destroy() + Gtk.main_quit() + +class MessageWindow(AbstractMessageWindow): + def __init__(self, title, text, *args, **kwargs): + AbstractMessageWindow.__init__(self, title, text, *args, **kwargs) + self.rc = 0 + + self.dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.OK, + type=Gtk.MessageType.INFO, + message_format=text) + self.dialog.set_title(title) + self.dialog.set_position(Gtk.WindowPosition.CENTER) + + def destroy(self, *args, **kwargs): + self.dialog.destroy() + + def run(self, *args, **kwargs): + self.dialog.show_all() + self.rc = self.dialog.run() + self.dialog.destroy() + +class ExitWindow(MessageWindow): + def __init__(self, title, text, *args, **kwargs): # pylint: disable=super-init-not-called + self.dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.NONE, + type=Gtk.MessageType.INFO, + message_format=text) + self.dialog.set_title(title) + self.dialog.add_button(_("_Exit"), 0) + self.dialog.set_position(Gtk.WindowPosition.CENTER) diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/text.py b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/text.py new file mode 100644 index 0000000..e4d99f2 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/lib/python3.14/site-packages/meh/ui/text.py @@ -0,0 +1,225 @@ +# Copyright (C) 2009, 2013 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# Vratislav Podzimek +# +from __future__ import print_function + +from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_SAVE, MAIN_RESPONSE_SHELL, MAIN_RESPONSE_QUIT +from meh.ui import AbstractIntf, AbstractSaveExceptionWindow, AbstractMainExceptionWindow, AbstractMessageWindow +import report +import report.io.TextIO +from report import LIBREPORT_WAIT, LIBREPORT_RUN_CLI + +import os +import sys +if sys.version_info.major == 3: + raw_input_fn = input +else: + raw_input_fn = raw_input # pylint: disable=undefined-variable + +import gettext +_ = lambda x: gettext.ldgettext("python-meh", x) + + +class IOHandler(object): + """ + Class that provides methods for input and output. Its instance is expected + to be passed to objects performing some I/O operations. + + """ + + def __init__(self, in_func=raw_input_fn, out_func=print): # pylint: disable=used-before-assignment + """ + Constructor for the IOhandler class. Arguments can be used to override + default I/O functions with the custom ones. + + :param in_func: input function similar to standard raw_input + :type in_func: str -> str + :param out_func: output function similar to standard print + :type out_func: str -> None + + """ + + self.in_func = in_func + self.out_func = out_func + + def print(self, msg=""): + self.out_func(msg) + + def raw_input(self, prompt): + return self.in_func(prompt) + +class TextWindow(object): + """Helper class providing some common methods needed by all text windows.""" + + def __init__(self, title, *args, **kwargs): + self._io = kwargs.get("io_handler", IOHandler()) + self._title = title + + # short (one-char) answer meaning "yes" + self._yes_answer = _("y") + + # short (one-char) answer meaning "no" + self._no_answer = _("n") + + @property + def _usable_width(self): + return os.environ.get("COLUMNS", 80) - 1 + + def _print_rule(self): + rule = self._usable_width * "=" + self._io.print(rule) + + def print_header(self): + self._io.print() + self._print_rule() + self._io.print(self._title) + self._print_rule() + + def destroy(self): + self._print_rule() + self._print_rule() + +class TextIntf(AbstractIntf): + def __init__(self, *args, **kwargs): + AbstractIntf.__init__(self, *args, **kwargs) + self.screen = kwargs.get("screen", None) + self._io = kwargs.get("io_handler", IOHandler()) + + def set_io_handler(self, handler): + """ + Set different IO handler. + + :type handler: an instance of the IOHandler class + + """ + self._io = handler + + def enableNetwork(self, *args, **kwargs): + """Should be provided by the inheriting class.""" + + return False + + def exitWindow(self, title, message, *args, **kwargs): + kwargs["io_handler"] = self._io + win = ExitWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def mainExceptionWindow(self, text, exnFile, *args, **kwargs): + kwargs["io_handler"] = self._io + win = MainExceptionWindow(text, exnFile, *args, **kwargs) + return win + + def messageWindow(self, title, message, *args, **kwargs): + kwargs["io_handler"] = self._io + win = MessageWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def saveExceptionWindow(self, signature, *args, **kwargs): + kwargs["io_handler"] = self._io + win = SaveExceptionWindow(signature, *args, **kwargs) + win.run() + win.destroy() + +class SaveExceptionWindow(TextWindow, AbstractSaveExceptionWindow): + def __init__(self, signature, *args, **kwargs): + AbstractSaveExceptionWindow.__init__(self, signature, + *args, **kwargs) + TextWindow.__init__(self, _("Save exception"), *args, **kwargs) + self.signature = signature + + def run(self, *args, **kwargs): + # Don't need to check the return value of report since it will + # handle all the UI reporting for us. + report.report_problem_in_memory(self.signature, + LIBREPORT_WAIT|LIBREPORT_RUN_CLI) + +class MainExceptionWindow(TextWindow, AbstractMainExceptionWindow): + def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs): + AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback, + *args, **kwargs) + TextWindow.__init__(self, _("An unknown error has occurred"), + *args, **kwargs) + self._short_traceback = shortTraceback + self._menu_items = [(_("Report Bug"), MAIN_RESPONSE_SAVE), + (_("Run shell"), MAIN_RESPONSE_SHELL), + (_("Quit"), MAIN_RESPONSE_QUIT)] + + allowDebug = kwargs.get("allowDebug", sys.stdout.isatty) + + if allowDebug and allowDebug(): + self._menu_items.insert(1, (_("Debug"), MAIN_RESPONSE_DEBUG)) + + def run(self, *args, **kwargs): + self.print_header() + self._io.print(self._short_traceback) + self._io.print(_("What do you want to do now?")) + for (idx, item) in enumerate(self._menu_items): + self._io.print("%d) %s" % (idx + 1, item[0])) + + ret = -1 + num_menu_items = len(self._menu_items) + self._io.print() + while not (0 < ret <= num_menu_items): + ret = self._io.raw_input(_("Please make your choice from above: ")) + try: + ret = int(ret) + except ValueError: + ret = -1 + + return self._menu_items[ret - 1][1] + +class MessageWindow(TextWindow, AbstractMessageWindow): + def __init__(self, title, text, *args, **kwargs): + AbstractMessageWindow.__init__(self, title, text, *args, **kwargs) + TextWindow.__init__(self, title, *args, **kwargs) + self._text = text + + def run(self, *args, **kwargs): + self.print_header() + self._io.print(self._text) + self._io.print() + self._io.raw_input(_("Hit ENTER to continue")) + +class ExitWindow(MessageWindow): + def __init__(self, title, text, *args, **kwargs): + MessageWindow.__init__(self, title, text, *args, **kwargs) + + def run(self, *args, **kwargs): + self.print_header() + self._io.print(self._text) + self._io.print() + + # self._no_answer may be non-ascii string (simple .upper() doesn't work) + no_answer_upper = self._no_answer.decode("utf-8").upper().encode("utf-8") + answer = self._io.raw_input(_( + "Are you sure you want to exit? [%(yes)s/%(no)s]") % + { "yes": self._yes_answer, + "no": no_answer_upper }) + + # no answer means accepting the default (self._no_answer) and the answer + # is case insensitive (and may be non-ascii) + lower_answer = answer.decode("utf-8").lower().encode("utf-8") + answer = lower_answer or self._no_answer + + if answer in (self._yes_answer, self._no_answer): + return answer == self._yes_answer + else: + self.run(*args, **kwargs) diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/share/licenses/python-meh/COPYING b/pkgbuilds/python-meh/pkg/python-meh/usr/share/licenses/python-meh/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/share/licenses/python-meh/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/pkgbuilds/python-meh/pkg/python-meh/usr/share/python-meh/exception-dialog.glade b/pkgbuilds/python-meh/pkg/python-meh/usr/share/python-meh/exception-dialog.glade new file mode 100644 index 0000000..0bed126 --- /dev/null +++ b/pkgbuilds/python-meh/pkg/python-meh/usr/share/python-meh/exception-dialog.glade @@ -0,0 +1,248 @@ + + + + + False + center-always + 600 + dialog + True + + + + True + False + vertical + + + True + False + start + center + 20 + 30 + + + True + False + gtk-dialog-warning + 5 + + + False + True + 7 + 0 + + + + + True + False + An unknown error has occurred + + + + + + + False + True + 1 + + + + + False + False + 0 + + + + + True + False + start + start + 40 + 40 + This program has encountered an unknown error. You may +report the bug below or quit the program. + + + False + True + 21 + 1 + + + + + True + False + start + 20 + 10 + end + + + _Report Bug + True + True + True + True + + + + False + True + 0 + + + + + _Quit + True + True + True + True + + + + False + True + 1 + + + + + False + True + 2 + + + + + True + True + 10 + 10 + 10 + True + + + + True + False + True + vertical + 6 + + + True + False + start + 2 + 0.10000000149011612 + The output below may help determine the cause of the error: + + + + + + False + True + 0 + + + + + True + True + True + in + + + True + True + natural + False + False + tracebackBuffer + + + + + True + True + 1 + + + + + True + False + 6 + + + True + False + 1 + 'Debug' may take you to tty1. + + + + + + + True + True + 0 + + + + + _Debug + True + True + True + True + + + + False + True + 1 + + + + + False + True + 2 + + + + + + + True + False + More _info... + True + + + + + False + True + 3 + + + + + + + No additional info available. + + diff --git a/pkgbuilds/python-meh/python-meh-0.43-1-any.pkg.tar.zst b/pkgbuilds/python-meh/python-meh-0.43-1-any.pkg.tar.zst new file mode 100644 index 0000000000000000000000000000000000000000..2f47ed1fc069483fc2001fccbd77ca49cb41afb0 GIT binary patch literal 64459 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 }1)8E;6jU9uxII>4W6QF^9 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 YKt=On!CAPscXNW{qbg;l4gMz>Yzo2l*#H0l literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-meh/python-meh-0.43.tar.gz b/pkgbuilds/python-meh/python-meh-0.43.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..d19374d0e1d6e18c855cedc8cf69f5bc18911319 GIT binary patch literal 39764 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 E0LoJF+W-In literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-meh/src/python-meh-0.43.tar.gz b/pkgbuilds/python-meh/src/python-meh-0.43.tar.gz new file mode 120000 index 0000000..cc9b758 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-0.43.tar.gz @@ -0,0 +1 @@ +/home/nocode/Files/FWS-ISO/pkgbuilds/python-meh/python-meh-0.43.tar.gz \ No newline at end of file diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/.gitignore b/pkgbuilds/python-meh/src/python-meh-r0.43-1/.gitignore new file mode 100644 index 0000000..60074ed --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/.gitignore @@ -0,0 +1,14 @@ +*.pyc +.*.swp + +python-meh*.tar.gz + +ChangeLog + +po/*.gmo +po/*.po +po/POTFILES + +build/ + +.directory diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/COPYING b/pkgbuilds/python-meh/src/python-meh-r0.43-1/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/MANIFEST.in b/pkgbuilds/python-meh/src/python-meh-r0.43-1/MANIFEST.in new file mode 100644 index 0000000..7d6499c --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/MANIFEST.in @@ -0,0 +1,6 @@ +include COPYING Makefile ChangeLog +recursive-include meh *.py +recursive-include ui *.glade +recursive-include pixmaps *.png +recursive-include po *.po *.pot Makefile +recursive-include tests *.py diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/Makefile b/pkgbuilds/python-meh/src/python-meh-r0.43-1/Makefile new file mode 100644 index 0000000..c736a31 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/Makefile @@ -0,0 +1,101 @@ +PKGNAME=python-meh +VERSION=$(shell awk '/Version:/ { print $$2 }' $(PKGNAME).spec) +RELEASE=$(shell awk '/Release:/ { print $$2 }' $(PKGNAME).spec | sed -e 's|%.*$$||g') +TAG=r$(VERSION)-$(RELEASE) + +PREFIX=/usr + +PYTHON2=python2 +PYTHON3=python3 +PYTHON=$(PYTHON2) + +TESTSUITE:=tests/baseclass.py + +PYCHECKEROPTS=--no-argsused --no-miximport --maxargs 0 --no-local -\# 0 --only -Q + +ZANATA_PULL_ARGS = --transdir po/ +ZANATA_PUSH_ARGS = --srcdir po/ --push-type source --force + +default: all + +all: + $(MAKE) -C po + +clean: + -rm *.tar.gz meh/*.pyc meh/ui/*.pyc tests/*.pyc ChangeLog + $(MAKE) -C po clean + $(PYTHON) setup.py -q clean --all + +test: + @echo "*** Running unittests with Python 2 ***" + PYTHONPATH=. $(PYTHON2) $(TESTSUITE) -v + + @echo "*** Running unittests with Python 3 ***" + PYTHONPATH=. $(PYTHON3) $(TESTSUITE) -v + +check: + PYTHONPATH=. tests/pylint/runpylint.py + +install: + $(PYTHON) setup.py install --root=$(DESTDIR) + $(MAKE) -C po install + +ChangeLog: + (GIT_DIR=.git git log > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2) + +tag: + git tag -a -m "Tag as $(TAG)" -f $(TAG) + @echo "Tagged as $(TAG)" + +release: tag archive + +archive: po-pull + @rm -f ChangeLog + @make ChangeLog + git archive --format=tar --prefix=$(PKGNAME)-$(VERSION)/ $(TAG) > $(PKGNAME)-$(VERSION).tar + mkdir $(PKGNAME)-$(VERSION) + cp -r po $(PKGNAME)-$(VERSION) + cp ChangeLog $(PKGNAME)-$(VERSION)/ + tar -rf $(PKGNAME)-$(VERSION).tar $(PKGNAME)-$(VERSION) + gzip -9 $(PKGNAME)-$(VERSION).tar + rm -rf $(PKGNAME)-$(VERSION) + git checkout -- po/$(PKGNAME).pot + @echo "The archive is in $(PKGNAME)-$(VERSION).tar.gz" + +local: po-pull + @rm -f ChangeLog + @make ChangeLog + @rm -rf $(PKGNAME)-$(VERSION).tar.gz + @rm -rf /tmp/$(PKGNAME)-$(VERSION) /tmp/$(PKGNAME) + @dir=$$PWD; cp -a $$dir /tmp/$(PKGNAME)-$(VERSION) + @cd /tmp/$(PKGNAME)-$(VERSION) ; $(PYTHON) setup.py -q sdist + @cp /tmp/$(PKGNAME)-$(VERSION)/dist/$(PKGNAME)-$(VERSION).tar.gz . + @rm -rf /tmp/$(PKGNAME)-$(VERSION) + @echo "The archive is in $(PKGNAME)-$(VERSION).tar.gz" + +rpmlog: + @git log --pretty="format:- %s (%ae)" $(TAG).. |sed -e 's/@.*)/)/' + @echo + +potfile: + $(MAKE) -C po potfile + +po-pull: + rpm -q zanata-python-client &>/dev/null || ( echo "need to run: dnf install zanata-python-client"; exit 1 ) + zanata pull $(ZANATA_PULL_ARGS) + +bumpver: potfile + zanata push $(ZANATA_PUSH_ARGS) || ( echo "zanata push failed"; exit 1 ) + @NEWSUBVER=$$((`echo $(VERSION) |cut -d . -f 2` + 1)) ; \ + NEWVERSION=`echo $(VERSION).$$NEWSUBVER |cut -d . -f 1,3` ; \ + DATELINE="* `LANG=c date "+%a %b %d %Y"` `git config user.name` <`git config user.email`> - $$NEWVERSION-1" ; \ + cl=`grep -n %changelog python-meh.spec |cut -d : -f 1` ; \ + tail --lines=+$$(($$cl + 1)) python-meh.spec > speclog ; \ + (head -n $$cl python-meh.spec ; echo "$$DATELINE" ; make --quiet rpmlog 2>/dev/null ; echo ""; cat speclog) > python-meh.spec.new ; \ + mv python-meh.spec.new python-meh.spec ; rm -f speclog ; \ + sed -i "s/Version: $(VERSION)/Version: $$NEWVERSION/" python-meh.spec ; \ + sed -i "s/version='$(VERSION)'/version='$$NEWVERSION'/" setup.py + +ci: check test + +.PHONY: clean install tag archive local diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/examples/meh_test.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/examples/meh_test.py new file mode 100755 index 0000000..5725b7d --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/examples/meh_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/python -tbBQnew +# -*- coding: utf-8 -*- + +import sys +import meh +import meh.handler +import meh.dump +import subprocess + +class MyTestError(Exception): + pass + +class MyObject(object): + def __init__(self): + self.unicode_str = u"řčšěčšěčěš" + self.encoded_unicode_str = self.unicode_str.encode("utf-8") + self.binary_data = '\xff\xff\xfe' + +if __name__ == "__main__": + print("***Running python-meh test***") + + config = meh.Config(programName="myMehTest", programVersion="1.0-1", + programArch="noarch", + fileList=["/proc/cmdline", "unicode.txt", "ascii.txt"]) + + if len(sys.argv) > 1 and sys.argv[1] == "g": + import meh.ui.gui + intf = meh.ui.gui.GraphicalIntf() + else: + import meh.ui.text + intf = meh.ui.text.TextIntf() + + handler = meh.handler.ExceptionHandler(config, intf, + meh.dump.ExceptionDump) + handler.install(MyObject()) + + #raise MyTestError("My testing exception.") + subprocess.call(["non_existing_executable"]) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/__init__.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/__init__.py new file mode 100644 index 0000000..6d554af --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/__init__.py @@ -0,0 +1,139 @@ +# +# __init__.py - Basic stuff for exception handling +# +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# + +from collections import namedtuple + +# These constants represent the return values of buttons on the initial +# exception handling dialog - the dialog that first pops up when an +# exception is hit. +MAIN_RESPONSE_DEBUG = 0 +MAIN_RESPONSE_SAVE = 1 +MAIN_RESPONSE_QUIT = 2 +MAIN_RESPONSE_SHELL = 3 +MAIN_RESPONSE_NONE = 4 + +class ConfigError(Exception): + """Exception class for the configuration related errors.""" + + pass + +class Config(object): + """Hold configuration info useful throughout the exception handling + classes. This prevents having to pass a bunch of arguments to a + bunch of different functions. A Config instance must be created + before creating an ExceptionHandler instance. + """ + def __init__(self, *args, **kwargs): + """Create a new Config instance. Arguments may be passed in to + set any of the configuration values. Unknown arguments will + be ignored. Instance attributes: + + attrSkipList -- A list of strings. When handling a traceback, + any attributes found with the same name as an + element of this list will not be written to + the dump. This is to prevent writing potentially + sensitive information like passwords. The names + must be given without the leading name of the + object passed to handler.install(). For instance, + if handler.install() gets an Anaconda instance + with the name "anaconda" and you want to skip + anaconda.id.rootPassword, "id.rootPassword" should + be listed in attrSkipList. + fileList -- A list of files to find on the system and add + to the traceback dump. + localSkipList -- A list of strings. When handling a traceback, + any local variables found with their name containing + an element of this list will not be written to + the dump. This is subtely different from + attrSkipList. + callbackDict -- A dictionary having item names as keys and pairs + (function, attchmnt_only) as values. + @see register_callback + programName -- The name of the erroring program. + programVersion -- The version number of the erroring program. + Both programName and programVersion are used + throughout the exception handler, so must be + set. + programArch -- The architecture of the erroring program. + """ + self.attrSkipList = [] + self.fileList = [] + self.localSkipList = [] + self.callbackDict = dict() + self.programName = None + self.programVersion = None + self.programArch = None + + # Override the defaults set above with whatever's passed in as an + # argument. Unknown arguments get thrown away. + for (key, val) in kwargs.items(): + if key in self.__dict__: + self.__dict__[key] = val + + # Make sure required things are set. + if not self.programName: + raise ValueError("programName must be set.") + + if not self.programVersion: + raise ValueError("programVersion must be set.") + + def register_callback(self, item_name, callback, attchmnt_only=False, + override=False): + """ + Register new callback that will be called when data about the + crash is collected. The returned value will be included as the + 'item_name' item. + + :param item_name: name of the item storing the value returned by the + 'callback' function + :type item_name: string + :param callback: a function to be called + :type callback: a function of type: () -> string + :param attchmnt_only: whether the returned valued should be included only + as an attachment or also in the main '*-tb' file + (defaults to False) + :type attchmnt_only: bool + :param override: whether to override the previously registered callback + with the same item name or not (may raise exception) + :type override: bool + + :raise ConfigError: if callback with the 'item_name' has already been + registered and 'override' is not set to True + :return: None + + """ + + if item_name not in self.callbackDict or override: + self.callbackDict[item_name] = (callback, attchmnt_only) + else: + msg = "Callback with name '%s' already registered" % item_name + raise ConfigError(msg) + +# type, value and stack are items provided by Python for the exception handler +ExceptionInfo = namedtuple("ExceptionInfo", ["type", "value", "stack"]) + +# ExceptionInfo instance plus the object that should be dumped +DumpInfo = namedtuple("DumpInfo", ["exc_info", "object"]) + +# information about a package (as provided e.g. by rpm) +PackageInfo = namedtuple("PackageInfo", ["name", "version", "release", "epoch", + "arch"]) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/dump.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/dump.py new file mode 100644 index 0000000..c746e57 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/dump.py @@ -0,0 +1,551 @@ +# +# dump.py - general exception formatting and saving +# +# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Matt Wilson +# Erik Troan +# Chris Lumens +# +# pylint: disable=bare-except,broad-except + +import copy +import inspect +import os +import traceback +import sys +import codecs +import six +from meh import PackageInfo +from meh.safe_string import SafeStr + +# Python 2/3 compatibilty +try: + longtype = long # pylint: disable=undefined-variable +except NameError: + longtype = int + +try: + unitype = unicode # pylint: disable=undefined-variable +except NameError: + unitype = str + +class ExceptionDump(object): + """This class represents a traceback and contains several useful methods + for manipulating a traceback. In general, clients should not have to + use this class. It is mainly for internal use. + """ + def __init__(self, exc_info, config_obj): + """Create a new ExceptionDump instance. Instance attributes: + + :param exc_info: info about the exception provided by Python + :type exc_info: an instance of the meh.ExceptionInfo class + :param config_obj: configuration for python-meh + :type config_obj: an instance of the meh.Config class + """ + + if inspect.istraceback(exc_info.stack): + self.stack = inspect.getinnerframes(exc_info.stack) + else: + self.stack = exc_info.stack + + self.conf = config_obj + self.type = exc_info.type + self.value = exc_info.value + + self._dumpHash = {} + + @property + def desc(self): + # The description is a single line of text that should be used anywhere + # the bug needs to quickly be summarized. The most obvious example of + # this is when saving to bugzilla. We can populate the UI with this + # string so the user doesn't need to come up with one. + if self.type and self.value: + return traceback.format_exception_only(self.type, self.value)[0].strip() + else: + return "" + + def _get_environment_info(self): + """ + Returns dictionary containing these items for a bugreport header + + architecture + cmdline + component + executable + kernel + package + release + other involved packages + + :rtype: dict (string -> string) + """ + + RELEASE_NAME_FILE = "/etc/system-release" + + class RPMinfoError(Exception): + """Exception for errors in rpm queries""" + pass + + def get_python_opts(): + """ + Returns python's command line options + + :return: list of python's command line options + :rtype: list + + """ + + flags_to_opts = { + "debug": "-d", + "py3k_warning": "-3", + "division_new": "-Qnew", + "division_warning": "-Q", + "inspect": "-i", + "interactive": "-i", + "optimize": "-O", + "dont_write_bytecode": "-B", + "no_user_site": "-s", + "no_site": "-S", + "ignore_environment": "-E", + "tabcheck": "-t", + "verbose": "-v", + "unicode": "-u", + "bytes_warning": "-b", + "quiet": "-q", + } + + ret = set() + for flag in flags_to_opts.keys(): + if getattr(sys.flags, flag, None): + ret.add(flags_to_opts[flag]) + ret = list(ret) + return ret + + def get_package_and_component(file_=sys.argv[0]): + """ + Returns package and component names for file (by default for script itself). + + :param file_: filename + :type file_: string + :return: tuple containing package info and component name for the file + :rtype: (PackageInfo, str) + :raise RPMinfoError: if package and component for the file cannot be found + + """ + + import rpm + ts = rpm.TransactionSet() + mi = ts.dbMatch("basenames", file_) + try: + header = next(mi) + except StopIteration: + raise RPMinfoError("Cannot get package and component for file "+ + "{0}".format(file_)) + pkg_info = PackageInfo(header["name"].decode("utf-8"), header["version"].decode("utf-8"), + header["release"].decode("utf-8"), + u"%d" % header["epoch"] if header["epoch"] else u"0", + header["arch"].decode("utf-8")) + + # cuts the name from the NVR format: foo-blah-2.8.8-2.fc17.src.rpm + srpm_name = header["sourcerpm"].decode("utf-8") + name_end = len(srpm_name) + try: + name_end = srpm_name.rindex('-') + name_end = srpm_name[:name_end].rindex('-') + except ValueError: + # expected exception + pass + + component = srpm_name[:name_end] + + return (pkg_info, component) + + def get_release_version(): + """Returns release version (according to RELEASE_NAME_FILE)""" + try: + with open(RELEASE_NAME_FILE, "r") as file_: + return file_.readline().rstrip() + except IOError: + return "Cannot get release name." + + def get_other_packages(self): + """ + Returns a set of additional packages whose files appear in + traceback. + + :rtype: set + + """ + packages = set() + if not self.stack: + return packages + + for (_frame, fn, _lineno, _func, _ctx, _idx) in self.stack: + try: + pkg_info = get_package_and_component(fn)[0] + package = "{0.name}-{0.version}-{0.release}.{0.arch}".format( + pkg_info) + packages.add(package) + except RPMinfoError: + continue + + try: + pkg_info = get_package_and_component()[0] + package = "{0.name}-{0.version}-{0.release}.{0.arch}".format( + pkg_info) + packages.discard(package) + except RPMinfoError: + pass + return packages + + def get_environment_variables(): + """ + Returns a list of strings containing defined environment + variables and their values in the following format: + + VARIABLE=VALUE + + :rtype: list + + """ + + ret = list() + for (key, value) in os.environ.items(): + ret.append("{0}={1}".format(key, value)) + + return ret + + + #--begining of the method _get_environment_info-- + try: + pkg_info, component = get_package_and_component() + except RPMinfoError: + pkg_info = None + component = None + + other_packages = ", ".join(get_other_packages(self)) + + ret = dict() + ret["architecture"] = os.uname()[4] + ret["cmdline"] = "{0} {1} {2}".format(sys.executable, + " ".join(get_python_opts()), + " ".join(sys.argv)) + if component: + ret["component"] = component + ret["executable"] = sys.argv[0] + ret["kernel"] = os.uname()[2] + if pkg_info: + ret["pkg_info"] = pkg_info + ret["release"] = get_release_version() + if other_packages: + ret["other involved packages"] = other_packages + ret["environ"] = "\n".join(get_environment_variables()) + + return ret + + @property + def environment_info(self): + return self._get_environment_info() + + def __str__(self): + lst = self._format_stack() + + lst.insert(0, "%s %s exception report\n" % (self.conf.programName, self.conf.programVersion)) + lst.insert(1, "Traceback (most recent call last):\n") + + if self.type is not None and self.value is not None: + lst.extend(traceback.format_exception_only(self.type, self.value)) + + return "".join(lst) + + def _format_stack(self): + if not self.stack: + return [] + + frames = [] + for (_frame, fn, lineno, func, ctx, _idx) in self.stack: + if isinstance(ctx, list): + code = "".join(ctx) + else: + code = ctx + + frames.append((fn, lineno, func, code)) + + return traceback.format_list(frames) + + # Create a string representation of a class. This method will recursively + # handle all attributes of the base given class. + def _dumpClass(self, instance, level=0, parentkey="", skipList=None): + # This is horribly cheesy, and bound to require maintainence in the + # future. The problem is that anything subclassed from object fails + # the types.InstanceType test we used to have which means those + # objects never get dumped. However, most everything basic in + # python is derived from object so we can't just check for the super + # class. Any instances of the following types will just be printed + # out, and everything else will be assumed to be something that + # needs to be recursed on. + def __isSimpleType(instance): + return isinstance(instance, bool) or \ + isinstance(instance, complex) or \ + isinstance(instance, float) or \ + isinstance(instance, int) or \ + isinstance(instance, longtype) or \ + isinstance(instance, type(None)) or \ + isinstance(instance, bytes) or \ + isinstance(instance, str) or \ + isinstance(instance, unitype) or \ + not hasattr(instance, "__class__") or \ + not hasattr(instance, "__dict__") + + ret = SafeStr() + + if not skipList: + skipList = [] + + # protect from loops + try: + # Store the id(), not the instance name to protect against + # instances that cannot be hashed. + if not id(instance) in self._dumpHash: + self._dumpHash[id(instance)] = None + else: + ret += "Already dumped (%s instance)\n" % instance.__class__.__name__ + return ret + except TypeError: + ret += "Cannot dump object\n" + return ret + + if ("__str__" in instance.__class__.__dict__ or + "__repr__" in instance.__class__.__dict__): + try: + ret += "%s\n" % (instance,) + except: + ret += "\n" + + return ret + + ret += "%s instance, containing members:\n" %\ + (instance.__class__.__name__) + pad = ' ' * ((level) * 2) + + for key, value in instance.__dict__.items(): + if key.startswith("_%s__" % instance.__class__.__name__): + continue + + if parentkey != "": + curkey = parentkey + "." + key + else: + curkey = key + + # Don't dump objects that are in our skip list, though ones that are + # None are probably okay. + if eval("instance.%s is not None" % key) and \ + eval("id(instance.%s)" % key) in skipList: + ret += "%s%s: Skipped\n" % (pad, curkey) + continue + + if isinstance(value, list): + ret += "%s%s: [" % (pad, curkey) + first = 1 + for item in value: + if not first: + ret += ", " + else: + first = 0 + + if __isSimpleType(item): + ret += "%s" % (item,) + else: + ret += self._dumpClass(item, level + 1, skipList=skipList) + ret += "]\n" + elif isinstance(value, dict): + # append things one after another so that e.g. binary data is + # replaced by hexa values separately + ret += pad + ret += curkey + ret += ": {" + first = 1 + for k, v in value.items(): + if not first: + ret += ", " + else: + first = 0 + if isinstance(k, str) or isinstance(k, unitype): + ret += "'" + ret += k + ret += "': " + else: + ret += "%s: " % (k,) + + if __isSimpleType(v): + ret += "%s" % (v,) + else: + ret += self._dumpClass(v, level + 1, parentkey = curkey, skipList=skipList) + ret += "}\n" + elif __isSimpleType(value): + ret += "%s%s: " % (pad, curkey) + ret += value + ret += "\n" + else: + ret += "%s%s: " % (pad, curkey) + ret += self._dumpClass(value, level + 1, parentkey=curkey, skipList=skipList) + + return ret + + def dump(self, obj): + """Dump the local variables and all attributes of a given object. + The lists of files and attrs to ignore are all taken from a + Config object instance provided when the ExceptionDump class was + created. + + obj -- Any Python object. This object will have all its attributes + written out, except for those mentioned in the attrSkipList. + """ + idSkipList = [] + ret = SafeStr() + + # We need to augment the environment eval() will run in with the + # bindings that were local when the traceback happened so that the + # idSkipList can be populated. However since we're not allowed to + # modify the results of locals(), we'll have to make a copy first. + localVars = copy.copy(locals()) + if self.stack: + localVars.update(self.stack[-1][0].f_locals) + + # Catch attributes that do not exist at the time we do the exception dump + # and ignore them. + for k in self.conf.attrSkipList: + try: + eval("idSkipList.append(id(obj.%s))" % k, None, localVars) + except: + pass + + # Write local variables to the given file descriptor, ignoring any of + # the local skips. + if self.stack: + frame = self.stack[-1][0] + ret += "\nLocal variables in innermost frame:\n" + try: + for (key, value) in frame.f_locals.items(): + lowered_key = key.lower() + if any(item.lower() in lowered_key + for item in self.conf.localSkipList): + continue + + ret += "%s: %s\n" % (key, value) + except: + pass + + # And now dump the object's attributes. + try: + ret += "\n\n" + ret += self._dumpClass(obj, skipList=idSkipList) + except: + ret += "\nException occurred during state dump:\n" + ret += traceback.format_exc(None) + + # Filter out item names and callbacks that should appear + # only as attachments + items_callbacks = ((name, cb) for (name, (cb, attchmnt_only)) + in self.conf.callbackDict.items() + if not attchmnt_only) + + # And now add data returned by the registered callbacks + ret += "\nRegistered callbacks:\n" + for (item_name, callback) in items_callbacks: + try: + callback_ret = callback() + if callback_ret: + ret += "%s:\n%s\n" % (item_name, callback_ret) + except Exception as exc: + ret += "%s: Caused error: %s\n" % (item_name, exc) + + # And finally, write a bunch of files into the dump too. + for fname in self.conf.fileList: + try: + if six.PY2: + with codecs.open(fname, "r", "utf-8", "ignore") as fobj: + ret += "\n\n%s:\n" % (fname,) + for line in fobj: + ret += line.encode("utf-8") + else: + with open(fname, "rt", encoding="utf-8") as fobj: + ret += "\n\n%s:\n" % (fname,) + for line in fobj: + ret += line + except IOError: + pass + except: + ret += "\nException occurred during %s file copy:\n" % (fname,) + ret += traceback.format_exc(None) + + return ret + + @property + def hash(self): + """Create a hash for this traceback object. This is most suitable for + searching bug filing systems for duplicates. The hash is composed + of the basename of each file in the stack, the method names, and + the bit of code. Line numbers and the actual exception message + itself are left out. + """ + import hashlib + s = "" + + if self.stack: + for (file, _lineno, func, text) in [f[1:5] for f in self.stack]: + if isinstance(text, list): + text = "".join(text) + s += "%s %s %s\n" % (os.path.basename(file), func, text) + else: + s = "%s %s" % (self.type, self.value) + + return hashlib.sha256(s.encode("utf-8")).hexdigest() + + def traceback_and_object_dump(self, obj): + """ + Return the traceback and a text representation of an object. + + :param obj: Any Python object. This object will have all its attributes + written out, except for those mentioned in the attrSkipList. + + """ + + ret = SafeStr(str(self)) + ret += self.dump(obj) + + return ret + +class ReverseExceptionDump(ExceptionDump): + """This class provides an alternate representation of an exception. In + this representation, the traceback is printed with the most recent call + at the top of the stack, and the most generic call at the bottom. Note + that this order does not affect the hash at all. + """ + def __str__(self): + lst = self._format_stack() + lst.reverse() + + lst.insert(0, "%s %s exception report\n" % (self.conf.programName, self.conf.programVersion)) + lst.insert(1, "Traceback (most recent call first):\n") + + if self.type is not None and self.value is not None: + lst.extend(traceback.format_exception_only(self.type, self.value)) + + return "".join(lst) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/handler.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/handler.py new file mode 100644 index 0000000..6ae0a5d --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/handler.py @@ -0,0 +1,299 @@ +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# +from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_SAVE, MAIN_RESPONSE_SHELL, MAIN_RESPONSE_QUIT, DumpInfo, ExceptionInfo +import bdb +import os +import sys +import report +import traceback +import subprocess + +import gettext +_ = lambda x: gettext.ldgettext("python-meh", x) + +class NoNetwork(Exception): + def __init__(self, msg=""): + Exception.__init__(self) + self.msg = msg + + def __str__(self): + return "No network is available" + +class ExceptionHandler(object): + def __init__(self, confObj, intfClass, exnClass): + """Create a new ExceptionHandler instance. Subclasses of this one may + be created, provided they are careful to provide all the methods + this one does. Instance attributes: + + conf -- A filled in Config instance. At least the programName + and programVersion are required. + exnClass -- An instance of ExceptionDump or a subclass of it. This + is required to know how to represent the Python + exception internally. + intfClass-- An instance of AbstractIntf. This is required to know + what UI classes to use. + """ + self.conf = confObj + self.exnClass = exnClass + self.intf = intfClass + + self._exitcode = 10 + self._exn = None + self.exnFile = None + self.exnText = "" + + def _setExitCode(self, code): + self._exitcode = code + + exitcode = property(lambda s: s._exitcode, + lambda s, v: s._setExitCode(v)) + + def _setExn(self, e): + self._exn = e + + exn = property(lambda s: s._exn, + lambda s, v: s._setExn(v)) + + def handleException(self, dump_info): + """This is the main exception handling entry point. When Python + gets an exception it doesn't know how to handle, this method will + be called. It then saves the traceback and displays the main + dialog asking the user what to do next. Once this method is + called, there's no good way to go back to what you were doing + before. + + All arguments are passed in from the handler created by calling + self.install(). This method should not usually be overridden by + a subclass. + + :type dump_info: an instance of the meh.DumpInfo class + + """ + + responseHash = { MAIN_RESPONSE_QUIT: self.runQuit, + MAIN_RESPONSE_DEBUG: self.runDebug, + MAIN_RESPONSE_SAVE: self.runSave, + MAIN_RESPONSE_SHELL: self.runShell, + } + + # Quit if we got an exception when running pdb. + if isinstance(dump_info.exc_info.value, bdb.BdbQuit): + sys.exit(self.exitcode) + + # Restore original exception handler. + sys.excepthook = sys.__excepthook__ + + self.preWriteHook(dump_info) + + # Save the exception to the filesystem first. + self.exn = self.exnClass(dump_info.exc_info, self.conf) + (fobj, self.exnFile) = self.openFile() + self.exnText = self.exn.traceback_and_object_dump(dump_info.object) + fobj.write(self.exnText) + fobj.close() + + self.postWriteHook(dump_info) + + # Run initial UI screen, asking whether to save/debug/quit. + while True: + win = self.intf.mainExceptionWindow(str(self.exn), self.exnText) + if not win: + self.runQuit(dump_info.exc_info) + + rc = win.run() + win.destroy() + + try: + responseHash[rc](dump_info.exc_info) + except KeyError: + # This happens if (for example) the user hits Escape instead + # of pressing a button. + continue + + win.destroy() + + def preWriteHook(self, dump_info): + """Subclasses may supply a function with this name that will be + called immediately before the traceback is written to disk in + order to have any sort of special pre-write processing that needs + to be done. + + :type dump_info: an instance of the meh.DumpInfo class + """ + pass + + def postWriteHook(self, dump_info): + """Subclasses may supply a function with this name that will be + called immediately after the traceback is written to disk, but + immediately before the UI is run. This is to provide a place for + any special handling to happen once there is a file on disk. + + :type dump_info: an instance of the meh.DumpInfo class + """ + pass + + def install(self, obj): + """Install ourselves as the top level exception handler with Python. + If this method is not called after an ExceptionHandler instance is + created, none of the rest of this code will ever be called. + + obj -- A Python object that may be dumped to a file when the + exception is saved. This should be something like the top + level object in a program. + """ + sys.excepthook = lambda ty, value, tb: \ + self.handleException(DumpInfo(ExceptionInfo(ty, value, tb), obj)) + + def openFile(self): + """Create a randomly named output file to write the exception dump to. + This requires a programName be set in the Config instance. The + return value is a (file descriptor, path) pair. The file must be + closed by the caller when writing is done. Subclasses should not + override this method unless they know what they're doing. + """ + import tempfile + (fd, path) = tempfile.mkstemp("", "%s-tb-" % self.conf.programName, "/tmp") + fo = os.fdopen(fd, "w") + return (fo, path) + + ### Methods called by the primary exception handling dialog. + + def runQuit(self, exc_info): + """This method is called when the "Exit" button is clicked. It may + be overridden by a subclass, but the basic behavior of eventually + quitting should be preserved. + + :type exc_info: an instance of the meh.ExceptionInfo class + """ + sys.exit(self.exitcode) + + def runDebug(self, exc_info): + """This method is called when the "Debug" button is clicked. It may + be overridden by a subclass if specialized behavior is required to + enter debug mode. + + :type exc_info: an instance of the meh.ExceptionInfo class + """ + + print("") + print(_("Use 'continue' command to quit the debugger and get back to " + "the main menu")) + import pdb + pdb.post_mortem(exc_info.stack) + #no need to quit here, let's just get back to the main dialog + + def runShell(self, exc_info): + """This method is called when user requests to run a shell. It may + be overridden by a subclass if specialized behavior is required to + run shell (e.g. TTY switching). + + :type exc_info: an instance of the meh.ExceptionInfo class + + """ + + print("") + print(_("Exit the shell to get back to the main menu")) + proc = subprocess.Popen(["bash", "--login"], shell=True, cwd="/") + proc.wait() + + def runSave(self, exc_info): + """This method is called when the "Save" button is clicked. It may + be overridden by a subclass, but that's going to be a lot of work. + + :type exc_info: an instance of the meh.ExceptionInfo class + """ + + params = dict() + params.update(self.exn.environment_info) + pkg_info = params.pop("pkg_info", None) + + #if rpmdb queries fail (anaconda), use self.conf.* values + if "component" not in params: + params["component"] = self.conf.programName + + if pkg_info: + params["pkg_name"] = pkg_info.name + params["pkg_version"] = pkg_info.version + params["pkg_release"] = pkg_info.release + params["pkg_epoch"] = pkg_info.epoch + params["pkg_arch"] = pkg_info.arch + params["package"] = "%s-%s-%s.%s" % (pkg_info.name, pkg_info.version, + pkg_info.release, pkg_info.arch) + else: + params["pkg_name"] = self.conf.programName + parts = self.conf.programVersion.rsplit("-", 1) + if len(parts) == 2: + version, release = parts + else: + version = parts[0] + # not given, make something up + release = "1" + params["pkg_version"] = version + params["pkg_release"] = release + # we don't support specifying epoch in the config object and only + # the anaconda which is not using epochs doesn't have the RPMdb to + # query + params["pkg_epoch"] = "0" + params["pkg_arch"] = self.conf.programArch + params["package"] = "{0.programName}-{0.programVersion}".format( + self.conf) + + params["hashmarkername"] = self.conf.programName + params["duphash"] = self.exn.hash + params["reason"] = self.exn.desc + params["description"] = "The following was filed automatically by %s:\n%s" \ + % (self.conf.programName, str(self.exn)) + + tb_item_name = "%s-tb" % self.conf.programName + params[tb_item_name] = self.exnText + + # save data generated by callbacks + for (item_name, (callback, _anc)) in self.conf.callbackDict.items(): + try: + ret = callback() + if ret: + params[item_name] = ret + except Exception as exc: # pylint: disable=broad-except + params[item_name] = "Caused error: %s" % exc + + for fpath in self.conf.fileList: + try: + with open(fpath, "r") as fobj: + # would be better to use the full path here, but libreport + # doesn't allow '/' characters in the item name + filename = os.path.basename(fpath) + if filename not in params: + params[filename] = fobj.read() + else: + params[filename+"_file"] = fobj.read() + except: # pylint: disable=bare-except + #skip files we cannot read + continue + + # tell ABRT some more things it requires + params["analyzer"] = "Python" + params["backtrace"] = "".join(traceback.format_exception(exc_info.type, + exc_info.value, + exc_info.stack)) + + signature = report.createPythonUnhandledExceptionSignature(**params) + + # We don't want to automatically quit here since the user may wish to + # save somewhere else, debug, etc. + self.intf.saveExceptionWindow(signature) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/network.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/network.py new file mode 100644 index 0000000..ede2b8a --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/network.py @@ -0,0 +1,45 @@ +# +# network.py - network configuration install data +# +# Copyright (C) 2008, 2009 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): David Cantrell +# +import dbus + +# This code was taken from anaconda, and slightly adapted to not rely +# on isys. +NM_SERVICE = "org.freedesktop.NetworkManager" +NM_MANAGER_PATH = "/org/freedesktop/NetworkManager" + +NM_STATE_CONNECTED = 3 + +DBUS_PROPS_IFACE = "org.freedesktop.DBus.Properties" + +def hasActiveNetDev(): + """Does the system have an enabled network interface?""" + try: + bus = dbus.SystemBus() + nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH) + props = dbus.Interface(nm, DBUS_PROPS_IFACE) + state = props.Get(NM_SERVICE, "State") + + if int(state) == NM_STATE_CONNECTED: + return True + else: + return False + except dbus.DBusException: + return False diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/safe_string.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/safe_string.py new file mode 100644 index 0000000..714ce37 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/safe_string.py @@ -0,0 +1,71 @@ +# +# Copyright (C) 2013 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author: Vratislav Podzimek +# +# + +import sys +PY = int(sys.version.split('.')[0]) + +""" +This module provides a SafeStr class. + +@see: SafeStr + +""" + +class SafeStr(str): + """ + String class that has a modified __add__ method so that ascii strings, + binary data represented as a byte string and unicode objects can be + safely appended to it (not causing traceback). BINARY DATA IS OMITTED. + + """ + + def __add__(self, other): + + if PY > 2: + return SafeStr(str.__add__(self, str(other))) + + if not (isinstance(other, str) or isinstance(other, unicode)): # pylint: disable=undefined-variable + if hasattr(other, "__str__"): + other = other.__str__() + else: + other = "OMITTED OBJECT WITHOUT __str__ METHOD" + + if isinstance(other, unicode): # pylint: disable=undefined-variable + ret = SafeStr(str.__add__(self, other.encode("utf-8"))) + else: + try: + # try to decode which doesn't cause traceback for utf-8 encoded + # non-ascii string and ascii string + other.decode("utf-8") + ret = SafeStr(str.__add__(self, other)) + except UnicodeDecodeError: + # binary data, get the representation used by Python for + # non-ascii bytes + + # hex(255) returns "0xff", we want "\xff" + other_hexa = (hex(ord(char)) for char in other) + other_backslashed = (hex_num.replace("0x", "\\x") + for hex_num in other_hexa) + other_repr = "".join(other_backslashed) + + ret = SafeStr(str.__add__(self, other_repr)) + + return ret diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/__init__.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/__init__.py new file mode 100644 index 0000000..8c174e1 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/__init__.py @@ -0,0 +1,181 @@ +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# + +class AbstractIntf(object): + """The base class for Interfaces. This is an abstract class. It + provides methods that create and run various kinds of windows. + We provide a basic level of graphical and text oriented interfaces + here, but it should be possible for things like anaconda to supply + their own much more complicated ones with little effort. + """ + def __init__(self, *args, **kwargs): + """Create a new AbstractInterface instance. This method need not + be overridden by subclasses. + """ + pass + + def enableNetwork(self, *args, **kwargs): + """Display and run a dialog that brings up the network, if it is + currently disabled. This method must be provided by all subclasses, + and should return False if unsuccessful. + """ + raise NotImplementedError + + def exitWindow(self, title, message, *args, **kwargs): + """Display and run a dialog that displays a message with the proper + buttons and images for quitting afterwards. This method must be + provided by all subclasses. + + title -- The window's title. + message -- The window's text. + """ + raise NotImplementedError + + def mainExceptionWindow(self, text, exnFile, *args, **kwargs): + """Create and return an instance of the initial execption handling + dialog. This method must be provided by all subclasses. + + text -- The short traceback (usually, just the stack trace). + exnFile -- A file containing the output of ExceptionDump.write(). + """ + raise NotImplementedError + + def messageWindow(self, title, message, *args, **kwargs): + """Display a generic informational message. This can be an error, + status update, and so forth. It must be provided by all subclasses. + + title -- The window's title. + message -- The window's text. + """ + raise NotImplementedError + + def saveExceptionWindow(self, exnFile, *args, **kwargs): + """Create and return an instance of the exception saving dialog. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractMainExceptionWindow(object): + """This abstract class describes the basic level of support required of + any interface that supplies a main exception window. The main exception + window is the initial dialog displayed by the exception handler that + provides the debug/save/quit options. + """ + def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs): + """Create a new MainExceptionWindow instance. This must handle + creating the dialog and populating it with widgets, but must not + run the dialog. A self.dialog attribute should be created that + refers to the dialog itself. + + shortTraceback -- The short traceback (usually, just the stack + trace). + longTraceback -- The long traceback (full traceback and the main + object dump). + """ + pass + + def destroy(self, *args, **kwargs): + """Destroy the current dialog. This method must be provided by all + subclasses. + """ + raise NotImplementedError + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up, but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractExitWindow(object): + """This abstract class describes the basic level of support required of + a basic message dialog that should be displayed before the program + exits. All interfaces must provide this class. + """ + def __init__(self, title, text, *args, **kwargs): + """Create a new ExitWindow instance. This must handle creating the + dialog and putting the text into it, but must not run the dialog. + This method must be provided by all subclasses. + + title -- The window's title. + text -- The window's text. + """ + pass + + def destroy(self, *args, **kwargs): + """Destroy the current dialog. This method must be provided by all + subclasses. + """ + raise NotImplementedError + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractMessageWindow(object): + """This abstract class describes the basic level of support required of + a basic message dialog. All interfaces must provide this class. + """ + def __init__(self, title, text, *args, **kwargs): + """Create a new MessageWindow instance. This must handle creating the + dialog and putting the text into it, but must not run the dialog. + This method must be provided by all subclasses. + + title -- The window's title. + text -- The window's text. + """ + pass + + def destroy(self, *args, **kwargs): + """Destroy the current dialog. This method must be provided by all + subclasses. + """ + raise NotImplementedError + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError + +class AbstractSaveExceptionWindow(object): + """This abstract class describes the basic level of support required of + any interface that supplies an exception saving window. The exception + saving window is the dialog displayed if the user clicks "save" on the + initial dialog, and presents multiple options for how the traceback + should be saved. + """ + def __init__(self, *args, **kwargs): + """Create a new SaveExceptionWindow instance. This must handle + creating the dialog and populating it with widgets, but must not + run the dialog. A self.dialog attribute should be created that + refers to the dialog itself. + """ + pass + + def run(self, *args, **kwargs): + """Run the window and set a return value. This method does everything + after the interface has been set up but does not destroy it. This + method must be provided by all subclasses. + """ + raise NotImplementedError diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/gui.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/gui.py new file mode 100644 index 0000000..b6920a3 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/gui.py @@ -0,0 +1,177 @@ +# Copyright (C) 2009 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# +from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_NONE, MAIN_RESPONSE_QUIT, MAIN_RESPONSE_SAVE +from meh.ui import AbstractIntf, AbstractSaveExceptionWindow, AbstractMainExceptionWindow, AbstractMessageWindow +import os +import sys +import report + +import gi +gi.require_version("Gtk", "3.0") + +from gi.repository import Gtk + +import gettext +_ = lambda x: gettext.ldgettext("python-meh", x) + +def find_glade_file(file): + path = os.environ.get("GLADEPATH", "./:ui/:/tmp/updates/:/tmp/updates/ui/:/usr/share/python-meh/") + for d in path.split(":"): + fn = d + file + if os.access(fn, os.R_OK): + return fn + raise RuntimeError("Unable to find glade file %s" % file) + +class GraphicalIntf(AbstractIntf): + def __init__(self, *args, **kwargs): + AbstractIntf.__init__(self, *args, **kwargs) + + def enableNetwork(self, *args, **kwargs): + """Should be provided by the inheriting class.""" + + return False + + def exitWindow(self, title, message, *args, **kwargs): + win = ExitWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def mainExceptionWindow(self, text, exnFile, *args, **kwargs): + win = MainExceptionWindow(text, exnFile, *args, **kwargs) + return win + + def messageWindow(self, title, message, *args, **kwargs): + win = MessageWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def saveExceptionWindow(self, signature, *args, **kwargs): + win = SaveExceptionWindow(signature) + win.run() + +class SaveExceptionWindow(AbstractSaveExceptionWindow): + def __init__(self, signature, *args, **kwargs): + AbstractSaveExceptionWindow.__init__(self, signature, *args, **kwargs) + self.signature = signature + + def run(self, *args, **kwargs): + # Don't need to check the return value of report since it will + # handle all the UI reporting for us. + report.report_problem_in_memory(self.signature, report.LIBREPORT_WAIT) + +class MainExceptionWindow(AbstractMainExceptionWindow): + def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs): + AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback, + *args, **kwargs) + + builder = Gtk.Builder() + builder.set_translation_domain("python-meh") + glade_file = find_glade_file("exception-dialog.glade") + builder.add_from_file(glade_file) + builder.connect_signals(self) + + self._main_window = builder.get_object("exceptionWindow") + + # this makes sure the Meh window remains active + # even if the exception has been triggered in a dialog + window_group = Gtk.WindowGroup() + window_group.add_window(self._main_window) + + self._traceback_buffer = builder.get_object("tracebackBuffer") + + self._traceback_buffer.set_text(longTraceback) + self._response = MAIN_RESPONSE_QUIT + + self._debug_button = builder.get_object("debugButton") + + allowDebug = kwargs.get("allowDebug", sys.stdout.isatty) + + if allowDebug and not allowDebug(): + self._debug_button.set_sensitive(False) + + @property + def main_window(self): + return self._main_window + + def destroy(self, *args, **kwargs): + self._main_window.destroy() + + def run(self, *args, **kwargs): + self._main_window.show_all() + # keep our window above dialogs + self._main_window.set_modal(True) + self._main_window.set_keep_above(True) + Gtk.main() + self.destroy() + return self._response + + def on_report_clicked(self, button): + # hide our window to not interfere with libreport window + self._main_window.hide() + self._response = MAIN_RESPONSE_SAVE + Gtk.main_quit() + + def on_quit_clicked(self, button): + self._response = MAIN_RESPONSE_QUIT + Gtk.main_quit() + + def on_debug_clicked(self, button): + self._response = MAIN_RESPONSE_DEBUG + Gtk.main_quit() + + def on_expander_activated(self, expander, *args): + if not expander.get_expanded(): + self._main_window.resize(600, 400) + else: + #resize the window back to the default size when expander is + #minimized + self._main_window.resize(600, 1) + + def on_main_window_deleted(self, *args): + self._response = MAIN_RESPONSE_NONE + self.destroy() + Gtk.main_quit() + +class MessageWindow(AbstractMessageWindow): + def __init__(self, title, text, *args, **kwargs): + AbstractMessageWindow.__init__(self, title, text, *args, **kwargs) + self.rc = 0 + + self.dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.OK, + type=Gtk.MessageType.INFO, + message_format=text) + self.dialog.set_title(title) + self.dialog.set_position(Gtk.WindowPosition.CENTER) + + def destroy(self, *args, **kwargs): + self.dialog.destroy() + + def run(self, *args, **kwargs): + self.dialog.show_all() + self.rc = self.dialog.run() + self.dialog.destroy() + +class ExitWindow(MessageWindow): + def __init__(self, title, text, *args, **kwargs): # pylint: disable=super-init-not-called + self.dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.NONE, + type=Gtk.MessageType.INFO, + message_format=text) + self.dialog.set_title(title) + self.dialog.add_button(_("_Exit"), 0) + self.dialog.set_position(Gtk.WindowPosition.CENTER) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/text.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/text.py new file mode 100644 index 0000000..e4d99f2 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/meh/ui/text.py @@ -0,0 +1,225 @@ +# Copyright (C) 2009, 2013 Red Hat, Inc. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Author(s): Chris Lumens +# Vratislav Podzimek +# +from __future__ import print_function + +from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_SAVE, MAIN_RESPONSE_SHELL, MAIN_RESPONSE_QUIT +from meh.ui import AbstractIntf, AbstractSaveExceptionWindow, AbstractMainExceptionWindow, AbstractMessageWindow +import report +import report.io.TextIO +from report import LIBREPORT_WAIT, LIBREPORT_RUN_CLI + +import os +import sys +if sys.version_info.major == 3: + raw_input_fn = input +else: + raw_input_fn = raw_input # pylint: disable=undefined-variable + +import gettext +_ = lambda x: gettext.ldgettext("python-meh", x) + + +class IOHandler(object): + """ + Class that provides methods for input and output. Its instance is expected + to be passed to objects performing some I/O operations. + + """ + + def __init__(self, in_func=raw_input_fn, out_func=print): # pylint: disable=used-before-assignment + """ + Constructor for the IOhandler class. Arguments can be used to override + default I/O functions with the custom ones. + + :param in_func: input function similar to standard raw_input + :type in_func: str -> str + :param out_func: output function similar to standard print + :type out_func: str -> None + + """ + + self.in_func = in_func + self.out_func = out_func + + def print(self, msg=""): + self.out_func(msg) + + def raw_input(self, prompt): + return self.in_func(prompt) + +class TextWindow(object): + """Helper class providing some common methods needed by all text windows.""" + + def __init__(self, title, *args, **kwargs): + self._io = kwargs.get("io_handler", IOHandler()) + self._title = title + + # short (one-char) answer meaning "yes" + self._yes_answer = _("y") + + # short (one-char) answer meaning "no" + self._no_answer = _("n") + + @property + def _usable_width(self): + return os.environ.get("COLUMNS", 80) - 1 + + def _print_rule(self): + rule = self._usable_width * "=" + self._io.print(rule) + + def print_header(self): + self._io.print() + self._print_rule() + self._io.print(self._title) + self._print_rule() + + def destroy(self): + self._print_rule() + self._print_rule() + +class TextIntf(AbstractIntf): + def __init__(self, *args, **kwargs): + AbstractIntf.__init__(self, *args, **kwargs) + self.screen = kwargs.get("screen", None) + self._io = kwargs.get("io_handler", IOHandler()) + + def set_io_handler(self, handler): + """ + Set different IO handler. + + :type handler: an instance of the IOHandler class + + """ + self._io = handler + + def enableNetwork(self, *args, **kwargs): + """Should be provided by the inheriting class.""" + + return False + + def exitWindow(self, title, message, *args, **kwargs): + kwargs["io_handler"] = self._io + win = ExitWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def mainExceptionWindow(self, text, exnFile, *args, **kwargs): + kwargs["io_handler"] = self._io + win = MainExceptionWindow(text, exnFile, *args, **kwargs) + return win + + def messageWindow(self, title, message, *args, **kwargs): + kwargs["io_handler"] = self._io + win = MessageWindow(title, message, *args, **kwargs) + win.run() + win.destroy() + + def saveExceptionWindow(self, signature, *args, **kwargs): + kwargs["io_handler"] = self._io + win = SaveExceptionWindow(signature, *args, **kwargs) + win.run() + win.destroy() + +class SaveExceptionWindow(TextWindow, AbstractSaveExceptionWindow): + def __init__(self, signature, *args, **kwargs): + AbstractSaveExceptionWindow.__init__(self, signature, + *args, **kwargs) + TextWindow.__init__(self, _("Save exception"), *args, **kwargs) + self.signature = signature + + def run(self, *args, **kwargs): + # Don't need to check the return value of report since it will + # handle all the UI reporting for us. + report.report_problem_in_memory(self.signature, + LIBREPORT_WAIT|LIBREPORT_RUN_CLI) + +class MainExceptionWindow(TextWindow, AbstractMainExceptionWindow): + def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs): + AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback, + *args, **kwargs) + TextWindow.__init__(self, _("An unknown error has occurred"), + *args, **kwargs) + self._short_traceback = shortTraceback + self._menu_items = [(_("Report Bug"), MAIN_RESPONSE_SAVE), + (_("Run shell"), MAIN_RESPONSE_SHELL), + (_("Quit"), MAIN_RESPONSE_QUIT)] + + allowDebug = kwargs.get("allowDebug", sys.stdout.isatty) + + if allowDebug and allowDebug(): + self._menu_items.insert(1, (_("Debug"), MAIN_RESPONSE_DEBUG)) + + def run(self, *args, **kwargs): + self.print_header() + self._io.print(self._short_traceback) + self._io.print(_("What do you want to do now?")) + for (idx, item) in enumerate(self._menu_items): + self._io.print("%d) %s" % (idx + 1, item[0])) + + ret = -1 + num_menu_items = len(self._menu_items) + self._io.print() + while not (0 < ret <= num_menu_items): + ret = self._io.raw_input(_("Please make your choice from above: ")) + try: + ret = int(ret) + except ValueError: + ret = -1 + + return self._menu_items[ret - 1][1] + +class MessageWindow(TextWindow, AbstractMessageWindow): + def __init__(self, title, text, *args, **kwargs): + AbstractMessageWindow.__init__(self, title, text, *args, **kwargs) + TextWindow.__init__(self, title, *args, **kwargs) + self._text = text + + def run(self, *args, **kwargs): + self.print_header() + self._io.print(self._text) + self._io.print() + self._io.raw_input(_("Hit ENTER to continue")) + +class ExitWindow(MessageWindow): + def __init__(self, title, text, *args, **kwargs): + MessageWindow.__init__(self, title, text, *args, **kwargs) + + def run(self, *args, **kwargs): + self.print_header() + self._io.print(self._text) + self._io.print() + + # self._no_answer may be non-ascii string (simple .upper() doesn't work) + no_answer_upper = self._no_answer.decode("utf-8").upper().encode("utf-8") + answer = self._io.raw_input(_( + "Are you sure you want to exit? [%(yes)s/%(no)s]") % + { "yes": self._yes_answer, + "no": no_answer_upper }) + + # no answer means accepting the default (self._no_answer) and the answer + # is case insensitive (and may be non-ascii) + lower_answer = answer.decode("utf-8").lower().encode("utf-8") + answer = lower_answer or self._no_answer + + if answer in (self._yes_answer, self._no_answer): + return answer == self._yes_answer + else: + self.run(*args, **kwargs) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/pixmaps/exception.png b/pkgbuilds/python-meh/src/python-meh-r0.43-1/pixmaps/exception.png new file mode 100644 index 0000000000000000000000000000000000000000..2e08889bddc19c16cbc7d4483d25510ed76cdc11 GIT binary patch literal 3920 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 ee4!x>b>&}HrjpeBV8!eJ0000 $$lang.pot ; then \ + mv -f $$lang.pot $$lang.po ; \ + echo "$(MSGMERGE) of $$lang succeeded" ; \ + else \ + echo "$(MSGMERGE) of $$lang failed" ; \ + rm -f $$lang.pot ; \ + fi \ + done + +clean: + @rm -fv *mo *~ .depend + @rm -rf tmp + +install: $(MOFILES) + @for n in $(MOFILES); do \ + l=`basename $$n .mo`; \ + $(INSTALL_DIR) $(INSTALL_NLS_DIR)/$$l/LC_MESSAGES; \ + $(INSTALL_DATA) --verbose $$n $(INSTALL_NLS_DIR)/$$l/LC_MESSAGES/$(NLSPACKAGE).mo; \ + done + +%.mo: %.po + $(MSGFMT) -o $@ $< + +.PHONY: missing depend + + diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/po/python-meh.pot b/pkgbuilds/python-meh/src/python-meh-r0.43-1/po/python-meh.pot new file mode 100644 index 0000000..e00f088 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/po/python-meh.pot @@ -0,0 +1,116 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-10-05 14:50+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../meh/handler.py:195 +msgid "" +"Use 'continue' command to quit the debugger and get back to the main menu" +msgstr "" + +#: ../meh/handler.py:211 +msgid "Exit the shell to get back to the main menu" +msgstr "" + +#. short (one-char) answer meaning "yes" +#: ../meh/ui/text.py:75 +msgid "y" +msgstr "" + +#. short (one-char) answer meaning "no" +#: ../meh/ui/text.py:78 +msgid "n" +msgstr "" + +#: ../meh/ui/text.py:145 +msgid "Save exception" +msgstr "" + +#: ../meh/ui/text.py:158 tmp/exception-dialog.glade.h:1 +msgid "An unknown error has occurred" +msgstr "" + +#: ../meh/ui/text.py:161 +msgid "Report Bug" +msgstr "" + +#: ../meh/ui/text.py:162 +msgid "Run shell" +msgstr "" + +#: ../meh/ui/text.py:163 +msgid "Quit" +msgstr "" + +#: ../meh/ui/text.py:168 +msgid "Debug" +msgstr "" + +#: ../meh/ui/text.py:173 +msgid "What do you want to do now?" +msgstr "" + +#: ../meh/ui/text.py:181 +msgid "Please make your choice from above: " +msgstr "" + +#: ../meh/ui/text.py:199 +msgid "Hit ENTER to continue" +msgstr "" + +#: ../meh/ui/text.py:213 +#, python-format +msgid "Are you sure you want to exit? [%(yes)s/%(no)s]" +msgstr "" + +#: ../meh/ui/gui.py:176 +msgid "_Exit" +msgstr "" + +#: tmp/exception-dialog.glade.h:2 +msgid "" +"This program has encountered an unknown error. You may\n" +"report the bug below or quit the program." +msgstr "" + +#: tmp/exception-dialog.glade.h:4 +msgid "_Report Bug" +msgstr "" + +#: tmp/exception-dialog.glade.h:5 +msgid "_Quit" +msgstr "" + +#: tmp/exception-dialog.glade.h:6 +msgid "The output below may help determine the cause of the error:" +msgstr "" + +#: tmp/exception-dialog.glade.h:7 +msgid "'Debug' may take you to tty1." +msgstr "" + +#: tmp/exception-dialog.glade.h:8 +msgid "_Debug" +msgstr "" + +#: tmp/exception-dialog.glade.h:9 +msgid "More _info..." +msgstr "" + +#: tmp/exception-dialog.glade.h:10 +msgid "No additional info available." +msgstr "" diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/python-meh.spec b/pkgbuilds/python-meh/src/python-meh-r0.43-1/python-meh.spec new file mode 100644 index 0000000..1ef255c --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/python-meh.spec @@ -0,0 +1,383 @@ +%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} +%global with_python3 1 + +%define libreportver 2.0.18-1 + +Summary: A python library for handling exceptions +Name: python-meh +Url: https://github.com/rhinstaller/python-meh +Version: 0.43 +Release: 1%{?dist} +# This is a Red Hat maintained package which is specific to +# our distribution. Thus the source is only available from +# within this srpm. +# This tarball was created from upstream git: +# git clone https://github.com/rhinstaller/python-meh +# cd python-meh && make archive +Source0: https://github.com/rhinstaller/python-meh/archive/%{name}-%{version}.tar.gz + +License: GPLv2+ +Group: System Environment/Libraries +BuildArch: noarch +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: python-devel +BuildRequires: gettext +BuildRequires: python-setuptools +BuildRequires: intltool +BuildRequires: dbus-python +BuildRequires: libreport-gtk >= %{libreportver} +BuildRequires: libreport-cli >= %{libreportver} +BuildRequires: libreport-python >= %{libreportver} +BuildRequires: python-six + +%if 0%{with_python3} +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-dbus +BuildRequires: libreport-python3 >= %{libreportver} +BuildRequires: python3-six +BuildRequires: python3-pocketlint +%endif + +Requires: python +Requires: dbus-python +Requires: rpm-python +Requires: libreport-cli >= %{libreportver} +Requires: libreport-python >= %{libreportver} +Requires: python-six + +%description +The python-meh package is a python library for handling, saving, and reporting +exceptions. + +%package gui +Summary: Graphical user interface for the python-meh library +Requires: python-meh = %{version}-%{release} +Requires: pygobject3 +Requires: gtk3 +Requires: libreport-gtk >= %{libreportver} + +%description gui +The python-meh-gui package provides a GUI for the python-meh library. + +%if 0%{with_python3} +%package -n python3-meh +Summary: A python 3 library for handling exceptions +Requires: python3 +Requires: python3-dbus +Requires: rpm-python3 +Requires: libreport-cli >= %{libreportver} +Requires: libreport-python3 >= %{libreportver} +Requires: python3-six + +%description -n python3-meh +The python3-meh package is a python 3 library for handling, saving, and reporting +exceptions. + +%package -n python3-meh-gui +Summary: Graphical user interface for the python3-meh library +Requires: python3-meh = %{version}-%{release} +Requires: python3-gobject, gtk3 +Requires: libreport-gtk >= %{libreportver} + +%description -n python3-meh-gui +The python3-meh-gui package provides a GUI for the python3-meh library. + +%endif + +%prep +%setup -q + +%if 0%{?with_python3} +rm -rf %{py3dir} +cp -a . %{py3dir} +%endif # with_python3 + +%build +make + +%if 0%{?with_python3} +pushd %{py3dir} +make PYTHON=%{__python3} +popd +%endif + +%check +make test + +%if 0%{?with_python3} +pushd %{py3dir} +# Needs UTF-8 locale +LANG=en_US.UTF-8 make PYTHON=%{__python3} test +popd +%endif + +%install +rm -rf %{buildroot} +make DESTDIR=%{buildroot} install + +%if 0%{?with_python3} +pushd %{py3dir} +make PYTHON=%{__python3} DESTDIR=%{buildroot} install +popd +%endif + +%find_lang %{name} + +%clean +rm -rf %{buildroot} + +%files -f %{name}.lang +%defattr(-,root,root,-) +%doc ChangeLog COPYING +%{python_sitelib}/* +%exclude %{python_sitelib}/meh/ui/gui.py* + +%files gui +%{python_sitelib}/meh/ui/gui.py* +%{_datadir}/python-meh + +%files -n python3-meh +%doc ChangeLog COPYING +%{python3_sitelib}/* +%exclude %{python3_sitelib}/meh/ui/gui.py* + +%files -n python3-meh-gui +%{python3_sitelib}/meh/ui/gui.py* +%{_datadir}/python-meh + +%changelog +* Mon Oct 05 2015 Martin Kolman - 0.43-1 +- Set translations domain for glade files (vtrefny) + +* Tue Sep 29 2015 Martin Kolman - 0.42-1 +- Add tests and ChangeLog to MANIFEST.in (vtrefny) +- Fix clicking on buttons on error pop-up doesn't work (#1250942) (vtrefny) +- Add Makefile to MANIFEST.in (vtrefny) +- Add archive target to Makefile (vtrefny) +- Add .gitignore (vtrefny) + +* Wed Sep 16 2015 Martin Kolman - 0.41-1 +- Make sure the Meh window has focus even if a dialog is displayed (mkolman) +- Run pylint as part of "make ci". (clumens) +- Add a new makefile target that does everything needed for jenkins. (clumens) +- Fix the other pylint-discovered errors. (clumens) +- Use isinstance instead of type. (clumens) +- Fix all the places we're redefining something. (clumens) +- Don't use [] as the default argument in a method. (clumens) +- Take care of exception-related pylint messages. (clumens) +- Get rid of all the unused variable warnings. (clumens) +- Get rid of all unused and wildcard imports. (clumens) +- Add pocketlint support to python-meh. (clumens) +- Use gi.require_version for Gtk import (vtrefny) + +* Tue Apr 28 2015 Martin Kolman - 0.40-1 +- Make sure the date in RPM changelog is always in English (mkolman) +- Update upstream URL (mkolman) + +* Wed Apr 01 2015 Martin Kolman - 0.39-1 +- Handle LANG=C (mkolman) + +* Tue Mar 31 2015 Martin Kolman - 0.38-1 +- Switch to Zanata for translations (mkolman) +- Run both Python 2 and Python 3 tests for "make test" (mkolman) +- Python 3 compatibility fixes for the Unicode test (mkolman) +- Make it possible to specify file open mode (mkolman) +- Add missing six dependency (mkolman) +- Fix date in changelog (mkolman) + +* Fri Mar 27 2015 Martin Kolman - 0.37-1 +- Fix dumping file attachments in Python 3 (vtrefny) +- meh has not required openssh-clients since 2009 (awilliam) + +* Thu Mar 05 2015 Martin Kolman - 0.36-1 +- Package's epoch returned by RPM is an integer (#1199263) (vpodzime) + +* Tue Feb 17 2015 Martin Kolman - 0.35-1 +- Add option to remove the 'Debug' option/button for mainExceptionWindow (vtrefny) + +* Tue Dec 09 2014 Vratislav Podzimek - 0.34-1 +- Encode str/unicode object before hashing it (vpodzime) +- Use dict.items() instead of dict.iteritems() (vpodzime) +- Add one more flag to test (for Python3) (vpodzime) +- Make sure we work with strings when we think we do (vpodzime) + +* Fri Dec 05 2014 Vratislav Podzimek - 0.33-1 +- Make sure fresh translations are always fetched (vpodzime) +- Add pieces needed to build the python3- subpackage (#985294) (mhroncok) +- Remove yum from requires and fix setuptools requires (mhroncok) +- raw_input is replaced by input in Python3 (vpodzime) +- Raise exception in a Python3 compatible way (mhroncok) +- Remove the --disable-overwrite parameter for the Transifex client (mkolman) +- Use /usr/bin/python2 in scripts (mkolman) +- Add example code using python-meh (vpodzime) + +* Mon Apr 28 2014 Martin Kolman - 0.32-1 +- Translation update + +* Fri Mar 21 2014 Martin Kolman - 0.31-1 +- Translation update + +* Wed Dec 18 2013 Vratislav Podzimek - 0.30-1 +- Exclude compiled versions of gui.py from the non-gui package (dshea) +- Skip callbacks providing no information (vpodzime) + +* Wed Nov 20 2013 Vratislav Podzimek - 0.29-1 +- Split GUI out into a separate package (vpodzime) +- Create archives in one Makefile target and reuse it (vpodzime) + +* Tue Nov 05 2013 Vratislav Podzimek - 0.28-1 +- Introduce support for Python 3 while keeping Python 2 working (miro) +- Sync spec with downstream (vpodzime) + +* Wed Oct 09 2013 Vratislav Podzimek - 0.27-1 +- Use join method instead of the joinfields function +- Translate the hints on how to quit debugger and shell +- Add a way to run shell when exception appears +- Get rid of constants that are no longer used anywhere +- Filter local variables in a nicer way and fix docstring + +* Sun Aug 04 2013 Fedora Release Engineering - 0.26-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Tue Jul 23 2013 Vratislav Podzimek - 0.26-1 +- Output binary data correctly as hexa strings (#986515) (vpodzime) +- Add newline before dumping callbacks' outputs (vpodzime) + +* Tue Jun 18 2013 Vratislav Podzimek - 0.25-1 +- Add and use the safe_string module and the SafeStr class (vpodzime) +- Give translators hint about the cryptic strings (vpodzime) + +* Thu May 02 2013 Vratislav Podzimek - 0.24-1 +- Epoch of the package from RPM db can be None (#957789) (vpodzime) + +* Wed Apr 17 2013 Vratislav Podzimek - 0.23-1 +- Use Sphinx syntax for docstrings (vpodzime) +- Allow a change of the I/O functions (vpodzime) +- Reword the 'Debug' button warning (#948256) (vpodzime) + +* Thu Apr 04 2013 Vratislav Podzimek - 0.22-1 +- Some more stuff for ABRT/libreport (#929181) (vpodzime) +- Tell ABRT we are reporting a Python excetion (vpodzime) +- Use named tuples instead of our magic tuples (vpodzime) + +* Thu Feb 14 2013 Fedora Release Engineering - 0.21-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Jan 21 2013 Vratislav Podzimek - 0.21-1 +- New purely textual text interface (vpodzime) +- Add dumb enableNetwork implementation to GraphicalIntf (vpodzime) +- Destroy main window after running it (vpodzime) +- Get rid of the accountManager and use new libreport API (vpodzime) +- Add a way to override previously registered callback (vpodzime) +- Allow callbacks marked as attachment only (vpodzime) +- Add support for callbacks providing additional data (vpodzime) + +* Tue Dec 11 2012 Vratislav Podzimek - 0.20-1 +- Handle non-ascii dict keys and values correctly (#883641) (vpodzime) + +* Wed Nov 14 2012 Vratislav Podzimek - 0.19-1 +- Add test for handling unicode strings and files (vpodzime) +- Read files as UTF-8 and ignore errors (#874250) (vpodzime) +- Add %check section to the spec file (vpodzime) +- Fix tests (vpodzime) + +* Thu Oct 25 2012 Vratislav Podzimek - 0.18-1 +- Handle tracebacks with no stack (#866441) (vpodzime) +- Parse component name correctly (#866526) (vpodzime) +- Spelling corrections (#865993) (vpodzime) + +* Tue Oct 09 2012 Vratislav Podzimek - 0.17-1 +- Handle unicode strings correctly (#854959) (vpodzime) + +* Tue Sep 11 2012 Vratislav Podzimek - 0.16-1 +- Do not overwrite process information with files having the same basename (vpodzime) +- Encode dump as utf-8 before writing to file (#854959) (vpodzime) + +* Mon Aug 20 2012 Vratislav Podzimek - 0.15-1 +- Add main_window property to the MainExceptionWindow (vpodzime) +- Don't try to dump objects without __dict__ (vpodzime) +- Change require from rpm to rpm-python (vpodzime) + +* Fri Aug 03 2012 Vratislav Podzimek - 0.14-1 +- Use just a basename of the attached file as the item name (vpodzime) +- Set the type hint for the mainExceptionWindow to Dialog (vpodzime) +- Store and then write out the string representation of the traceback and object dump (vpodzime) + +* Fri Jul 27 2012 Vratislav Podzimek - 0.13-1 +- Add files specified in the Config object as attachments to bugreports (vpodzime) +- Display hint how to quit the debugger (vpodzime) +- Do not kill the process when 'continue' is used in pdb (vpodzime) +- Port to Gtk3 and the new design (vpodzime) +- Remove the rc attribute and getrc methods (vpodzime) +- Fix 'all' and 'install' Makefile targets (vpodzime) +- Migrate l10n to Transifex (vpodzime) + +* Sat Jul 21 2012 Fedora Release Engineering - 0.12-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Dec 20 2011 Vratislav Podzimek 0.12 +- Use new libreport API to get more information to bugzilla (vpodzime). +- Adapt to the new API of libreport (vpodzime). +- Move "import rpm" to where it's needed to avoid nameserver problems (clumens). + Resolves: rhbz#749330 +- Change dependency to libreport-* (mtoman). + Resolves: rhbz#730924 +- Add abrt-like information to bug reports (vpodzime). + Resolves: rhbz#728871 +- Propagate the screen attr when using text mode (jmoskovc). + +* Tue Feb 08 2011 Fedora Release Engineering - 0.11-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Jan 25 2011 Chris Lumens - 0.11-1 +- Update the spec file URL to something valid (#670601). (clumens) +- Don't use _D for Debug, since that's already used by the expander (#640929). (clumens) +- Translation updates. + +* Tue Jun 22 2010 Chris Lumens 0.10-1 +- Treat classes like simple types, too. (clumens) + +* Thu Jun 10 2010 Chris Lumens - 0.9-1 +- Remove the requirement on python-bugzilla (#602794). (clumens) +- Rename ba.po -> bs.po (#583055). (clumens) +- Translation updates. + +* Thu Mar 04 2010 Chris Lumens - 0.8-1 +- And add a requirement for report as well. (clumens) +- filer.py is now completely taken over by meh. (clumens) +- Everything from savers.py has moved into report. (clumens) +- Remove unused UI code now that report handles all this for me. (clumens) +- Switch ExceptionHandler to use report (#562656). (clumens) +- Don't allow an exception when writing out an attribute stop the whole dump. (clumens) +- Credit where credit is due. (clumens) + +* Tue Nov 03 2009 Chris Lumens - 0.7-1 +- Add a test case framework. +- Move src -> meh for ease of test case writing. +- Another attempt at making the attrSkipList work (#532612, #532737). + +* Thu Oct 08 2009 Chris Lumens - 0.6-1 +- Make idSkipList work again. +- Support dumping objects derived from Python's object. +- Use the right method to set text on a snack.Entry (#526884). + +* Tue Sep 29 2009 Chris Lumens - 0.5-1 +- Always compare version numbers as strings (#526188). + +* Fri Sep 25 2009 Chris Lumens - 0.4-1 +- Add a default description to bug reports. +- Handle the user pressing Escape by continuing to show the dialog. +- Lots more translation updates. + +* Thu Sep 10 2009 Chris Lumens - 0.3-1 +- Pull in lots of new translations (#522410). + +* Wed Aug 19 2009 Chris Lumens - 0.2-1 +- Add a title to the main exception dialog so it looks right in anaconda. +- Don't include an extra '/' in the displayed bug URL (#517515). +- Now that there's .po files, package them. +- Use the new exception icon (#517164). + +* Tue Jul 28 2009 Chris Lumens - 0.1-1 +- Initial package. diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/setup.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/setup.py new file mode 100644 index 0000000..ee7f066 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/setup.py @@ -0,0 +1,10 @@ +#!/usr/bin/python2 + +from distutils.core import setup + +setup(name='python-meh', version='0.43', + description='Python module for handling exceptions', + author='Chris Lumens', author_email='clumens@redhat.com', + url='http://git.fedoraproject.org/git/?p=python-meh.git', + data_files = [('/usr/share/python-meh', ['ui/exception-dialog.glade'])], + packages=['meh', 'meh.ui']) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/__init__.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/attrSkipList.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/attrSkipList.py new file mode 100644 index 0000000..b21c6d1 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/attrSkipList.py @@ -0,0 +1,25 @@ +import unittest +from tests.baseclass import BaseTestCase + +from meh import Config + +class Example: + def __init__(self): + self.rootPassword = "blahblah" + self.dontSkipMe = 12345 + +class AttrSkipList_TestCase(BaseTestCase): + def runTest(self): + example = Example() + + conf = Config(programName="test", + programVersion="47", + attrSkipList=[ "rootPassword" ]) + + dump = self.dump(conf, example) + + self.assertIn("rootPassword: Skipped", dump) + self.assertNotIn("dontSkipMe: Skipped", dump) + +if __name__ == "__main__": + unittest.main() diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/baseclass.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/baseclass.py new file mode 100644 index 0000000..d242ce3 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/baseclass.py @@ -0,0 +1,103 @@ +import glob +import importlib +import os +import sys +import tempfile +import unittest +import six + +from meh import ExceptionInfo +from meh.dump import ExceptionDump + +class BaseTestCase(unittest.TestCase): + def dump(self, conf, obj): + from inspect import stack as _stack + stack = _stack()[1:] + + dump = ExceptionDump(ExceptionInfo(None, None, stack), conf) + return dump.dump(obj) + + def openFile(self, mode="w"): + (fd, path) = tempfile.mkstemp() + # only Python 3 has supports the "encoding" keyword argument + if six.PY2: + fo = os.fdopen(fd, mode) + else: + fo = os.fdopen(fd, mode, encoding="utf-8") + + return (fo, path) + + def tracebackContains(self, path, s): + f = open(path) + while True: + l = f.readline() + if l == "": + f.close() + return False + + if l.find(s) != -1: + f.close() + return True + + f.close() + return False + +def loadModules(moduleDir, cls_pattern="_TestCase", skip_list=None): + '''taken from firstboot/loader.py''' + + if not skip_list: + skip_list = ["__init__", "baseclass"] + + # Guaruntee that __init__ is skipped + if skip_list.count("__init__") == 0: + skip_list.append("__init__") + + tests = list() + + # Make sure moduleDir is in the system path so imputil works. + if not moduleDir in sys.path: + sys.path.insert(0, moduleDir) + + # Get a list of all *.py files in moduleDir + lst = map(lambda x: os.path.splitext(os.path.basename(x))[0], + glob.glob(moduleDir + "/*.py")) + + # Inspect each .py file found + for module in lst: + if module in skip_list: + continue + + # Attempt to load the found module. + try: + loaded = importlib.import_module(module) + except ImportError: + print("Error loading module %s." % module) + continue + + # Find class names that match the supplied pattern (default: "_TestCase") + beforeCount = len(tests) + for obj in loaded.__dict__.keys(): + if obj.endswith(cls_pattern): + tests.append(loaded.__dict__[obj]) + afterCount = len(tests) + + # Warn if no tests found + if beforeCount == afterCount: + print("Module %s does not contain any test cases; skipping." % module) + continue + + return tests + +# Run the tests +if __name__ == "__main__": + + # Create a test suite + MehTestSuite = unittest.TestSuite() + + # Find tests to add + tstList = loadModules(os.path.join(os.environ.get("PWD"), "tests/")) + for tst in tstList: + MehTestSuite.addTest(tst()) + + # Run tests + unittest.main(defaultTest="MehTestSuite") diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/callbacks.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/callbacks.py new file mode 100644 index 0000000..5407f12 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/callbacks.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +from tests.baseclass import BaseTestCase +from meh import Config, ConfigError + +def callback1(): + return "This was generated by the callback1" + +def callback2(): + return "This was generated by the callback2" + +def callback3(): + raise RuntimeError("Testing callback raising exception") + +def callback4(): + return "This was generated by the callback4" + +def callback5(): + return "" + +class Callbacks_TestCase(BaseTestCase): + def runTest(self): + conf = Config(programName="CallbacksTest", + programVersion="1.0", + callbackDict={"callback1": (callback1, False), + "callback2": (callback2, False)}) + + # another way to register callback + conf.register_callback("callback3", callback2) + + # callback with given item name already registered + with self.assertRaises(ConfigError): + conf.register_callback("callback3", callback3) + + # should not raise exception + conf.register_callback("callback3", callback3, override=True) + + conf.register_callback("callback4", callback4, attchmnt_only=True) + conf.register_callback("callback5", callback5, attchmnt_only=False) + + # should not raise exception + dump = self.dump(conf, None) + + self.assertIn("callback1:\nThis was generated by the callback1\n", + dump) + self.assertIn("callback2:\nThis was generated by the callback2\n", + dump) + self.assertIn("callback3: Caused error", dump) + + # should not appear in the dump (attachment only) + self.assertNotIn("callback4", dump) + + # should not appear in the dump (nothing provided) + self.assertNotIn("callback5", dump) + + diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_binary.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_binary.py new file mode 100644 index 0000000..fe35ed4 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_binary.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +from tests.baseclass import BaseTestCase +from meh import Config + +BINARY_DATA = b"\xff\x61\xfe\xdd" +BINARY_DATA2 = b"\xfe\x61\xff\xdd" +BINARY_DATA3 = b"\xfe\x62\xff\xdd" + +class BinaryExample(object): + def __init__(self): + self.bin_data = BINARY_DATA + + # crazy, but possible + self.dict = dict() + self.dict[BINARY_DATA2] = BINARY_DATA2 + + self.list = [BINARY_DATA3] + +class HandleBinary_TestCase(BaseTestCase): + def runTest(self): + binary_example = BinaryExample() + + conf = Config(programName="UnicodeTest", + programVersion="1.0") + + # should not raise exception + dump = self.dump(conf, binary_example) + + # should contain the attribute name and hexa representation of binary + # data ('\x61' == 'a' which shouldn't be translated) + self.assertTrue("bin_data: \\xff\\x61\\xfe\\xdd\n" in dump or + "bin_data: b'\\xffa\\xfe\\xdd'\n" in dump) + + # should contain the binary-keyed dict + self.assertTrue("dict: {'\\xfe\\x61\\xff\\xdd': \\xfe\\x61\\xff\\xdd" in dump or + "dict: {b'\\xfea\\xff\\xdd': b'\\xfea\\xff\\xdd'" in dump) + + # should contain the list with binary item(s) + self.assertTrue("list: [\\xfe\\x62\\xff\\xdd]" in dump or + "list: [b'\\xfeb\\xff\\xdd']" in dump) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_unicode.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_unicode.py new file mode 100644 index 0000000..a4e88d0 --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/handle_unicode.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +import six + +from tests.baseclass import BaseTestCase +from meh import Config + +UNICODE_STR = u"řěšččšě" +UNICODE_LINE = u"řčšřščřčš\n" +ASCII_STR = "fsdkljfdsldfs" +ASCII_LINE = "fdsfsdakjfdsa\n" + +class UnicodeExample(object): + def __init__(self): + self.ascii_str = ASCII_STR + self.unicode_str = UNICODE_STR + self.encoded_str = self.unicode_str.encode("utf-8") + self.unicode_dict = { u"úú" : u"áá" } + +class HandleUnicode_TestCase(BaseTestCase): + def setUp(self): + # write UTF-8 and ASCII files for testing + if six.PY2: + (fobj, self.uni_file_path) = self.openFile() + else: + (fobj, self.uni_file_path) = self.openFile(mode="wt") + try: + fobj.write(UNICODE_LINE) + except UnicodeEncodeError: + fobj.write(UNICODE_LINE.encode("utf-8")) + fobj.close() + + (fobj, self.ascii_file_path) = self.openFile() + fobj.write(ASCII_LINE) + fobj.close() + + def runTest(self): + unicode_example = UnicodeExample() + + conf = Config(programName="UnicodeTest", + programVersion="1.0", + fileList=[self.uni_file_path, self.ascii_file_path]) + + # should not raise exception + dump = self.dump(conf, unicode_example) + + self.assertIn("_str: " + str(UNICODE_STR.encode("utf-8")), dump) + self.assertIn("encoded_str: " + str(UNICODE_STR.encode("utf-8")), dump) + if six.PY2: + self.assertIn(str(UNICODE_LINE.encode("utf-8")), dump) + else: + self.assertIn(UNICODE_LINE, dump) + + self.assertIn("ascii_str: " + ASCII_STR, dump) + self.assertIn(ASCII_LINE.rstrip(), dump) + diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/pylint/runpylint.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/pylint/runpylint.py new file mode 100755 index 0000000..146d04a --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/pylint/runpylint.py @@ -0,0 +1,19 @@ +#!/usr/bin/python3 + +import sys + +from pocketlint import PocketLintConfig, PocketLinter + +class MehLintConfig(PocketLintConfig): + @property + def pylintPlugins(self): + retval = super(MehLintConfig, self).pylintPlugins + retval.remove("pocketlint.checkers.eintr") + retval.remove("pocketlint.checkers.markup") + return retval + +if __name__ == "__main__": + conf = MehLintConfig() + linter = PocketLinter(conf) + rc = linter.run() + sys.exit(rc) diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/safe_string_test.py b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/safe_string_test.py new file mode 100755 index 0000000..e771afd --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/tests/safe_string_test.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +from tests.baseclass import BaseTestCase +from meh.safe_string import SafeStr, PY + +class TestClass(object): + def __str__(self): + return "string representation of TestClass instance" + +class TestClass2(): + pass + +class SafeStr_TestCase(BaseTestCase): + def setUp(self): + self.safestr = SafeStr() + self.unistr = u"ááááá" + self.enc_unistr = self.unistr.encode("utf-8") + self.asciistr = "aaaa" + self.bindata = b'\xff\xff\xfe' + self.test_object = TestClass() + self.test_object2 = TestClass2() + + def runTest(self): + self.safestr += self.asciistr + self.safestr += self.enc_unistr + self.safestr += self.unistr + self.safestr += self.bindata + self.safestr += self.test_object + self.safestr += self.test_object2 + + self.assertIn(self.asciistr, self.safestr) + + if PY == 2: + self.assertIn("OMITTED OBJECT WITHOUT __str__ METHOD", self.safestr) + # should be included twice -- appended enc_unistr and unistr + self.assertIn(str(self.enc_unistr), self.safestr) + else: + self.assertIn(" + + + + False + center-always + 600 + dialog + True + + + + True + False + vertical + + + True + False + start + center + 20 + 30 + + + True + False + gtk-dialog-warning + 5 + + + False + True + 7 + 0 + + + + + True + False + An unknown error has occurred + + + + + + + False + True + 1 + + + + + False + False + 0 + + + + + True + False + start + start + 40 + 40 + This program has encountered an unknown error. You may +report the bug below or quit the program. + + + False + True + 21 + 1 + + + + + True + False + start + 20 + 10 + end + + + _Report Bug + True + True + True + True + + + + False + True + 0 + + + + + _Quit + True + True + True + True + + + + False + True + 1 + + + + + False + True + 2 + + + + + True + True + 10 + 10 + 10 + True + + + + True + False + True + vertical + 6 + + + True + False + start + 2 + 0.10000000149011612 + The output below may help determine the cause of the error: + + + + + + False + True + 0 + + + + + True + True + True + in + + + True + True + natural + False + False + tracebackBuffer + + + + + True + True + 1 + + + + + True + False + 6 + + + True + False + 1 + 'Debug' may take you to tty1. + + + + + + + True + True + 0 + + + + + _Debug + True + True + True + True + + + + False + True + 1 + + + + + False + True + 2 + + + + + + + True + False + More _info... + True + + + + + False + True + 3 + + + + + + + No additional info available. + + diff --git a/pkgbuilds/python-meh/src/python-meh-r0.43-1/zanata.xml b/pkgbuilds/python-meh/src/python-meh-r0.43-1/zanata.xml new file mode 100644 index 0000000..a70990f --- /dev/null +++ b/pkgbuilds/python-meh/src/python-meh-r0.43-1/zanata.xml @@ -0,0 +1,106 @@ + + + https://fedora.zanata.org/ + python-meh + master + gettext + + + sq + ar + as + ast + bal + eu + bn + bn-IN + brx + bs + br + bg + ca + zh-CN + zh-HK + zh-TW + kw + kw-GB + cs + da + nl + en-GB + eo + et + fi + fr + gl + ka + de + el + gu + he + hi + hu + is + id + ia + it + ja + kn + kk + km + ky + ko + lt + nds + mk + mai + ms + ml + mr + mn + ne + nb + nn + or + pa + fa + pl + pt + pt-BR + ro + ru + sr + sr@latin + si + sk + sl + es + sv + tg + ta + te + bo + tr + uk + ur + wba + cy + lv + kw@uccor + kw@kkcor + af + am + be + hr + de-CH + th + vi + zu + ilo + nso + tw + yo + anp + + + diff --git a/pkgbuilds/python-simpleline/PKGBUILD b/pkgbuilds/python-simpleline/PKGBUILD new file mode 100644 index 0000000..144eace --- /dev/null +++ b/pkgbuilds/python-simpleline/PKGBUILD @@ -0,0 +1,27 @@ +# Maintainer: FWS +# Dépendance de l'installateur Anaconda (rhinstaller) — framework TUI texte. +# Pur Python (setuptools find_packages, aucune extension C) : on installe +# l'arborescence à la main pour éviter d'exiger python-build/python-installer. +pkgname=python-simpleline +pkgver=1.8 +pkgrel=1 +pkgdesc="Python3 text UI framework (dépendance Anaconda)" +arch=('any') +url="https://github.com/rhinstaller/python-simpleline" +license=('LGPL-3.0-or-later') +depends=('python' 'python-gobject') +_tag="simpleline-$pkgver" +source=("$pkgname-$pkgver.tar.gz::https://github.com/rhinstaller/python-simpleline/archive/refs/tags/$_tag.tar.gz") +sha256sums=('b58cfb3ac4166b8bbbd1d3789713dc364c50509a513ead7be66a237a5b3affa3') +_srcdir="python-simpleline-$_tag" + +package() { + cd "$srcdir/$_srcdir" + local sitedir + sitedir=$(python -c 'import site; print(site.getsitepackages()[0])') + install -d "$pkgdir$sitedir" + cp -a simpleline "$pkgdir$sitedir/simpleline" + # -d : grave le chemin d'exécution réel dans les .pyc (pas le $pkgdir de build). + python -m compileall -q -d "$sitedir/simpleline" "$pkgdir$sitedir/simpleline" || true + install -Dm644 LICENSE.md "$pkgdir/usr/share/licenses/$pkgname/LICENSE.md" +} diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/.BUILDINFO b/pkgbuilds/python-simpleline/pkg/python-simpleline/.BUILDINFO new file mode 100644 index 0000000..609eff9 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/.BUILDINFO @@ -0,0 +1,898 @@ +format = 2 +pkgname = python-simpleline +pkgbase = python-simpleline +pkgver = 1.8-1 +pkgarch = any +pkgbuild_sha256sum = 7502d64c9ab7b8658cf85b6919f95cec8bbdc1febca98f91b01de326450080ea +packager = Unknown Packager +builddate = 1781307804 +builddir = /home/nocode/Files/FWS-ISO/pkgbuilds/python-simpleline +startdir = /home/nocode/Files/FWS-ISO/pkgbuilds/python-simpleline +buildtool = makepkg +buildtoolver = 7.1.0 +buildenv = !distcc +buildenv = color +buildenv = !ccache +buildenv = check +buildenv = !sign +options = strip +options = docs +options = !libtool +options = !staticlibs +options = emptydirs +options = zipman +options = purge +options = debug +options = lto +installed = aardvark-dns-1.17.1-1-x86_64 +installed = abseil-cpp-20260107.1-1-x86_64 +installed = accountsservice-26.13.3-1-x86_64 +installed = acl-2.3.2-2-x86_64 +installed = adwaita-cursors-50.0-1-any +installed = adwaita-fonts-50.0-1-any +installed = adwaita-icon-theme-50.0-1-any +installed = adwaita-icon-theme-legacy-46.2-3-any +installed = alsa-card-profiles-1:1.6.6-1-x86_64 +installed = alsa-lib-1.2.16-1-x86_64 +installed = alsa-plugins-1:1.2.12-5-x86_64 +installed = alsa-topology-conf-1.2.5.1-4-any +installed = alsa-ucm-conf-1.2.16-2-any +installed = aom-3.14.1-1-x86_64 +installed = appstream-1.1.2-1-x86_64 +installed = aquamarine-0.12.1-1-x86_64 +installed = arch-install-scripts-31-1-any +installed = archiso-88-1-any +installed = archlinux-keyring-20260420-1-any +installed = argon2-20190702-6-x86_64 +installed = at-spi2-core-2.60.4-1-x86_64 +installed = atkmm-2.28.5-2-x86_64 +installed = attr-2.5.2-2-x86_64 +installed = audit-4.1.4-2-x86_64 +installed = autoconf-2.73-1-any +installed = automake-1.18.1-1-any +installed = avahi-1:0.9rc4-1-x86_64 +installed = base-3-3-any +installed = base-devel-1-2-any +installed = bash-5.3.15-1-x86_64 +installed = bemoji-0.4.0-1-any +installed = binutils-2.46+r70+g155188ea10a7-1-x86_64 +installed = bison-3.8.2-8-x86_64 +installed = blas-3.12.1-2-x86_64 +installed = bluez-libs-5.86-6-x86_64 +installed = boost-libs-1.91.0-1-x86_64 +installed = brightnessctl-0.5.1-3-x86_64 +installed = brotli-1.2.0-1-x86_64 +installed = bubblewrap-0.11.2-1-x86_64 +installed = bzip2-1.0.8-6-x86_64 +installed = c-ares-1.34.6-1-x86_64 +installed = ca-certificates-20240618-1-any +installed = ca-certificates-mozilla-3.124-1-x86_64 +installed = ca-certificates-utils-20240618-1-any +installed = cabextract-1.11-2-x86_64 +installed = cairo-1.18.4-1-x86_64 +installed = cairomm-1.14.6-1-x86_64 +installed = cairomm-1.16-1.18.1-1-x86_64 +installed = catatonit-0.2.1-2-x86_64 +installed = cblas-3.12.1-2-x86_64 +installed = cliphist-1:0.7.0-2-x86_64 +installed = clucene-2.3.3.4-17-x86_64 +installed = cmake-4.3.3-1-x86_64 +installed = compiler-rt-22.1.6-1-x86_64 +installed = composefs-1.0.8-1-x86_64 +installed = conmon-1:2.2.1-1-x86_64 +installed = containers-common-1:0.67.1-3-any +installed = coreutils-9.11-1-x86_64 +installed = cpio-2.15-3-x86_64 +installed = cppdap-1.58.0-3-x86_64 +installed = cracklib-2.10.3-1-x86_64 +installed = criu-4.2-3-x86_64 +installed = crun-1.28-1-x86_64 +installed = cryptsetup-2.8.6-1-x86_64 +installed = curl-8.20.0-7-x86_64 +installed = dav1d-1.5.3-1-x86_64 +installed = db5.3-5.3.28-7-x86_64 +installed = dbus-1.16.2-1-x86_64 +installed = dbus-broker-37-3-x86_64 +installed = dbus-broker-units-37-3-x86_64 +installed = dbus-units-37-3-x86_64 +installed = dconf-0.49.0-1-x86_64 +installed = debugedit-5.3-1-x86_64 +installed = default-cursors-3-1-any +installed = desktop-file-utils-0.28-1-x86_64 +installed = device-mapper-2.03.41-1-x86_64 +installed = diffutils-3.12-2-x86_64 +installed = discord-1:1.0.142-1-x86_64 +installed = dkms-3.4.1-1-any +installed = dos2unix-7.5.6-1-x86_64 +installed = dosfstools-4.2-5-x86_64 +installed = double-conversion-3.4.0-1-x86_64 +installed = duktape-2.7.0-7-x86_64 +installed = e2fsprogs-1.47.4-1-x86_64 +installed = efibootmgr-18-4-x86_64 +installed = efivar-39-2-x86_64 +installed = egl-gbm-1.1.3-1-x86_64 +installed = egl-wayland-4:1.1.21-1-x86_64 +installed = egl-wayland2-1.0.1-1-x86_64 +installed = egl-x11-1.0.5-1-x86_64 +installed = eglexternalplatform-1.2.1-1-any +installed = electron41-41.7.2-1-x86_64 +installed = elfutils-0.195-1-x86_64 +installed = erofs-utils-1.9.1-1-x86_64 +installed = exo-4.20.0-2-x86_64 +installed = expat-2.8.1-1-x86_64 +installed = extra-cmake-modules-6.26.0-1-any +installed = fakeroot-1:1.37.2-1-x86_64 +installed = fcft-3.3.3-1-x86_64 +installed = ffmpeg-2:8.1.1-2-x86_64 +installed = fftw-3.3.11-1-x86_64 +installed = file-5.48-1-x86_64 +installed = filesystem-2025.10.12-1-any +installed = findutils-4.10.0-3-x86_64 +installed = firefox-151.0.4-1-x86_64 +installed = flac-1.5.0-1-x86_64 +installed = flatpak-1:1.18.0-1-x86_64 +installed = flex-2.6.4-6-x86_64 +installed = fmt-12.1.0-2-x86_64 +installed = fontconfig-2:2.18.1-1-x86_64 +installed = freerdp-2:3.26.0-1-x86_64 +installed = freetype2-2.14.3-1-x86_64 +installed = fribidi-1.0.16-2-x86_64 +installed = fuse-common-3.18.2-1-x86_64 +installed = fuse2-2.9.9-5-x86_64 +installed = fuse3-3.18.2-1-x86_64 +installed = fuzzel-1.14.1-1-x86_64 +installed = gawk-5.4.0-1-x86_64 +installed = gc-8.2.12-1-x86_64 +installed = gcc-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = gcc-libs-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = gcr-3.41.2-2-x86_64 +installed = gcr-4-4.4.0.1-1-x86_64 +installed = gdb-17.2-1-x86_64 +installed = gdb-common-17.2-1-x86_64 +installed = gdbm-1.26-2-x86_64 +installed = gdk-pixbuf2-2.44.6-2-x86_64 +installed = gettext-1.0-2-x86_64 +installed = giflib-6.1.3-1-x86_64 +installed = git-2.54.0-1-x86_64 +installed = glib-networking-1:2.80.1-1-x86_64 +installed = glib2-2.88.1-1-x86_64 +installed = glibc-2.43+r22+g8362e8ce10b2-2-x86_64 +installed = glibmm-2.66.8-2-x86_64 +installed = glibmm-2.68-2.88.0-2-x86_64 +installed = glslang-1:1.4.350.0-1-x86_64 +installed = glycin-2.1.1-1-x86_64 +installed = gmp-6.3.0-3-x86_64 +installed = gnome-themes-extra-1:3.28-1-any +installed = gnulib-l10n-20241231-1-any +installed = gnupg-2.4.9-1-x86_64 +installed = gnutls-3.8.13-2-x86_64 +installed = go-2:1.26.4-1-x86_64 +installed = gobject-introspection-1.86.0-2-x86_64 +installed = gobject-introspection-runtime-1.86.0-2-x86_64 +installed = gparted-1.8.1-2-x86_64 +installed = gperftools-2.18.1-1-x86_64 +installed = gpgme-2.1.0-1-x86_64 +installed = gpgmepp-2.1.0-1-x86_64 +installed = gpm-1.20.7.r38.ge82d1a6-6-x86_64 +installed = gpsd-3.27.5-1-x86_64 +installed = gptfdisk-1.0.10-2-x86_64 +installed = graphene-1.10.8-2-x86_64 +installed = graphite-1:1.3.15-1-x86_64 +installed = grep-3.12-2-x86_64 +installed = grim-1.5.0-2-x86_64 +installed = groff-1.24.1-1-x86_64 +installed = grub-2:2.14-1-x86_64 +installed = gsettings-desktop-schemas-50.1-1-any +installed = gsettings-system-schemas-50.1-1-any +installed = gsm-1.0.24-1-x86_64 +installed = gssdp-1.6.5-1-x86_64 +installed = gst-plugins-bad-libs-1.28.3-1-x86_64 +installed = gst-plugins-base-libs-1.28.3-1-x86_64 +installed = gstreamer-1.28.3-1-x86_64 +installed = gtest-1.17.0-2-x86_64 +installed = gtk-layer-shell-0.10.1-1-x86_64 +installed = gtk-update-icon-cache-1:4.22.4-1-x86_64 +installed = gtk3-1:3.24.52-1-x86_64 +installed = gtk4-1:4.22.4-1-x86_64 +installed = gtkmm-4.0-4.22.0-2-x86_64 +installed = gtkmm3-3.24.11-1-x86_64 +installed = guile-3.0.11-1-x86_64 +installed = gupnp-1:1.6.10-1-x86_64 +installed = gupnp-igd-1.6.0-2-x86_64 +installed = gzip-1.14-2-x86_64 +installed = harfbuzz-14.2.1-1-x86_64 +installed = harfbuzz-icu-14.2.1-1-x86_64 +installed = hicolor-icon-theme-0.18-1-any +installed = hidapi-0.15.0-1-x86_64 +installed = highway-1.4.0-1-x86_64 +installed = hunspell-1.7.3-1-x86_64 +installed = hwdata-0.408-1-any +installed = hwloc-2.13.0-1-x86_64 +installed = hyphen-2.8.9-1-x86_64 +installed = hyprcursor-0.1.13-6-x86_64 +installed = hyprgraphics-0.5.1-2-x86_64 +installed = hypridle-0.1.7-9-x86_64 +installed = hyprland-0.55.4-1-x86_64 +installed = hyprland-guiutils-0.2.1-6-x86_64 +installed = hyprland-qt-support-0.1.0-12-x86_64 +installed = hyprlang-0.6.8-4-x86_64 +installed = hyprlock-0.9.5-4-x86_64 +installed = hyprpaper-0.8.4-2-x86_64 +installed = hyprpicker-0.4.7-1-x86_64 +installed = hyprpolkitagent-0.1.3-7-x86_64 +installed = hyprshot-1.3.0-4-any +installed = hyprtoolkit-0.5.4-2-x86_64 +installed = hyprutils-0.13.1-1-x86_64 +installed = hyprwayland-scanner-0.4.6-1-x86_64 +installed = hyprwire-0.3.1-2-x86_64 +installed = iana-etc-20260530-1-any +installed = icu-78.3-1-x86_64 +installed = imagemagick-7.1.2.25-1-x86_64 +installed = iniparser-4.2.6-2-x86_64 +installed = iproute2-7.0.0-1-x86_64 +installed = iptables-1:1.8.13-1-x86_64 +installed = iputils-20250605-1-x86_64 +installed = iso-codes-4.20.1-1-any +installed = jack2-1.9.22-2-x86_64 +installed = jansson-2.15.0-1-x86_64 +installed = jbigkit-2.1-8-x86_64 +installed = jq-1.8.1-3-x86_64 +installed = json-c-0.18-2-x86_64 +installed = json-glib-1.10.8-1-x86_64 +installed = jsoncpp-1.9.6-3-x86_64 +installed = kbd-2.10.0-1-x86_64 +installed = kcoreaddons-6.26.0-1-x86_64 +installed = keyutils-1.6.3-4-x86_64 +installed = ki18n-6.26.0-1-x86_64 +installed = kitty-0.47.1-1-x86_64 +installed = kitty-shell-integration-0.47.1-1-x86_64 +installed = kitty-terminfo-0.47.1-1-x86_64 +installed = kmod-34.2-1-x86_64 +installed = kpmcore-26.04.2-1-x86_64 +installed = krb5-1.22.2-1-x86_64 +installed = kwidgetsaddons-6.26.0-1-x86_64 +installed = l-smash-2.14.5-4-x86_64 +installed = lame-3.101.r6531-1-x86_64 +installed = lapack-3.12.1-2-x86_64 +installed = lcms2-2.19.1-1-x86_64 +installed = leancrypto-1.7.2-1-x86_64 +installed = lib32-alsa-lib-1.2.16-1-x86_64 +installed = lib32-alsa-plugins-1.2.12-1-x86_64 +installed = lib32-brotli-1.1.0-1-x86_64 +installed = lib32-bzip2-1.0.8-4-x86_64 +installed = lib32-curl-8.20.0-7-x86_64 +installed = lib32-dbus-1.16.2-1-x86_64 +installed = lib32-e2fsprogs-1.47.4-1-x86_64 +installed = lib32-expat-2.8.1-1-x86_64 +installed = lib32-fontconfig-2:2.18.1-1-x86_64 +installed = lib32-freetype2-2.14.3-1-x86_64 +installed = lib32-gcc-libs-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = lib32-glib2-2.88.1-1-x86_64 +installed = lib32-glibc-2.43+r22+g8362e8ce10b2-2-x86_64 +installed = lib32-gmp-6.3.0-2-x86_64 +installed = lib32-gnutls-3.8.13-3-x86_64 +installed = lib32-icu-78.3-1-x86_64 +installed = lib32-json-c-0.18-2-x86_64 +installed = lib32-keyutils-1.6.3-4-x86_64 +installed = lib32-krb5-1.22.2-1-x86_64 +installed = lib32-libdrm-2.4.134-1-x86_64 +installed = lib32-libelf-0.195-1-x86_64 +installed = lib32-libffi-3.5.2-1-x86_64 +installed = lib32-libgcrypt-1.12.2-1-x86_64 +installed = lib32-libglvnd-1.7.0-1-x86_64 +installed = lib32-libgpg-error-1.61-1-x86_64 +installed = lib32-libidn2-2.3.8-1-x86_64 +installed = lib32-libldap-2.6.13-1-x86_64 +installed = lib32-libnghttp2-1.69.0-1-x86_64 +installed = lib32-libnghttp3-1.16.0-1-x86_64 +installed = lib32-libngtcp2-1.23.0-1-x86_64 +installed = lib32-libnm-1.56.1-1-x86_64 +installed = lib32-libpciaccess-0.19-1-x86_64 +installed = lib32-libpipewire-1:1.6.6-1-x86_64 +installed = lib32-libpng-1.6.58-1-x86_64 +installed = lib32-libpsl-0.21.5-1-x86_64 +installed = lib32-libssh2-1.11.1-1-x86_64 +installed = lib32-libtasn1-4.21.0-1-x86_64 +installed = lib32-libunistring-1.4.2-1-x86_64 +installed = lib32-libva-2.22.0-1-x86_64 +installed = lib32-libx11-1.8.13-1-x86_64 +installed = lib32-libxau-1.0.12-1-x86_64 +installed = lib32-libxcb-1.17.0-1-x86_64 +installed = lib32-libxcrypt-4.5.2-1-x86_64 +installed = lib32-libxcrypt-compat-4.5.2-1-x86_64 +installed = lib32-libxdmcp-1.1.5-1-x86_64 +installed = lib32-libxext-1.3.7-1-x86_64 +installed = lib32-libxfixes-6.0.1-2-x86_64 +installed = lib32-libxinerama-1.1.6-1-x86_64 +installed = lib32-libxml2-2.15.3-1-x86_64 +installed = lib32-libxshmfence-1.3.3-1-x86_64 +installed = lib32-libxss-1.2.5-1-x86_64 +installed = lib32-libxxf86vm-1.1.5-2-x86_64 +installed = lib32-llvm-libs-1:22.1.6-1-x86_64 +installed = lib32-lm_sensors-1:3.6.2-2-x86_64 +installed = lib32-mesa-1:26.1.2-1-x86_64 +installed = lib32-ncurses-6.6-2-x86_64 +installed = lib32-nettle-4.0-2-x86_64 +installed = lib32-nspr-4.39-1-x86_64 +installed = lib32-nss-3.124-1-x86_64 +installed = lib32-nvidia-utils-610.43.02-1-x86_64 +installed = lib32-openssl-1:3.6.3-1-x86_64 +installed = lib32-p11-kit-0.26.2-1-x86_64 +installed = lib32-pcre2-10.47-1-x86_64 +installed = lib32-pipewire-1:1.6.6-1-x86_64 +installed = lib32-spirv-tools-1:1.4.350.0-1-x86_64 +installed = lib32-sqlite-3.53.2-1-x86_64 +installed = lib32-systemd-260.2-1-x86_64 +installed = lib32-util-linux-2.42.1-1-x86_64 +installed = lib32-vulkan-icd-loader-1.4.350.0-1-x86_64 +installed = lib32-wayland-1.25.0-1-x86_64 +installed = lib32-xz-5.8.3-1-x86_64 +installed = lib32-zlib-1.3.2-1-x86_64 +installed = lib32-zstd-1.5.7-2-x86_64 +installed = libabw-0.1.4-1-x86_64 +installed = libadwaita-1:1.9.1-1-x86_64 +installed = libaio-0.3.113-4-x86_64 +installed = libappindicator-12.10.1-1-x86_64 +installed = libarchive-3.8.7-1-x86_64 +installed = libasan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libass-0.17.4-2-x86_64 +installed = libassuan-3.0.0-1-x86_64 +installed = libasyncns-1:0.8+r3+g68cd5af-3-x86_64 +installed = libatomic-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libatomic_ops-7.8.2-2-x86_64 +installed = libavc1394-0.5.4-7-x86_64 +installed = libavif-1.4.2-1-x86_64 +installed = libb2-0.98.1-3-x86_64 +installed = libblake3-1.8.4-1-x86_64 +installed = libbluray-1.4.1-1-x86_64 +installed = libbpf-1.7.0-1-x86_64 +installed = libbs2b-3.1.0-10-x86_64 +installed = libbsd-0.12.2-2-x86_64 +installed = libburn-1.5.8-1-x86_64 +installed = libcanberra-1:0.30+r2+gc0620e4-6-x86_64 +installed = libcap-2.78-1-x86_64 +installed = libcap-ng-0.9.3-1-x86_64 +installed = libcbor-0.14.0-1-x86_64 +installed = libcdio-2.3.0-1-x86_64 +installed = libcdio-paranoia-10.2+2.0.2-2-x86_64 +installed = libcdr-0.1.9-1-x86_64 +installed = libcloudproviders-0.4.0-1-x86_64 +installed = libcmis-0.6.3-1-x86_64 +installed = libcolord-1.4.8-1-x86_64 +installed = libcups-2:2.4.19-1-x86_64 +installed = libdaemon-0.14-6-x86_64 +installed = libdatrie-0.2.14-1-x86_64 +installed = libdbusmenu-glib-18.10.20180917-1-x86_64 +installed = libdbusmenu-gtk3-18.10.20180917-1-x86_64 +installed = libdecor-0.2.5-1-x86_64 +installed = libdeflate-1.25-1-x86_64 +installed = libdisplay-info-0.3.0-1-x86_64 +installed = libdovi-3.3.2-1-x86_64 +installed = libdrm-2.4.134-1-x86_64 +installed = libdvdnav-7.0.0-1-x86_64 +installed = libdvdread-7.0.1-1-x86_64 +installed = libe-book-0.1.3-20-x86_64 +installed = libebur128-1.2.6-2-x86_64 +installed = libedit-20260512_3.1-1-x86_64 +installed = libei-1.6.0-1-x86_64 +installed = libelf-0.195-1-x86_64 +installed = libepoxy-1.5.10-3-x86_64 +installed = libepubgen-0.1.1-6-x86_64 +installed = libetonyek-0.1.13-2-x86_64 +installed = libevdev-1.13.6-1-x86_64 +installed = libevent-2.1.12-5-x86_64 +installed = libexif-0.6.26-1-x86_64 +installed = libexttextcat-3.4.8-1-x86_64 +installed = libfdk-aac-2.0.3-2-x86_64 +installed = libffi-3.5.2-1-x86_64 +installed = libfido2-1.17.0-1-x86_64 +installed = libfontenc-1.1.9-1-x86_64 +installed = libfreeaptx-0.2.2-1-x86_64 +installed = libfreehand-0.1.3-1-x86_64 +installed = libfyaml-0.9.6-2-x86_64 +installed = libgcc-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libgcrypt-1.12.2-1-x86_64 +installed = libgfortran-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libgirepository-1.86.0-2-x86_64 +installed = libgit2-1:1.9.4-1-x86_64 +installed = libglvnd-1.7.0-3-x86_64 +installed = libgomp-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libgpg-error-1.61-1-x86_64 +installed = libgtop-2.41.3-2-x86_64 +installed = libgudev-238-3-x86_64 +installed = libice-1.1.2-1-x86_64 +installed = libidn2-2.3.8-1-x86_64 +installed = libiec61883-1.2.0-9-x86_64 +installed = libimobiledevice-1.4.0-2-x86_64 +installed = libimobiledevice-glue-1.3.2-1-x86_64 +installed = libinih-62-2-x86_64 +installed = libinput-1.31.3-1-x86_64 +installed = libisl-0.27-1-x86_64 +installed = libisoburn-1.5.8.2-1-x86_64 +installed = libisofs-1.5.8.2-1-x86_64 +installed = libixion-0.20.0-7-x86_64 +installed = libjpeg-turbo-3.1.4.1-1-x86_64 +installed = libjxl-0.11.2-2-x86_64 +installed = libksba-1.8.0-1-x86_64 +installed = liblangtag-0.6.8-1-x86_64 +installed = liblc3-1.1.3-2-x86_64 +installed = libldac-2.0.2.3-3-x86_64 +installed = libldap-2.6.13-1-x86_64 +installed = liblqr-0.4.3-1-x86_64 +installed = liblsan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libmakepkg-dropins-20-1-any +installed = libmalcontent-0.14.0-4-x86_64 +installed = libmd-1.2.0-1-x86_64 +installed = libmm-glib-1.24.2-1-x86_64 +installed = libmnl-1.0.5-2-x86_64 +installed = libmodplug-0.8.9.0-7-x86_64 +installed = libmpc-1.4.1-1-x86_64 +installed = libmpdclient-2.23-1-x86_64 +installed = libmspub-0.1.5-1-x86_64 +installed = libmwaw-0.3.22-4-x86_64 +installed = libmysofa-1.3.4-1-x86_64 +installed = libndp-1.9-1-x86_64 +installed = libnet-2:1.3-2-x86_64 +installed = libnetfilter_conntrack-1.1.1-1-x86_64 +installed = libnewt-0.52.25-2-x86_64 +installed = libnfnetlink-1.0.2-2-x86_64 +installed = libnftnl-1.3.1-1-x86_64 +installed = libnghttp2-1.69.0-1-x86_64 +installed = libnghttp3-1.16.0-1-x86_64 +installed = libngtcp2-1.23.0-1-x86_64 +installed = libnice-0.1.23-1-x86_64 +installed = libnl-3.12.0-1-x86_64 +installed = libnm-1.56.1-1-x86_64 +installed = libnma-1.10.6-3-x86_64 +installed = libnma-common-1.10.6-3-x86_64 +installed = libnotify-0.8.8-1-x86_64 +installed = libnsl-2.0.1-2-x86_64 +installed = libnumbertext-1.0.11-3-x86_64 +installed = libobjc-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libodfgen-0.1.8-5-x86_64 +installed = libogg-1.3.6-1-x86_64 +installed = libopenmpt-0.8.7-1-x86_64 +installed = libopenrazer-0.4.0-1-x86_64 +installed = liborcus-0.21.0-6-x86_64 +installed = libp11-kit-0.26.2-1-x86_64 +installed = libpagemaker-0.0.4-5-x86_64 +installed = libpcap-1.10.6-1-x86_64 +installed = libpciaccess-0.19-1-x86_64 +installed = libpgm-5.3.128-4-x86_64 +installed = libpipewire-1:1.6.6-1-x86_64 +installed = libplacebo-7.360.1-2-x86_64 +installed = libplist-2.7.0-3-x86_64 +installed = libpng-1.6.58-1-x86_64 +installed = libproxy-0.5.12-1-x86_64 +installed = libpsl-0.21.5-2-x86_64 +installed = libpulse-17.0+r98+gb096704c0-1-x86_64 +installed = libpwquality-1.4.5-7-x86_64 +installed = libquadmath-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libqxp-0.0.3-1-x86_64 +installed = libraqm-0.10.5-1-x86_64 +installed = libraw1394-2.1.2-4-x86_64 +installed = libreoffice-fresh-26.2.4-1-x86_64 +installed = librevenge-0.0.5-4-x86_64 +installed = librsvg-2:2.62.3-1-x86_64 +installed = librsync-1:2.3.4-2-x86_64 +installed = libsamplerate-0.2.2-3-x86_64 +installed = libsasl-2.1.28-5-x86_64 +installed = libseccomp-2.6.0-1-x86_64 +installed = libsecret-0.21.7-1-x86_64 +installed = libsigc++-2.12.2-1-x86_64 +installed = libsigc++-3.0-3.8.1-1-x86_64 +installed = libsixel-1.10.5-1-x86_64 +installed = libsm-1.2.6-1-x86_64 +installed = libsndfile-1.2.2-4-x86_64 +installed = libsodium-1.0.22-1-x86_64 +installed = libsoup3-3.6.6-2-x86_64 +installed = libsoxr-0.1.3-4-x86_64 +installed = libssh-0.12.0-1-x86_64 +installed = libssh2-1.11.1-1-x86_64 +installed = libstaroffice-0.0.7-5-x86_64 +installed = libstdc++-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libstemmer-3.1.1-1-x86_64 +installed = libsysprof-capture-50.0-2-x86_64 +installed = libtasn1-4.21.0-1-x86_64 +installed = libtatsu-1.0.5-1-x86_64 +installed = libteam-1.32-3-x86_64 +installed = libthai-0.1.30-1-x86_64 +installed = libtheora-1.2.0-1-x86_64 +installed = libtiff-4.7.1-2-x86_64 +installed = libtirpc-1.3.7-1-x86_64 +installed = libtommath-1.3.0-2-x86_64 +installed = libtool-2.6.1-1-x86_64 +installed = libtsan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libubsan-16.1.1+r12+g301eb08fa2c5-1-x86_64 +installed = libunibreak-7.0-1-x86_64 +installed = libunistring-1.4.2-1-x86_64 +installed = libunwind-1.8.2-1-x86_64 +installed = liburing-2.14-1-x86_64 +installed = libusb-1.0.30-1-x86_64 +installed = libusbmuxd-2.1.1-2-x86_64 +installed = libutf8proc-2.11.3-1-x86_64 +installed = libuv-1.52.1-1-x86_64 +installed = libva-2.23.0-1-x86_64 +installed = libva-nvidia-driver-0.0.17-1-x86_64 +installed = libvdpau-1.5-4-x86_64 +installed = libverto-0.3.2-6-x86_64 +installed = libvisio-0.1.11-1-x86_64 +installed = libvorbis-1.3.7-4-x86_64 +installed = libvpl-2.16.0-2-x86_64 +installed = libvpx-1.16.0-3-x86_64 +installed = libwacom-2.19.0-1-x86_64 +installed = libwebp-1.6.0-2-x86_64 +installed = libwireplumber-0.5.14-1-x86_64 +installed = libwpd-0.10.3-6-x86_64 +installed = libwps-0.4.14-4-x86_64 +installed = libx11-1.8.13-1-x86_64 +installed = libxau-1.0.12-1-x86_64 +installed = libxcb-1.17.0-1-x86_64 +installed = libxcomposite-0.4.7-1-x86_64 +installed = libxcrypt-4.5.2-1-x86_64 +installed = libxcrypt-compat-4.5.2-1-x86_64 +installed = libxcursor-1.2.3-1-x86_64 +installed = libxcvt-0.1.3-1-x86_64 +installed = libxdamage-1.1.7-1-x86_64 +installed = libxdmcp-1.1.5-2-x86_64 +installed = libxext-1.3.7-1-x86_64 +installed = libxfce4ui-4.20.2-1-x86_64 +installed = libxfce4util-4.20.1-1-x86_64 +installed = libxfixes-6.0.2-1-x86_64 +installed = libxfont2-2.0.7-1-x86_64 +installed = libxft-2.3.9-1-x86_64 +installed = libxi-1.8.3-1-x86_64 +installed = libxinerama-1.1.6-1-x86_64 +installed = libxkbcommon-1.13.2-1-x86_64 +installed = libxkbcommon-x11-1.13.2-1-x86_64 +installed = libxkbfile-1.2.0-1-x86_64 +installed = libxml2-2.15.3-1-x86_64 +installed = libxml2-legacy-2.13.9-2-x86_64 +installed = libxmlb-0.3.27-1-x86_64 +installed = libxmp-4.7.0-1-x86_64 +installed = libxmu-1.3.1-1-x86_64 +installed = libxpresent-1.0.2-1-x86_64 +installed = libxrandr-1.5.5-1-x86_64 +installed = libxrender-0.9.12-1-x86_64 +installed = libxshmfence-1.3.3-1-x86_64 +installed = libxslt-1.1.45-2-x86_64 +installed = libxss-1.2.5-1-x86_64 +installed = libxt-1.3.1-1-x86_64 +installed = libxtst-1.2.5-1-x86_64 +installed = libxv-1.0.13-1-x86_64 +installed = libxxf86vm-1.1.7-1-x86_64 +installed = libyaml-0.2.5-3-x86_64 +installed = libyuv-r2426+464c51a03-1-x86_64 +installed = libzip-1.11.4-1-x86_64 +installed = libzmf-0.0.2-20-x86_64 +installed = licenses-20240728-1-any +installed = lilv-0.26.4-1-x86_64 +installed = linux-7.0.11.arch1-1-x86_64 +installed = linux-api-headers-7.0-1-x86_64 +installed = linux-firmware-20260519-1-any +installed = linux-firmware-amdgpu-20260519-1-any +installed = linux-firmware-atheros-20260519-1-any +installed = linux-firmware-broadcom-20260519-1-any +installed = linux-firmware-cirrus-20260519-1-any +installed = linux-firmware-intel-20260519-1-any +installed = linux-firmware-mediatek-20260519-1-any +installed = linux-firmware-nvidia-20260519-1-any +installed = linux-firmware-other-20260519-1-any +installed = linux-firmware-radeon-20260519-1-any +installed = linux-firmware-realtek-20260519-1-any +installed = linux-firmware-whence-20260519-1-any +installed = linux-headers-7.0.11.arch1-1-x86_64 +installed = lld-22.1.6-1-x86_64 +installed = llhttp-9.3.1-1-x86_64 +installed = llvm-libs-22.1.6-1-x86_64 +installed = lm_sensors-1:3.6.2-1-x86_64 +installed = lmdb-0.9.35-1-x86_64 +installed = lpsolve-5.5.2.14-1-x86_64 +installed = lsb-release-2.0.r55.a25a4fc-1-any +installed = lsof-4.99.6-1-x86_64 +installed = lua-5.5.0-2-x86_64 +installed = lua54-5.4.8-6-x86_64 +installed = luajit-2.1.1780076327+b925b3e-1-x86_64 +installed = lug-helper-1:4.13-1-any +installed = lv2-1.18.10-2-x86_64 +installed = lz4-1:1.10.0-2-x86_64 +installed = lzo-2.10-5-x86_64 +installed = m4-1.4.21-2-x86_64 +installed = mailcap-2.1.54-2-any +installed = make-4.4.1-3-x86_64 +installed = mako-1.11.0-1-x86_64 +installed = md4c-0.5.3-1-x86_64 +installed = mesa-1:26.1.2-1-x86_64 +installed = meson-1.11.1-3-any +installed = mingw-w64-binutils-2.46.0-1-x86_64 +installed = mingw-w64-crt-14.0.0-1-any +installed = mingw-w64-gcc-16.1.0-1-x86_64 +installed = mingw-w64-headers-14.0.0-1-any +installed = mingw-w64-winpthreads-14.0.0-1-any +installed = minizip-1:1.3.2-3-x86_64 +installed = mkinitcpio-41-4-any +installed = mkinitcpio-busybox-1.36.1-1-x86_64 +installed = mobile-broadband-provider-info-20251101-1-any +installed = mpdecimal-4.0.1-3-x86_64 +installed = mpfr-4.2.2-1-x86_64 +installed = mpg123-1.33.5-1-x86_64 +installed = mpv-1:0.41.0-3-x86_64 +installed = mpvpaper-1.8-1-x86_64 +installed = mtdev-1.1.7-1-x86_64 +installed = mtools-1:4.0.49-1-x86_64 +installed = mujs-1.3.9-1-x86_64 +installed = muparser-2.3.5-2-x86_64 +installed = nano-9.0-1-x86_64 +installed = ncurses-6.6-2-x86_64 +installed = neon-0.37.1-1-x86_64 +installed = netavark-1.17.2-2-x86_64 +installed = nettle-4.0-1-x86_64 +installed = network-manager-applet-1.36.0-2-x86_64 +installed = networkmanager-1.56.1-1-x86_64 +installed = nftables-1:1.1.6-3-x86_64 +installed = ninja-1.13.2-3-x86_64 +installed = nm-connection-editor-1.36.0-2-x86_64 +installed = noto-fonts-1:2026.06.01-1-any +installed = noto-fonts-cjk-20240730-1-any +installed = noto-fonts-emoji-1:2.051-1-any +installed = noto-fonts-extra-1:2026.06.01-1-any +installed = npth-1.8-1-x86_64 +installed = nspr-4.39-1-x86_64 +installed = nss-3.124-1-x86_64 +installed = nvidia-open-610.43.02-2-x86_64 +installed = nvidia-utils-610.43.02-2-x86_64 +installed = ocl-icd-2.3.4-1-x86_64 +installed = onetbb-2023.0.0-1-x86_64 +installed = oniguruma-6.9.10-1-x86_64 +installed = openal-1.25.2-1-x86_64 +installed = opencore-amr-0.1.6-2-x86_64 +installed = openjpeg2-2.5.4-1-x86_64 +installed = openrazer-daemon-3.12.2-2-any +installed = openrazer-driver-dkms-3.12.2-2-any +installed = openssh-10.3p1-1-x86_64 +installed = openssl-3.6.3-1-x86_64 +installed = opus-1.6.1-1-x86_64 +installed = opusfile-0.12-4-x86_64 +installed = orc-0.4.42-1-x86_64 +installed = os-prober-1.84-1-x86_64 +installed = ostree-2025.7-3-x86_64 +installed = p11-kit-0.26.2-1-x86_64 +installed = pacman-7.1.0.r9.g54d9411-2-x86_64 +installed = pacman-mirrorlist-20260610-1-any +installed = pahole-1:1.31-2-x86_64 +installed = pam-1.7.2-2-x86_64 +installed = pambase-20250719-1-any +installed = pango-1:1.57.1-1-x86_64 +installed = pangomm-2.46.4-3-x86_64 +installed = pangomm-2.48-2.56.1-2-x86_64 +installed = papirus-icon-theme-20250501-1-any +installed = parted-3.7-1-x86_64 +installed = paru-2.1.0-2-x86_64 +installed = paru-debug-2.1.0-2-x86_64 +installed = passt-2026_05_26.038c51e-1-x86_64 +installed = patch-2.8-1-x86_64 +installed = pavucontrol-1:6.2-1-x86_64 +installed = pciutils-3.15.0-1-x86_64 +installed = pcre-8.45-4-x86_64 +installed = pcre2-10.47-1-x86_64 +installed = pcsclite-2.5.1-1-x86_64 +installed = perl-5.42.2-1-x86_64 +installed = perl-error-0.17030-3-any +installed = perl-mailtools-2.22-3-any +installed = perl-timedate-2.35-1-any +installed = pinentry-1.3.2-2-x86_64 +installed = pipewire-1:1.6.6-1-x86_64 +installed = pipewire-audio-1:1.6.6-1-x86_64 +installed = pipewire-pulse-1:1.6.6-1-x86_64 +installed = pixman-0.46.4-1-x86_64 +installed = pkgconf-2.5.1-1-x86_64 +installed = playerctl-2.4.1-5-x86_64 +installed = podman-5.8.3-1-x86_64 +installed = podman-compose-1.6.0-1-any +installed = podman-desktop-1.27.2-2-x86_64 +installed = polkit-127-3-x86_64 +installed = polkit-qt6-0.201.1-1-x86_64 +installed = poppler-26.05.0-1-x86_64 +installed = popt-1.19-2-x86_64 +installed = portaudio-1:19.7.0-4-x86_64 +installed = portmidi-1:2.0.8-1-x86_64 +installed = pps-tools-1.0.3-2-x86_64 +installed = procps-ng-4.0.6-1-x86_64 +installed = protobuf-35.0-1-x86_64 +installed = protobuf-c-1.5.2-10-x86_64 +installed = psmisc-23.7-2-x86_64 +installed = pugixml-1.15-3-x86_64 +installed = python-3.14.5-1-x86_64 +installed = python-attrs-26.1.0-1-any +installed = python-autocommand-2.2.2-9-any +installed = python-cffi-2.0.0-2-x86_64 +installed = python-click-8.3.3-1-any +installed = python-cryptography-48.0.1-1-x86_64 +installed = python-daemonize-2.5.0-10-any +installed = python-dbus-1.4.0-2-x86_64 +installed = python-dotenv-1.2.2-1-any +installed = python-filelock-3.29.0-1-any +installed = python-gobject-3.56.3-1-x86_64 +installed = python-jaraco.collections-5.1.0-3-any +installed = python-jaraco.context-6.1.2-1-any +installed = python-jaraco.functools-4.1.0-3-any +installed = python-jaraco.text-4.0.0-4-any +installed = python-mako-1.3.11-1-any +installed = python-markdown-3.10.2-1-any +installed = python-markupsafe-3.0.3-1-x86_64 +installed = python-more-itertools-11.1.0-1-any +installed = python-numpy-2.4.6-1-x86_64 +installed = python-openrazer-3.12.2-2-any +installed = python-packaging-26.2-1-any +installed = python-pip-26.1.2-1-any +installed = python-pkg_resources-81.0.0-1-any +installed = python-platformdirs-4.10.0-1-any +installed = python-protobuf-35.0-1-x86_64 +installed = python-pycparser-3.00-1-any +installed = python-pygame-2.6.1-5-x86_64 +installed = python-pyudev-0.24.4-1-any +installed = python-setproctitle-1.3.7-2-x86_64 +installed = python-setuptools-1:82.0.1-1-any +installed = python-tqdm-4.68.1-1-any +installed = python-typing_extensions-4.15.0-3-any +installed = python-wheel-0.47.0-1-any +installed = python-yaml-6.0.3-2-x86_64 +installed = qt5-base-5.15.19+kde+r96-1-x86_64 +installed = qt5-declarative-5.15.19+kde+r23-1-x86_64 +installed = qt5-graphicaleffects-5.15.19-1-x86_64 +installed = qt5-quickcontrols2-5.15.19+kde+r5-1-x86_64 +installed = qt5-svg-5.15.19+kde+r5-1-x86_64 +installed = qt5-translations-5.15.19-1-any +installed = qt5-wayland-5.15.19+kde+r55-1-x86_64 +installed = qt6-5compat-6.11.1-1-x86_64 +installed = qt6-base-6.11.1-1-x86_64 +installed = qt6-declarative-6.11.1-3-x86_64 +installed = qt6-shadertools-6.11.1-1-x86_64 +installed = qt6-svg-6.11.1-1-x86_64 +installed = qt6-tools-6.11.1-1-x86_64 +installed = qt6-translations-6.11.1-1-any +installed = qt6-wayland-6.11.1-1-x86_64 +installed = raptor-2.0.16-9-x86_64 +installed = rasqal-1:0.9.33-9-x86_64 +installed = rav1e-0.8.1-2-x86_64 +installed = razergenie-1.3.0-1-x86_64 +installed = re2-2:2025.11.05-4-x86_64 +installed = readline-8.3.003-1-x86_64 +installed = redland-1:1.0.17-10-x86_64 +installed = reflector-2023-5-any +installed = resvg-0.47.0-2-x86_64 +installed = rhash-1.4.6-1-x86_64 +installed = rsync-3.4.4-1-x86_64 +installed = rtkit-0.14-1-x86_64 +installed = rubberband-4.0.0-2-x86_64 +installed = rustup-1.29.0-2-x86_64 +installed = sbc-2.2-1-x86_64 +installed = scdoc-1.11.4-1-x86_64 +installed = sdbus-cpp-2.3.1-1-x86_64 +installed = sddm-0.21.0-7-x86_64 +installed = sddm-catppuccin-git-r42.10831de-1-any +installed = sdl2-compat-2.32.70-1-x86_64 +installed = sdl2_image-2.8.12-1-x86_64 +installed = sdl2_mixer-2.8.2-1-x86_64 +installed = sdl2_ttf-2.24.0-2-x86_64 +installed = sdl3-3.4.10-1-x86_64 +installed = sdl3_ttf-3.2.2-3-x86_64 +installed = seatd-0.9.3-1-x86_64 +installed = sed-4.10-1-x86_64 +installed = serd-0.32.10-1-x86_64 +installed = shaderc-2026.2-1-x86_64 +installed = shadow-4.18.0-1-x86_64 +installed = shared-mime-info-2.4-3-x86_64 +installed = slang-2.3.3-4-x86_64 +installed = slurp-1.5.0-2-x86_64 +installed = smartmontools-7.5-1-x86_64 +installed = snappy-1.2.2-3-x86_64 +installed = sndio-1.10.0-1-x86_64 +installed = sord-0.16.22-1-x86_64 +installed = sound-theme-freedesktop-0.8-6-any +installed = source-highlight-3.1.9-18-x86_64 +installed = spandsp-0.0.6-7-x86_64 +installed = spdlog-1.17.0-2-x86_64 +installed = speex-1.2.1-2-x86_64 +installed = speexdsp-1.2.1-2-x86_64 +installed = spirv-tools-1:1.4.350.0-1-x86_64 +installed = sqlite-3.53.2-1-x86_64 +installed = squashfs-tools-4.7.5-1-x86_64 +installed = sratom-0.6.22-1-x86_64 +installed = srt-1.5.5-1-x86_64 +installed = startup-notification-0.12-9-x86_64 +installed = steam-1.0.0.85-7-x86_64 +installed = steam-devices-1.0.0.85-7-x86_64 +installed = sudo-1.9.17.p2-2-x86_64 +installed = svt-av1-4.1.0-1-x86_64 +installed = systemd-260.2-2-x86_64 +installed = systemd-libs-260.2-2-x86_64 +installed = systemd-sysvcompat-260.2-2-x86_64 +installed = tar-1.35-2-x86_64 +installed = tcl-8.6.16-1-x86_64 +installed = tdb-1.4.15-1-x86_64 +installed = texinfo-7.3-1-x86_64 +installed = thunar-4.20.8-3-x86_64 +installed = tinysparql-3.11.1-1-x86_64 +installed = tk-8.6.16-1-x86_64 +installed = tomlplusplus-3.4.0-2-x86_64 +installed = tpm2-tss-4.1.3-1-x86_64 +installed = tslib-1.24-1-x86_64 +installed = ttf-jetbrains-mono-nerd-3.4.0-2-any +installed = tzdata-2026b-1-x86_64 +installed = uchardet-0.0.8-4-x86_64 +installed = uefitool-debug-1:0.28.0-3-x86_64 +installed = unzip-6.0-23-x86_64 +installed = upower-1.91.2-1-x86_64 +installed = usbutils-019-1-x86_64 +installed = util-linux-2.42.1-1-x86_64 +installed = util-linux-libs-2.42.1-1-x86_64 +installed = v4l-utils-1.32.0-2-x86_64 +installed = vapoursynth-76-1-x86_64 +installed = vid.stab-1.1.1-2-x86_64 +installed = vim-9.2.0623-1-x86_64 +installed = vim-runtime-9.2.0623-1-x86_64 +installed = vmaf-3.1.0-1-x86_64 +installed = vmware-keymaps-1.0-3-any +installed = vmware-workstation-26H1-3-x86_64 +installed = vscodium-bin-1.121.03429-1-x86_64 +installed = vulkan-icd-loader-1.4.350.0-1-x86_64 +installed = vulkan-tools-1.4.350.0-1-x86_64 +installed = waybar-0.15.0-2-x86_64 +installed = wayland-1.25.0-1-x86_64 +installed = wayland-protocols-1.49-1-any +installed = webrtc-audio-processing-1-1.3-5-x86_64 +installed = which-2.25-1-x86_64 +installed = winboat-bin-0.9.0-1-x86_64 +installed = wine-staging-11.10-1-x86_64 +installed = wireplumber-0.5.14-1-x86_64 +installed = wl-clipboard-1:2.3.0-1-x86_64 +installed = wlogout-1.2.2-0-x86_64 +installed = woff2-font-awesome-7.2.0-1-any +installed = wpa_supplicant-2:2.11-5-x86_64 +installed = x264-3:0.165.r3222.b35605a-2-x86_64 +installed = x265-4.1-1-x86_64 +installed = xautomation-1.09-6-x86_64 +installed = xcb-proto-1.17.0-4-any +installed = xcb-util-0.4.1-2-x86_64 +installed = xcb-util-cursor-0.1.6-1-x86_64 +installed = xcb-util-errors-1.0.1-2-x86_64 +installed = xcb-util-image-0.4.1-3-x86_64 +installed = xcb-util-keysyms-0.4.1-5-x86_64 +installed = xcb-util-renderutil-0.3.10-2-x86_64 +installed = xcb-util-wm-0.4.2-2-x86_64 +installed = xdg-dbus-proxy-0.1.7-1-x86_64 +installed = xdg-desktop-portal-1.22.0-1-x86_64 +installed = xdg-desktop-portal-gtk-1.15.3-1-x86_64 +installed = xdg-desktop-portal-hyprland-1.3.12-2-x86_64 +installed = xdg-user-dirs-0.20-1-x86_64 +installed = xdg-utils-1.2.1-2-any +installed = xf86-input-libinput-1.5.0-1-x86_64 +installed = xfconf-4.20.0-2-x86_64 +installed = xkeyboard-config-2.47-1-any +installed = xmlsec-1.3.11-1-x86_64 +installed = xorg-fonts-encodings-1.1.0-2-any +installed = xorg-server-21.1.23-1-x86_64 +installed = xorg-server-common-21.1.23-1-x86_64 +installed = xorg-setxkbmap-1.3.5-1-x86_64 +installed = xorg-xauth-1.1.5-1-x86_64 +installed = xorg-xkbcomp-1.5.0-1-x86_64 +installed = xorg-xprop-1.2.8-1-x86_64 +installed = xorg-xrandr-1.5.4-1-x86_64 +installed = xorg-xwayland-24.1.12-1-x86_64 +installed = xorgproto-2025.1-1-any +installed = xvidcore-1.3.7-3-x86_64 +installed = xxhash-0.8.3-1-x86_64 +installed = xz-5.8.3-1-x86_64 +installed = yaml-cpp-0.9.0-1-x86_64 +installed = yay-12.6.0-1-x86_64 +installed = yay-debug-12.6.0-1-x86_64 +installed = zenity-4.2.2-1-x86_64 +installed = zeromq-4.3.5-3-x86_64 +installed = zimg-3.0.6-1-x86_64 +installed = zint-2.16.0-2-x86_64 +installed = zix-0.8.0-1-x86_64 +installed = zlib-1:1.3.2-3-x86_64 +installed = zlib-ng-2.3.3-1-x86_64 +installed = zstd-1.5.7-3-x86_64 +installed = zxing-cpp-3.0.2-1-x86_64 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/.MTREE b/pkgbuilds/python-simpleline/pkg/python-simpleline/.MTREE new file mode 100644 index 0000000000000000000000000000000000000000..00916a29df0a1d492265945f6b6d353f73bac5f0 GIT binary patch literal 3233 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/.PKGINFO b/pkgbuilds/python-simpleline/pkg/python-simpleline/.PKGINFO new file mode 100644 index 0000000..546682c --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/.PKGINFO @@ -0,0 +1,15 @@ +# Generated by makepkg 7.1.0 +# using fakeroot version 1.37.2 +pkgname = python-simpleline +pkgbase = python-simpleline +xdata = pkgtype=pkg +pkgver = 1.8-1 +pkgdesc = Python3 text UI framework (dépendance Anaconda) +url = https://github.com/rhinstaller/python-simpleline +builddate = 1781307804 +packager = Unknown Packager +size = 346552 +arch = any +license = LGPL-3.0-or-later +depend = python +depend = python-gobject diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__init__.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__init__.py new file mode 100644 index 0000000..1d4dfc7 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__init__.py @@ -0,0 +1,136 @@ +# Base class for Simpleline Text UI framework. +# +# Library containing the Text UI framework. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +__all__ = ["App"] + + +from simpleline.logging import setup_logging +from simpleline.errors import NothingScheduledError + +setup_logging() + + +class App(): + """This is the main class for Simpleline library. + + Do not create instance of this class. Use this class as static! + The `initialize()` method must be called before use. + + It is giving you access to the scheduler and event loop. You can have only one instance of this + class in your application. + + To create this instance call `App.initialize()` method. This method can also be used to + reset settings in the App class to start with new event loop or scheduler. + """ + __app = None + + class AppPimpl(): + + def __init__(self, scheduler, event_loop, configuration): + self.event_loop = event_loop + self.scheduler = scheduler + self.configuration = configuration + + @classmethod + def initialize(cls, scheduler=None, event_loop=None, global_configuration=None): + """Create app instance inside of this class. + + This method can be called multiple times to reset App settings. + + :param scheduler: scheduler used for rendering screens; if not specified use + `simpleline.render.screen_scheduler.ScreenScheduler`. + :type scheduler: instance of `simpleline.render.screen_scheduler.ScreenScheduler`. + + :param event_loop: event loop used for asynchronous tasks; + if not specified use `simpleline.event_loop.main_loop.MainLoop`. + :type event_loop: object based on class `simpleline.event_loop.AbstractEventLoop`. + + :param global_configuration: instance of the global configuration object; if not specified + use `simpleline.global_configuration.GlobalConfiguration` + :type global_configuration: object based on class + `simpleline.global_configuration.GlobalConfiguration` + """ + from simpleline.event_loop.main_loop import MainLoop # pylint: disable=import-outside-toplevel + from simpleline.render.screen_scheduler import ScreenScheduler # pylint: disable=import-outside-toplevel + from simpleline.global_configuration import GlobalConfiguration # pylint: disable=import-outside-toplevel + + if event_loop is None: + event_loop = MainLoop() + if scheduler is None: + scheduler = ScreenScheduler(event_loop) + if global_configuration is None: + global_configuration = GlobalConfiguration() + + cls.__app = cls.AppPimpl(scheduler, event_loop, global_configuration) + + cls._post_init() + + @classmethod + def _post_init(cls): + from simpleline.input.input_threading import InputThreadManager # pylint: disable=import-outside-toplevel + # FIXME: This should be done by more general way not by calling exact class here. + # Create new instance of InputThreadManager because it needs new event loop + InputThreadManager.create_new_instance() + + @classmethod + def is_initialized(cls): + """Is the App already initialized? + + :returns: True if the `App.initialized()` method was called, False otherwise. + """ + if cls.__app is None: + return False + + return True + + @classmethod + def get_scheduler(cls): + """Get instance of class responsible for rendering of the screen.""" + return cls.__app.scheduler + + @classmethod + def get_event_loop(cls): + """Get instance of class responsible for processing asynchronous events.""" + return cls.__app.event_loop + + @classmethod + def get_configuration(cls): + """Get application defaults configuration object.""" + return cls.__app.configuration + + @classmethod + def run(cls): + """Run event loop. + + Raise an exception if no screen is scheduled. This behavior can be changed by + `should_run_with_empty_stack` global configuration option. + + This is shortcut to `App.event_loop().run()`. + :raises NothingScheduledError: when there is no screen scheduled + """ + if not cls.__app.configuration.should_run_with_empty_stack: + # Check if the screen stack is not empty + if cls.__app.scheduler.nothing_to_render: + raise NothingScheduledError("Can't run application with the empty screen stack! " + "To avoid this please see should_run_with_empty_stack " + "global configuration option.") + App.get_event_loop().run() diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2f4f6fda8ac668c891f283a94b85a6c378eeabe GIT binary patch literal 5462 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/errors.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/errors.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a659ee293021bbee00ebfb301d2d6787a180508 GIT binary patch literal 693 zcma)4yKdVs6eTS=b@MVh7zK>NWsoI75DQ6+3`NnQs8<(I);br8%tSrAuetMes<**c%etIPY37q}C4` zwi$ZZK0lWfQKS;-)_%quE-~0+7*^ z0~G53Q#Hv`hc^Lk@+e(q+5neA8|yBS3eztDCMrhI0WdbQB8JFXEiQ7)4S@D>>bav( zoCdkkK`JhS?A|6yp7f6fff1G;W>I_{U2%inia@{}1Jlp$wUewgP5|S?{YrlL$9i)W zf0kUm|K#e7PzNEe&fLdnGgCECfw&RZ_)hn cD5Z-5r6=FSg5b7jQ97jGKmSH&NXrBM0b6;ghX4Qo literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/global_configuration.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/global_configuration.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dbc584a928a26d28afca415843df653d719955a7 GIT binary patch literal 3946 zcmbtX|4$T06rcODa4sAmiueWUP!T!M!=^T|q-i8l)U>(M1GPT@+huRyHty|iXJ$n( zCis)uH1_BI38sHb6Z}QY#WW`UslS1=u|M{`+1qo`^-Jg`H#a*oZ|1$vd!ILNM?3O* zh7hvw)8^pKC%^ykC-j?7w$a-;2c31YK+35r55RPA1b6M%iw=N7mpo3F6)x0@ z14F$fYWluoTM8#yVM}J!z-v0XM6LT~JXzUZ&Qp$1}S81=q{s4YgbC*VkN z7@BqR?9hq(*`M2<9X{&ldX2r zb?}$l4{mSdj`IC5WJQ#OK52wP`%br7e7(!XQT2q*T?=O3qp@#tvliMkPD?>;k#V%m zs=~M>A%^Kn)wZfpfchLPgBX<_^;|~LV?}*juKFz611&G{1E549&GYcb4?-hQ)uAB; zfEwUEFmM)U_CW)Nc97n_hi##a%`k?krj31SU2?cLtev{(Fq0#TIMNf8t2Eq&91{Qq z`m8}*@YiHW;c=Hi)=ro8_&+j^57p0IK zydRp&h-Q;gM}{8e{~x916DSp_@e1nq(5rD>6dV6dImI-*osvVUHzZPY+^fJEO$w~H zEdCAwX)^E#1qLQS^5G2pb*AbC4rD+kBru4odyfi>;|;H_KcG_B<w&tYurtnorTApg^gTc4}3KX06S9F4lh%zk76i< zTD%2^5aT%Nkh+vF0Oi@RbW$bNP16a?MF;LD^vbFi&=nK>0kjrYl~n?mF(damCfs;* zaTQ9k5Lj>yXJ!Q*7iJ0Ejg8a2Iqx(Ys=Q`n8R0lOeeD73L!Z0gR}7wtEqupZWuQWd z4+88_F3^-FyK=xubp8-DKfq65k_I1jlc7HWw0;zU#qst6@|; z%P@E+>{8Fc9SLQ>TvZiLy#)#mh$oKKC|3!30DH)a~#8fZ?=4F5X3NFT?nhGEN+SorhoApH2>ZMo43;$E%!ptXro|#OUHIv z(~j+AptprRD7RYL?#%WnuN4`yzDCm;5};BMzbf%~mFrO8qlJQhm?c=!QP9-uk?&dp-a3@bL}O^Ri_o Ml^We4*s87m0~Lq^f&c&j literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/logging.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/__pycache__/logging.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56247863a1a6e4276109fb0250b2571ce9ec46f6 GIT binary patch literal 797 zcmZuvJ#W)M7{0UJ1Y%-HMZ`d$XBCDB5eJCqQn8>YL<%NyrA`r%YhM$qu5Fz!Lpp_t zm6e~s@8Azq4Wh`f!NL|1egN;ewzF`OpL_hi&->v=exy|^GD2we^yBC6ZRg}C@Zv}r zTi*w=KyQ(S`-me;;@Fb!ATC)7plsn?)ZF?l#AZ^7z0=62z86p@D^D*m1RiC53}k^u zI8Sym5}{E(4-J((ySa5#DDfd0mN%K49pX;bbq6+uouo5zKskw67*R(2a5C|N2{{fK zv5D^;F`LcJrjpbrl#e%SkA;x3q?{EbsyXxhS9aj~5Utp*oAIWU$e>Be0p!P1Hx~O7 zlI$6?m>Dp@h~|762G3egI!5eq`Z%(k6MI5qc*{*PvMH@-o>XJXXHhyI7G*b}op3&W z0I)#6Dm%-HzIgdVt6ysRg{CjH-9_)4Qhsl~Ge7KoRqn1qhyL&S^R&fC2+}hwyv`#C z>1b5=o;wLH;a5hUfsS_8y9Nh%e~f8 zHO>_yEodrfb9PIV2*0k1Yl0OGlWY5@p*!>G3$_gj@sGp}fR&6fUbhjxxhkQ$evWE? ON(yfL)g;_btN#JOF|Gdq literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/errors.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/errors.py new file mode 100644 index 0000000..4532c61 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/errors.py @@ -0,0 +1,31 @@ +# Base exceptions for the Simpleline application. +# +# Base class for Simpleline Text UI framework. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# This can't be moved to __init__.py because of cyclic imports error. +# + + +class SimplelineError(Exception): + """Base exception for all other exceptions.""" + + +class NothingScheduledError(SimplelineError): + """Exception when running the loop with no screens scheduled.""" diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__init__.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__init__.py new file mode 100644 index 0000000..1b68307 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__init__.py @@ -0,0 +1,264 @@ +# Abstract base class for Simpleline Event Loop. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# This class can be overridden to use any existing event loop of your program. +# +# Author(s): Jiri Konecny +# + +import sys + +from abc import ABCMeta, abstractmethod +from collections import namedtuple + +from simpleline.errors import SimplelineError +from simpleline.event_loop.ticket_machine import TicketMachine +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + +__all__ = ["AbstractEventLoop", "AbstractSignal", "ExitMainLoop"] + +QuitCallback = namedtuple("QuitCallback", ["callback", "args"]) + + +class ExitMainLoop(SimplelineError): + """This exception ends the whole event loop.""" + + +class AbstractEventLoop(metaclass=ABCMeta): + + def __init__(self): + super().__init__() + self._handlers = {} + self._processed_signals = TicketMachine() + self._quit_callback = None + # end most inner loop politely by setting to False + self._run_loop = True + self._force_quit = False + + def register_signal_handler(self, signal, callback, data=None): + """Register a callback which will be called when message "event" + is encountered during process_events. + + The callback has to accept two arguments: + - the received message in the form of (type, [arguments]) + - the data registered with the handler + + :param signal: Signal class we want to react on. + :type signal: Class based on the simpleline.event_loop.AbstractSignal class. + + :param callback: The callback function. + :type callback: func(event_message, data) + + :param data: Optional data to pass to callback. + :type data: Anything. + """ + if signal not in self._handlers: + self._handlers[signal] = [] + + event_handler = self._create_event_handler(callback, data) + self._handlers[signal].append(event_handler) + + @abstractmethod + def register_signal_source(self, signal_source): + """Register source of signal for actual event queue. + + :param signal_source: Source for future signals. + :type signal_source: `simpleline.render.ui_screen.UIScreen` + """ + + @abstractmethod + def enqueue_signal(self, signal): + """Enqueue new event for processing. + + :param signal: Signal which you want to add to the event queue for processing. + :type signal: Instance based on AbstractEvent class. + """ + log.debug("New signal %s enqueued with source %s", + signal, + signal.source.__class__.__name__) + + @abstractmethod + def run(self): + """Starts the event loop.""" + log.debug("Starting main loop") + self._force_quit = False + + def force_quit(self): + """Force quit all running event loops. + + Kill all loop including inner loops (modal window). + None of the Simpleline events will be processed anymore. + """ + log.debug("Force quit called. Killing all loops!") + self._force_quit = True + + @abstractmethod + def execute_new_loop(self, signal): + """Starts the new event loop and pass `signal` in it. + + This is required for processing a modal screens. + + :param signal: Signal passed to the new event loop. + :type signal: The `AbstractSignal` based class. + """ + log.debug("Executing inner loop") + + @abstractmethod + def close_loop(self): + """Close active event loop. + + Close an event loop created by the `execute_new_loop()` method. + """ + log.debug("Closing inner loop") + + @abstractmethod + def process_signals(self, return_after=None): + """This method processes incoming async messages. + + Process signals enqueued by the `self.enqueue_signal()` method. Call handlers + registered to the signals by the `self.register_signal_handler()` method. + + When `return_after` is specified then wait to the point when this signal is processed. + NO warranty that this method will return immediately after the signal was processed! + + Without `return_after` parameter this method will return after all queued signals + with the highest priority will be processed. + + The method is NOT thread safe! + + :param return_after: Wait on this signal to be processed. + :type return_after: Class of the signal. + """ + + def set_quit_callback(self, callback, args=None): + """Call this callback when event loop quits. + + :param callback: Call this callback when event loops ends (application quit). + :type callback: Function with one parameter data `func(data)`. + + :param args: Arguments passed to the quit callback. + :type args: Anything. + """ + self._quit_callback = QuitCallback(callback, args) + + def kill_app_with_traceback(self, exception_signal, data=None): + """Print exception and screen stack and kill the application. + + :param exception_signal: ExceptionSignal encapsulating the original exception which + will be passed to the sys.excepthook method. + :type exception_signal: Instance of `simpleline.event_loop.signals.ExceptionSignal` class. + + :param data: To be usable as signal handler. + :type data: Anything will be ignored. + """ + log.debug("Unhandled error in handler raised:") + sys.excepthook(*exception_signal.exception_info) + + from simpleline import App # pylint: disable=import-outside-toplevel + stack_dump = App.get_scheduler().dump_stack() + print("") + print(stack_dump) + log.error(stack_dump) + + log.debug("Killing application!") + sys.exit(1) + + @staticmethod + def _create_event_handler(callback, data): + """Create event handler data object and return it.""" + return EventHandler(callback=callback, data=data) + + def _register_wait_on_signal(self, wait_on_signal): + """Register process waiting on signal `wait_on_signal` and return id for later checking. + + ID is returned which is then used in the `self._check_if_signal_processed()` method. + + :param wait_on_signal: Signal we are waiting for. + :type wait_on_signal: Class based on `simpleline.event_loop.AbstractSignal`. + """ + return self._processed_signals.take_ticket(wait_on_signal.__name__) + + def _mark_signal_processed(self, signal): + """Mark that processes waiting on this signal that they are able to go. + + :param signal: Signal which was processed. + :type signal: Class based on `simpleline.event_loop.AbstractSignal`. + """ + self._processed_signals.mark_line_to_go(signal.__class__.__name__) + + def _check_if_signal_processed(self, wait_on_signal, unique_id): + """Check if the signal was processed. + + :param wait_on_signal: Signal the process is waiting for. + :type wait_on_signal: Class based on `simpleline.event_loop.AbstractSignal`. + + :param unique_id: Unique id returned by the `self._register_wait_on_signal()` method. + :type unique_id: int + """ + return self._processed_signals.check_ticket(wait_on_signal.__name__, unique_id) + + +class EventHandler(): + """Data class to save event handlers.""" + + def __init__(self, callback, data): + self.callback = callback + self.data = data + + +class AbstractSignal(metaclass=ABCMeta): + """This class is base class for signals. + + .. NOTE: + Ordering and equality is based on priority. + """ + + def __init__(self, source, priority=0): + self._source = source + self._priority = priority + + def __lt__(self, other): + """Order Signal classes by priority.""" + return self._priority < other.priority + + def __eq__(self, other): + """Order Signal classes by priority.""" + return self._priority == other.priority + + def __str__(self): + """For easier logging.""" + return self.__class__.__name__ + + @property + def priority(self): + """Priority of this event. + + Values less than 0 denote higher priorities. Values greater than 0 denote lower priorities. + Events from high priority sources are always processed before events from lower priority + sources. + """ + return self._priority + + @property + def source(self): + """Source which emitted this event.""" + return self._source diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fdf39886c05594aa157477fb0d5864293cf2c62 GIT binary patch literal 11671 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/event_queue.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/event_queue.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ebe6c521ccfd98e60daa1515e74b65d7ecf0bc2 GIT binary patch literal 5808 zcmd5=-A^3X6~D8yvn;y{yXMO_!QoaXI(~f^-ejOFPWTY6NxdW zXu-lbon`Jk&GFiDvO89m%O!W4GiFoj_DOhs7SFjyRRxP{xTjt*2f8z|W`1LZ|gbe*TN zCk6+&Ev(~ZGk?*XvpD<;Y&KxwzKxRWmi^-EXy9ylku`uaDJT>;{`xWbJfdoGmJV8W zH}-jGHpAxb6KV%>0Uc=a{RE8;GKM%14Y~$0u7meQquu~Ap~pcc^+u2>Jpr;wPm1Pg zBGP&aoYhoK)cvsZ@eAk&>7IGhG3RV&j&gg>F-z3jNg|hTe40&vJ0$`Z{=jMe{2Z3(CCdI;nvy+oq(|v035>s)fm7F zJX=+{C8{k(-gN{Z+$tD6&n(N~EQ-A}fI|M_H8@|~D$R0S$WfNT7C^1-*a8sPS~q_- zsQeam;g5n?Cbv6!FT0nb?}HPC*3)wEG?{?E zJHLtAmg_BnL2#2xW4a|O%%Or+ENaivmvE~TTx`vk#Uh;2AtpNv(J8-&Y+yKz92!_Sz3(ncPW`Oxx;PD{pP2=~|lJ zOdq}xKkRMWr#9#&5r8O2ZJm^(9)8=?%Ak*qZa7e|`N-05PD#XB0q%wC!7{-AP}yYW zyx%%RC%x0LP_*+!%8PELRG>4K4_m81cMKmAi{(IdZLlOiI%9I^59FAu6G~Pd21zJc z|LkN(X1HKxUU)MD4~_>`R?8Iu<%3{^YRvDBW;*JFuE9G@R<$K;a&Nn6IgY*pqo+t? z(`s@hxtd-{Uyc1S-tAdD3>z#@oL?(mNu0UxR6-(a#Ya}$CVKp41?ONs%vlw4P>USD(AOHdp zL;cRClHF^`?q9|> zl6`+j_T5TlR?n=QSv|LM?&|1zs`sJY*=4@c2oX^chV1sjt??&1Pevrc<%M6tIl{H0m9h}5~+vcy&CP!S>l1v@&uxyIpk&N^fLOh z-ScOQA6Qo3UU~awn%;=hF9|Cj$uSQfR)T0+j!Z`;qA+;JH?2JL3LymmE07^j+8&xQ zOWg6*DK!XK=7~Bogj=ph9`6(*ht)DL4B?m-BL(Jy+FX{N0~pANO>^U}V?j&_I4kHh zM0FSm;DQh(V^U3NKoj+zwj)9*!ZrxtY5+Dx-~d+B7mVC(9bYG6C|)}J{f+lWJtmPj zi3dyAMl8p{_K>+?O7HUu^^&)PfF%QLZOAs{jbQvXUfHwP3@GN$fB;@;A^X~|BtJ-A zNq>;Ond!Nt-AZOwpIdqE>MQHXBez-)Tsr%gc&ZkRwe|R;pQT$LgepQs#^YZ|wYvjq zSTU4Jq@o(N47dA#j>Wp7E5Vi1gCZrzND$}eAij4IJJL-Kk#6}9v#VkC5V4j1h#3dS zjuZ;iu@>N_fcbyua_~TWmK^3&4*OI}4RG%r9zSY?1LSN4QsW@AfE#N#p{sQdLM8RmLOGi?55V`-0wco}SSrHo zO=XzuvJMbc6;^c3PvM%jErN$LxkNqFsJ4elu3pVR8%G2K#yUuI%j)^n^Y5I8n6;7W zT}$0{L}OIIo^Rj>>AcSO^&1*^WiM5hOj?NrH|}ETHg$e zQF0*$%amV?6j~6CDIjaM&RcFHu6zIUQ%Ur z{JPISCj98mWo;dplqkTUh?pyxAf^0=4KE8A6&mW{srSQ(%rT9kC-&QSA(2Wk=HfJ`TW6fR?s88MV@l$A;J7 zf9r6Kgx&!X!q>MCo3q-llg~E-T9FvN+3|il-k)K}QY?WYi6Vuf2?f4P%2x$;7)uzA z7)E$DfC3*D*f0uQ3u^{Z-Demw`z+Xbk+(`E!@&2^P$fJNLbM{^lcAphlMpFTHGdYw ze|`eH`gbIz#Wypm*0q_?wBF6;m_|1<`?U7Wqm5e6W=FHuwn~^qDzuuX&wF7y={<%% v$6ka6+yZ|b1e`HN`FxNl^iQPopXB)6SX7Ds%)LwC&%I`*C?~fFN~!6;U!=;c literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/glib_event_loop.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/glib_event_loop.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d1f3ef5941c5f092add4d990cfae731d54818f5 GIT binary patch literal 10356 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 S(;1&<`c_2xZ$=G1>;C~{{{8j< literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/signals.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/__pycache__/signals.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e43edb6413944fa76b7e9f7dff43f6b7ae89a76 GIT binary patch literal 4276 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 EKPM4r3jhEB literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/event_queue.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/event_queue.py new file mode 100644 index 0000000..c0351d3 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/event_queue.py @@ -0,0 +1,153 @@ +# Default event queue for Simpleline application. +# +# This class is thread safe. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +from queue import PriorityQueue +from threading import Lock + +from simpleline.errors import SimplelineError + + +class EventQueueError(SimplelineError): + """Main exception for `EventQueue` class. + + Inherits from `simpleline.SimplelineError`. + """ + + +class EventQueue(): + """Class for managing signal queue. + + Responsibilities of this class are: + * sorting by priority of signals + * managing sources for this event queue + * enqueuing signals + """ + + def __init__(self): + self._queue = PriorityQueue() + self._contained_screens = set() + self._lock = Lock() + + def empty(self): + """Return true if Queue is empty. + + :return: True if empty, False otherwise. + """ + return self._queue.empty() + + def enqueue(self, signal): + """Enqueue signal to this queue. + + :param signal: Signal which should be enqueued to this queue. + :type signal: Signal class based on `simpleline.event_loop.signals.AbstractSignal`. + """ + self._queue.put(signal) + + def enqueue_if_source_belongs(self, signal, source): + """Enqueue signal to this queue if the signal source belongs to this queue. + + Enqueue the `signal` only if the `source` belongs to this queue. + See the `add_source()` method. + + :param signal: Signal which should be enqueued to this queue. + :type signal: Signal class based on `simpleline.event_loop.signals.AbstractSignal`. + :param source: Source of this signal. + :type source: Anything. + :return: True if the source belongs to this queue and signal was queued, False otherwise. + :rtype: bool + """ + if self.contains_source(source): + self._queue.put(signal) + return True + + return False + + def get(self): + """Return enqueued signal with the highest priority. + + This is FIFO implementation for the same priority. + If the queue is empty this method will wait for the input signal. + + :return: Queued signal. + :rtype: Signal based on class `simpleline.event_loop.signals.AbstractSignal`. + """ + return self._queue.get() + + def get_top_event_if_priority(self, priority): + """Return top enqueued signal if priority is equal to `priority`. Otherwise `None`. + + :param priority: Requested event priority. + :type priority: int + + :return: Queued signal if it has requested priority. Otherwise `None`. + :rtype: Signal based on class `simpleline.event_loop.signals.AbstractSignal` or `None`. + """ + event = self._queue.get() + if event.priority == priority: + return event + + self._queue.put(event) + return None + + def add_source(self, signal_source): + """Add new source of signals to this queue. + + This method is mandatory for `enqueue_if_source_belongs()` method. + The same source will be added only once. + + :param signal_source: Source of future signals. + :type signal_source: Anything which will emit signals in future. + """ + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._contained_screens.add(signal_source) + + def remove_source(self, signal_source): + """Remove signal source from this queue. + + :param signal_source: Source of future signals. + :type signal_source: Anything. + :raise: EventQueueError""" + try: + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._contained_screens.remove(signal_source) + except KeyError as e: + raise EventQueueError("Can't remove non-existing event source!") from e + + def contains_source(self, signal_source): + """Test if `signal_source` belongs to this queue. + + :param signal_source: Source of signals. + :type signal_source: Anything. + :return: True if signal source belongs to this queue. + :rtype: bool + """ + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + return signal_source in self._contained_screens diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/glib_event_loop.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/glib_event_loop.py new file mode 100644 index 0000000..25847e5 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/glib_event_loop.py @@ -0,0 +1,230 @@ +# Glib event queue used by Simpleline application. +# +# This class is thread safe. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# +from collections import namedtuple + +import gi + +from simpleline.event_loop import AbstractEventLoop, ExitMainLoop +from simpleline.event_loop.signals import ExceptionSignal +from simpleline.logging import get_simpleline_logger + +gi.require_version("GLib", "2.0") + +from gi.repository import GLib # pylint: disable=wrong-import-order, wrong-import-position + +log = get_simpleline_logger() + +CallbackArgs = namedtuple("CallbackArgs", ["signal", "source", "handlers"]) + + +__all__ = ["GLibEventLoop"] + + +class GLibEventLoop(AbstractEventLoop): + + def __init__(self): + super().__init__() + # Create first loop + loop = GLib.MainLoop() + self._event_loops = [EventLoopData(loop)] + log.debug("GLib event loop is used!") + + @property + def active_main_loop(self): + """Return GLib mainloop object.""" + return self._event_loops[-1].loop + + def register_signal_source(self, signal_source): + """Register source of signal for actual event queue. + + :param signal_source: Source for future signals. + :type signal_source: `simpleline.render.ui_screen.UIScreen` + """ + super().register_signal_source(signal_source) + loop_data = self._event_loops[-1] + loop_data.sources.add(signal_source) + + def enqueue_signal(self, signal): + """Enqueue new event for processing. + + :param signal: signal which you want to add to the event queue for processing + :type signal: instance based on AbstractEvent class + """ + if self._force_quit: + return + + super().enqueue_signal(signal) + + loop_data = self._find_loop_data_for_source(signal.source) + self._register_handlers_to_loop(loop_data.loop, signal) + + def _find_loop_data_for_source(self, source): + """Find event loop belonging to this signal source.""" + for loop_data in reversed(self._event_loops): + if source in loop_data.sources: + return loop_data + + return self._event_loops[-1] + + def _register_handlers_to_loop(self, event_loop, signal): + """Register handlers to the event loop.""" + context = event_loop.get_context() + handlers = [] + + if type(signal) in self._handlers: # pylint: disable=unidiomatic-typecheck + handlers = self._handlers[type(signal)] + elif isinstance(signal, ExceptionSignal): + handler_data = self._create_event_handler(self.kill_app_with_traceback, None) + handlers = [handler_data] + + # GLib event source which contains handler callback + # Every source can hold only one callback + source = GLib.idle_source_new() + source.set_priority(signal.priority) + data = CallbackArgs(signal, source, handlers) + + source.set_callback(self._run_handlers, data) + # attach source to the event loop + source.attach(context) + + def _run_handlers(self, data): + """Run handlers attached to this signal and clean source afterwards.""" + signal = data.signal + source = data.source + handlers = data.handlers + + if not self._force_quit: + try: + for handler in handlers: + handler.callback(signal, handler.data) + except ExitMainLoop: + self._quit_all_loops() + except Exception: # pylint: disable=broad-except + self.enqueue_signal(ExceptionSignal(self)) + + # based on GLib documentation we should clean source + # source will be removed from event loop context this way + source.destroy() + + self._mark_signal_processed(signal) + + def _quit_all_loops(self): + for loop_data in reversed(self._event_loops): + loop_data.loop.quit() + + def run(self): + """Starts the event loop.""" + super().run() + if len(self._event_loops) != 1: + raise ValueError("Can't run event loop multiple times.") + + self._event_loops[0].loop.run() + log.debug("Main loop ended. Running callback if set.") + + if self._quit_callback: + cb = self._quit_callback.callback + cb(self._quit_callback.args) + + def force_quit(self): + """Force quit all running event loops. + + Kill all loop including inner loops (modal window). + None of the Simpleline events will be processed anymore. + """ + super().force_quit() + self._quit_all_loops() + + def execute_new_loop(self, signal): + """Starts the new event loop and pass `signal` in it. + + This is required for processing a modal screens. + + :param signal: signal passed to the new event loop + :type signal: `AbstractSignal` based class + """ + super().execute_new_loop(signal) + + if self._force_quit: + return + + new_context = GLib.MainContext() + new_loop = GLib.MainLoop(new_context) + loop_data = EventLoopData(new_loop) + self._event_loops.append(loop_data) + + self.enqueue_signal(signal) + new_loop.run() + + def close_loop(self): + """Close active event loop. + + Close an event loop created by the `execute_new_loop()` method. + """ + super().close_loop() + old_loop_data = self._event_loops.pop() + old_loop_data.loop.quit() + + def process_signals(self, return_after=None): + """This method processes incoming async messages. + + Process signals en-queued by the `self.enqueue_signal()` method. Call handlers registered + to the signals by the `self.register_signal_handler()` method. + + When `return_after` is specified then wait to the point when this signal is processed. + NO warranty that this method will return immediately after the signal was processed! + + Without `return_after` parameter this method will return after all queued signals with + the highest priority will be processed. + + The method is NOT thread safe! + + :param return_after: Wait on this signal to be processed. + :type return_after: Class of the signal. + """ + super().process_signals(return_after) + loop_data = self._event_loops[-1] + + if return_after is not None: + ticket_id = self._register_wait_on_signal(return_after) + + while not self._check_if_signal_processed(return_after, ticket_id) and \ + not self._force_quit: + self._iterate_event_loop(loop_data.loop) + else: + self._iterate_event_loop(loop_data.loop) + + @staticmethod + def _iterate_event_loop(event_loop): + context = event_loop.get_context() + # This is useful for tests + wait_on_timeout = False + context.iteration(wait_on_timeout) + + +class EventLoopData(): + + def __init__(self, loop): + super().__init__() + self.loop = loop + self.sources = set() diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/main_loop.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/main_loop.py new file mode 100644 index 0000000..bf64a15 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/main_loop.py @@ -0,0 +1,247 @@ +# Default event loop for Simpleline application. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from threading import Lock + +from simpleline.event_loop import AbstractEventLoop, ExitMainLoop +from simpleline.event_loop.event_queue import EventQueue +from simpleline.event_loop.signals import ExceptionSignal +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + +__all__ = ["MainLoop"] + + +class MainLoop(AbstractEventLoop): + """Default main event loop for the Simpleline. + + This event loop can be replaced by your event loop by implementing + `simpleline.event_loop.AbstractEventLoop` class. + """ + + def __init__(self): + super().__init__() + self._active_queue = EventQueue() + self._event_queues = [self._active_queue] + self._lock = Lock() + + def register_signal_source(self, signal_source): + """Register source of signal for actual event queue. + + :param signal_source: Source for future signals. + :type signal_source: `simpleline.render.ui_screen.UIScreen`. + """ + super().register_signal_source(signal_source) + self._active_queue.add_source(signal_source) + + def run(self): + """This methods starts the application. + + Do not use self.mainloop() directly as run() handles all the required exceptions + needed to keep nested mainloop working. + """ + super().run() + self._run_loop = True + + try: + self._mainloop() + except ExitMainLoop: + pass + + log.debug("Main loop ended. Running callback if set.") + + if self._quit_callback: + cb = self._quit_callback.callback + cb(self._quit_callback.args) + + def force_quit(self): + """Force quit all running event loops. + + Kill all loop including inner loops (modal window). + None of the Simpleline events will be processed anymore. + """ + super().force_quit() + self._event_queues.clear() + self._run_loop = False + + def execute_new_loop(self, signal): + """Starts the new event loop and pass `signal` in it. + + This is required for processing a modal screens. + + :param signal: Signal passed to the new event loop. + :type signal: The `AbstractSignal` based class. + """ + super().execute_new_loop(signal) + + if self._force_quit: + return + + self._active_queue = EventQueue() + + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._event_queues.append(self._active_queue) + + self.enqueue_signal(signal) + self._mainloop() + log.debug("Inner loop is closed") + + def close_loop(self): + """Close active event loop. + + Close an event loop created by the `execute_new_loop()` method. + """ + super().close_loop() + self.process_signals() + + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._event_queues.pop() + try: + self._active_queue = self._event_queues[-1] + except IndexError: + log.error("No more event queues to work with!") + raise ExitMainLoop() # pylint: disable=raise-missing-from + + self._run_loop = False + + def enqueue_signal(self, signal): + """Enqueue new event for processing. + + Enqueue signal to the most inner queue (nearest to the active queue) where + the `signal.source` belongs. + If it belongs nowhere enqueue it to the active one. + + This method is thread safe. + + :param signal: Event which you want to add to the event queue for processing. + :type signal: Instance based on AbstractEvent class. + """ + if self._force_quit: + return + + super().enqueue_signal(signal) + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + for queue in reversed(self._event_queues): + if queue.enqueue_if_source_belongs(signal, signal.source): + return + + self._active_queue.enqueue(signal) + + def _mainloop(self): + """Single mainloop. Do not use directly, start the application using run().""" + # run infinite loop + # this will always wait on input processing or similar so it should not busy waiting + while self._run_loop: + self._process_signals_loop() + + if not self._force_quit: + # set back to True to leave outer loop working + self._run_loop = True + + def process_signals(self, return_after=None): + """This method processes incoming async messages. + + Process signals en-queued by the `self.enqueue_signal()` method. Call handlers + registered to the signals by the `self.register_signal_handler()` method. + + When `return_after` is specified then wait to the point when this signal is processed. + NO warranty that this method will return immediately after the signal was processed! + + Without `return_after` parameter this method will return after all queued signals + with the highest priority will be processed. + + The method is NOT thread safe! + + :param return_after: Wait on this signal to be processed. + :type return_after: Class of the signal. + """ + super().process_signals(return_after) + if return_after is not None: + self._process_signals_with_return(return_after) + else: + self._process_signals_iteration() + + def _process_signals_with_return(self, return_after): + """Process signals until the return_after signal was processed. + + Or the loop quited. + """ + # get unique ID when waiting for the signal + unique_id = self._register_wait_on_signal(return_after) + + while self._run_loop: + signal = self._active_queue.get() + + # do the signal processing (call handlers) + self._process_signal(signal) + + # was our signal processed if yes, return this method + if self._check_if_signal_processed(return_after, unique_id): + return + + def _process_signals_iteration(self): + """Process queued signal and then return.""" + priority = None + + while not self._active_queue.empty() and self._run_loop: + if priority is None: + # take first signal to find out the highest priority in queue + signal = self._active_queue.get() + priority = signal.priority + else: + # get signal with this priority only + signal = self._active_queue.get_top_event_if_priority(priority) + + # Signal with this priority is not available anymore + if signal is None: + return + + self._process_signal(signal) + + def _process_signals_loop(self): + """Process signal until the event loop quited.""" + while self._run_loop: + signal = self._active_queue.get() + self._process_signal(signal) + + def _process_signal(self, signal): + log.debug("Processing signal %s", signal) + + self._mark_signal_processed(signal) + + if type(signal) in self._handlers: # pylint: disable=unidiomatic-typecheck + for handler_data in self._handlers[type(signal)]: + try: + handler_data.callback(signal, handler_data.data) + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + self.enqueue_signal(ExceptionSignal(self)) + elif isinstance(signal, ExceptionSignal): + self.kill_app_with_traceback(signal) diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/signals.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/signals.py new file mode 100644 index 0000000..dd4a5e3 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/signals.py @@ -0,0 +1,110 @@ +# Set of default signals used inside of widgets. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from sys import exc_info +from simpleline.event_loop import AbstractSignal + +__all__ = ["ExceptionSignal", "InputReadySignal", "RenderScreenSignal", "CloseScreenSignal", + "InputReceivedSignal"] + + +class ExceptionSignal(AbstractSignal): + """Emit this signal when exception is raised. + + This class must be created inside of exception handler or `exception_info` must be specified + in creation process. + + If you register handler for this exception then the Simpleline's exception handling + is disabled! + """ + + def __init__(self, source, exception_info=None): + """Create exception signal with higher priority (-20) than other signals. + + :param source: source of this signal + :type source: class which emits this signal + + :param exception_info: if specified raise your exception, otherwise create exception here; + to create exception here it needs to be created inside of exception + handler + :type exception_info: output of `sys.exc_info()` method + """ + super().__init__(source, priority=-20) + if exception_info: + self.exception_info = exception_info + else: + self.exception_info = exc_info() + + +class InputReadySignal(AbstractSignal): + """Input from user is ready for processing.""" + def __init__(self, source, input_handler_source, data, priority=0, success=True): + """Store user input inside of this signal + + Read the data from user input in `data` attribute. + + The only way how a user should ask for input is to use InputHandler and inherited classes. + The input_handler_source param must be set but this signal instance can be attached to + another source object which is registered to a specific event loop. + + If no requester (object who uses InputHandler) is specified then source and + input_handler_source will both point to InputHandler instance. + + :param source: Source of this signal. + :type source: Any object. + + :param input_handler_source: InputHandler who is asking for input. + :type input_handler_source: The `simpleline.input.input_handler.InputHandler` based + instance. + + :param data: User input data. + :type data: str + + :param priority: Priority of this event. + :type priority: Int greater than 0. + + :param success: Was the input successful? True on successful input False otherwise. + :type success: bool + """ + super().__init__(source, priority=priority) + self.input_handler_source = input_handler_source + self.data = data + self.success = success + + +class InputReceivedSignal(AbstractSignal): + """Raw input received. + + This signal will be further processed and InputReadySignal should be enqueued soon. + Most probably you are looking for InputReadySignal instead. + """ + def __init__(self, source, data, priority=0): + super().__init__(source, priority=priority) + self.data = data + + +class RenderScreenSignal(AbstractSignal): + """Render UIScreen to terminal.""" + + +class CloseScreenSignal(AbstractSignal): + """Close current screen.""" diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/ticket_machine.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/ticket_machine.py new file mode 100644 index 0000000..6234720 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/event_loop/ticket_machine.py @@ -0,0 +1,81 @@ +# Ticket machine synchronization class. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +class TicketMachine(): + """Hold signals processed by the event loop if someone wait on them. + + This is useful when recursive process events will skip required signal. + """ + + def __init__(self): + self._lines = {} + self._counter = 0 + + def take_ticket(self, line_id): + """Take ticket (id) and go line (processing events). + + Use `check_ticket` if you are ready to go. + + :param line_id: Line where you are waiting. + :type line_id: Anything. + """ + obj_id = self._counter + if line_id not in self._lines: + self._lines[line_id] = {obj_id: False} + else: + self._lines[line_id][obj_id] = False + + self._counter += 1 + return obj_id + + def check_ticket(self, line, unique_id): + """Check if you are ready to go. + + If True the unique_id is not valid anymore. + + :param unique_id: Your id used to identify you in the line. + :type unique_id: int + + :param line: Line where you are waiting. + :type line: Anything. + + :return: True if the ticket was already marked, False otherwise + :rtype: bool + """ + if self._lines[line][unique_id]: + return self._lines[line].pop(unique_id) + + return False + + def mark_line_to_go(self, line): + """All in the `line` are ready to go. + + Mark all tickets in the line as True. + + :param line: Line which should processed. + :type line: Anything. + """ + if line in self._lines: + our_line = self._lines[line] + for key in our_line: + our_line[key] = True diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/global_configuration.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/global_configuration.py new file mode 100644 index 0000000..1fa91a7 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/global_configuration.py @@ -0,0 +1,112 @@ +# Global configuration for the whole application. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from getpass import getpass + +__all__ = ["GlobalConfiguration"] + +DEFAULT_WIDTH = 80 +DEFAULT_PASSWORD_FUNC = getpass + + +class GlobalConfiguration(): + """Class for global configuration of application defaults. + + All stored data are persistent between App.initialize() calls and can be used before this call. + """ + + def __init__(self): + self._width = DEFAULT_WIDTH + self._getpass = DEFAULT_PASSWORD_FUNC + self._run_with_empty_stack = False + + @property + def width(self): + """Get width of the application. + + :returns: int + """ + return self._width + + @width.setter + def width(self, width): + """Set width of the application. + + :param width: Number of characters which can be printed to one line. + :type width: int + """ + self._width = width + + def clear_width(self): + """Clear user defined width and set the default. + + Default: 80 characters + """ + self._width = DEFAULT_WIDTH + + @property + def password_function(self): + """Get function to get user passwords from a console. + + :returns: Function with one argument which is text representation of prompt. + """ + return self._getpass + + @password_function.setter + def password_function(self, password_func): + """Set function to get user passwords from a console. + + :param password_func: Function to get password from a command line. + :type password_func: Function with one argument which is text representation of prompt. + """ + self._getpass = password_func + + def clear_password_function(self): + """Clear user defined password function and set the default. + + Default: getpass.getpass function + """ + self._getpass = getpass + + @property + def should_run_with_empty_stack(self): + """Should test on empty screen stack when starting event loop. + + :returns: If False the App.run() call will end with an exception (default), True otherwise. + """ + return self._run_with_empty_stack + + @should_run_with_empty_stack.setter + def should_run_with_empty_stack(self, value): + """Set if the App.run() call should end with an exception when screen stack is empty. + + This can be valuable when you want to schedule a screen later by an other thread. + + :param value: If False the App.run() call will end with an exception, if True it will + run with nothing displayed. + """ + self._run_with_empty_stack = value + + def clear_should_run_with_empty_stack(self): + """Clear user defined test to run with an empty screen stack. + + Default: False + """ + self._run_with_empty_stack = False diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__init__.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__init__.py new file mode 100644 index 0000000..e632883 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__init__.py @@ -0,0 +1,22 @@ +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from simpleline.input.input_handler import InputHandler, PasswordInputHandler + +__all__ = ["InputHandler", "PasswordInputHandler"] diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e31aa929462bf0b638f07760ef55b23e3c19f524 GIT binary patch literal 303 zcmdPq-EThY9;_IB-KAR7*tpsdewKt=;Y977PJCxZuL38M#736nfS5K|Dd z9#aW(5Q{Q{ChJR(Voj!7Jf3+4r6nGTc_}%mMYlu(5{rw=^NUiDMTbds1v#lXnR%&tnIOFoGCl)h1VZsG_W1b3oSgXhl?EFQ_cZ z$j>v@Gc?gJ&MZmQEl5nxPE1cN2J&EL>x0eKkB`sH%PfhH*DI*J#bJ}1pHiBWYFESs nG>#F7i^YJ%2WCb_#_t*ojDCy{xFs)08(!ctYGNtF}}e literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/input_handler.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/input_handler.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7ad19f09bbc2f24fe8583bf76f01b11ded65264 GIT binary patch literal 12640 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/input_threading.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/__pycache__/input_threading.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7a94ac42536d763fcae06f59d53463f9263addf GIT binary patch literal 10368 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. +# + +import sys + +from simpleline import App +from simpleline.event_loop.signals import InputReadySignal +from simpleline.render.widgets import TextWidget +from simpleline.input.input_threading import InputThreadManager, InputRequest + +__all__ = ["InputHandler", "PasswordInputHandler"] + + +class InputHandler(): + + def __init__(self, callback=None, source=None): + """Class to handle input from the terminal. + + This class is designed to be instantiated on place where it should be used. + The main method is `get_input()` which is non-blocking asynchronous call. It can be used + as synchronous call be calling the `wait_on_input` method. + + To get result from this class use the `value` property. + + :param callback: You can specify callback which will be called when user give input. + :type callback: Callback function with one argument which will be user input. + + :param source: Source of this input. It will be helpful in case of debugging an issue. + :type source: Class which will process an input from this InputHandler. + """ + super().__init__() + self._input = None + self._input_callback = callback + self._input_received = False + self._input_successful = False + self._skip_concurrency_check = False + self._source = source + + App.get_event_loop().register_signal_handler(InputReadySignal, + self._input_received_handler) + + def _input_received_handler(self, signal, args): + if signal.input_handler_source != self: + return + + self._input_received = True + self._input_successful = signal.success + + if not self._input_successful: + return + + self._input = signal.data + + # call async callback + if self._input_callback is not None: + cb = self._input_callback + self._input_callback = None + + cb(self._input) + + @property + def value(self): + """Return user input. + + :returns: String or None if no is input received. + """ + return self._input + + @property + def source(self): + """Get source of this input. + + :returns: Anything probably UIScreen. + """ + return self._source + + @property + def skip_concurrency_check(self): + """Is this InputHandler skipping concurrency check? + + :returns bool + """ + return self._skip_concurrency_check + + @skip_concurrency_check.setter + def skip_concurrency_check(self, value): + """Set if this InputHandler should skip concurrency check. + + Note if you skip this check, you can have unexpected behavior. Use with caution. + + :param value: True to skip the check, False if not. + """ + self._skip_concurrency_check = value + + def set_callback(self, callback): + """Set a callback to get user input asynchronously. + + :param callback: Callback called when user write their input. + :type callback: Method with 1 argument which is user input: def cb(user_input) + """ + self._input_callback = callback + + def input_received(self): + """Was user input already received? + + :returns: True if yes, False otherwise. + """ + return self._input_received + + def wait_on_input(self): + """Blocks execution till the user input is received. + + Events will works as expected during this blocking. + + Please check the `input_successful` method to test the input. + """ + # we already received input from user + if self._input_received: + return + + while not self._input_received: + App.get_event_loop().process_signals(InputReadySignal) + + def input_successful(self): + """Was input successful? + + :returns: bool + """ + return self._input_successful + + def get_input(self, prompt): + """Use prompt to ask for user input and wait (non-blocking) on user input. + + This is an asynchronous call. If you want to wait for user input then use + the `wait_on_input` method. If you want to get results asynchronously then register + callback in constructor or by the `set_callback` method. + + Check if user input was already received can be done by the `input_received` method call. + + :param prompt: Ask user what you want to get. + :type prompt: String or Prompt instance. + + :returns: User input. + :rtype: str + """ + self._clear_input() + self._invoke_input_thread(prompt) + + def _invoke_input_thread(self, prompt): + thread_object = self.create_thread_object(prompt) + InputThreadManager.get_instance().start_input_thread(thread_object, + not self._skip_concurrency_check) + + def create_thread_object(self, prompt): + """Create thread object containing all the information how to get user input. + + :returns: Instance of class inherited from `simpleline.input.InputThread`. + """ + return InputHandlerRequest(App.get_configuration().width, prompt, self) + + def _clear_input(self): + self._input_received = False + self._input = None + + +class InputHandlerRequest(InputRequest): + """This is thread object to get input from user without blocking main thread.""" + + def __init__(self, width, prompt, input_handler): + """Create request object to get input in InputThreadManager. + + :param width: Width of the screen prompt. + :type width: int + + :param prompt: Input prompt. + :type prompt: Instance of `simpleline.render.prompt.Prompt` class. + + :param input_handler: InputHandler instance which created this object. + :type input_handler: InputHandler based instance. + """ + super().__init__(input_handler, input_handler.source) + self._width = width + self._prompt = prompt + + def get_input(self): + """This method is responsible for interruptable user input. + + It is expected to be used in a thread started on demand + and returns the input via the communication Queue. + """ + # lock acquired, we can run input + try: + data = self._ask_input() + except EOFError: + data = "" + + return data + + def text_prompt(self): + widget = TextWidget(str(self._prompt)) + widget.render(self._width) + lines = widget.get_lines() + return "\n".join(lines) + " " + + def _ask_input(self): + text_prompt = self.text_prompt() + sys.stdout.write(text_prompt) + sys.stdout.flush() + + return self._get_input() + + @staticmethod + def _get_input(): + return input() + + +class PasswordInputHandler(InputHandler): + + def __init__(self, callback=None, source=None): + """Class to handle hidden password input from the terminal. + + This class is designed to be instantiated on place where it should be used. + The main method is `get_input()` which is non-blocking asynchronous call. It can be used + as synchronous call be calling the `wait_on_input` method. + + To get result from this class use the `value` property. + + :param callback: You can specify callback which will be called when user give input. + :type callback: Callback function with one argument which will be user input. + + :param source: Source of this input. It will be helpful in case of debugging an issue. + :type source: Class which will process an input from this InputHandler. + """ + super().__init__(callback=callback, source=source) + self._getpass_func = App.get_configuration().password_function + + def set_pass_func(self, getpass_func): + """Set a function for getting passwords.""" + if not getpass_func: + return + + self._getpass_func = getpass_func + + def create_thread_object(self, prompt): + """Return PasswordInputThread for getting user password.""" + return PasswordInputHandlerRequest(App.get_configuration().width, prompt, self, + self._getpass_func) + + +class PasswordInputHandlerRequest(InputHandlerRequest): + """Similar as InputHandlerRequest but don't echo user keys.""" + + def __init__(self, width, prompt, input_handler, getpass_func): + """Create request object to get password input in InputThreadManager. + + :param width: Width of the screen prompt. + :type width: int + + :param prompt: Input prompt. + :type prompt: Instance of `simpleline.render.prompt.Prompt` class. + + :param input_handler: InputHandler instance which created this object. + :type input_handler: InputHandler based instance. + + :param getpass_func: Function to get user password. + :type getpass_func: Function which gets prompt as only parameter and returns user input + string. + """ + super().__init__(width, prompt, input_handler) + self._getpass_func = getpass_func + + def _ask_input(self): + text_prompt = self.text_prompt() + + return self._getpass_func(text_prompt) diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/input_threading.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/input_threading.py new file mode 100644 index 0000000..b8926c8 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/input/input_threading.py @@ -0,0 +1,238 @@ +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import threading +from abc import ABCMeta, abstractmethod + +from simpleline import App +from simpleline.logging import get_simpleline_logger +from simpleline.event_loop.signals import InputReceivedSignal, InputReadySignal + +log = get_simpleline_logger() + + +INPUT_THREAD_NAME = "SimplelineInputThread" + + +class InputThreadManager(): + """Manager object for input threads. + + This manager helps with concurrent user input (still you really shouldn't do that). + """ + + __instance = None + + def __init__(self): + super().__init__() + self._input_stack = [] + self._processing_input = False + + @classmethod + def create_new_instance(cls): + instance = InputThreadManager() + cls.__instance = instance + + instance._post_init_configuration() # pylint: disable=protected-access + + def _post_init_configuration(self): + # pylint: disable=protected-access + App.get_event_loop().register_signal_handler(InputReceivedSignal, + self.__instance._input_received_handler) + + @classmethod + def get_instance(cls): + if not cls.__instance: + cls.create_new_instance() + + return cls.__instance + + def _input_received_handler(self, signal, args): + thread_object = self._input_stack.pop() + thread_object.emit_input_ready_signal(signal.data) + + if thread_object.thread: + thread_object.thread.join() + + # wait until used object ends + for t in self._input_stack: + t.emit_failed_input_ready_signal() + if t.thread: + t.thread.join() + + # remove all other items waiting for input + self._input_stack.clear() + self._processing_input = False + + def start_input_thread(self, input_thread_object, concurrent_check=True): + """Start input thread to get user input. + + :param input_thread_object: Input thread object based on InputThread class. + :param concurrent_check: Should the concurrent thread check be fatal? (default True). + """ + self._input_stack.append(input_thread_object) + self._check_input_thread_running(concurrent_check) + self._start_user_input_async() + + def _check_input_thread_running(self, raise_concurrent_check): + if len(self._input_stack) != 1: + if not raise_concurrent_check: + log.warning("Asking for multiple inputs with concurrent check bypassed, " + "last who asked wins! Others are dropped.") + else: + msg = "" + for t in self._input_stack: + requester_source = t.requester_source or "Unknown" + msg += "Input handler: {} Input requester: {}\n".format(t.source, + requester_source) + + msg.rstrip() + + raise KeyError("Can't run multiple input threads at the same time!\n" + "Asking for input:\n" + "{}".format(msg)) + + def _start_user_input_async(self): + thread_object = self._input_stack[-1] + + if self._processing_input: + self._print_new_prompt(thread_object) + return + + thread_object.initialize_thread() + self._processing_input = True + thread_object.start_thread() + + @staticmethod + def _print_new_prompt(thread_object): + prompt = thread_object.text_prompt() + + # print new prompt + print(prompt, end="") + + +class InputRequest(metaclass=ABCMeta): + """Base input request class. + + This should be overloaded for every InputHandler class. Purpose of this class is to print + prompt and get input from user. + + The `run_input` method is the entry point for this class. Output from this method must be + a user input. + The `text_prompt` method is used to get textual representation of a prompt. This will be used + on concurrent input to replace existing prompt to get new input. + + WARNING: + The `run_input` method will run in a separate thread! + """ + + def __init__(self, source, requester_source=None): + super().__init__() + self._source = source + self._requester_source = requester_source + self.thread = None + + @property + def source(self): + """Get direct source of this input request. + + :returns: InputHandler instance. + """ + return self._source + + @property + def requester_source(self): + """Get requester -- source of this input. + + :returns: Anything probably UIScreen based instance. + """ + return self._requester_source + + def emit_input_ready_signal(self, input_data): + """Emit the InputReadySignal signal with collected input data. + + :param input_data: Input data received. + :type input_data: str + """ + handler_source = self.source + signal_source = self._get_request_source() + + new_signal = InputReadySignal(source=signal_source, input_handler_source=handler_source, + data=input_data, success=True) + App.get_event_loop().enqueue_signal(new_signal) + + def emit_failed_input_ready_signal(self): + """Emit the InputReadySignal with failed state.""" + handler_source = self.source + signal_source = self._get_request_source() + + new_signal = InputReadySignal(source=signal_source, input_handler_source=handler_source, + data="", success=False) + App.get_event_loop().enqueue_signal(new_signal) + + def _get_request_source(self): + """Get user input request source. + + That means object who is using InputHandler. + If this object is not specified then return InputHandler as a source. + """ + return self.requester_source or self.source + + def initialize_thread(self): + """Initialize thread for this input request. + + Do not call this directly! Will be called by InputThreadManager. + """ + self.thread = threading.Thread(name=INPUT_THREAD_NAME, target=self.run) + self.thread.daemon = True + + def start_thread(self): + """Start input thread. + + Do not call this directly! Will be called by InputThreadManager. + """ + self.thread.start() + + def run(self): + """Run the `run_input` method and propagate input outside. + + Do not call this method directly. It will be called by InputThreadManager. + """ + data = self.get_input() + + App.get_event_loop().enqueue_signal(InputReceivedSignal(self, data)) + + @abstractmethod + def text_prompt(self): + """Get text representation of the user prompt. + + This will be used to get high priority input. + + :returns: String representation of the prompt or None if no prompt is present. + """ + return None + + @abstractmethod + def get_input(self): + """Print prompt and get an input from user. + + ..NOTE: Overload this method in your class. + + Return this input from a function. + """ + return "" diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/logging.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/logging.py new file mode 100644 index 0000000..f22ddaa --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/logging.py @@ -0,0 +1,39 @@ +# Logging functions and methods used by Simpleline. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +import logging + + +SIMPLELINE_LOGGER = "simpleline" + + +def setup_logging(): + """Set proper logging for a library""" + log = get_simpleline_logger() + null_hd = logging.NullHandler() + log.addHandler(null_hd) + + +def get_simpleline_logger(): + """Return logging instance that can be used in the application.""" + return logging.getLogger(SIMPLELINE_LOGGER) diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__init__.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__init__.py new file mode 100644 index 0000000..20125e6 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__init__.py @@ -0,0 +1,31 @@ +# Module with classes to handle rendering and input. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from simpleline.errors import SimplelineError + + +class RenderError(SimplelineError): + """Exception raised when error in rendering happens.""" + + +class RenderUnexpectedError(RenderError): + """Exception raised when something goes really wrong.""" diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0735a0ddae6362ba717d9949ee87791d66e7744 GIT binary patch literal 751 zcma)4O^Xvj5be(7i>MnGiNb>Gs30uj4Eu32yPg&lA%_-^*`jx*O&TZNV|Rz$c-oU^ zkN$=I0sa8b{(}L%c=9GBdbWBdiHIKTL(S`|;?1j9{b1u-Cm@7;x$*H<=l-V;UlFfQ zV~OTR2rkG8Ve~0^LLI$LdgKmawVQ+mLweu|@VHu;tz)(^tgW*FYu+O}t#7_%hZf!E za*}5vlS&*LqfO%Tt3#JyzJ=g|42h!*c~7=nz^JRUnrpBC+3Lj=CR8d+N%3a)_&gE0 zlUjv_ODodwY%EkLJbx%LS@udb3dcOpg|g8l8C*7tHh|(20Z?=RCOVyF9$y7`J>}W5 z(gk=ajdfnI(pYW*q&h*+1F()enE-dr$kVA47Qi%7`rOY^JdUT<#F;#e^O+lKwIA&s z#8x`-Fz3lDJ`xshD>LFsWDFpcbO2F4GkyVO@OD^#drLmoADN9+{=dxI{>!{xW!?)V z&U2ACkybYD{o6*XC&G=rdm}9@n#r?l7M>ZcMo~HKz_h#|KX@gr>(S;aY$I5U?^hkZ zIKVY-{x%>g*JX`=P1WQj!=J20yI<|;$Xv%h|6c4}4BrDv>5queXwjs!|1Mq-{4Cm( N9=?C}6Y*jB-(L_ay8{3K literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/adv_widgets.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/adv_widgets.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1d3331c9553fbc9448702433459aba45a65dec4 GIT binary patch literal 11804 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 K9}<4JhWt0$S~ENV literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/containers.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/containers.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14b2b31803da987d60465949c443fb47f2d3dd38 GIT binary patch literal 18941 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_scheduler.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_scheduler.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb2dfce204ff3c55a8a2a60b2b21819e9a6e913a GIT binary patch literal 14095 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_stack.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/__pycache__/screen_stack.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bc9f2876221ce23be2f0911bab2883c3f6dca22 GIT binary patch literal 4532 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. +# + +import sys + +from simpleline.render import widgets +from simpleline.render.containers import WindowContainer +from simpleline.render.prompt import Prompt +from simpleline.render.screen import UIScreen, InputState +from simpleline.input.input_handler import PasswordInputHandler +from simpleline.utils.i18n import _, N_, C_ + +__all__ = ["ErrorDialog", "GetInputScreen", "GetPasswordInputScreen", "HelpScreen", + "PasswordDialog", "YesNoDialog"] + + +class ErrorDialog(UIScreen): + """Dialog screen for reporting errors to user.""" + + def __init__(self, message): + """ + :param message: the message to show to the user + :type message: str + """ + super().__init__() + self.title = N_("Error") + self._message = message + + def refresh(self, args=None): + super().refresh(args) + text = widgets.TextWidget(self._message) + self.window.add_with_separator(widgets.CenterWidget(text)) + + def prompt(self, args=None): + return Prompt(_("Press %s to exit") % Prompt.ENTER) + + def input(self, args, key): + """This dialog is closed by any input. + + And causes the program to quit. + """ + sys.exit(1) + + +class PasswordDialog(UIScreen): + """Dialog screen for password input.""" + + def __init__(self, message=None): + """ + :param message: password prompt question + :type message: string + """ + super().__init__() + self.title = N_("Password") + self._message = message or _("Enter your passphrase") + self._password = None + + def refresh(self, args=None): + super().refresh(args) + text = widgets.TextWidget(self._message) + self.window.add_with_separator(widgets.CenterWidget(text)) + + def prompt(self, args=None): + handler = PasswordInputHandler(source=self) + if self.password_func: + handler.set_pass_func(self.password_func) + + handler.get_input(_("Passphrase: ")) + handler.wait_on_input() + + if not handler.input_successful(): + return None + + self._password = handler.value + + # this may seem innocuous, but it's really a giant hack; we should + # not be calling close() from prompt(), but the input handling code + # in the TUI is such that without this very simple workaround, we + # would be forever pelting users with a prompt to enter their pw + self.close() + return None + + @property + def answer(self): + """The response can be None (no response) or the password entered.""" + return self._password + + def input(self, args, key): + if key: + self._password = key + return InputState.PROCESSED_AND_CLOSE + + return InputState.DISCARDED + + +class YesNoDialog(UIScreen): + """Dialog screen for Yes - No questions.""" + + def __init__(self, message): + """ + :param message: the message to show to the user + :type message: unicode + """ + super().__init__() + self.title = N_("Question") + self._message = message + self._response = None + + def refresh(self, args=None): + super().refresh(args) + text = widgets.TextWidget(self._message) + self.window.add_with_separator(widgets.CenterWidget(text)) + + def prompt(self, args=None): + return Prompt(_("Please respond '%(yes)s' or '%(no)s'") % { + # TRANSLATORS: 'yes' as positive reply + "yes": C_('TUI|Spoke Navigation', 'yes'), + # TRANSLATORS: 'no' as negative reply + "no": C_('TUI|Spoke Navigation', 'no') + }) + + def input(self, args, key): + # TRANSLATORS: 'yes' as positive reply + if key == C_('TUI|Spoke Navigation', 'yes'): + self._response = True + return InputState.PROCESSED_AND_CLOSE + + # TRANSLATORS: 'no' as negative reply + if key == C_('TUI|Spoke Navigation', 'no'): + self._response = False + return InputState.PROCESSED_AND_CLOSE + + return InputState.DISCARDED + + @property + def answer(self): + """The response can be True (yes), False (no) or None (no response).""" + return self._response + + +class HelpScreen(UIScreen): + """Screen to display a help message.""" + + def __init__(self, help_path): + """ + :param help_path: help file name + :type help_path: str + """ + super().__init__() + self.title = N_("Help") + self.help_path = help_path + + def refresh(self, args=None): + """ Show the help. """ + super().refresh(args) + help_message = _("The help is not available.") + + if self.help_path: + with open(self.help_path, 'r') as f: + help_message = f.read() + + self.window.add_with_separator(widgets.TextWidget(help_message)) + + def input(self, args, key): + """ Handle user input. """ + return InputState.PROCESSED_AND_CLOSE + + def prompt(self, args=None): + return Prompt(_("Press %s to return") % Prompt.ENTER) + + +class GetInputScreen(UIScreen): + """Screen for getting user input.""" + + def __init__(self, message): + """ + :param message: Prompt printed before user input. + :type message: str + """ + super().__init__() + self._message = message + self._value = None + self._conditions = [] + + @property + def value(self): + """User input.""" + return self._value + + def add_acceptance_condition(self, acceptance_function, args=None): + """Add acceptance condition to the conditions list. + + :param acceptance_function: Functions that accepts or rejects a user input. + :type acceptance_function: `function(input, args) -> bool` - function which takes + user input (string) and arguments (`args`) and return True when + input is accepted or False if rejected so we will ask for + a new input. + + :param args: Second argument for `acceptance_function` the first one will be user input. + :type args: Anything. + """ + self._conditions.append((acceptance_function, args)) + + def clear_acceptance_conditions(self): + """Clear list of the acceptance conditions.""" + self._conditions.clear() + + def refresh(self, args=None): + super().refresh(args) + self._window = WindowContainer() + + def prompt(self, args=None): + return Prompt(message=self._message) + + def input(self, args, key): + if not self._test_input(key): + return InputState.DISCARDED + + self._value = key + + return InputState.PROCESSED_AND_CLOSE + + def _test_input(self, key): + for f, args in self._conditions: + if not f(key, args): + return False + + return True + + +class GetPasswordInputScreen(GetInputScreen): + """Screen for getting user password input.""" + + def __init__(self, message): + super().__init__(message) + self.hide_user_input = True diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/containers.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/containers.py new file mode 100644 index 0000000..fb233b2 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/containers.py @@ -0,0 +1,475 @@ +# Widgets for holding other widgets. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from math import ceil + +from simpleline.render.widgets import Widget, TextWidget, SeparatorWidget + +from simpleline.logging import get_simpleline_logger + +__all__ = ["ListRowContainer", "ListColumnContainer", "WindowContainer"] + +log = get_simpleline_logger() + + +class Container(Widget): + """Base class for containers which will do positioning of the widgets.""" + + def __init__(self, items=None, numbering=True): + """Construct Container. + + :param items: List of items for positioning in this Container. Callback + can't be specified this way. + :type items: List of items for rendering. + + :param numbering: Enable/disable automatic numbering (labels) for items. + Enabled by default (True). + :type numbering: bool + """ + super().__init__() + self._key_pattern = None + self._items = [] + if items: + for i in items: + self._items.append(ContainerItem(i)) + + if numbering: + self._key_pattern = KeyPattern() + else: + self._key_pattern = None + + @property + def size(self): + """Return items count.""" + return len(self._items) + + @property + def key_pattern(self): + """Return key pattern which will be used for items numbering. + + Will return `None` if not set. + """ + return self._key_pattern + + @key_pattern.setter + def key_pattern(self, key_pattern): + """Set the key pattern object which will be used for items numbering. + + Setting `None` will stop doing numbering. + """ + self._key_pattern = key_pattern + + def add(self, item, callback=None, data=None): + """Add item to the Container. + + :param item: Add item to this container. + :type item: Could be item (based on `simpleline.render.widgets.Widget`) + or other container (based on `simpleline.render.containers.Container`). + + :param callback: Add callback for this item. This callback will be called when user + activate this `item`. + :type callback: function ``func(data)``. + + :param data: Data which will be passed to the callback. + :param data: Anything. + + :returns: ID of the item in this Container. + :rtype: int + """ + self._items.append(ContainerItem(item, callback, data)) + return len(self._items) - 1 + + def process_user_input(self, key): + """Process input from the user if any of the items in the list was called. + + This method must be called in `UIScreen.input()` method if list widget should call + the callbacks. + + :param key: Key pressed from user. + :type key: str + + :returns: True if key was processed. False otherwise. + """ + if not self._key_pattern: + return False + + if not isinstance(key, str): + return False + + res = self._key_pattern.translate_input_to_widget_id(key) + if res is not None and res >= 0: + try: + item = self._items[res] + if item.callback is not None: + item.callback(item.data) + return True + except IndexError: # container widget with this id doesn't exists + return False + + return False + + def create_number_label(self, item_id): + """Create TextWidget from KeyPattern. + + :param item_id: Create label for item with this id. + :type item_id: int + + :returns: Widget with label for the item with item_id. + :rtype: `simpleline.render.widgets.TextWidget` instance. + """ + number_widget = TextWidget(self._key_pattern.get_widget_label(item_id)) + return number_widget + + +class WindowContainer(Container): + """Base container for screens. + + This can hold other containers or Widgets for rendering. + """ + + def __init__(self, title=None): + """Construct base container for screens. + + This container doesn't have numbering support. Input other containers in it to + allow numbering and input processing. + + :param title: Title line with separator after this title. + :type title: str + """ + super().__init__(numbering=False) + self._title = title + + def add_with_separator(self, item, callback=None, data=None, blank_lines=1): + """Add widget and after widget add blank line. + + This method will call + `self.add(item, callback, data)` + `self.add_separator(lines)` + + :param item: Add item to this container. + :type item: Could be item (based on `simpleline.render.widgets.Widget`) + or other container (based on `simpleline.render.containers.Container`). + + :param callback: Add callback for this item. This callback will be called when user + activate this `item`. + :type callback: function ``func(data)``. + + :param data: Data which will be passed to the callback. + :param data: Anything. + + :param blank_lines: How many blank lines should be printed. + :type blank_lines: int greater than 0. + + :returns: ID of the item in this Container. + :rtype: int + """ + item_id = self.add(item, callback, data) + self.add_separator(blank_lines) + + return item_id + + def add_separator(self, lines=1): + """Add blank lines between widgets. + + :param lines: How many blank lines should be printed. + :type lines: int greater than 0. + """ + self.add(SeparatorWidget(lines)) + + @property + def title(self): + """Title of WindowContainer.""" + return self._title + + def render(self, width): + """Render widgets to it's internal buffer. + + :param width: the maximum width the item can use + :type width: int + + :return: nothing + """ + super().render(width) + + # set cursor position to top-left corner + self.set_cursor_position(0, 0) + + if self._title: + self._draw_title_and_separator(width) + + for item in self._items: + widget = item.widget + widget.render(width) + self.draw(widget) + + def _draw_title_and_separator(self, width): + title_widget = TextWidget(self._title) + sep = SeparatorWidget() + + title_widget.render(width) + sep.render(width) + + self.draw(title_widget) + self.draw(sep) + + +class ListRowContainer(Container): + """Place widgets in rows automatically. + + Compared to the ColumnWidget this is able to handle word wrapping correctly. + + There is numbering N) automatically for all items. To disable this feature call + `self.key_pattern = None`. If you want other numbering then look on `KeyPattern` class. + + Widgets will be placed based on the number of columns in the following way: + + 1) w1 2) w2 3) w3 + 4) w4 5) w5 6) w6 + .... + """ + + def __init__(self, columns, items=None, columns_width=None, spacing=3, numbering=True): + """Create ListWidget with specific number of columns. + + :param columns: How many columns we want. + :type columns: int, bigger than 0 + + :param items: List of items for positioning in this Container. Callback can't be + specified this way. + :type items: List of items for rendering. + + :param columns_width: Width of every column. If nothing specified the maximum width + will be distributed to columns. + :type columns_width: int or None + + :param spacing: Set the spacing between columns. + :type spacing: int + + :param numbering: Enable/disable automatic numbering (labels) for items. + Enabled by default (True). + :type numbering: bool + """ + super().__init__(items, numbering) + self._columns = columns + self._columns_width = columns_width + self._spacing = spacing + self._numbering_widgets = [] + + def render(self, width): + """Render widgets to it's internal buffer. + + :param width: the maximum width the item can use + :type width: int + + :return: nothing + """ + super().render(width) + + if self._columns_width is None: + spaces_between_columns = self._columns - 1 + sum_spacing = spaces_between_columns * self._spacing + self._columns_width = int((width - sum_spacing) / self._columns) + + ordered_map = self._get_ordered_map() + lines_per_rows = self._lines_per_every_row(ordered_map) + + # the leftmost empty column + col_pos = 0 + + for col in ordered_map: + row_pos = 0 + + # render and draw contents of column + for row_id, item_id in enumerate(col): + container = self._items[item_id] + widget = container.widget + + # set cursor to first line and leftmost empty column + self.set_cursor_position(row_pos, col_pos) + + if self._key_pattern is not None: + number_widget = self._numbering_widgets[item_id] + widget_width = len(number_widget.text) + self.draw(number_widget) + self.set_cursor_position(row_pos, col_pos + widget_width) + + self.draw(widget, block=True) + row_pos = row_pos + lines_per_rows[row_id] + + # recompute the leftmost empty column + col_pos = max((col_pos + self._columns_width), self.width) + self._spacing + + def _lines_per_every_row(self, items): + self._render_all_items() + # call `self._render_and_calculate_lines_per_rows()` method instead + lines_per_row = [] + + # go through all items and find how many lines we need for each row + # printed (because of wrapping) + for column_items in items: + for row_id, item_id in enumerate(column_items): + item = self._items[item_id] + if len(lines_per_row) <= row_id: + lines_per_row.append(0) + + lines_per_row[row_id] = max(lines_per_row[row_id], len(item.widget.get_lines())) + + return lines_per_row + + def _render_all_items(self): + for item_id, item in enumerate(self._items): + item_width = self._columns_width + + if item_width <= 0: + raise ValueError("Widget can't be rendered! Columns width is too small.") + + if self._key_pattern: + number_widget = self.create_number_label(item_id) + # render numbers before widgets + number_width = len(number_widget.text) + number_widget.render(number_width) + self._numbering_widgets.append(number_widget) + # reduce the size of widget because of the number + item_width -= number_width + + if item_width <= 0: + raise ValueError("Widget can't be rendered with numbering on! " + "Increase column width or disable numbering.") + + item.widget.render(item_width) + + def _get_ordered_map(self): + """Return list of identifiers (index) to the original item list. + + .. NOTE: Use of ``self._prepare_list()` is encouraged to create output list and + just fill up this list. + """ + # create list of columns (lists) + ordering_map = self._prepare_list() + + for item_id in range(self.size): + ordering_map[item_id % self._columns].append(item_id) + + return ordering_map + + def _prepare_list(self): + """Prepare list for items ordering to rows and columns. + + List will be prepared as ([column 1], [column 2], ...) + """ + return list(map(lambda x: [], range(0, self._columns))) + + +class ListColumnContainer(ListRowContainer): + """Place widgets in columns automatically. + + Compared to the ColumnWidget this is able to handle word wrapping correctly. + + There is numbering N) automatically for all items. To disable this feature call + `self.key_pattern = None`. If you want other numbering then look on `KeyPattern` class. + + Widgets will be placed based on the number of columns in the following way: + + 1) w1 4) w4 7) w7 + 2) w2 5) w5 8) w8 + 3) w3 6) w6 9) w9 + """ + + def _get_ordered_map(self): + ordering_map = self._prepare_list() + items_in_column = ceil(len(self._items) / self._columns) + + for item_id in range(self.size): + col_position = int(item_id // items_in_column) + ordering_map[col_position].append(item_id) + + return ordering_map + + +class KeyPattern(): + """Pattern for automatic key printing before items.""" + + def __init__(self, pattern="{:d}) ", offset=1): + """Create the pattern class. + + For enabling greater functionality than python 3 format is able to do, feel free to + override this class and use your subclass instead. + + :param pattern: Set pattern which will be called for every item. + :type pattern: Strings format method. + See https://docs.python.org/3.3/library/string.html#format-string-syntax. + + :param offset: Set the offset for numbering items. Default is 1 to start indexing + naturally for user. + :type offset: int + """ + self._pattern = pattern + self._offset = offset + + def get_widget_label(self, item_id): + """Get widget identifier for user input description. + + It should be something similar to the pattern. + + :param item_id: Position of the widget in the list. + :type item_id: int starts from 0. + """ + return self._pattern.format(item_id + self._offset) + + def translate_input_to_widget_id(self, user_input): + """Get id of the widget from the user input. + + This is reverse translation to `self.get_widget_identifier()`. + + :param user_input: Input from user: + :type user_input: str + + :return: ID of the widget in the list or None if the input can't be translated. + :rtype: int or None + """ + try: + return int(user_input) - 1 + except ValueError: + log.debug("No callback registered for user input %s", user_input) + return None + + +class ContainerItem(): + """Item used inside of containers to store widgets callbacks and data. + + Internal representation for Containers. Do not use this class directly. + """ + + def __init__(self, widget, callback=None, data=None): + """Construct WidgetContainer. + + :param widget: Any item from `simpleline.render.widgets` or `Container`. + :type widget: Class subclassing the `simpleline.render.widgets.Widget` class + or `simpleline.render.containers.Container`. + + :param callback: This callback will be called as reaction on user input. + :type callback: Function with one data parameter: `def func(data):`. + + :param data: Params which will be passed to callback. + :type data: Anything. + """ + self.widget = widget + self.callback = callback + self.data = data diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/prompt.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/prompt.py new file mode 100644 index 0000000..4c99e35 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/prompt.py @@ -0,0 +1,154 @@ +# Class for the Anaconda TUI prompt. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Vendula Poncova +# +import logging + +from simpleline.utils.i18n import N_, _ + +log = logging.getLogger("simpleline") + + +class Prompt(): + """Class to create a prompt message with options.""" + # Default message of the prompt + DEFAULT_MESSAGE = N_("Please make a selection from the above") + + # String to use in a prompt when we want users to press the key ENTER. + ENTER = N_("ENTER") + + # TRANSLATORS: 'q' to quit + QUIT_DESCRIPTION = N_("to quit") + QUIT = 'q' + + # TRANSLATORS:'c' to continue + CONTINUE_DESCRIPTION = N_("to continue") + CONTINUE = 'c' + + # TRANSLATORS:'r' to refresh + REFRESH_DESCRIPTION = N_("to refresh") + REFRESH = 'r' + + # TRANSLATORS:'h' to help + HELP_DESCRIPTION = N_("to help") + HELP = 'h' + + def __init__(self, message=DEFAULT_MESSAGE): + """ + :param message: the message of the prompt + :type message: str|None + """ + self.message = message + self.options = dict() + + def set_message(self, message): + """Set the prompt message. + + :param message: the message of the prompt + :type message: str|None + """ + self.message = message + + def add_option(self, key, description): + """Add an option to the prompt. + Causes a warning if the option already exists. + + :param key: the key for choosing the option + :type key: str + + :param description: the description of the option + :type description: str + """ + if key in self.options: + log.warning("The option '%s' does already exist in '%s'.", key, self) + + self.options[key] = description + + def update_option(self, key, description): + """Update an option in the prompt. + Causes a warning if the option does not exist. + + :param key: the key for choosing the option + :type key: str + + :param description: the description of the option + :type description: str + """ + if key not in self.options: + log.warning("The option '%s' does not exist in '%s'.", key, self) + + self.options[key] = description + + def add_refresh_option(self, description=REFRESH_DESCRIPTION): + """Add the option to refresh.""" + if Prompt.REFRESH in self.options: + self.update_option(Prompt.REFRESH, description) + else: + self.add_option(Prompt.REFRESH, description) + + def add_continue_option(self, description=CONTINUE_DESCRIPTION): + """Add the option to continue.""" + if Prompt.CONTINUE in self.options: + self.update_option(Prompt.CONTINUE, description) + else: + self.add_option(Prompt.CONTINUE, description) + + def add_quit_option(self, description=QUIT_DESCRIPTION): + """Add the option to quit.""" + if Prompt.QUIT in self.options: + self.update_option(Prompt.QUIT, description) + else: + self.add_option(Prompt.QUIT, description) + + def add_help_option(self, description=HELP_DESCRIPTION): + """Add the option to help.""" + if Prompt.HELP in self.options: + self.update_option(Prompt.HELP, description) + else: + self.add_option(Prompt.HELP, description) + + def remove_option(self, key): + """Remove an option with the given key. + + :param key: the key of the option + :type key: str + + :return: the removed option + :rtype: str|None + """ + return self.options.pop(key, None) + + def __str__(self): + """Return the string representation of the prompt.""" + if not self.message and not self.options: + return "" + + parts = [] + + if self.message: + parts.append(_(self.message)) + + if self.options: + opt_list = ["'%s' %s" % (key, _(self.options[key])) + for key in sorted(self.options.keys())] + opt_str = "[%s]" % ", ".join(opt_list) + parts.append(opt_str) + + return " ".join(parts) + ": " diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__init__.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__init__.py new file mode 100644 index 0000000..6918b28 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__init__.py @@ -0,0 +1,313 @@ +# Base class for text window screens. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from enum import Enum + +from simpleline import App +from simpleline.render.containers import WindowContainer +from simpleline.render.prompt import Prompt +from simpleline.render.screen.signal_handler import SignalHandler +from simpleline.render.screen.input_manager import InputManager +from simpleline.utils.i18n import _ + +__all__ = ["UIScreen", "InputState"] + + +class UIScreen(SignalHandler): + """Base class representing one TUI Screen. + + Shares some API with anaconda's GUI to make it easy for devs to create similar UI + with the familiar API. + """ + + def __init__(self, title=None, screen_height=30): + """ Constructor of the TUI screen. + + :param title: Title line of the screen. + :type title: str + + :param screen_height: height of the screen (useful for printing long widgets) + :type screen_height: int (the value must be bigger than 4) + """ + self._title = title + self._screen_height = screen_height + self._screen_ready = False + + # ask for password + self._hide_user_input = False + self._password_func = None + + # do not print separator for this screen + self._no_separator = False + + # list that holds the content to be printed out + self._window = WindowContainer(self.title) + + # should the input be required after draw + self._input_required = True + + # index of the page (subset of screen) shown during show_all + # indexing starts with 0 + self._page = 0 + + self._input_manager = InputManager(ui_screen=self) + + def __str__(self): + """For easier logging.""" + return self.__class__.__name__ + + @property + def title(self): + """Screen title.""" + return self._title + + @title.setter + def title(self, title): + """Set screen title. + + Set `None` to remove title. + """ + self._title = title + + @property + def password_func(self): + """Get password function. + + This is function with one argument to get password from command line. + """ + return self._password_func + + @password_func.setter + def password_func(self, value): + """Set password function. + + :param value: Function to get password from a command line. + :type value: Function with one argument which is text representation of prompt. + """ + self._password_func = value + + @property + def screen_ready(self): + """This screen is ready for use.""" + return self._screen_ready + + @screen_ready.setter + def screen_ready(self, screen_ready): + """Set ready status for this screen.""" + self._screen_ready = screen_ready + + @property + def input_required(self): + """Return if the screen requires input.""" + return self._input_required + + @input_required.setter + def input_required(self, input_required): + """Set if the screen should require input.""" + self._input_required = input_required + + @property + def no_separator(self): + """Should we print separator for this screen? + + :returns: True to print separator before this screen (default). + False do not print separator. + """ + return self._no_separator + + @no_separator.setter + def no_separator(self, no_separator): + """Print or do not print separator. + + :param no_separator: Specify if the separator should be printed. + :type no_separator: bool (default: False). + """ + self._no_separator = no_separator + + @property + def hide_user_input(self): + """Hide typed user input. + + This is main solution how to ask for password. + + :returns: True if user input should be hidden. + False otherwise (default). + """ + return self._hide_user_input + + @hide_user_input.setter + def hide_user_input(self, hide_input): + """Should be the user input hidden. + + :param hide_input: True if user input should be hidden. + False if not (default). + :type hide_input: bool (default: False). + """ + self._hide_user_input = hide_input + + @property + def window(self): + """Return WindowContainer instance.""" + return self._window + + @window.setter + def window(self, window): + """Set base WindowContainer instance. + + :param window: Base window container containing other widgets and containers. + :type window: Instance of `simpleline.render.containers.WindowContainer` class. + """ + self._window = window + + def get_user_input(self, message, hidden=False): + """Get immediately input from the user. + + Use this with cautious. Never call this in middle of rendering or when other + input is already waiting. It is recommended to use `self.input_required` instead. + + :param message: Message prompt for the user. + :type message: str + + :param hidden: Do not echo user input (password typing). + :type hidden: bool + """ + return self._input_manager.get_input_blocking(message, hidden) + + def setup(self, args): + """Do additional setup right before this screen is used. + + It is mandatory to call this ancestor method in the child class to set ready status. + + :param args: arguments for the setup + :type args: array of values + :return: whether this screen should be scheduled or not + :rtype: bool + """ + self._screen_ready = True + App.get_event_loop().register_signal_source(self) + return True + + def refresh(self, args=None): + """Method which prepares the content desired on the screen to `self.window`. + + :param args: optional argument passed from switch_screen calls + :type args: anything + """ + self.window = WindowContainer(self._title) + + def _print_widget(self, widget): + """Prints a widget with user interaction (when needed). + + Could be longer than the screen height. + + :param widget: widget to print + :type widget: Widget instance + """ + # TODO: Work even for lower screen_height than 4 + pos = 0 + lines = widget.get_lines() + num_lines = len(lines) + + if num_lines == 0: + return + + prompt_height = 2 + real_screen_height = self._screen_height - prompt_height + + if num_lines < real_screen_height: + # widget plus prompt are shorter than screen height, just print the widget + print(u"\n".join(lines)) + return + + # long widget, print it in steps and prompt user to continue + last_line = num_lines - 1 + while pos <= last_line: + if pos + real_screen_height > last_line: + # enough space to print the rest of the widget plus regular + # prompt (2 lines) + for line in lines[pos:]: + print(line) + pos += self._screen_height - 1 + else: + # print part with a prompt to continue + for line in lines[pos:(pos + real_screen_height)]: + print(line) + custom_prompt = Prompt(_("\nPress %s to continue") % Prompt.ENTER) + self._ask_user_input_blocking(custom_prompt) + pos += real_screen_height + + def _ask_user_input_blocking(self, prompt): + return self._input_manager.get_input_blocking(prompt, False) + + def show_all(self): + """Print WindowContainer in `self.window` with all its content.""" + self.window.render(App.get_configuration().width) + self._print_widget(self.window) + + def input(self, args, key): + """Method called to process input. If the input is not handled here, return it. + + :param key: input string to process + :type key: str + :param args: optional argument passed from switch_screen calls + :type args: anything + :return: return `simpleline.render.InputState.PROCESSED` if key was handled, + `simpleline.render.InputState.DISCARDED` if the screen should not process input + on the scheduler and key if you want it to. + :rtype: `simpleline.render.InputState` enum | str + """ + return key + + def get_input_with_error_check(self, args): + """Get user input and redraw if user add too many invalid inputs. + + This method should be used only by ScreenScheduler. + + :param args: Arguments passed in when scheduling this screen. + :type args: Anything. + """ + self._input_manager.get_input(args=args) + + def prompt(self, args=None): + """Return the text to be shown as prompt or handle the prompt and return None. + + :param args: optional argument passed from switch_screen calls + :type args: anything + :return: returns an instance of Prompt with text to be shown next to the prompt + for input or None to skip further input processing + :rtype: Prompt instance|None + """ + prompt = Prompt() + prompt.add_refresh_option() + prompt.add_continue_option() + prompt.add_quit_option() + return prompt + + def closed(self): + """Callback when this screen is closed.""" + + +class InputState(Enum): + PROCESSED = 1 + PROCESSED_AND_REDRAW = 2 + PROCESSED_AND_CLOSE = 3 + DISCARDED = 0 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93faa7d393d91f325fd307e38e375413f185b39a GIT binary patch literal 11639 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/input_manager.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/input_manager.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b750402322d3f44e511112d5c0746c1d45ad6b5 GIT binary patch literal 7602 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/signal_handler.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/__pycache__/signal_handler.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e39ddaf2d1442ac320e1525b5862281a6d292ed2 GIT binary patch literal 3593 zcmd5*$jr|Ze_p)z<-xDeZ?#m^JG=m$U2=nzjVolukj6>uC$1z`k}|oHlBttqg3OU} za*~u&#e~+9>2i9W@eWbzmZz%7|7XK{PafNclLDb>rA)00H@l`|mCav#Y4vI#O< z?w11_MCQr~a4;7RYByGFzv?k=4;h54^We5yWrEh3tOZp;w*pRUxWM(dsZeeUYWog# zY|q=YotvVN&9=2{*N;_8SqiP<1isH4c_v@MA+&SnXf#J<%@y>HTis@o20q<(Z!H^OiqPkmt4m=)z;%c#S`#5M~cyC9rb$JwXuz45$Ol*B!m&dk+7Em z|7DGqMn<1aM*?7ywJz@f_fo^=c0GckbQB~zL6hFGeMw~yqn<6vod#4mNtdtwj(uTDy^+!7L*j)@rZ6UeMh>1AMF*-m(+(d+HRc* zVQ;guv}#K`-?E6K61@bHb~@j{FvB4*sIj@oy4G0ocYsd*c6KeFLDy3PDCZ_6ZBTmbPPJXWW$&v*Aj7Y0-_oADiWKEXA7^=Q=|L`Pap&sY2G57QVfejz%+Ub6Ct?&jWBWk^L{u%IK=#0P1cO>koyT0D4v6F0`ZH3l0sj?vF=#l+(leD z0|L@;q&p24_RNK^-Z?POKPMdTD$NbD9zhDjR%-*@NWcmVVNcsgJQIp~l)3F-z;#^J z7o98Pz`(rSI#b%tsyS#!Wuh2!sin63X;L$4uD5eQM2~P1@5E082 zc;S#%twuDCC{8uShaa{CTMWeJkx*%#nZ>9UqjYsk?-b(1M3^JyF+5jAfkq%)l14&it= zzPA^je)u;azrH_u;rSr*aZt@0Yk7ksLGy#5X<5EqXOn;!OamUXLXd(oF+%i40ekoZLN1Nhu$S=GR?EIxuKX=N*?IGjgu8bml@Sx{P~ z>sYpw+}&(SCO~`C()V-Kb)>^Q&$8fumcfomP(w1jtumYUp*<9ei3RBV@hQ;jQ6iHz zpN!(J(G-MY!-ka#Om;&)IX&A=u1!BznLf(IxSvHK~Awj8B{{o87 Bq{;vQ literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/input_manager.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/input_manager.py new file mode 100644 index 0000000..dc0c220 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/input_manager.py @@ -0,0 +1,203 @@ +# Class for managing input and output for application. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from enum import Enum + +from simpleline import App +from simpleline.event_loop import ExitMainLoop +from simpleline.event_loop.signals import ExceptionSignal +from simpleline.render.prompt import Prompt +from simpleline.input import InputHandler, PasswordInputHandler + +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + + +class InputManager(): + + def __init__(self, ui_screen): + """Processor for user input. + + This class is mainly helper class for ScreenScheduler. + + :param ui_screen: Screen associated with this input manager. + :type ui_screen: The `simpleline.render.screen.UIScreen` based instance. + """ + super().__init__() + self._ui_screen = ui_screen + self._input_error_counter = 0 + self._input_error_threshold = 5 + self._input_args = None + + @property + def input_error_counter(self): + """Return how many times the user provided bad input.""" + return self._input_error_counter + + @property + def input_error_threshold_exceeded(self): + """Did the error counter pass the threshold? + + The screen should be redraw. + """ + errors = self._input_error_counter % self._input_error_threshold + return errors == 0 + + def get_input_blocking(self, message, hidden): + """Get blocking input from the user. + + :param message: Message prompt for the user. + :type message: str + + :param hidden: Do not echo user input (password typing). + :type hidden: bool + """ + if hidden: + handler = PasswordInputHandler(source=self) + if self._ui_screen.password_func: + handler.set_pass_func(self._ui_screen.password_func) + else: + handler = InputHandler(source=self) + + handler.get_input(message) + handler.wait_on_input() + return handler.value + + def get_input(self, args=None): + """Get input from user. + + :param args: Arguments passed in when UIScreen was scheduled. + :type args: Anything. + """ + prompt = self._ui_screen.prompt(args) + if not self._is_input_expected(prompt): + return + + self._input_args = args + + if not self._ui_screen.hide_user_input: + handler = InputHandler(source=self._ui_screen) + else: + handler = PasswordInputHandler(source=self._ui_screen) + if self._ui_screen.password_func: + handler.set_pass_func(self._ui_screen.password_func) + + handler.set_callback(self.process_input) + handler.get_input(prompt) + + def _is_input_expected(self, prompt): + """Check if user handled input processing some other way. + + Do nothing if user did handled user input. + + :returns: True if prompt is set and we can use it to get user input. + False if prompt is not available, which means that user handled input on their + own. + """ + # None means prompt handled the input by itself -> continue + if prompt is None: + self._input_error_counter = 0 + return False + + return True + + def process_input(self, user_input): + """Process input from the screens. + + :param user_input: User input string. + :type user_input: String. + + :raises: ExitMainLoop or any other kind of exception from screen processing. + """ + # process the input, if it wasn't processed (valid) + # increment the error counter + try: + result = self._process_input(user_input) + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + App.get_event_loop().enqueue_signal(ExceptionSignal(self)) + return + + if result.was_successful(): + self._input_error_counter = 0 + else: + self._input_error_counter += 1 + + App.get_scheduler().process_input_result(result, self.input_error_threshold_exceeded) + + def _process_input(self, key): + """Method called internally to process unhandled input key presses. + + :param key: The string entered by user. + :type key: String. + + :return: Return state result object. + :rtype: `simpleline.render.in_out_manager.UserInputResult` class. + + :raises: Anything the Screen can raise in the input processing. + """ + from simpleline.render.screen import InputState # pylint: disable=import-outside-toplevel + # delegate the handling to active screen first + key = self._ui_screen.input(self._input_args, key) + if key == InputState.PROCESSED: + return UserInputAction.NOOP + + if key == InputState.PROCESSED_AND_REDRAW: + return UserInputAction.REDRAW + + if key == InputState.PROCESSED_AND_CLOSE: + return UserInputAction.CLOSE + + if key == InputState.DISCARDED: + return UserInputAction.INPUT_ERROR + + # global refresh command + if key == Prompt.REFRESH: + return UserInputAction.REDRAW + + # global close command + if key == Prompt.CONTINUE: + return UserInputAction.CLOSE + + # global quit command + if key == Prompt.QUIT: + return UserInputAction.QUIT + + if key is None: + log.warning("Returned key from screen is None. " + "This could be missing return in a screen input method?") + + return UserInputAction.INPUT_ERROR + + +class UserInputAction(Enum): + """Store user input result.""" + INPUT_ERROR = -1 + NOOP = 0 + REDRAW = 5 + CLOSE = 6 + QUIT = 7 + + def was_successful(self): + return self != UserInputAction.INPUT_ERROR diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/signal_handler.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/signal_handler.py new file mode 100644 index 0000000..e5e1eb5 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen/signal_handler.py @@ -0,0 +1,94 @@ +# Signal handler is giving ability connect and emit to all widgets. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from simpleline import App +from simpleline.event_loop.signals import RenderScreenSignal, CloseScreenSignal + + +class SignalHandler(): + """Provides methods for handling signals anc callbacks. + + Provides main methods: + `connect()` -- connect this widget on given signal + `create_signal()` -- create signal class which can be used in the emit method + `emit()` -- emit signal given signal + """ + + def connect(self, signal, callback, data=None): + """Connect this class method with given signal. + + :param signal: signal class which you want to connect + :type signal: class based on `simpleline.event_loop.AbstractSignal` + + :param callback: the callback function + :type callback: func(event_message, data) + + :param data: Data you want to pass to the callback + :type data: Anything + """ + App.get_event_loop().register_signal_handler(signal, callback, data) + + def create_signal(self, signal_class, priority=0): + """Create signal instance usable in the emit method. + + :param signal_class: signal you want to use + :type signal_class: class based on `simpleline.event_loop.AbstractSignal` + + :param priority: priority of the signal; please look on the + `simpleline.event_loop.AbstractSignal.priority` for further info + :type priority: int + """ + return signal_class(self, priority) + + def emit(self, signal): + """Emit the signal. + + This will add `signal` to the event loop. + + :param signal: signal to emit + :type signal: instance of class based on `simpleline.event_loop.AbstractSignal` + """ + App.get_event_loop().enqueue_signal(signal) + + def create_and_emit(self, signal): + """Create the signal and emit it. + + This is basically shortcut for calling `self.create_signal` and `self.emit`. + """ + created_signal = self.create_signal(signal) + self.emit(created_signal) + + def redraw(self): + """Emit signal to initiate draw. + + Add RenderScreenSignal to the event loop. + """ + signal = self.create_signal(RenderScreenSignal) + App.get_event_loop().enqueue_signal(signal) + + def close(self): + """Emit signal to close this screen. + + Add CloseScreenSignal to the event loop. + """ + signal = self.create_signal(CloseScreenSignal) + App.get_event_loop().enqueue_signal(signal) diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_handler.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_handler.py new file mode 100644 index 0000000..19655f7 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_handler.py @@ -0,0 +1,58 @@ +# Serves shortcuts for easy screen scheduling. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from simpleline import App + + +class ScreenHandler(): + + @classmethod + def schedule_screen(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.schedule_screen()`. + """ + App.get_scheduler().schedule_screen(ui_screen=ui_screen, args=args) + + @classmethod + def replace_screen(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.replace_screen()`. + """ + App.get_scheduler().replace_screen(ui_screen=ui_screen, args=args) + + @classmethod + def push_screen(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.push_screen()`. + """ + App.get_scheduler().push_screen(ui_screen=ui_screen, args=args) + + @classmethod + def push_screen_modal(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.push_screen_modal()`. + """ + App.get_scheduler().push_screen_modal(ui_screen=ui_screen, args=args) diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_scheduler.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_scheduler.py new file mode 100644 index 0000000..cfc4cbf --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_scheduler.py @@ -0,0 +1,311 @@ +# Class handling rendering of the screens to console. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +import threading + + +from simpleline import App +from simpleline.event_loop import ExitMainLoop +from simpleline.event_loop.signals import ExceptionSignal, RenderScreenSignal, CloseScreenSignal +from simpleline.render import RenderUnexpectedError +from simpleline.render.screen.input_manager import UserInputAction +from simpleline.render.screen_stack import ScreenStack, ScreenData, ScreenStackEmptyException + +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + +RAW_INPUT_LOCK = threading.Lock() + + +__all__ = ["ScreenScheduler"] + + +class ScreenScheduler(): + + def __init__(self, event_loop, scheduler_stack=None): + """Constructor where you can pass your own scheduler stack. + + The ScreenStack will be used automatically if scheduler stack will be None. + + :param event_loop: Event loop used for the scheduler. + :type event_loop: Class based on `simpleline.event_loop.AbstractEventLoop`. + :param scheduler_stack: Use custom scheduler stack if you need to. + :type scheduler_stack: `simpleline.screen_stack.ScreenStack` based class. + """ + self._quit_screen = None + self._event_loop = event_loop + + if scheduler_stack: + self._screen_stack = scheduler_stack + else: + self._screen_stack = ScreenStack() + self._register_handlers() + + self._first_screen_scheduled = False + + @staticmethod + def _spacer(): + return "\n".join(2 * [App.get_configuration().width * "="]) + + def _register_handlers(self): + self._event_loop.register_signal_handler(RenderScreenSignal, self._process_screen_callback) + self._event_loop.register_signal_handler(CloseScreenSignal, self._close_screen_callback) + + @property + def quit_screen(self): + """Return quit UIScreen.""" + return self._quit_screen + + @quit_screen.setter + def quit_screen(self, quit_screen): + """Set the UIScreen based instance which will be showed before the Application will quit. + + You can also use `simpleline.render.adv_widgets.YesNoDialog` or `UIScreen` based class + with the `answer` property. Without the `answer` property the application will always + close. + """ + self._quit_screen = quit_screen + + @property + def nothing_to_render(self): + """Is something for rendering in the scheduler stack? + + :return: True if the rendering stack is empty + :rtype: bool + """ + return self._screen_stack.empty() + + def dump_stack(self): + """Get string representation of actual screen stack.""" + return self._screen_stack.dump_stack() + + def schedule_screen(self, ui_screen, args=None): + """Add screen to the bottom of the stack. + + This is mostly useful at the beginning to prepare the first screen hierarchy to display. + + :param ui_screen: screen to show + :type ui_screen: UIScreen instance + :param args: optional argument, please see switch_screen for details + :type args: anything + """ + log.debug("Scheduling screen %s", ui_screen) + screen = ScreenData(ui_screen, args) + self._screen_stack.add_first(screen) + self._redraw_on_first_scheduled_screen() + + def _redraw_on_first_scheduled_screen(self): + if not self._first_screen_scheduled: + self.redraw() + self._first_screen_scheduled = True + + def replace_screen(self, ui_screen, args=None): + """Schedules a screen to replace the current one. + + :param ui_screen: screen to show + :type ui_screen: instance of UIScreen + :param args: optional argument to pass to ui's refresh and setup methods + (can be used to select what item should be displayed or so) + :type args: anything + """ + log.debug("Replacing screen %s", ui_screen) + try: + execute_new_loop = self._screen_stack.pop().execute_new_loop + except ScreenStackEmptyException as e: + raise ScreenStackEmptyException("Switch screen is not possible when there is no " + "screen scheduled!") from e + + # we have to keep the old_loop value so we stop + # dialog's mainloop if it ever uses switch_screen + screen = ScreenData(ui_screen, args, execute_new_loop) + self._screen_stack.append(screen) + self.redraw() + + def push_screen(self, ui_screen, args=None): + """Schedules a screen to show, but keeps the current one in stack to + return to, when the new one is closed. + + :param ui_screen: screen to show + :type ui_screen: UIScreen instance + :param args: optional argument + :type args: anything + """ + log.debug("Pushing screen %s to stack", ui_screen) + screen = ScreenData(ui_screen, args, False) + self._screen_stack.append(screen) + self.redraw() + + def push_screen_modal(self, ui_screen, args=None): + """Starts a new screen right away, so the caller can collect data back. + + When the new screen is closed, the caller is redisplayed. + + This method does not return until the new screen is closed. + + :param ui_screen: screen to show + :type ui_screen: UIScreen instance + :param args: optional argument, please see switch_screen for details + :type args: anything + """ + log.debug("Pushing modal screen %s to stack", ui_screen) + screen = ScreenData(ui_screen, args, True) + self._screen_stack.append(screen) + # only new events will be processed now + # the old one will wait after this event loop will be closed + self._event_loop.execute_new_loop(RenderScreenSignal(self)) + + def _close_screen_callback(self, signal, data): + self.close_screen(signal.source) + + def close_screen(self, closed_from=None): + """Close the currently displayed screen and exit it's main loop if necessary. + + Next screen from the stack is then displayed. + """ + screen = self._screen_stack.pop() + log.debug("Closing screen %s from %s", screen, closed_from) + + # User can react when screen is closing + screen.ui_screen.closed() + + if closed_from is not None and closed_from is not screen.ui_screen: + raise RenderUnexpectedError("You are trying to close screen %s from screen %s! " + "This is most probably not intentional." % + (closed_from, screen.ui_screen)) + + if screen.execute_new_loop: + self._event_loop.close_loop() + + # redraw screen if there is what to redraw + # and if it is not modal screen (modal screen parent is blocked) + if not self._screen_stack.empty() and not screen.execute_new_loop: + self.redraw() + + # we can't draw anything more. Kill the application. + if self._screen_stack.empty(): + raise ExitMainLoop() + + def redraw(self): + """Register rendering to the event loop for processing.""" + self._event_loop.enqueue_signal(RenderScreenSignal(self)) + + def _process_screen_callback(self, signal, data): + self._process_screen() + + def _process_screen(self): + """Process the current screen. + + 1) It will call setup if the screen is not already set. + 2a) If setup was success then draw the screen. + 2b) If setup wasn't successful then pop the screen and try to process next in the stack. + Continue by (1). + 3)Ask for user input if requested. + """ + top_screen = self._get_last_screen() + + log.debug("Processing screen %s", top_screen) + + # this screen is used first time (call setup() method) + if not top_screen.ui_screen.screen_ready: + if not top_screen.ui_screen.setup(top_screen.args): + # remove the screen and skip if setup went wrong + self._screen_stack.pop() + self.redraw() + log.warning("Screen %s setup wasn't successful", top_screen) + return + + # get the widget tree from the screen and show it in the screen + try: + # refresh screen content + top_screen.ui_screen.refresh(top_screen.args) + + # Screen was closed in the refresh method + if top_screen != self._get_last_screen(): + return + + # draw screen to the console + self._draw_screen(top_screen) + + if top_screen.ui_screen.input_required: + log.debug("Input is required by %s screen", top_screen) + top_screen.ui_screen.get_input_with_error_check(top_screen.args) + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + self._event_loop.enqueue_signal(ExceptionSignal(self)) + return + + def _draw_screen(self, active_screen): + """Draws the current `active_screen`. + + :param active_screen: Screen which should be draw to the console. + :type active_screen: Classed based on `simpleline.render.screen.UIScreen`. + """ + # get the widget tree from the screen and show it in the screen + try: + if not active_screen.ui_screen.no_separator: + # separate the content on the screen from the stuff we are about to display now + print(self._spacer()) + + # print UIScreen content + active_screen.ui_screen.show_all() + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + self._event_loop.enqueue_signal(ExceptionSignal(self)) + + def _get_last_screen(self): + if self._screen_stack.empty(): + raise ExitMainLoop() + + return self._screen_stack.pop(False) + + def process_input_result(self, input_result, should_redraw): + active_screen = self._get_last_screen() + + if not input_result.was_successful(): + if should_redraw: + self.redraw() + else: + log.debug("Input was not successful, ask for new input.") + active_screen.ui_screen.get_input_with_error_check(active_screen.args) + else: + if input_result == UserInputAction.NOOP: + return + + if input_result == UserInputAction.REDRAW: + self.redraw() + elif input_result == UserInputAction.CLOSE: + self.close_screen() + elif input_result == UserInputAction.QUIT: + if self.quit_screen: + self.push_screen_modal(self.quit_screen) + try: + if self.quit_screen.answer is True: + raise ExitMainLoop() + + self.redraw() + except AttributeError as e: + raise ExitMainLoop() from e + else: + raise ExitMainLoop() diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_stack.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_stack.py new file mode 100644 index 0000000..9d0d7c2 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/screen_stack.py @@ -0,0 +1,117 @@ +# Classes implementation for storing and manipulating Screen stack. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +from simpleline.errors import SimplelineError + + +class ScreenStackException(SimplelineError): + """General screen stack exception.""" + + +class ScreenStackEmptyException(ScreenStackException): + """Screen stack exception when stack is empty.""" + + +class ScreenStack(): + """Managing screen stack used in `ScreenScheduler`.""" + + def __init__(self): + self._screens = [] + + def empty(self): + """Test if screen stack is empty. + + :return: True if empty. + :rtype: bool + """ + return not self._screens + + def size(self): + """Get size of the stack. + + :return: Size of the stack. + """ + return len(self._screens) + + def append(self, screen): + """Add new screen to the top of the stack. + + :param screen: Screen for the future rendering. + :type screen: Class based on `simpleline.render.ui_screen.UIScreen`. + """ + self._screens.append(screen) + + def pop(self, remove=True): + """Return top item from the stack. + + :param remove: If True (default) also remove this items from the stack. + :return: The top screen on the stack. + """ + try: + if remove: + return self._screens.pop() + + return self._screens[-1] + except IndexError as e: + raise ScreenStackEmptyException(e) from e + + def add_first(self, screen): + """Add `screen` to the bottom of the stack. + + :param screen: Add the `screen` to the bottom of the stack. + :type screen: Class based on `simpleline.render.ui_screen.UIScreen`. + """ + self._screens.insert(0, screen) + + def dump_stack(self): + """Dump screen stack structure. + + :returns: Screen stack representation. + :rtype: str + """ + msg = '======= Screen stack =======\n' + msg += '----------- TOP ------------\n' + + for screen in reversed(self._screens): + msg += str(screen) + msg += "\n" + + msg += '============================\n' + + return msg + + +class ScreenData(): + """Inner data class to store screen data.""" + + def __init__(self, ui_screen, args=None, execute_new_loop=False): + self.ui_screen = ui_screen + self.args = args + self.execute_new_loop = execute_new_loop + + def __str__(self): + msg = self.__class__.__name__ + msg += "(" + msg += ",".join((str(self.ui_screen), str(self.args), str(self.execute_new_loop))) + msg += ")" + return msg diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/widgets.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/widgets.py new file mode 100644 index 0000000..2f645a0 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/render/widgets.py @@ -0,0 +1,495 @@ +# Widgets for Text UI framework. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import functools +from textwrap import wrap +from simpleline.utils.i18n import _ +from simpleline.utils import ensure_str + +__all__ = ["Widget", "TextWidget", "SeparatorWidget", "EntryWidget", "ColumnWidget", + "CheckboxWidget", "CenterWidget"] + + +class Widget(): + + def __init__(self, max_width=None, default=None): + """Initializes base Widgets buffer. + + This class can be subclassed to create customized widgets. + + :param max_width: serves as a hint about screen size to write method with default arguments + :type max_width: int + + :param default: string containing the default content to fill the buffer with + :type default: string + """ + self._buffer = [] + if default: + self._buffer = [[c for c in l] for l in default.split("\n")] # pylint: disable=unnecessary-comprehension + self._max_width = max_width + self._cursor = (0, 0) # row, col + + @property + def height(self): + """The current height of the internal buffer.""" + return len(self._buffer) + + @property + def width(self): + """The current width of the internal buffer (id of the first empty column).""" + return functools.reduce(lambda acc, l: max(acc, len(l)), self._buffer, 0) + + def clear(self): + """Clears this widgets buffer and resets cursor.""" + self._buffer = list() + self._cursor = (0, 0) + + @property + def content(self): + """Return a list (rows) of lists (columns) with one character elements.""" + return self._buffer + + def render(self, width): + """Redraw the widget's self._buffer. + + :param width: the width of buffer requested by the caller + :type width: int + + Commonly, call render of child widgets and then draw and write + methods to copy their contents to self._buffer. + """ + self.clear() + + def get_lines(self): + """Return lines to write out in order to show this widget. + + :return: lines representing this widget + :rtype: list(str) + """ + return [str(u"".join(line)) for line in self._buffer] + + def set_cursor_position(self, row, col): + """Set cursor position. + + :param row: row id, starts with 0 at the top of the screen + :type row: int + + :param col: column id, starts with 0 on the left side of the screen + :type col: int + """ + self._cursor = (row, col) + + @property + def cursor(self): + return self._cursor + + def set_end(self): + """Set the cursor to first column in new line at the end.""" + self._cursor = (self.height, 0) + + def draw(self, w, row=None, col=None, block=False): + """Copy w widget's content to this widget's buffer at row, col position. + + :param w: widget to take content from + :type w: class Widget + + :param row: row number to start at (default is at the cursor position) + :type row: int + + :param col: column number to start at (default is at the cursor position) + :type col: int + + :param block: when printing newline, start at column col (True) or at column 0 (False) + :type block: boolean + """ + # if the starting row is not present, start at the cursor position + if row is None: + row = self._cursor[0] + + # if the starting column is not present, start at the cursor position + if col is None: + col = self._cursor[1] + + # fill up rows to accommodate for w.height + if self.height < row + w.height: + for _i in range(row + w.height - self.height): + self._buffer.append(list()) + + # append columns to accommodate for w.width + for l in range(row, row + w.height): + l_len = len(self._buffer[l]) + w_len = len(w.content[l - row]) + if l_len < col + w_len: + self._buffer[l] += ((col + w_len - l_len) * list(u" ")) + self._buffer[l][col:col + w_len] = w.content[l - row][:] + + # move the cursor to new spot + if block: + self._cursor = (row + w.height, col) + else: + self._cursor = (row + w.height, 0) + + def write(self, text, row=None, col=None, width=None, block=False, wordwrap=False): + """Emulate the typing machine writing to this widget's buffer. + + :param text: text to type + :type text: str + + :param row: row number to start at (default is at the cursor position) + :type row: int + + :param col: column number to start at (default is at the cursor position) + :type col: int + + :param width: wrap at "col" + "width" column (default is at self._max_width) + :type width: int + + :param block: when printing newline, start at column col (True) or at column 0 (False) + :type block: boolean + + :param wordwrap: wrap by words + :type wordwrap: boolean + """ + if not text: + return + + text = ensure_str(text) + if row is None: + row = self._cursor[0] + + if col is None: + col = self._cursor[1] + + if width is None and self._max_width: + width = self._max_width - col + + x = row + y = col + + if wordwrap: + text = self._wrap_words(text, width) + + # emulate typing machine + for character in text: + # FIXME: Remove the code duplication below and optimize it + # process newline + if character == "\n": + x += 1 + if block: + y = col + else: + y = 0 + + self._increase_x_buffer_size(x) + continue + + self._increase_x_buffer_size(x) + self._increase_y_buffer_size(x, y) + + self._save_character_to_buffer(x, y, character) + + # shift to the next char + y += 1 + if width is not None and y >= col + width: + x += 1 + if block: + y = col + else: + y = 0 + + self._cursor = (x, y) + + def _increase_x_buffer_size(self, x): + if x >= len(self._buffer): + for _i in range(x - len(self._buffer) + 1): + self._buffer.append(list()) + + def _increase_y_buffer_size(self, x, y): + if y >= len(self._buffer[x]): + self._buffer[x] += ((y - len(self._buffer[x]) + 1) * list(u" ")) + + def _save_character_to_buffer(self, x, y, character): + self._buffer[x][y] = character + + @staticmethod + def _wrap_words(text, width): + lines = [] + # Wrap each line separately + for line in text.split('\n'): + sublines = [] + for subline in wrap(line, width): + sublines.append(subline) + if len(subline) < width: + # line shorter than width will be wrapped by '\n' we add + sublines.append('\n') + # line with length == width will be wrapped by the width based + # wrapping logic + # end of line will be wrapped by '\n' following the line in + # original text + if sublines and sublines[-1] == '\n': + sublines.pop() + lines.append("".join(sublines)) + return '\n'.join(lines) + + +class TextWidget(Widget): + """Class to handle wrapped text output.""" + + def __init__(self, text): + """ + :param text: text to format + :type text: str + """ + super().__init__() + self._text = text + + @property + def text(self): + """Contains text of this widget.""" + return self._text + + def render(self, width): + """Renders the text widget limited to width number of columns. + + Wraps to the next line when the text is longer. + + :param width: maximum width allocated to the string + :type width: int + """ + super().render(width) + self.write(self._text, width=width, wordwrap=True) + + +class EntryWidget(TextWidget): + """This is the easy way how to generate entry items for containers. + + If the numbering in a container is turned on the output looks like: + + N) title + value + + Without numbering turned on: + + title + value + """ + + def __init__(self, title, value=None): + """ Create Entry widget instance. + + :param title: Title of this entry. + :type title: String. + + :param value: Actual value printed in second line below the title. + :type value: String. + """ + text = self._create_text(title=title, value=value) + super().__init__(text) + + @staticmethod + def _create_text(title, value): + msg = title + + if value: + msg += "\n" + msg += value + + return msg + + +class SeparatorWidget(Widget): + """Print empty line.""" + + def __init__(self, lines=1): + """Construct SeparatorWidget for printing blank lines. + + :param lines: How many lines should be blank. + :type lines: int greater than 0. + """ + super().__init__() + self._lines = lines + + def render(self, width): + """Render empty line to the buffer. + + :param width: maximum width allocated to the string + :type width: int + """ + super().render(width) + self.write("") + + def write(self, text, row=None, col=None, width=None, block=False, wordwrap=False): + """Optimize write function. + + To print just a blank line we don't need too much logic. + """ + for i in range(0, self._lines): + self._buffer.append(list()) + self._buffer[i] += u"" + self.set_cursor_position(self._lines - 1, 0) + + +class CenterWidget(Widget): + """Class to handle horizontal centering of content.""" + + def __init__(self, w): + """ + :param w: widget to center + :type w: Widget + """ + super().__init__() + self._w = w + + def render(self, width): + """Render the centered widget to internal buffer. + + :param width: maximum width the widget should use + :type width: int + """ + super().render(width) + self._w.render(width) + # make sure col is an integer + self.draw(self._w, col=(width - self._w.width) // 2) + + +class CheckboxWidget(Widget): + """Widget to show checkbox with (un)checked box, name and description.""" + + def __init__(self, key="x", title=None, text=None, completed=None): + """ + :param key: tick character to be used inside [ ] + :type key: character + + :param title: the title next to the [ ] box + :type title: str + + :param text: the description text to be shown on the second row in () + :type text: str + + :param completed: is the checkbox ticked or not? + :type completed: True|False + """ + super().__init__() + self._key = key + self._title = title + self._text = text + self._completed = completed + + def render(self, width): + """Render the widget to internal buffer. + + It should be max width characters wide. + """ + super().render(width) + + if self.completed: + checkchar = self._key + else: + checkchar = " " + + # prepare the checkbox + checkbox = TextWidget("[%s]" % checkchar) + + data = [] + + # append lines + if self.title: + data.append(TextWidget(_(self.title))) + + if self.text: + data.append(TextWidget("(%s)" % self.text)) + + # the checkbox has two columns + # [x] is one and is 3 chars wide + # text is second and can occupy width - 3 - 1 (for space) chars + cols = ColumnWidget([(3, [checkbox]), (width - 4, data)], 1) + cols.render(width) + + # transfer the column widget rendered stuff to internal buffer + self.draw(cols) + + @property + def title(self): + """Returns the first line (main title) of the checkbox.""" + return self._title + + @property + def completed(self): + """Returns the state of the checkbox, checked is True.""" + return self._completed + + @property + def text(self): + """Contains the description text from the second line.""" + return self._text + + +class ColumnWidget(Widget): + + def __init__(self, columns, spacing=0): + """Create text columns + + Deprecated. Please do not use this widget, use containers instead. + + :param columns: list containing (column width, [list of widgets to put into this column]) + :type columns: [(int, [...]), ...] + + :param spacing: number of spaces to use between columns + :type spacing: int + """ + super().__init__() + self._spacing = spacing + self._columns = columns + + def render(self, width): + """Render the widget to it's internal buffer + + :param width: the maximum width the widget can use + :type width: int + + :return: nothing + """ + super().render(width) + + # the leftmost empty column + col_pos = 0 + + # iterate over tuples (column width, column content) + for col_width, col in self._columns: + + # set cursor to first line and leftmost empty column + self.set_cursor_position(0, col_pos) + + # if requested width is None, limit the maximum to width + # and set minimum to 0 + if col_width is None: + col_max_width = width - self.cursor[1] + col_width = 0 + else: + col_max_width = col_width + + # render and draw contents of column + for item in col: + item.render(col_max_width) + self.draw(item, block=True) + + # recompute the leftmost empty column + col_pos = max((col_pos + col_width), self.width) + self._spacing diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__init__.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__init__.py new file mode 100644 index 0000000..bb1622c --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__init__.py @@ -0,0 +1,94 @@ +# iutil.py - generic install utility functions +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import sys +import string # pylint: disable=deprecated-module +import unicodedata + + +def ensure_str(str_or_bytes, keep_none=True): + """ + Returns a str instance for given string or ``None`` if requested to keep it. + + :param str_or_bytes: string to be kept or converted to str type + :type str_or_bytes: str or bytes + :param bool keep_none: whether to keep None as it is or raise ValueError if + ``None`` is passed + :raises ValueError: if applied on an object not being of type bytes nor str + (nor NoneType if ``keep_none`` is ``False``) + """ + if keep_none and str_or_bytes is None: + return None + if isinstance(str_or_bytes, str): + return str_or_bytes + if isinstance(str_or_bytes, bytes): + return str_or_bytes.decode(sys.getdefaultencoding()) + + raise ValueError( + "str_or_bytes must be of type 'str' or 'bytes', not '%s'" % type(str_or_bytes)) + + +# Define translations between ASCII uppercase and lowercase for +# locale-independent string conversions. The tables are 256-byte string used +# with str.translate. If str.translate is used with a unicode string, +# even if the string contains only 7-bit characters, str.translate will +# raise a UnicodeDecodeError. +_ASCIIlower_table = str.maketrans(string.ascii_uppercase, string.ascii_lowercase) +_ASCIIupper_table = str.maketrans(string.ascii_lowercase, string.ascii_uppercase) + + +def _toASCII(s): + """Convert a unicode string to ASCII""" + if isinstance(s, str): + # Decompose the string using the NFK decomposition, which in addition + # to the canonical decomposition replaces characters based on + # compatibility equivalence (e.g., ROMAN NUMERAL ONE has its own code + # point but it's really just a capital I), so that we can keep as much + # of the ASCII part of the string as possible. + s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').decode("ascii") + elif not isinstance(s, bytes): + s = '' + return s + + +def lowerASCII(s): + """Convert a string to lowercase using only ASCII character definitions. + + The returned string will contain only ASCII characters. This function is + locale-independent. + """ + # XXX: Python 3 has str.maketrans() and bytes.maketrans() so we should + # ideally use one or the other depending on the type of 's'. But it turns + # out we expect this function to always return string even if given bytes. + s = ensure_str(s) + return str.translate(_toASCII(s), _ASCIIlower_table) + + +def upperASCII(s): + """Convert a string to uppercase using only ASCII character definitions. + + The returned string will contain only ASCII characters. This function is + locale-independent. + """ + # XXX: Python 3 has str.maketrans() and bytes.maketrans() so we should + # ideally use one or the other depending on the type of 's'. But it turns + # out we expect this function to always return string even if given bytes. + s = ensure_str(s) + return str.translate(_toASCII(s), _ASCIIupper_table) diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__pycache__/__init__.cpython-314.pyc b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c959136b2ba92b3875fa9e06a327198ddc76e5a GIT binary patch literal 2861 zcmd5;O>7%Q6rS~e*6Wz`H*Er}lh($NCaMx>V%kbkOMiqC88@;j;nvyMV|(dlcbOTt zN=`l&aiB;@Akjl5dVm{(OU0Q(kBJR(*p?H$aI2a~aOBPY*-cZ4V@LAy%zN|x=Y94& zg9$N+5c+9;{?A{k-%b4mdw+%8-F6!`Ep#0fgv*FI-vSftbASa3kwV}w(gYT~7Rtwc zZGUr3$V>jg-vD>eKlq!OfU{+>m)hDxYi|#}t${-DFk)gM1TsqUVT0Lei7}u@6{H) zaR0dDClCI1uTsq8ybvfQy?qgRHzs(#?(%pIAsbYF1`}cd zvnJ80tjLrRS=A|1^a_@129fLPO{{aas@G*WFE1||I$mCu)tXH3r%g;5uFA}iZ(wZ7 zDw`C=oT(6HmFtuZQeIhOnC3hSaB&60U6XNR6+^#?iEDtnW@{!EbDX}Y&J}E9o`V&` z&}_G59YV^#1cojvx@@d`f-6kc4F-AIC9BynX1vLa#__?RxVGPYnF(0 z+9bFPZU}$aN8v*;kQVyq5Q+`mDYXw~|48nC938qdaX;9N9&1OBZ6!xGVj~VK+>NH& z(KN8S$+6Ak*!}75_*{E@t~36ACwY1!cKV5UU@JEN>-mSHo%6-tW5w;D5WgxsMMC(h zunmq-#RmX5@PW30!vV|x2@Z37*h@Yb4G zRkb2&9iA?>0B8x%kc5F)aaXshFvS{x3#*Ezu45}=za~sL>=9mu9|TLFl$SV7IObci zGBa#9WCV^-IYd7O(n3$5#i_5ZbfZVw(IYz&N(^_UR9i~jOMjp0NE2OYdQ+PI@#2H4 z9qB?>TG*5p9@aZj@wV_Zf}}+2(oPr+4u2!ueYcxPwG*i=Y4EnN6_;9<$ZKH#xi0e* z>@HuoJ@|Ph(=Sf(<->W!0a}FDTVVZFZlZpa})r4^c z@YS_7*{+LRX#m1j7+@VtC?6Ho&?zAAQUe1hb1VlyaxL9bHH`x;Q&fPbJ#5fPd8q;D zQfulJZU~S@)QpOv;S;J}#U=)#1FmPo_WU{B9biP!sir^-yh+wj*^bPPxy+Om4U;3l z?{6y@g@l~Oz6r96@Yx;*(n34?(7^sXCqGZL<{!rgzc};RnY+XHQs0jJmOj;q&u)Zf zU&#hFP4ks)5P2O6`&?`6XkXSETj;cgcVvkx%bf7R$O=o@1mS;4tcdfd$RRG{Xzad* zRpkb@UxbykF`?|&#$))enY_W(#yH_Ghw!IBxYHjTZ!QL$UNx#s4WA`h5OHvz3XrEk zK@hgzMne1%N<2dQb|U))fa>?q!QrnLzFfGM?vBlFj?F$ucXRp8T)uPQqYX5)b>Q&J Uh0h{!A@OWf6y|o00DTF5)FTP)dmyHLz0m)(NxBntzh#s1PNRmW{>aXx2FkUGe93Z^6Ro1Q*AfEE4q z7#R%wG4tHTKsp+Igix*rp)NGb-1$gV>8KiDjRF-qP;el2Y|kFup4M5EWDokBbg=kObi& zKRx5$zEe)$dA6{lMYpx6e|lt7Dr-|a+Knyk#yji1mh!c%Z)HJ}FvMgT{OYLDp@YTy zKLMPA8UZZ&$jD$r7!Ga#_#$ZphcwYZ!lnrpauNhpiveV?D$IaaDSqs*$ap+{1aBu; zohS$oz0B-HdbT4yeqwynEk~~JL}s=kGrp1WXYZCHa}|Vt7LR3Q^I(F<8)ytSKxquj z)C?s1#JP5UEmu-hRC{>Vkv5!_-6+^6+xg=-ON63=lRqc=@fvJ!(6CuKWC1Gt#8#q~J$zCRwO>vR1;#Npwkf8WA z+Qi9}Nf>8CFr8iyfAiM5KJzB}zWD-B7ydVOa5E!<3ezU(28CCFij%Nqc@rvCOcTDL zX;xbE4D(?Thu-8Y+cIxXF=wq(RdsxEDYtCrC&)QCWrg8?a!ScY2V}~ fPxvHdJ^V?Y^Mw5-6}SIrLrTOGe}==johSSaA^8Xa literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/i18n.py b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/i18n.py new file mode 100644 index 0000000..c740c34 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/lib/python3.14/site-packages/simpleline/utils/i18n.py @@ -0,0 +1,61 @@ +# Translation functions we use all over the place +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +__all__ = ["_", "N_", "P_", "C_", "CN_", "CP_"] + +import gettext + +N_ = lambda x: x +_ = lambda x: gettext.translation("python-simpleline", fallback=True).gettext(x) if x != "" else "" +P_ = lambda x, y, z: gettext.translation("python-simpleline", fallback=True).ngettext(x, y, z) + +# This is equivalent to "pgettext" in GNU gettext. The pgettext functions +# are not exported by Python, but all they really do is a stick a EOT +# character between msgctxt and msgid and check that msgctxt isn't part +# of the return value. + + +def C_(msgctxt, msgid): + ctxid = "%s\x04%s" % (msgctxt, msgid) + translation = _(ctxid) + + # If there is no translation for msgctxtmsgid, return only msgid + if translation == ctxid: + return msgid + + return translation + +# Mark as translatable with context +CN_ = lambda c, x: x + +# npgettext; i.e., gettext with plural form and context + + +def CP_(msgctxt, msgid, msgid_plural, n): + ctxid = "%s\x04%s" % (msgctxt, msgid) + translation = P_(ctxid, msgid_plural, n) + + # If the returned value is msgctxtmsgid, ngettext was trying to + # fallback to msgid. We don't add msgctxt to msgid_plural, so any other + # return value is correct. + if translation == ctxid: + return msgid + + return translation diff --git a/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/share/licenses/python-simpleline/LICENSE.md b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/share/licenses/python-simpleline/LICENSE.md new file mode 100644 index 0000000..0927556 --- /dev/null +++ b/pkgbuilds/python-simpleline/pkg/python-simpleline/usr/share/licenses/python-simpleline/LICENSE.md @@ -0,0 +1,157 @@ +### GNU LESSER GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the +terms and conditions of version 3 of the GNU General Public License, +supplemented by the additional permissions listed below. + +#### 0. Additional Definitions. + +As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the +GNU General Public License. + +"The Library" refers to a covered work governed by this License, other +than an Application or a Combined Work as defined below. + +An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + +A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + +The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + +The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +#### 1. Exception to Section 3 of the GNU GPL. + +You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +#### 2. Conveying Modified Versions. + +If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + +- a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or +- b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + +#### 3. Object Code Incorporating Material from Library Header Files. + +The object code form of an Application may incorporate material from a +header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + +- a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the object code with a copy of the GNU GPL and this + license document. + +#### 4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + +- a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. +- c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. +- d) Do one of the following: + - 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + - 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. +- e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +#### 5. Combined Libraries. + +You may place library facilities that are a work based on the Library +side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + +- a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. +- b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + +#### 6. Revised Versions of the GNU Lesser General Public License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License "or any later version" applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, you +may choose any version of the GNU Lesser General Public License ever +published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/pkgbuilds/python-simpleline/python-simpleline-1.8-1-any.pkg.tar.zst b/pkgbuilds/python-simpleline/python-simpleline-1.8-1-any.pkg.tar.zst new file mode 100644 index 0000000000000000000000000000000000000000..5b082334216ed2b6e54768b418fb57ac94f2be83 GIT binary patch literal 106541 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 *{DHK!e4X+DU{!p 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 literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/python-simpleline-1.8.tar.gz b/pkgbuilds/python-simpleline/python-simpleline-1.8.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ba895b40f716a63cc61a8c62888626c20b743b57 GIT binary patch literal 84535 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�H@uB0}8qb6v|Q5r~Hk^nibGZw+7 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 SpY5~a=l=uE)*wj$SO)->;o=$q literal 0 HcmV?d00001 diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-1.8.tar.gz b/pkgbuilds/python-simpleline/src/python-simpleline-1.8.tar.gz new file mode 120000 index 0000000..082f130 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-1.8.tar.gz @@ -0,0 +1 @@ +/home/nocode/Files/FWS-ISO/pkgbuilds/python-simpleline/python-simpleline-1.8.tar.gz \ No newline at end of file diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.github/workflows/validate.yml b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.github/workflows/validate.yml new file mode 100644 index 0000000..8de6b5b --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.github/workflows/validate.yml @@ -0,0 +1,16 @@ +name: validate +on: [push, pull_request] +jobs: + rawhide: + runs-on: ubuntu-latest + container: + image: registry.fedoraproject.org/fedora:rawhide + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: install test dependencies + run: dnf install -y python3-pylint python3-gobject-base make + + - name: run tests + run: make ci diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.gitignore b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.gitignore new file mode 100644 index 0000000..d607e1b --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.gitignore @@ -0,0 +1,23 @@ +*.pyc +.*.swp + +.coverage +tests/coverage-report.log + +ChangeLog + +po/*.gmo +po/*.po +po/python-simpleline.pot +po/POTFILES + +tests/pylint/.pylint.d/ +pylint-log + +build/ +dist/ +simpleline.egg-info/ + +.directory + +doc/_build diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.packit.yaml b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.packit.yaml new file mode 100644 index 0000000..a9974f7 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.packit.yaml @@ -0,0 +1,46 @@ +specfile_path: python-simpleline.spec +upstream_package_name: simpleline +upstream_tag_template: simpleline-{version} +actions: + create-archive: + - "make BUILD_ARGS=sdist archive" + - 'bash -c "cp dist/*.tar.gz ."' + - 'bash -c "ls *.tar.gz"' +jobs: + - job: propose_downstream + trigger: release + metadata: + dist_git_branches: fedora-development + + - job: tests + trigger: pull_request + metadata: + targets: + - fedora-all + + - job: copr_build + trigger: pull_request + metadata: + targets: + - fedora-eln + + - job: copr_build + trigger: commit + metadata: + targets: + - fedora-rawhide + - fedora-eln + branch: master + owner: "@rhinstaller" + project: Anaconda + preserve_project: True + + - job: copr_build + trigger: commit + metadata: + targets: + - fedora-34 + branch: master + owner: "@rhinstaller" + project: Anaconda-devel + preserve_project: True diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.pylintrc b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.pylintrc new file mode 100644 index 0000000..a9d4ab1 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/.pylintrc @@ -0,0 +1,504 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore= + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=0 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=fixme, + invalid-name, + missing-docstring, + no-self-use, + too-few-public-methods, + too-many-arguments, + too-many-instance-attributes, + too-many-public-methods, + too-many-return-statements, + unnecessary-pass, + unused-argument, + useless-return, + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +#enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template='{msg_id}({symbol}):{path}:{line},{column}: {obj}: {msg}' + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=colorized + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=no + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=99 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[LOGGING] + +# Format style used to check logging format string. `old` means using % +# formatting, while `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: en_US (myspell), cs_CZ +# (myspell), en_GB (myspell), en_AG (myspell), en_AU (myspell), en_BS +# (myspell), en_BW (myspell), en_BZ (myspell), en_CA (myspell), en_DK +# (myspell), en_GH (myspell), en_HK (myspell), en_IE (myspell), en_IN +# (myspell), en_JM (myspell), en_MW (myspell), en_NA (myspell), en_NG +# (myspell), en_NZ (myspell), en_PH (myspell), en_SG (myspell), en_TT +# (myspell), en_ZA (myspell), en_ZM (myspell), en_ZW (myspell).. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[STRING] + +# This flag controls whether the implicit-str-concat-in-sequence should +# generate a warning on implicit string concatenation in sequences defined over +# several lines. +check-str-concat-over-line-jumps=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=DefaultInstall,Popen,QueueFactory,TransactionSet,Namespace + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +# callbacks=cb_, +# _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=yes + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected= + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[DESIGN] + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement. +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules=optparse,tkinter.tix,string,regsub,TERMINOS,Bastion,rexec,mock + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/LICENSE.md b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/LICENSE.md new file mode 100644 index 0000000..0927556 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/LICENSE.md @@ -0,0 +1,157 @@ +### GNU LESSER GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the +terms and conditions of version 3 of the GNU General Public License, +supplemented by the additional permissions listed below. + +#### 0. Additional Definitions. + +As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the +GNU General Public License. + +"The Library" refers to a covered work governed by this License, other +than an Application or a Combined Work as defined below. + +An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + +A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + +The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + +The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +#### 1. Exception to Section 3 of the GNU GPL. + +You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +#### 2. Conveying Modified Versions. + +If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + +- a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or +- b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + +#### 3. Object Code Incorporating Material from Library Header Files. + +The object code form of an Application may incorporate material from a +header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + +- a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the object code with a copy of the GNU GPL and this + license document. + +#### 4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + +- a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. +- c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. +- d) Do one of the following: + - 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + - 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. +- e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +#### 5. Combined Libraries. + +You may place library facilities that are a work based on the Library +side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + +- a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. +- b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + +#### 6. Revised Versions of the GNU Lesser General Public License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License "or any later version" applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, you +may choose any version of the GNU Lesser General Public License ever +published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/MANIFEST.in b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/MANIFEST.in new file mode 100644 index 0000000..bd2f3e5 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/MANIFEST.in @@ -0,0 +1,4 @@ +include LICENSE.md Makefile ChangeLog README.md +recursive-include simpleline *.py +recursive-include po *.po *.pot Makefile +recursive-include tests *.py *.sh diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/Makefile b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/Makefile new file mode 100644 index 0000000..476b951 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/Makefile @@ -0,0 +1,154 @@ +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . + +PKGNAME=simpleline +SPECNAME=python-$(PKGNAME) +VERSION=$(shell awk '/Version:/ { print $$2 }' $(SPECNAME).spec) +RELEASE=$(shell awk '/Release:/ { print $$2 }' $(SPECNAME).spec | sed -e 's|%.*$$||g') +TAG=$(PKGNAME)-$(VERSION) + +PYTHON?=python3 +COVERAGE?=coverage3 + +# Arguments used for setup.py call for creating archive +BUILD_ARGS ?= sdist bdist_wheel + +# LOCALIZATION SETTINGS +L10N_REPOSITORY ?= https://github.com/rhinstaller/python-simpleline-l10n.git +L10N_REPOSITORY_RW ?= git@github.com:rhinstaller/python-simpleline-l10n.git + +# Branch used in localization repository. This should be master all the time. +GIT_L10N_BRANCH ?= master +# Directory in localization repository specific for this branch. +L10N_DIR ?= master + +default: all + +.PHONY: all +all: + $(MAKE) -C po + +.PHONY: clean +clean: + -rm -rf *.tar.gz simpleline/*.pyc tests/*.pyc ChangeLog dist build simpleline.egg-info + $(MAKE) -C po clean + $(PYTHON) setup.py -q clean --all + +.PHONY: test +test: + @echo "*** Running unittests ***" + ./tests/units/run_test.sh + +.PHONY: coverage +coverage: + @echo "*** Running unittests with coverage ***" + PYTHON="$(COVERAGE) run --branch" ./tests/units/run_test.sh + $(COVERAGE) report -m --include="simpleline/*" | tee tests/coverage-report.log + +.PHONY: check +check: + @echo "*** Running pylint ***" + $(PYTHON) -m pylint simpleline/ examples/*/*.py tests/units/ + +.PHONY: install +install: + $(PYTHON) setup.py install --root=$(DESTDIR) + $(MAKE) -C po install + +.PHONY: ChangeLog +ChangeLog: + (GIT_DIR=.git git log > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2) + +.PHONY: tag +tag: + git tag -a -m "Tag as $(TAG)" -f $(TAG) + @echo "Tagged as $(TAG)" + +.PHONY: release +release: tag archive + +.PHONY: archive +archive: po-pull ChangeLog + $(PYTHON) setup.py $(BUILD_ARGS) + @echo "The archive is in dist/$(PKGNAME)-$(VERSION).tar.gz" + +.PHONY: rpmlog +rpmlog: + @git log --no-merges --pretty="format:- %s (%ae)" $(TAG).. |sed -e 's/@.*)/)/' + @echo + +.PHONY: potfile +potfile: + $(MAKE) -C po potfile + +.PHONY: po-pull +po-pull: + TEMP_DIR=$$(mktemp --tmpdir -d $(SPECNAME)-localization-XXXXXXXXXX) && \ + git clone --depth 1 -b $(GIT_L10N_BRANCH) -- $(L10N_REPOSITORY) $$TEMP_DIR && \ + cp $$TEMP_DIR/$(L10N_DIR)/*.po ./po/ && \ + rm -rf $$TEMP_DIR + +.PHONY: po-push +po-push: potfile +# This algorithm will make these steps: +# - clone localization repository +# - copy pot file to this repository +# - check if pot file is changed (ignore the POT-Creation-Date otherwise it's always changed) +# - if not changed: +# - remove cloned repository +# - if changed: +# - add pot file +# - commit pot file +# - tell user to verify this file and push to the remote from the temp dir + TEMP_DIR=$$(mktemp --tmpdir -d $(SPECNAME)-localization-XXXXXXXXXX) || exit 1 ; \ + git clone --depth 1 -b $(GIT_L10N_BRANCH) -- $(L10N_REPOSITORY_RW) $$TEMP_DIR || exit 2 ; \ + cp ./po/$(SPECNAME).pot $$TEMP_DIR/$(L10N_DIR)/ || exit 3 ; \ + pushd $$TEMP_DIR/$(L10N_DIR) ; \ + git difftool --trust-exit-code -y -x "diff -u -I '^\"POT-Creation-Date: .*$$'" HEAD ./$(SPECNAME).pot &>/dev/null ; \ + if [ $$? -eq 0 ] ; then \ + popd ; \ + echo "Pot file is up to date" ; \ + rm -rf $$TEMP_DIR ; \ + else \ + git add ./$(SPECNAME).pot && \ + git commit -m "Update $(SPECNAME).pot" && \ + popd && \ + echo "Pot file updated for the localization repository $(L10N_REPOSITORY)" && \ + echo "Please confirm changes and push:" && \ + echo "$$TEMP_DIR" ; \ + fi ; + +.PHONY: bumpver +bumpver: po-push + read -p "Please see the above message. Verify and push localization commit. Press anything to continue." -n 1 -r + + @NEWSUBVER=$$((`echo $(VERSION) |cut -d . -f 2` + 1)) ; \ + NEWVERSION=`echo $(VERSION).$$NEWSUBVER |cut -d . -f 1,3` ; \ + DATELINE="* `LC_ALL=C.UTF-8 date "+%a %b %d %Y"` `git config user.name` <`git config user.email`> - $$NEWVERSION-1" ; \ + cl=`grep -n %changelog $(SPECNAME).spec |cut -d : -f 1` ; \ + tail --lines=+$$(($$cl + 1)) $(SPECNAME).spec > speclog ; \ + (head -n $$cl $(SPECNAME).spec ; echo "$$DATELINE" ; make --quiet rpmlog 2>/dev/null ; echo ""; cat speclog) > $(SPECNAME).spec.new ; \ + mv $(SPECNAME).spec.new $(SPECNAME).spec ; rm -f speclog ; \ + sed -i "s/Version: $(VERSION)/Version: $$NEWVERSION/" $(SPECNAME).spec ; \ + sed -i "s/version='$(VERSION)'/version='$$NEWVERSION'/" setup.py + +.PHONY: pypi-upload +pypi-upload: + $(PYTHON) -m twine upload dist/* + +.PHONY: ci +ci: check test diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/README.md b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/README.md new file mode 100644 index 0000000..e1de238 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/README.md @@ -0,0 +1,48 @@ +[![Copr build status](https://copr.fedorainfracloud.org/coprs/g/rhinstaller/Anaconda/package/python-simpleline/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/g/rhinstaller/Anaconda/package/python-simpleline/) +[![Translation status](https://translate.fedoraproject.org/widgets/python-simpleline/-/master/svg-badge.svg)](https://translate.fedoraproject.org/engage/python-simpleline/?utm_source=widget) + +Python Simpleline +================= + +This is a text UI framework originally which was a part of the +[Anaconda](https://github.com/rhinstaller/anaconda) installer project. + +This UI is simple and easy to use. It is designed to be used with line-based +machines and tools (e.g. serial console) so that every new line is appended +to the bottom of the screen. Printed lines are never rewritten! + +How to +====== + +[Link](https://python-simpleline.readthedocs.io) to the documentation. + +Another way to learn how to use this library is to view the +[examples directory](https://github.com/rhinstaller/python-simpleline/tree/master/examples). +Examples can be run without installing Simpleline to the system. You can test +them by running the script `run_example.sh`. + +1. `cd examples` +2. `./run_example.sh example_folder_name` + +For example: +`./run_example.sh basic` + +Dependencies +============ + +This is a Python3-only project. This code should not be difficult to migrate to +Python2. However, there is no need from the community, so it is only compatible +with Python3 at the moment. +No special libraries are required to use this library. If you want to use glib +event loop instead of the original one you need to install glib and Python3 +gobject introspection. + +If you want to run tests (`make ci`), you need to install +[Pocketlint](https://github.com/rhinstaller/pocketlint) and glib with gobject +introspection for Python3. + +Note +==== + +Thanks to Martin Sivák for the original Anaconda project. It was really nice +starting place for the new Simpleline's form. diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/Makefile b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/Makefile new file mode 100644 index 0000000..8f7141e --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build-3 +SPHINXPROJ = Simpleline +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api.rst new file mode 100644 index 0000000..ee79e6e --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api.rst @@ -0,0 +1,22 @@ +.. _public_api_label: + +Public API +========== + +API listed here is the public API. Developers shouldn't use anything which is not mentioned here! + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + App + UIScreen + Screen Handling + Widgets + Containers + Prompt + Advanced Widgets + Event loops + Signals + Errors + Advanced Input diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/adv_widgets.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/adv_widgets.rst new file mode 100644 index 0000000..62a8d0b --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/adv_widgets.rst @@ -0,0 +1,13 @@ +Advanced Widgets +================ + +Advanced widgets are :class:`screens ` which can be used for a +specific purpose. For example, reading input from the user and testing acceptance conditions on this +input, or asking the user a yes/no question. + +Advanced widget classes +----------------------- + +.. automodule:: simpleline.render.adv_widgets + :members: + :show-inheritance: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/advanced_input.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/advanced_input.rst new file mode 100644 index 0000000..d58fad1 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/advanced_input.rst @@ -0,0 +1,92 @@ +Advanced Input +============== + +.. automodule:: simpleline.input.input_handler + +.. WARNING:: + This section contains advanced input techniques which may lead to buggy code in your + program if they are not used correctly. + +The default technique to get user input is already described in :ref:`UIScreen `, +and that should be the preferred way to obtain user input. However, if the default technique is +not enough for your situation then read the text below to find out how to implement custom input. + +Input handler classes +--------------------- +Input handler classes are classes created to obtain user input. If required +:class:`InputHandler` can block an application until user input is received. + +This class can be instantiated everywhere in the code and used to ask for user input:: + + handler = InputHandler() + handler.get_input("Shut up and give me your input:") + handler.wait_for_input() + if handler.input_successful: + user_input = handler.value + +The :meth:`InputHandler.wait_on_input` method will block code processing until user input is +received. Input should always be checked before processing. + +In case some other work needs to be done before user input is received, then pass +a callback to the constructor of the :class:`InputHandler` class and do not use +the :meth:`InputHandler.wait_on_input` method. However, the callback is using +the :ref:`event loop` so it won't be called until event loop +processing is active. If :ref:`concurrent input` is used then this +callback might never get called! + +If what a user types must not be displayed, then the :class:`PasswordInputHandler` class +should be used. It shares most of its implementation with the :class:`InputHandler` but overrides +how to obtain the code. For more info look at the :class:`PasswordInputHandler` class +documentation. + +.. _concurrent_input_label: + +Concurrent input +---------------- + +Concurrent input is something which should be avoided. It drags unexpected behavior into an +application and is hard to debug. However, there could be an instance when user input is required +immediately, even when an application is already waiting for other input. + +By default, every attempt for concurrent input will raise an exception and kill the application to +prevent unexpected behavior. In order to allow for concurrent input, the +:attr:`InputHandler.skip_concurrency_check` property must be set. After this property is disabled +for the :class:`InputHandler` instance, then the handler instance then it can support +concurrent input. + +The last registered concurrent input will result in dropping all other waiting inputs -- even other +waiting inputs with :attr:`InputHandler.skip_concurrency_check` will be dropped. The dropped +waiting inputs will get a failed input signal to unblock :meth:`InputHandler.wait_on_input` +methods. + + +Creating a custom InputHandler +------------------------------ + +If the :class:`InputHandler` class or the :class:`PasswordInputHandler` class is not enough, +developers can create their own handler. The structure of an input handler is based on two +classes. First is a handler itself, and second is the request object it creates. + +The handler class is used as an interface for the rest of the application. It also creates +the requester instance. The requester object is a low-level implementation of obtaining user input. +The requester object has to have the ``get_input`` method and should contain the ``text_prompt`` +method. The ``get_input`` method is called in a separate thread and should prompt the user for +input. The ``text_prompt`` method is required mainly for concurrent input, and it returns +a string representation of the prompt. + +For more details, please look at the implementation of the :class:`InputHandler` class. + + +InputHandler class +------------------ + +.. autoclass:: InputHandler + :members: + +PasswordInputHandler class +-------------------------- + +.. autoclass:: PasswordInputHandler + :members: + :inherited-members: + diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/app.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/app.rst new file mode 100644 index 0000000..f0b058d --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/app.rst @@ -0,0 +1,48 @@ +App +=== + +.. automodule:: simpleline + +The App class is the heart of Simpleline. It holds the :ref:`event loop ` +instance and scheduler which are used by Simpleline. Both can be replaced if needed in the +initialization phase by calling the :meth:`App.initialize` method. However, by replacing the +scheduler you are replacing most of the logic in Simpleline. Replacing the scheduler is not +supported, since it is currently not a part of the public API. + +All Simpleline applications must be run by the :meth:`App.run` method. This method will start +the event loop instance created in the initialization process. + +If a reaction on application quit is required, please set +:meth:`set_quit_callback ` in the used event loop. +This can be done by:: + + loop = App.get_event_loop() + loop.set_quit_callback(callback_function) + +**Do not instantiate the** :class:`App` **class!** It is designed to be used in a purely static way. + + +Application configuration +------------------------- + +Configuration of the application is saved in the +:class:`GlobalConfiguration ` class. This class can be +created before :meth:`App.initialize` is called and passed in as a +parameter. This way the same configuration can be used between re-initialization of the +application. The configuration can easily be changed, even while an application is running, +by setting desired properties. + +Look at the :class:`GlobalConfiguration ` to find out +all the configuration possibilities. + +App class +--------- + +.. autoclass:: App + :members: + +GlobalConfiguration class +------------------------- + +.. autoclass:: simpleline.global_configuration.GlobalConfiguration + :members: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/containers.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/containers.rst new file mode 100644 index 0000000..d15aad1 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/containers.rst @@ -0,0 +1,47 @@ +.. _containers_label: + +Containers +========== + +Containers are structures to hold widgets and handle automatic positioning. Containers are +essentially widgets containing other widgets. Below is a collection of default containers which +can position :ref:`widgets `, but they can do more (e.g. handle user input). +Recursive composition of containers is supported. + +Customized containers can also be created. See the :ref:`creating_a_custom_container_label` +section. + +Container classes +----------------- + +.. automodule:: simpleline.render.containers + :members: + :inherited-members: + :show-inheritance: + +.. _creating_a_custom_container_label: + +Creating a custom container +--------------------------- + +If an existing container is missing a required feature, a new, customized container can be +created based on the :class:`Container` class. Container creation is essentially the same as +:ref:`custom widget creation ` because containers are based on widgets. +The main difference is that containers are working with widgets added by a developer when using +the container. As an example, every :class:`UIScreen ` has a +:class:`WindowContainer`, and this is used as the main rendering point. + +To create a customized container, the :meth:`Container.render` method should be overridden and +the positioning of widgets and containers should be done here. It can even enhance these widgets, +for example, by adding numbering (this is done in :class:`ListRowContainer` or +:class:`ListColumnContainer`). The :meth:`Container.render` method should call the +:meth:`Container.draw` method. The :meth:`Container.draw` method should be called for every +widget placed. For a better understanding please refer to the existing implementation. + +Base container class +-------------------- + +.. autoclass:: Container + :members: + :inherited-members: + :show-inheritance: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/errors.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/errors.rst new file mode 100644 index 0000000..ebf7111 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/errors.rst @@ -0,0 +1,39 @@ +Errors module +============= + +.. automodule:: simpleline.errors + +Collection of generic exception classes used everywhere in the project. The most important one is +:class:`SimplelineError`, which is the base exception for all the other exceptions used in +the Simpleline project. + +.. autoexception:: SimplelineError + :members: + :show-inheritance: + +Render exceptions +----------------- + +Exceptions used for rendering errors. + + +.. automodule:: simpleline.render + +.. autoexception:: RenderError + :members: + :show-inheritance: + +.. autoexception:: RenderUnexpectedError + :members: + :show-inheritance: + +Event loop exceptions +--------------------- + +Exceptions used for errors in event loops. + +.. automodule:: simpleline.event_loop + +.. autoexception:: simpleline.event_loop.ExitMainLoop + :members: + :show-inheritance: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/event_loops.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/event_loops.rst new file mode 100644 index 0000000..35503e5 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/event_loops.rst @@ -0,0 +1,92 @@ +.. _event_loops_label: + +Event Loops +=========== + +.. currentmodule:: simpleline.event_loop + +Event loops are the heart of Simpleline. Every event loop is based on the +:class:`AbstractEventLoop`, and they all work with :ref:`signals `. +A signal is a message passed to the loop containing some information. Signals are passed to +an event loop by calling :meth:`AbstractEventLoop.enqueue_signal`. These signals are then +processed by calling :meth:`AbstractEventLoop.process_signals`. This method can be called by +an application developer manually or by the :meth:`AbstractEventLoop.run` method, which is +called by :meth:`App.run() ` to start the Simpleline-based application. +When a signal is processed, all handlers attached to this signal are called. Signal handler +assignment is done by the :meth:`AbstractEventLoop.register_signal_handler` method. + +Event loops can also be started recursively by :meth:`AbstractEventLoop.execute_new_loop`. +The old event loop is waiting for this event loop to stop. New loop execution is mandatory for +modal screens to work, since they can't be interrupted by other screens. This new event +loop is terminated by closing the last screen in the event loop or by calling +the :meth:`AbstractEventLoop.close_loop` method. + +The last event loop should be terminated by closing the last screen in the screen stack or by +calling :meth:`AbstractEventLoop.close_loop`. In case a fatal error occurs the +:meth:`AbstractEventLoop.force_quit` method can be used to immediately kill the loop. + +If a reaction on quitting the application (closing the last event loop) is required, the quit +callback can be used. The quit callback can be set by +the :meth:`AbstractEventLoop.set_quit_callback` method. + +The following event loops are supported by Simpleline, but you can also +:ref:`Create_your_own_loop_label` : + +* :ref:`MainLoop_label` +* :ref:`GLib_Event_loop_label` + +.. _MainLoop_label: + +Main Loop +--------- + +The main loop is the default event loop for Simpleline projects. The benefit of using +:class:`MainLoop ` is that it isn't necessary to have any dependencies on +other libraries. It is a lightweight event loop implemented completely in Python. + +.. autoclass:: simpleline.event_loop.main_loop.MainLoop + :members: + :inherited-members: + :show-inheritance: + +.. _GLib_Event_loop_label: + +GLib Event loop +--------------- + +The GLib event loop was added in order to utilize existing event loops used by other libraries, +for example, DBus connections. Simpleline with this loop should have the same behavior as with +the :ref:`MainLoop_label`. + +To use this loop you need to set it via the :class:`App ` class:: + + # Create Glib event loop. + glib_loop = GLibEventLoop() + + # Use glib event loop instead of the original one. + # Everything else should behave the same as with the original Simpleline loop. + App.initialize(event_loop=glib_loop) + +The GLib loop can be accessed by the +:attr:`GLibEventLoop.active_main_loop ` +property, or by getting the default loop from GLib directly +`GLib.MainLoop() `_. + +.. autoclass:: simpleline.event_loop.glib_event_loop.GLibEventLoop + :members: + :inherited-members: + :show-inheritance: + +.. _Create_your_own_loop_label: + +Create your own loop +-------------------- + +If new loop support is required, it should inherit from :class:`AbstractEventLoop` and +implement the same behavior as the :ref:`MainLoop_label`. You can use existing tests from the +event loops to start. If the new loop is stable enough, pull requests are always welcome at +`Simpleline repository `_. + +.. autoclass:: simpleline.event_loop.AbstractEventLoop + :members: + :inherited-members: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/prompt.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/prompt.rst new file mode 100644 index 0000000..eaf9e9c --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/prompt.rst @@ -0,0 +1,23 @@ +.. _prompt_label: + +Prompt +====== + +.. automodule:: simpleline.render.prompt + +Class for prompting a user for input. New user options can be added by :meth:`Prompt.add_option`, +removed by :meth:`Prompt.remove_option` or updated by :meth:`Prompt.update_option`. +A message for the user can also be set by the :meth:`Prompt.set_message` method. + +This class is used in the :class:`UIScreen ` class. The default +instance always handles *r* (refresh), *c* (continue) and *q* (quit) and is created in the +:meth:`UIScreen.prompt() ` method. To create your own +custom prompt please override +the :meth:`UIScreen.prompt() ` method. + +Prompt class +------------ + +.. autoclass:: Prompt + :members: + :inherited-members: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen.rst new file mode 100644 index 0000000..5b0da9d --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen.rst @@ -0,0 +1,126 @@ +.. _uiscreen_label: + +UIScreen +======== + +.. automodule:: simpleline.render.screen + +The base class for creating a new screen. :class:`UIScreen` is used for any user interaction. +:class:`UIScreen` uses :ref:`containers ` and :ref:`widgets ` +to present information to a user, and the :meth:`UIScreen.input` method to get input from a user +to an application. Screens are pushed to the screen stack, which are then used to +communicate with a user. See the :ref:`screen handling ` section to find +out more. + +The methods :meth:`UIScreen.redraw`, :meth:`UIScreen.close`, :meth:`UIScreen.emit` and +:meth:`UIScreen.create_and_emit` are asynchronous. These methods will create a signal which +is passed to the event loop for later processing. + +**Beware**, methods :meth:`UIScreen.redraw` and :meth:`UIScreen.close` can lead to unexpected +behavior when multiple instances of these signals are emitted (methods are called multiple times). +This can even crash your application. + +Lifecycle +--------- + +Every :class:`UIScreen` has a distinct lifecycle: *uninitialized*, *initialized*, *draw*, +*process input* and *closed*. If the screen has already been initialized +(it was *drawn* to a monitor) and will be shown again, then the screen skips +the *uninitialized* stage. The screen can cycle between *draw* and *process input* stages by +calling the :meth:`UIScreen.redraw` method after processing user input. + +In case :meth:`UIScreen.redraw` won't be called and no new screen is pushed, or this screen +wasn't closed, then an application will stay in an infinite loop waiting for something to happen. +This is correct behavior because there could be something in an event loop which will +call :meth:`UIScreen.redraw` later. + +Rendering widgets +----------------- + +The :meth:`UIScreen.refresh` method is the most important part of the :class:`UIScreen`. +It contains preparations for rendering (creating widgets and adding them to containers). +The :meth:`UIScreen.refresh` method will be called before anything is drawn on a monitor. + +The :attr:`UIScreen.window` attribute, which is the +:class:`WindowContainer ` instance, contains +all items (widgets, containers) which are to be rendered by the screen. +A new :class:`WindowContainer ` is created in the +:meth:`UIScreen.refresh` method for every screen redraw. The :attr:`UIScreen.title` attribute is +passed to the :attr:`WindowContainer.title ` +property, and a developer can add :ref:`widgets ` and other +:ref:`containers ` to present items to a user by calling +:meth:`WindowContainer.add() ` or +:meth:`WindowContainer.add_with_separator() `. +Multiple items can be added by calling these methods repeatedly. + +When everything is prepared properly in the :meth:`UIScreen.refresh` method, it needs to be drawn +on the monitor for a user. This is handled by the :meth:`UIScreen.show_all` method. This method +works automatically, but it could also be useful for a developer, especially when the screen will +not process input. In this case, the :meth:`UIScreen.input` method is not called at all. +Developers can override this method and call the parent class's :meth:`UIScreen.show_all`, +which will handle drawing the screen and any additional processing. + +Redrawing the screen can be invoked by the :meth:`UIScreen.redraw` method. However, this is +not processed immediately. Instead it will be added to the event loop and processed later, when the +loop is idle. Beware, after every :meth:`redraw ` call the input is processed +if not disabled, so if multiple redraw signals are emitted, than the application will +crash. + +The :meth:`UIScreen.redraw` method is also invoked when a screen is +:ref:`pushed ` to the stack. + +User input processing +--------------------- + +If the screen shouldn't process user input, the :attr:`UIScreen.input_required` property needs +to be set to `False`. `True` is the default value for this property. + +After everything is printed to a monitor, the :class:`UIScreen` will wait for user input. +For this purpose there is :meth:`UIScreen.input`, which is called when a user passes string input +to a screen. The screen needs to react upon user input and return one of the options from the +:class:`InputState` enum or the user input string. + +To accept the user input, :attr:`InputState.PROCESSED`, :attr:`InputState.PROCESSED_AND_REDRAW` or +:attr:`InputState.PROCESSED_AND_CLOSE` should be returned. Addition to accepting user input the +:attr:`InputState.PROCESSED_AND_REDRAW` value will also redraw active screen and +:attr:`InputState.PROCESSED_AND_CLOSE` will close active screen. However, if +:attr:`InputState.PROCESSED` is used then the developer is responsible for not ending in frozen +application. The :meth:`UIScreen.refresh` or the :meth:`UIScreen.close` methods must be called +manually. + +In case the user input is invalid, the :attr:`InputState.DISCARDED` value should be returned. +This will reject the user input and wait for another attempt. The :class:`UIScreen.refresh` +method will be called after 5 rejections and show the screen output again. + +If the user input string is returned it will be checked for +options of the :class:`Prompt ` instance which can either +close the screen, refresh the screen (this will call :meth:`UIScreen.refresh`) +or quit the application. + +Closing screens +--------------- + +There are several ways to close a screen. One is by calling :meth:`UIScreen.close` or +by pressing *c* to continue (with the default +:class:`Prompt ` class). When the screen is closed +the next screen on the stack will be shown. A screen can also be +:ref:`replaced `. Then the original screen is removed from the stack +without closing a screen. If a reaction on closing a screen is required then the +:meth:`UIScreen.closed` callback should be overridden. + +**Beware**, when calling :meth:`UIScreen.close` multiple times it will close multiple screens. +This is because the close signal will always close the top screen on the screen stack. + +UIScreen class +-------------- + +.. autoclass:: UIScreen + :members: + :inherited-members: + +InputState enum +--------------- + +.. autoclass:: InputState + :members: + :undoc-members: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen_handling.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen_handling.rst new file mode 100644 index 0000000..561ed52 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/screen_handling.rst @@ -0,0 +1,82 @@ +.. _screen_handling_label: + +Screen Handling +=============== + +.. automodule:: simpleline.render.screen_handler + +The :class:`ScreenHandler` class is used to schedule a +:class:`UIScreen ` to the screen stack. + +Screen handling is an important part of using the Simpleline library, and it is recommended +for a developer to get familiar with this principle. Screen handling is the gateway by which +a developer manages the stack, by either adding or removing screens from it. +There are many ways to add a screen to the stack. To remove a screen from the stack, the screen +must be closed, or it can be replaced by another screen. +To close a :class:`UIScreen ` a developer should call +the :meth:`UIScreen.close() ` +method. A screen can also be closed when a user presses `c` (which can be disabled). This will +close the screen automatically. When a screen is closed, the next screen on the top of +the stack will be rendered. If the stack is empty then the application will close. + +**Do not instantiate the** :class:`ScreenHandler` **class!** All methods in the +:class:`ScreenHandler` class are class methods so the :class:`ScreenHandler` shouldn't be +instantiated at all. + +The following operations can be used to schedule a screen. + +Schedule screen +--------------- + +To schedule a screen use the :meth:`ScreenHandler.schedule_screen` method. +Scheduling a screen should be used on the first screen in your application before starting the +event loop. The screen is added to the bottom of the screen stack, and it will be visible as +the last screen in a stack. + +This is the only way to add a screen to the screen stack without emitting a redraw call. + +.. _push_screen_label: + +Push screen +----------- + +To push a screen to the stack use the :meth:`ScreenHandler.push_screen` method. +Pushing a screen to the stack will place a screen on top of the stack, so it will be +drawn on the next redraw call. The original screen will remain on the stack, so after the new +screen is closed, the original screen will be rendered again. If you need to avoid this behavior +please close the active screen before pushing a new screen to the stack. + +The redraw signal will be emitted automatically when a screen is pushed. + +.. _push_screen_modal_label: + +Push screen as modal +-------------------- + +To push a modal screen to the stack use the :meth:`ScreenHandler.push_screen_modal` method. +This behaves the same as :ref:`push_screen_label` with one important difference. The pushed screen +will act as a modal screen. A modal screen has its own event loop, so event processing of the old +loop is blocked until the modal screen is closed. The code processing is also blocked by the +:meth:`ScreenHandler.push_screen_modal` method call. + +The :meth:`UIScreen.redraw() ` method may be +required if the original screen was already drawn before invoking the +:meth:`ScreenHandler.push_screen_method` method. + +The redraw signal will be emitted automatically when a screen is pushed. + +.. _replace_screen_label: + +Replace screen +-------------- + +Replace an existing screen with a new screen. This behaves like :ref:`push_screen_label` but it +replaces the original screen, so there is no need to close the original screen. + +The redraw signal will be emitted automatically when a screen is replaced. + +ScreenHandler class +------------------- + +.. autoclass:: ScreenHandler + :members: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/signals.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/signals.rst new file mode 100644 index 0000000..b5f4931 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/signals.rst @@ -0,0 +1,22 @@ +.. _signals_label: + +Signals +======= + +This is a collection of signals that can be used in the +:class:`event loop `. + +.. automodule:: simpleline.event_loop.signals + :members: + :inherited-members: + :show-inheritance: + +Creating custom signals +----------------------- + +New signals can be created by subclassing an existing signal class or +:class:`AbstractSignal ` + +.. autoclass:: simpleline.event_loop.AbstractSignal + :members: + :inherited-members: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/widgets.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/widgets.rst new file mode 100644 index 0000000..7f48fe6 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/api/widgets.rst @@ -0,0 +1,44 @@ +.. _widgets_label: + +Widgets +======= + +.. currentmodule:: simpleline.render.widgets + +Widgets are the basic units to render items on a +:class:`screen `. Widgets can wrap a common text +(:class:`TextWidget`) or create empty lines (:class:`SeparatorWidget`). They can also be more +complex structures (:class:`CheckboxWidget`). A new widget can also be created. +See :ref:`create_custom_widget_label`. + +These widgets should be used in :ref:`containers_label`. + +Widgets classes +--------------- + +.. automodule:: simpleline.render.widgets + :members: + :inherited-members: + :show-inheritance: + +.. _create_custom_widget_label: + +Creating a custom widget +------------------------ + +To create a custom widget you should subclass the :class:`Widget` class. The most important method +for creating a customized widget is :meth:`Widget.render`. This method is responsible for +presenting a user textual information. + +If the new widget is composed of other widgets the :meth:`Widget.draw` method should be +called on every widget used. The :meth:`Widget.write` method should be called if the input +is a string. These calls can be repeated multiple times. For an example please look at the +existing implementation. + +Base Widget class +----------------- + +.. autoclass:: Widget + :members: + :inherited-members: + :show-inheritance: diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/conf.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/conf.py new file mode 100644 index 0000000..c6941bc --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/conf.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Simpleline documentation build configuration file, created by +# sphinx-quickstart on Fri Nov 3 11:00:41 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +from unittest.mock import MagicMock + + +sys.path.insert(0, os.path.abspath('..')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.imgmath'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'Simpleline' +copyright = '2017, Jiri Konecny' # pylint: disable=redefined-builtin +author = 'Jiri Konecny' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + + +def get_version(): + """Read version from ../python-simpleline.spec .""" + import re + version_re = re.compile(r"^Version: *([\d.]+)$") + with open("../python-simpleline.spec", "r") as f: + for line in f: + m = version_re.match(line) + if m: + return m.group(1) + + +# The short X.Y version. +version = get_version() +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Simplelinedoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Simpleline.tex', 'Simpleline Documentation', + 'Jiri Konecny', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'simpleline', 'Simpleline Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Simpleline', 'Simpleline Documentation', + author, 'Simpleline', 'One line description of project.', + 'Miscellaneous'), +] + + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/3': None} + + +# -- Mock missing stuff in readthedocs ------------------------------------ + + +class Mock(MagicMock): + @classmethod + def __getattr__(cls, name): + return MagicMock() + + +MOCK_MODULES = ['gi', 'gi.repository'] +sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/guide.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/guide.rst new file mode 100644 index 0000000..ea3ed3b --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/guide.rst @@ -0,0 +1,176 @@ +.. _guide_label: + +Guide to Simpleline +=================== + +Simpleline is a text user interface framework written completely in Python 3 with a possibility to +have :ref:`non-python event loops `. With the exception of optional event loops, +Simpleline has almost no dependency on external libraries. + +This UI is simple and easy to use. It is designed to be used with line-based machines and tools +(e.g. serial console) so that every new line is appended to the bottom of the screen. +Printed lines are never rewritten! + +Basic components +---------------- + +For every application, the following parts are always required. + +* The :class:`App ` static class to initialize and run application. +* The :class:`ScreenHandler ` static class for + scheduling screens. +* The :class:`UIScreen ` based classes to create screens which + will form the application. +* :ref:`Widgets ` to show anything on the screens. +* :ref:`Containers ` to position widgets on the screen. + +Look at the next section to see how everything fits together. + +How to create a simple application +---------------------------------- + +.. currentmodule:: simpleline.render.screen + +Interaction with a user is necessary to have a useful UI framework. To show anything to a user the +:class:`UIScreen` class must be used. So we will subclass this class to create our screen and set +a title for it:: + + class DividerScreen(UIScreen): + + def __init__(self): + # Set title of the screen. + super().__init__(title=u"Divider") + self._message = 0 + +The ``self._message`` variable will be used later to show results to the user. + +The screen's main purpose is to present content to a user. For this we need widgets and containers. + +The :attr:`UIScreen.window` attribute is the most important part of the screen for rendering. +It contains the :class:`WindowContainer ` +container which is created and filled up by the :meth:`UIScreen.refresh` method. +Everything added to this container is printed to the monitor. +We should override the :meth:`UIScreen.refresh` method and call the parent's version to +prepare the container. Then we can add :ref:`widgets ` to the container. +The screen will continue like this: + +.. code-block:: python + :dedent: 0 + + def refresh(self, args=None): + # Fill the self.window attribute by the WindowContainer and set screen title as header. + super().refresh() + + widget = TextWidget("Result: " + str(self._message)) + self.window.add_with_separator(widget) + +The :meth:`WindowContainer.add_with_separator() ` +method will print a blank line after the +:class:`TextWidget's ` text. + +Now the user has the header and result printed on the screen but it would be nice to give them a +hint about how to use the Divider screen. The best part of the screen for this is the +:class:`Prompt `. +The :class:`Prompt ` class is responsible for guiding the user +by giving them a set of possible options to choose from. + +We will set the message of the prompt inside of the :meth:`UIScreen.prompt` method. We also +remove the default option to continue, because it functions the same as quitting when there is +only one screen in the application. + +.. code-block:: python + :dedent: 0 + + def prompt(self, args=None): + # Change user prompt + prompt = super().prompt() + + # Set message to the user prompt. Give a user hint how he/she may control our application. + prompt.set_message("Pass numbers to divider in a format: 'num / num'") + + # Remove continue option from the control. There is no need for that + # when we have only one screen. + prompt.remove_option('c') + + return prompt + +When we are able to present our content to a user, we want to have the possibility to process +user input. For this purpose there is the :meth:`UIScreen.input` method. Input from a user is +passed to this method, and the screen may process it, discard it or return it for further +processing. + +If input processing is not required and the screen should only be used for displaying +information to a user, then the :attr:`UIScreen.input_required` property should be set to `False`. +However, in this case you need to :meth:`close `, :meth:`redraw ` +or :ref:`push ` a new screen manually. This can be done, for example, in the +:meth:`UIScreen.show_all` method. + +.. code-block:: python + :dedent: 0 + + def input(self, args, key): + """Process input from user and catch numbers with '/' symbol.""" + + # Test if user passed valid input for divider. + # This will basically take number + number and nothing else and only positive numbers. + groups = re.match(r'(\d+) *\/ *(\d+)$', key) + if groups: + num1 = int(groups[1]) + num2 = int(groups[2]) + + # Dividing by zero is not valid so we won't accept this input from the user. New + # input is then required from the user. + if num2 == 0: + return InputState.DISCARDED + + self._message = int(num1 / num2) + + # Because this input is processed we need to show this screen (show the result) + # again by returning PROCESSED_AND_REDRAW. + # This will call the refresh method so our new result will be processed inside + # of the refresh() method. + return InputState.PROCESSED_AND_REDRAW + else: + # Not input for our screen, try other default inputs. This will result in the + # same state as DISCARDED when no default option is used. + return key + + +.. py:currentmodule:: simpleline + +Our screen is finished. Next, we need to use it in our application. To run an application the +:class:`App` static class must be used. + +This class will initialize an event loop and the scheduler by the :meth:`App.initialize` method. +When the application is initialized, we need to pass our screen to the screen stack (you can +pass multiple screens but we have only one here). To pass a screen to the screen stack we will use +:class:`ScreenHandler `. For further explanation +on screen scheduling, refer to the :ref:`screen_handling_label` section. + +.. code-block:: python + :dedent: 0 + + if __name__ == "__main__": + # Initialize application (create scheduler and event loop). + App.initialize() + + # Create our screen. + screen = DividerScreen() + + # Schedule screen to the screen scheduler. + # This can be called only after App.initialize(). + ScreenHandler.schedule_screen(screen) + + # Run the application. You must have some screen scheduled + # otherwise it will end in an infinite loop. + App.run() + +Well done! You have your first application in Simpleline. + +Further reading +--------------- + +I would recommend everyone who wants to use Simpleline to look at the +`examples `_ which is one +of the best sources of information. Another place to look is the :ref:`public_api_label` +documentation section. diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/index.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/index.rst new file mode 100644 index 0000000..e03ca11 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/index.rst @@ -0,0 +1,23 @@ +.. Simpleline documentation master file, created by + sphinx-quickstart on Fri Nov 3 11:00:41 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Simpleline's documentation! +====================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + introduction + guide + api + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/introduction.rst b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/introduction.rst new file mode 100644 index 0000000..8ca6de6 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/introduction.rst @@ -0,0 +1,102 @@ +Introduction +============ + +Simpleline is a text UI framework. Originally a part of the Anaconda installer project. + +It is designed to be used with line-based machines and tools (e.g. serial console) so that +every new line it appended to the bottom of the screen. Printed lines are never rewritten! + +How to use +---------- + +The best learning sources can be found in the +`examples directory `_ in +the `GitHub repository `_ and you can read the +:ref:`guide_label` section of this documentation. However, some basic usage of Simpleline will be +shown here too, to get an idea of how Simpleline works:: + + from simpleline import App + from simpleline.render.screen import UIScreen + from simpleline.render.screen_handler import ScreenHandler + from simpleline.render.widgets import TextWidget + + + # UIScreen is the main building item for Simpleline. Every screen + # which will user see should be inherited from UIScreen. + class HelloWorld(UIScreen): + + def __init__(self): + # Set title of the screen. + super().__init__(title=u"Hello World") + + def refresh(self, args=None): + # Fill the self.window attribute by the WindowContainer and set screen title as header. + super().refresh() + widget = TextWidget("Body text") + self.window.add_with_separator(widget) + + + if __name__ == "__main__": + # Initialize application (create scheduler and event loop). + App.initialize() + + # Create our screen. + screen = HelloWorld() + + # Schedule screen to the screen scheduler. + # This can be called only after App.initialize(). + ScreenHandler.schedule_screen(screen) + + # Run the application. You must have some screen scheduled + # otherwise it will end in an infinite loop. + App.run() + +The output from the simple *Hello World* example above:: + + $ ./run_example.sh 00_basic + ================================================================================ + ================================================================================ + Hello World + + Body text + + Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to + refresh]: + +If a user presses **r** and then **enter** to refresh, the same screen is printed again. +This will be printed to a monitor:: + + $ ./run_example.sh 00_basic + ================================================================================ + ================================================================================ + Hello World + + Body text + + Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to + refresh]: r + ================================================================================ + ================================================================================ + Hello World + + Body text + + Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to + refresh]: + +As you can see the whole screen is not rewritten -- only printed again on the bottom. This +is the expected behavior so the actual screen is always at the bottom but you can see the whole +history. This behavior makes working with line based machines and tools much easier. + +Dependencies +------------ + +This is a Python3-only project. This code should not be difficult to migrate to Python2. However, +there is no need from the community, so it is only compatible with Python3 at the moment. No special +libraries are required to use this library. If you want to use glib event loop instead of the +original one you need to install glib and Python3 gobject introspection. + +If you want to run tests (make ci), you need to install +`Pocketlint `_ and +`glib `_ with gobject introspection for +`Python3 `_. diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/make.bat b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/make.bat new file mode 100644 index 0000000..63f06ba --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/doc/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=Simpleline + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/00_basic/00_basic.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/00_basic/00_basic.py new file mode 100755 index 0000000..9ace13c --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/00_basic/00_basic.py @@ -0,0 +1,60 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Basic usage of Simpleline. +# +# Only show screen with header and text in it. +# + +from simpleline import App +from simpleline.render.screen import UIScreen +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget + + +# UIScreen is the main building item for Simpleline. Every screen +# which will user see should be inherited from UIScreen. +class HelloWorld(UIScreen): + + def __init__(self): + # Set title of the screen. + super().__init__(title=u"Hello World") + + def refresh(self, args=None): + # Fill the self.window attribute by the WindowContainer and set screen title as header. + super().refresh() + widget = TextWidget("Body text") + self.window.add_with_separator(widget) + + +if __name__ == "__main__": + # Initialize application (create scheduler and event loop). + App.initialize() + + # Create our screen. + screen = HelloWorld() + + # Schedule screen to the screen scheduler. + # This can be called only after App.initialize(). + ScreenHandler.schedule_screen(screen) + + # Run the application. You must have some screen scheduled + # otherwise it will end in an infinite loop. + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/01_base_widgets/01_base_widgets.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/01_base_widgets/01_base_widgets.py new file mode 100755 index 0000000..0f821f3 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/01_base_widgets/01_base_widgets.py @@ -0,0 +1,75 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Usage of base widgets. +# +# Show base widgets for user interaction in one screen. +# + +from simpleline import App +from simpleline.render.screen import UIScreen +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget, CenterWidget, CheckboxWidget + + +class HelloWorld(UIScreen): + + def __init__(self): + # Set title of the screen. + super().__init__(title=u"Show Widgets") + + def refresh(self, args=None): + super().refresh() + + # Text widget + # Show text to user. This is basic widget which will handle + # wrapping of words for you. + text_widget = TextWidget("Text widget") + self.window.add_with_separator(text_widget) + + # Center widget + # Wrap extisting widget and center it to the middle of the screen. + text = TextWidget("Center widget") + center_widget = CenterWidget(text) + self.window.add_with_separator(center_widget, blank_lines=3) # Add two more blank lines + + # Checkbox widget + # Checkbox which can hold 2 states. + checkbox_widget = CheckboxWidget(key="o", + title="Checkbox title", + text="Checkbox text", + completed=True) + self.window.add_with_separator(checkbox_widget) + + # Checkbox widget unchecked + checkbox_widget_unchecked = CheckboxWidget(key="o", + title="Checkbox title", + text="Unchecked", + completed=False) + self.window.add_with_separator(checkbox_widget_unchecked) + + +if __name__ == "__main__": + App.initialize() + + screen = HelloWorld() + ScreenHandler.schedule_screen(screen) + + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/02_ignore_continue/02_ignore_continue.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/02_ignore_continue/02_ignore_continue.py new file mode 100755 index 0000000..ba5e732 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/02_ignore_continue/02_ignore_continue.py @@ -0,0 +1,78 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# How to block the input from a user. +# +# This can be used for example to force a user to set all the required values. +# Application quit callback is also used here. +# + +from simpleline import App +from simpleline.render.prompt import Prompt +from simpleline.render.screen import UIScreen, InputState +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget, CenterWidget + + +def application_quit_cb(args): + """Call this callback when the application is quitting.""" + print("Application is closing. Bye!") + + +class InfiniteScreen(UIScreen): + + def __init__(self): + # We are using title as message here. Any text could be passed to the title. + super().__init__("You need to use 'q' to quit") + self.continue_count = 0 + + def refresh(self, args=None): + """Print text to user with number of continue clicked.""" + super().refresh(args) + # Print counter to the screen. + widget = TextWidget("You pressed {} times on continue".format(self.continue_count)) + # Center this counter to middle of the screen. + center_widget = CenterWidget(widget) + # Add the centered widget to the window container. + self.window.add(center_widget) + + def input(self, args, key): + """Catch 'c' keys for continue and increase counter.""" + if key == Prompt.CONTINUE: + self.continue_count += 1 + # Do not process 'c' continue anymore. + # This will refresh screen to refresh counter number + return InputState.PROCESSED_AND_REDRAW + + # Process other input e.g.: 'r' refresh and 'q' quit. + return key + + +if __name__ == "__main__": + App.initialize() + screen = InfiniteScreen() + + # Get event loop from application. + loop = App.get_event_loop() + # Set quit callback to the loop. When the loop quits this callback will be triggered. + loop.set_quit_callback(application_quit_cb) + + ScreenHandler.schedule_screen(screen) + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/03_entry_counter/03_entry_counter.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/03_entry_counter/03_entry_counter.py new file mode 100755 index 0000000..da26507 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/03_entry_counter/03_entry_counter.py @@ -0,0 +1,89 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from simpleline import App +from simpleline.render.screen import UIScreen, InputState +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget, CenterWidget + + +class Hub(UIScreen): + + def __init__(self): + super().__init__("Hub for entry counter") + self._counter_spoke = CounterScreen() + + def refresh(self, args=None): + super().refresh(args) + + w = CenterWidget(TextWidget("Press '1' to enter Entry counter")) + + self.window.add_with_separator(w) + + def input(self, args, key): + """Run spokes based on the user choice.""" + if key == "1": + ScreenHandler.push_screen(self._counter_spoke) + # this input was processed + return InputState.PROCESSED + + # return for outer processing + # the basic processing is 'c' for continue, 'r' for refresh, 'q' to quit + # otherwise the input is discarded and waiting for a new input + return key + + def prompt(self, args=None): + """Add our information to the prompt.""" + prompt = super().prompt(args) + prompt.add_option("1", "to enter counter spoke") + return prompt + + +class CounterScreen(UIScreen): + + def __init__(self): + super().__init__("Counter Screen") + self._counter = 0 + + def closed(self): + super().closed() + self.screen_ready = False + + def setup(self, args=None): + super().setup(args) + self._counter += 1 + return True + + def refresh(self, args=None): + """Write message to user.""" + super().refresh(args) + w = TextWidget("Counter {}".format(self._counter)) + self.window.add_with_separator(CenterWidget(w)) + + @property + def counter(self): + return self._counter + + +if __name__ == "__main__": + App.initialize() + hub = Hub() + ScreenHandler.schedule_screen(hub) + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/04_help.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/04_help.py new file mode 100755 index 0000000..cb73811 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/04_help.py @@ -0,0 +1,37 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Show help screen. +# +# Usage of the HelpScreen advanced widget. +# There are many of advanced widgets which have different uses. +# I've recommend developer to look on them. + +from simpleline import App +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.adv_widgets import HelpScreen + + +if __name__ == "__main__": + App.initialize() + # You need to pass file with help text to the screen. + s = HelpScreen("./04_help/example_help.txt") + ScreenHandler.schedule_screen(s) + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/example_help.txt b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/example_help.txt new file mode 100644 index 0000000..c5a26fe --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/04_help/example_help.txt @@ -0,0 +1,3 @@ +This is help to our AWESOME application. + +Everything is so simple, therefore no help is needed! diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/05_hub_spoke/05_hub_spoke.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/05_hub_spoke/05_hub_spoke.py new file mode 100755 index 0000000..498a177 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/05_hub_spoke/05_hub_spoke.py @@ -0,0 +1,202 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Hub and spoke implementation. +# + +# Advanced example of Simpleline use. +# Hub is the main screen from where you can go to spokes and do work in the spokes +# then you will return to the hub back. You can continue when all the required items +# is set. +# The example of containers use will be showed here. +# + +from simpleline import App +from simpleline.render.adv_widgets import PasswordDialog +from simpleline.render.containers import ListRowContainer +from simpleline.render.prompt import Prompt +from simpleline.render.screen import UIScreen, InputState +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget, CenterWidget + + +class Hub(UIScreen): + + def __init__(self): + super().__init__("Hub") + + # Container will be used for spokes positioning. Container is always created in + # the refresh() method. + self._container = None + + self._create_spokes() + + def _create_spokes(self): + """Create spokes and use their value.""" + + # Create name spoke + self._name_spoke = SetNameScreen("First name", "John") + # Create surname spoke + self._surname_spoke = SetNameScreen("Surname", "Doe") + # Create the PasswordDialog advanced widget for getting password from a user. + self._password_spoke = PasswordDialog() + + def refresh(self, args=None): + """Refresh method is called always before the screen will be printed. + + All items for printing should be updated or created here. + """ + # Init window container. The windows container will be erased here. + # The window container is the base container. Everything for rendering should be put + # into this container, including other containers. + super().refresh(args) + + # Add the screen header message before our items. + header = TextWidget("Please complete all the spokes to continue") + header = CenterWidget(header) + self.window.add_with_separator(header, blank_lines=2) + + # Create the empty container. + # It will add numbering, process user input and positioning for us. + self._container = ListRowContainer(2) + + # Create widget to get user name. + widget = self._create_name_widget() + # Add widget, callback, arguments to the container. + # + # widget - Widget we want to render. It will be numbered automatically. + # Could be container if needed. + # callback - This callback will be called by the ListRowContainer.process_user_input() + # method when a user press the number of this item. Callback will get args + # passed as 3rd argument. + # args - Argument for callback. + self._container.add(widget, self._push_screen_callback, self._name_spoke) + + # Create surname widget and add it to the container. + widget = self._create_surname_widget() + self._container.add(widget, self._push_screen_callback, self._surname_spoke) + + # Create password widget and add it to the container. + widget = self._create_password_widget() + self._container.add(widget, self._push_screen_callback, self._password_spoke) + + # Add the ListRowContainer container to the WindowContainer container. + self.window.add_with_separator(self._container) + + def _create_name_widget(self): + """Create name spoke widget. + + Add the actual value below the spoke name. + """ + msg = "First name" + if self._name_spoke.value: + msg += "\n{}".format(self._name_spoke.value) + + return TextWidget(msg) + + def _create_surname_widget(self): + """Create surname spoke widget. + + Add the actual value below the spoke name. + """ + msg = "Surname" + if self._surname_spoke.value: + msg += "\n{}".format(self._surname_spoke.value) + + return TextWidget(msg) + + def _create_password_widget(self): + """Create password spoke widget. + + Add the "Password set" text below the spoke name if set. + """ + msg = "Password" + if self._password_spoke.answer: + msg += "\nPassword set." + + return TextWidget(msg) + + def input(self, args, key): + """Run spokes based on the user choice.""" + # Find out if a user pressed number for an existing widget and call the callback attached + # to it with arguments passed in the refresh() method. + # Return False if the input is not related to the widget. + if self._container.process_user_input(key): + # Do not process other input if spoke is entered. + return InputState.PROCESSED + + # Block continue ('c') if everything is not set. + if key == Prompt.CONTINUE: + if self._name_spoke and self._surname_spoke and self._password_spoke.answer: + return key + # catch 'c' key if not everything set + return InputState.DISCARDED + + return key + + @staticmethod + def _push_screen_callback(target_screen): + """Push target screen as new screen. + + Target screen is passed in as an argument in the refresh() method. + """ + ScreenHandler.push_screen(target_screen) + + def prompt(self, args=None): + """Add information to prompt for user.""" + prompt = super().prompt(args) + # Give user hint that he can press 1, 2 or 3 to enter spokes. + prompt.add_option("1,2,3", "to enter spokes") + return prompt + + +class SetNameScreen(UIScreen): + + def __init__(self, message, def_value): + """Create spoke for setting name and surname. + + :param message: Text message as the body for user. + :param def_value: Default value for this spoke. + """ + super().__init__() + self._value = def_value + self._message = message + + def refresh(self, args=None): + """Write message to user.""" + super().refresh(args) + w = TextWidget(self._message) + self.window.add(CenterWidget(w)) + + def prompt(self, args=None): + """Take user input.""" + self._value = self.get_user_input("Write your name: ") + self.close() + + @property + def value(self): + """Return value set by a user in this spoke.""" + return self._value + + +if __name__ == "__main__": + App.initialize() + screen = Hub() + ScreenHandler.schedule_screen(screen) + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/06_glib_loop/06_glib_loop.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/06_glib_loop/06_glib_loop.py new file mode 100755 index 0000000..94147c6 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/06_glib_loop/06_glib_loop.py @@ -0,0 +1,62 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Use glib event loop instead of the original Simpleline loop. +# +# You need to have the python3-gobject installed. +# +# You can install it on Fedora by running: +# +# dnf install python3-gobject-base +# +# +# This is basic example using Glib event loop. +# You can implement your own loop abstraction. See simpleline/event_loop/glib_event_loop. +# + +from simpleline import App +from simpleline.event_loop.glib_event_loop import GLibEventLoop +from simpleline.render.screen import UIScreen +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget + + +class HelloWorld(UIScreen): + + def __init__(self): + super().__init__(title=u"Hello World with GLib") + + def refresh(self, args=None): + super().refresh() + self.window.add_with_separator(TextWidget("Body text")) + + +if __name__ == "__main__": + # Create Glib event loop. + glib_loop = GLibEventLoop() + # Use glib event loop instead of the original one. + # Everything else should behave the same as with the original Simpleline loop. + App.initialize(event_loop=glib_loop) + + screen = HelloWorld() + ScreenHandler.schedule_screen(screen) + + # Run the application. + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/07_divider/07_divider.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/07_divider/07_divider.py new file mode 100755 index 0000000..6c74f55 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/07_divider/07_divider.py @@ -0,0 +1,102 @@ +#!/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Simple divider screen. +# +# User input processing example. +# +# + +import re + +from simpleline import App +from simpleline.render.screen import UIScreen, InputState +from simpleline.render.screen_handler import ScreenHandler +from simpleline.render.widgets import TextWidget + + +class DividerScreen(UIScreen): + + def __init__(self): + # Set title of the screen. + super().__init__(title=u"Divider") + self._message = 0 + + def refresh(self, args=None): + # Fill the self.window attribute by the WindowContainer and set screen title as header. + super().refresh() + + widget = TextWidget("Result: " + str(self._message)) + self.window.add_with_separator(widget) + + def prompt(self, args=None): + # Change user prompt + prompt = super().prompt() + + # Set message to the user prompt. Give a user hint how he/she may control our application. + prompt.set_message("Pass numbers to divider in a format: 'num / num'") + + # Remove continue option from the control. There is no need for that + # when we have only one screen. + prompt.remove_option('c') + + return prompt + + def input(self, args, key): + """Process input from user and catch numbers with '/' symbol.""" + + # Test if user passed valid input for divider. + # This will basically take number + number and nothing else and only positive numbers. + groups = re.match(r'(\d+) *\/ *(\d+)$', key) + if groups: + num1 = int(groups[1]) + num2 = int(groups[2]) + + # Dividing by zero is not valid so we won't accept this input from the user. New + # input is then required from the user. + if num2 == 0: + return InputState.DISCARDED + + self._message = int(num1 / num2) + + # Because this input is processed we need to show this screen (show the result). + # This will call refresh so our new result will be processed inside of the refresh() + # method. + return InputState.PROCESSED_AND_REDRAW + + # Not input for our screen, try other default inputs. This will result in the + # same state as DISCARDED when no default option is used. + return key + + +if __name__ == "__main__": + # Initialize application (create scheduler and event loop). + App.initialize() + + # Create our screen. + screen = DividerScreen() + + # Schedule screen to the screen scheduler. + # This can be called only after App.initialize(). + ScreenHandler.schedule_screen(screen) + + # Run the application. You must have some screen scheduled + # otherwise it will end in an infinite loop. + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/run_example.sh b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/run_example.sh new file mode 100755 index 0000000..4916480 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/examples/run_example.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Script for starting examples from source code. +# +# Author(s): Jiri Konecny +# + + +function print_help { + echo "run_example.sh - easy way how to run example without installing module" + echo "" + echo "./run_example.sh [example]" + echo "" + echo "There is one required argument [example] which is name of the test." + echo "" +} + +if [[ $# -ne 1 ]]; then + echo "Bad number of arguments" 1>&2 + print_help + exit 1 +elif [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then + print_help + exit 0 +fi + +PROJECT_NAME=${1%%/} + +pushd $(pwd) +cd $(dirname $0)/ +PYTHONPATH="..:." python3 ./$PROJECT_NAME/$PROJECT_NAME.py +popd + diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/po/Makefile b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/po/Makefile new file mode 100644 index 0000000..772e0a2 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/po/Makefile @@ -0,0 +1,86 @@ +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# Makefile for the PO files (translation) catalog +# +# $Id$ + +TOP = ../.. + +# What is this package? +NLSPACKAGE = python-simpleline +POTFILE = $(NLSPACKAGE).pot +INSTALL = /usr/bin/install -c +INSTALL_DATA = $(INSTALL) -m 644 +INSTALL_DIR = /usr/bin/install -d + +# destination directory +INSTALL_NLS_DIR = $(RPM_BUILD_ROOT)/usr/share/locale + +# PO catalog handling +MSGMERGE = msgmerge -v +XGETTEXT = xgettext --default-domain=$(NLSPACKAGE) \ + --add-comments +MSGFMT = msgfmt --statistics --verbose + +# What do we need to do +POFILES = $(wildcard *.po) +MOFILES = $(patsubst %.po,%.mo,$(POFILES)) +PYSRC = $(wildcard ../simpleline/*.py) $(wildcard ../simpleline/**/*.py) + +all:: update-po $(MOFILES) + +potfile: $(PYSRC) + $(XGETTEXT) -L Python --keyword=_ --keyword=N_ $(PYSRC) + @if cmp -s $(NLSPACKAGE).po $(POTFILE); then \ + rm -f $(NLSPACKAGE).po; \ + else \ + mv -f $(NLSPACKAGE).po $(POTFILE); \ + fi; \ + +update-po: Makefile potfile refresh-po + +refresh-po: Makefile + for cat in $(POFILES); do \ + lang=`basename $$cat .po`; \ + if $(MSGMERGE) $$lang.po $(POTFILE) > $$lang.pot ; then \ + mv -f $$lang.pot $$lang.po ; \ + echo "$(MSGMERGE) of $$lang succeeded" ; \ + else \ + echo "$(MSGMERGE) of $$lang failed" ; \ + rm -f $$lang.pot ; \ + fi \ + done + +clean: + @rm -fv *mo *~ .depend + +install: $(MOFILES) + @for n in $(MOFILES); do \ + l=`basename $$n .mo`; \ + $(INSTALL_DIR) $(INSTALL_NLS_DIR)/$$l/LC_MESSAGES; \ + $(INSTALL_DATA) --verbose $$n $(INSTALL_NLS_DIR)/$$l/LC_MESSAGES/$(NLSPACKAGE).mo; \ + done + +%.mo: %.po + $(MSGFMT) -o $@ $< + +.PHONY: missing depend + + diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/python-simpleline.spec b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/python-simpleline.spec new file mode 100644 index 0000000..10d38ed --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/python-simpleline.spec @@ -0,0 +1,408 @@ +%global srcname simpleline + +Name: python-%{srcname} +Summary: A Python library for creating text UI +Url: https://github.com/rhinstaller/python-%{srcname} +Version: 1.8 +Release: 1%{?dist} +# This tarball was created from upstream git: +# git clone https://github.com/rhinstaller/python-simpleline +# cd python-simpleline && make archive +Source0: https://github.com/rhinstaller/python-%{srcname}/releases/download/%{srcname}-%{version}/%{srcname}-%{version}.tar.gz + +License: LGPLv3+ +BuildArch: noarch +BuildRequires: make +BuildRequires: python3-devel +BuildRequires: gettext +BuildRequires: python3-setuptools +BuildRequires: intltool +BuildRequires: python3-gobject-base + +%description +Simpleline is a Python library for creating text UI. +It is designed to be used with line-based machines +and tools (e.g. serial console) so that every new line +is appended to the bottom of the screen. +Printed lines are never rewritten! + + +%package -n python3-%{srcname} +Summary: A Python3 library for creating text UI +Requires: rpm-python3 + +%{?python_provide:%python_provide python3-%{srcname}} + +%description -n python3-%{srcname} +Simpleline is a Python3 library for creating text UI. +It is designed to be used with line-based machines +and tools (e.g. serial console) so that every new line +is appended to the bottom of the screen. +Printed lines are never rewritten! + +%prep +%setup -q -n %{srcname}-%{version} + +%build +%make_build + +%install +make DESTDIR=%{buildroot} install +%find_lang python-%{srcname} + +%check +make test + + +%files -n python3-%{srcname} -f python-%{srcname}.lang +%license LICENSE.md +%doc ChangeLog README.md +%{python3_sitelib}/* + +%changelog +* Mon Feb 22 2021 Jiri Konecny - 1.8-1 +- Add missing make command to spec file (jkonecny) +- Don't translate the prompt keys (vponcova) +- Enable daily build for Anaconda-devel COPR repository (jkonecny) +- Use Fedora container registry instead of Dockerhub (jkonecny) +- Migrate COPR daily COPR builds to Packit (jkonecny) +- Test build on Fedora ELN (jkonecny) +- Remove packit get-current-action (jkonecny) +- Run tests in GitHub workflow (martin) +- Fix raise-missing-from (W0707) pylint warnings (martin) +- Fix pylint to check test code correctly (jkonecny) +- Use script to run unit tests (jkonecny) +- Use relative imports in tests (jkonecny) +- Change directory structure of unit tests (jkonecny) +- Fix documentation of _process_screen method (jkonecny) +- Fix pylint issues (jkonecny) +- Use pylint instead of pocketlint (jkonecny) +- Add coverage support (jkonecny) +- Make link to exmples directory in Readme (jkonecny) +- Fix homepage of the project in setup.py (jkonecny) +- Fix classifiers in setup.py (jkonecny) +- Add pypi-upload to Makefile (jkonecny) +- Use correct variant of the field (jkonecny) +- Propose Fedora update only to Fedora in development (jkonecny) +- Add upstream tag template to packit for releasing (jkonecny) +- Packit will download archive from Source0 if needed (jkonecny) + +* Thu Jun 25 2020 Jiri Konecny - 1.7-1 +- Testing farm seems like a better option (jkonecny) +- Fix upstream package name (jkonecny) +- Copy archive to the project root for packit (jkonecny) +- Use BUILD_ARGS for packit to remove wheel dependency (jkonecny) +- Correct how packit sniffing package version (jkonecny) +- Add packit action to create archive correctly (jkonecny) +- Simplify Packit configuration file (jkonecny) +- Enable copr builds and add packit config (dhodovsk) +- Add possibility to change setup.py arguments (jkonecny) +- Fix typo in setup.py (jkonecny) +- Add translation badge from Weblate (jkonecny) +- Add potfile to the .gitignore (jkonecny) +- Pause releasing when calling bumpver (jkonecny) +- Remove unused PREFIX from the Makefile (jkonecny) +- Remove Zanata from the Simpleline (jkonecny) +- Switch po-push from Zanata to Weblate (jkonecny) +- Download translations from Weblate (jkonecny) +- Remove pot file from this repository (jkonecny) +- Add new directories to .gitignore and make clean (jkonecny) +- Add Makefile PHONY targets (jkonecny) +- Simplify archive creation (jkonecny) +- Reflect rename of COPYING to LICENSE.md (jkonecny) +- Change license in spec file to LGPLv3+ (jkonecny) +- Add COPR badge for daily builds (jkonecny) +- Improve setup.py (jkonecny) +- Change license to LGPLv3 for all the files (jkonecny) +- Change License from GPLv2+ to LGPLv3+ (jkonecny) + +* Thu Aug 22 2019 Jiri Konecny - 1.6-1 +- Always close the password dialog (vponcova) +- Remove unnecessary pass statements (jkonecny) + +* Mon May 13 2019 Jiri Konecny - 1.5-1 +- Update spec file from the downstream (jkonecny) +- Fix translation issue for lt language (jkonecny) + +* Sat Feb 02 2019 Fedora Release Engineering - 1.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Mon Nov 19 2018 Jiri Konecny - 1.4-1 +- Fix and add tests for the new changes (#1646568) (jkonecny) +- Add should_run_with_empty_stack configuration (#1646568) (jkonecny) +- Remove wrong line in password_function conf (jkonecny) +- Tweak date lang settings in make bumpver command (jkonecny) +- Drop python-pocketlint build dependency (jkonecny) +- Update spec file from Fedora (jkonecny) + +* Sat Jul 14 2018 Fedora Release Engineering - 1.3-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Mon Jul 02 2018 Miro Hrončok - 1.3-4 +- Rebuilt for Python 3.7 + +* Wed Jun 20 2018 Jiri Konecny - 1.3-3 +- Drop python-pocketlint dependency + +* Mon Jun 18 2018 Miro Hrončok - 1.3-2 +- Rebuilt for Python 3.7 + +* Mon Jun 11 2018 Jiri Konecny - 1.3-1 +- Fix pylint errors raised by new pylint version (jkonecny) +- Setup logging handler properly for a library (jkonecny) + +* Tue May 29 2018 Jiri Konecny - 1.2-1 +- Document GlobalConfiguration class (jkonecny) +- Add advanced input processing section to docs (jkonecny) +- Make makefile zanata check more robust (jkonecny) +- Add missing newline characters at the end (jkonecny) +- Abstract widget buffer extensions (jkonecny) +- Use python 3 sphinx module (jkonecny) + +* Tue Apr 10 2018 Jiri Konecny - 1.1-1 +- Add global configuration initialize test (jkonecny) +- Use default password function from GlobalConfiguration (jkonecny) +- Add tests for GlobalConfiguration class (jkonecny) +- Move default width to GlobalConfiguration class (jkonecny) +- Add GlobalConfiguration object (jkonecny) +- Fix a missing article in docs. (jkonecny) +- Add tests for UIScreen get_user_input method (jkonecny) +- Only InputManager is used to get input in UIScreen (jkonecny) +- Move emit of InputReadySignal to InputRequest (jkonecny) +- Get only last input on concurrent input (jkonecny) +- Add concurrency tests for InputHandler (jkonecny) +- Add requester source to the InputHandler (#1557472) (jkonecny) +- Use InputManager as screen helper not in ScreenScheduler (#1557472) (jkonecny) +- Add test to check InputThreadManager after initialization (jkonecny) +- Reinitialize InputThreadManager when app is initialized (jkonecny) +- Input requests are now handled by InputThreadManager (jkonecny) +- Remove io_manager property from ScreenScheduler (jkonecny) +- Rename io_manager to input_manager (jkonecny) +- Change IOManager to InputManager (jkonecny) +- Move draw from IOManager to ScreenScheduler (jkonecny) +- Separate password input to PasswordInputHandler (jkonecny) +- Add DEFAULT_WIDTH constant (jkonecny) +- Add tests for InputHandler (jkonecny) +- Replace get_input_without_check by new property (jkonecny) +- Separate input to a new module (jkonecny) + +* Wed Feb 28 2018 Jiri Konecny - 1.0-1 +- Fix docs based on the new PROCESSED feature (jkonecny) +- Use new PROCESS_AND* in examples (jkonecny) +- Add tests for PROCESSED_AND_{CLOSE|REDRAW} (jkonecny) +- Use new PROCESSED_AND_{CLOSE|REDRAW} in advanced widgets (jkonecny) +- Support PROCESSED_AND_CLOSE UserInputState (jkonecny) +- Rename UserInputResult to UserInputAction (jkonecny) +- Support PROCESSED_AND_REDRAW (jkonecny) +- Fix link to the documentation in README (jkonecny) +- Add link to the documentation (jkonecny) +- Write documentation for Simpleline (jkonecny) +- Disable pylint error for doc copyright variable (jkonecny) +- Add new example used in the documentation (jkonecny) +- Mock modules for readthedocs (jkonecny) +- Do a small fixes to improve documentation (jkonecny) +- Get version from the spec file (jkonecny) +- Add documentation skeleton (jkonecny) + +* Thu Oct 19 2017 Jiri Konecny - 0.8-1 +- Test clean-up (jkonecny) +- Move and rename force_quit loop (jkonecny) +- Add dump screen stack method (jkonecny) + +* Tue Oct 17 2017 Jiri Konecny - 0.7-1 +- Fix crash when container callback is not set (jkonecny) +- Add EntryWidget to show item title and value (jkonecny) +- Add GetPasswordInputScreen for getting passwords (jkonecny) +- UIScreen can have hidden input (jkonecny) +- Move getpass func inside locks (jkonecny) +- Implement GetInputScreen (jkonecny) +- Do not print new line with empty container (jkonecny) +- Add no_separator to UIScreen (jkonecny) +- Fix HelpScreen title (jkonecny) +- Remove original classes from GLib tests (jkonecny) +- Fix test case name (jkonecny) +- Move tests to subfolder (jkonecny) +- Move base widgets as second example (jkonecny) +- Add example with basic widgets usage (jkonecny) +- Improve README.md (jkonecny) +- Improve example starting script (jkonecny) +- Add glib loop example (jkonecny) +- Add prefixes to examples to impress difficulty (jkonecny) +- Add comments to the examples (jkonecny) +- Update examples to use new features (jkonecny) + +* Fri Sep 08 2017 Jiri Konecny - 0.6-1 +- Implement the force quit all loops feature (jkonecny) +- Improved GLib event loop testing (jkonecny) +- Handle GLib event loop exceptions better (jkonecny) +- Support for GLib event loop (jkonecny) +- Wrap exceptions from handlers as ExceptionSignal (jkonecny) +- Only highest priority events are processed in one iteration (jkonecny) +- Move parts from MainLoop to AbstractEventLoop (jkonecny) +- MainLoop won't wait in busy loop anymore (jkonecny) +- Don't block loop when waiting on user input (jkonecny) +- Fix user input lock (jkonecny) + +* Mon Sep 04 2017 Jiri Konecny - 0.5-1 +- Fix exception in Screen input caused infinite loop (jkonecny) +- Add test if app is initialized (jkonecny) +- Redraw on first scheduled screen (#1487326) (jkonecny) +- Redraw after YesNoDialog modal window close (jkonecny) + +* Fri Aug 18 2017 Jiri Konecny - 0.4-1 +- Screen scheduling is moved to ScreenHandler (jkonecny) +- Remove merge commits from changelog (jkonecny) + +* Thu Aug 17 2017 Jiri Konecny - 0.3-1 +- Remove merge commits from changelog (jkonecny) +- Fix bad input processing for list containers (jkonecny) +- Rename quit callback and add args there. (jkonecny) +- Add tests for new container feature (jkonecny) +- List containers take max width if not specified (jkonecny) +- Remove leftover print in containers parsing input (jkonecny) + +* Mon Aug 14 2017 Jiri Konecny - 0.2-1 +- Merge pull request #26 from jkonecny12/master-fix-ExitMainLoop-exception (jkonecny) +- Merge pull request #28 from jkonecny12/master-fix-container-callback (jkonecny) +- Fix docs for container callbacks (jkonecny) +- Merge pull request #25 from jkonecny12/master-fix-big-screen-printing (jkonecny) +- Remove missed test helper for local testing (jkonecny) +- The ExitMainLoop exception should kill whole app (jkonecny) +- Do not run an old event queue from modal screen (jkonecny) +- Merge pull request #23 from jkonecny12/master-add-possibility-to-end-loop-politely (jkonecny) +- Merge pull request #24 from jkonecny12/master-fix-compatibility (jkonecny) +- Add possibility to end loop politely (jkonecny) +- Merge pull request #22 from jkonecny12/master-add-logging (jkonecny) +- Fix printing issues for bigger screens (jkonecny) +- Set default screen height to 30 (jkonecny) +- Keep backward compatibility for UIScreen args (jkonecny) +- Add logging to the Simpleline (jkonecny) +- Merge pull request #19 from jkonecny12/master-rework-wait-on-input (jkonecny) +- Merge pull request #21 from jkonecny12/master-fix-adv-widgets (jkonecny) +- Merge pull request #20 from jkonecny12/master-move-InputState (jkonecny) +- Wait on input thread to finish (jkonecny) +- return_after don't skip signals in recursion (jkonecny) +- Add TicketMachine helper class (jkonecny) +- Return user input in the signal handler (jkonecny) +- Merge pull request #16 from jkonecny12/master-modify-exception-handling (jkonecny) +- Merge pull request #18 from jkonecny12/master-ignore-pylint-with-lock (jkonecny) +- Reflect changes in adv_widgets (jkonecny) +- Move InputState next to UIScreen (jkonecny) +- Break App's cyclic imports (jkonecny) +- Add temporal pylint-disable for with Lock (jkonecny) +- Re-raise exception only if no handler is registered (jkonecny) +- Merge pull request #15 from jkonecny12/master-thread-safe-eventqueue (jkonecny) +- Merge pull request #11 from jkonecny12/master-add-args-to-scheduler-shortcut (jkonecny) +- Make the EventQueue thread safe (jkonecny) +- Merge pull request #13 from jkonecny12/master-enhance-WindowContainer-add (jkonecny) +- Merge pull request #12 from jkonecny12/master-fix-ready-collision (jkonecny) +- Add args param to the scheduler_handler shortcuts (jkonecny) +- Fix bad param name for scheduling methods (jkonecny) +- Merge pull request #10 from jkonecny12/master-add-hidden-user-input (jkonecny) +- Merge pull request #8 from jkonecny12/master-remove-base-file (jkonecny) +- Merge pull request #9 from jkonecny12/master-remove-quit-message (jkonecny) +- Add method add_with_separator to WindowContainer (jkonecny) +- Fix `ready` property collision with Anaconda (jkonecny) +- Add hidden parameter to UIScreen get input (jkonecny) +- Remove unused quit message (jkonecny) +- Move App from base to __init__.py (jkonecny) +- Merge pull request #6 from jkonecny12/fix-make-potfile-generation (jkonecny) +- Merge pull request #7 from jkonecny12/master-fix-make-archive (jkonecny) +- Fix make archive (jkonecny) +- Fix potfile generation (jkonecny) +- Merge pull request #5 from jkonecny12/master-add-containers (jkonecny) +- Examples now using WindowContainer (jkonecny) +- Fix error when getting input directly (jkonecny) +- Add WindowContainer and use it in UIScreen (jkonecny) +- Add SeparatorWidget (jkonecny) +- Add input processing to containers (jkonecny) +- Add containers numbering (jkonecny) +- Add containers, checkbox and center widget tests (jkonecny) +- Add row and column list containers (jkonecny) +- Merge pull request #4 from jkonecny12/master-split-renderer (jkonecny) +- Fix setup.py modules (jkonecny) +- Change INPUT_PROCESSED and INPUT_DISCARDED to Enum (jkonecny) +- Rename renderer and event_loop in App class (jkonecny) +- Add scheduler_handler and rename switch_screen (jkonecny) +- Process signals when waiting on user input (jkonecny) +- Move draw screen to the InOutManager (jkonecny) +- Change UIScreen properties (jkonecny) +- Move input processing to the InOutManager class (jkonecny) +- Move SignalHandler to the screen module (jkonecny) +- Move ui_screen to the screen module (jkonecny) +- Rename Renderer to ScreenScheduler (jkonecny) +- Merge pull request #3 from jkonecny12/master-change-close-to-signal (jkonecny) +- Change separator tests to reflect close as signal (jkonecny) +- Close screen is now signal (jkonecny) +- Rename emit_draw_signal to redraw (jkonecny) +- Merge pull request #2 from jkonecny12/master-fix-modal (jkonecny) +- Add missing doc for EventQueue and ScreeStack (jkonecny) +- Add tests for event queue (jkonecny) +- Modal screens are now executing new event loop (jkonecny) +- Separator should be printed just before show_all() (jkonecny) +- Move screen scheduling tests to new file (jkonecny) +- Merge pull request #1 from jkonecny12/master-refactorization (jkonecny) +- Implement small fixes and tweaks (jkonecny) +- Move ScreenStack to render module (jkonecny) +- Add SimplelineError as base class for Exceptions (jkonecny) +- Clean up unused code and do a small tweaks (jkonecny) +- Fix pylint errors (jkonecny) +- Modify examples to reflect new changes (jkonecny) +- Add emit_draw_signal to the SignalHandler (jkonecny) +- Do not call draw when prompt is not present (jkonecny) +- Remove old INPUT_* constants (jkonecny) +- Do not redraw when input was processed (jkonecny) +- Add license to all test classes (jkonecny) +- Add new tests for render_screen, renderer, widgets (jkonecny) +- Remove hubQ (jkonecny) +- Split input from drawing (jkonecny) +- Fix rendering errors by removing _redraw variable (jkonecny) +- Replace array with priority by Signal ordering (jkonecny) +- Add tests for SignalHandler (jkonecny) +- Use SignalHandler (jkonecny) +- Add screen rendering tests (jkonecny) +- Raise exceptions instead of silently quitting (jkonecny) +- Reflect code changes in tests (jkonecny) +- Fix missing super().__init__() in Signals (jkonecny) +- Fix modal screen by removing execute_new_loop (jkonecny) +- Fail when UIScreen is not closing itself (jkonecny) +- Add constants INPUT_PROCESSED and INPUT_DISCARDED (jkonecny) +- Fix issues in Renderer and MainLoop (jkonecny) +- Use RenderScreenSignal signal for rendering (jkonecny) +- Add App.run as a shortcut to start application (jkonecny) +- Move widgets and adv_widgets to render module (jkonecny) +- Fix cosmetic bugs in widgets (jkonecny) +- Move prompt to render module (jkonecny) +- Modify ScreenStack tests to reflect UIScreen changes (jkonecny) +- Modify UIScreen to use new App class structure (jkonecny) +- Fix renderer tests after moving the Renderer class (jkonecny) +- Move renderer to separate file renderer.py (jkonecny) +- Add quit_callback to the event loop abstract class (jkonecny) +- Add tests for the App class (jkonecny) +- Change base class to singleton like class (jkonecny) +- Add tests for event loop processing (jkonecny) +- Implementation of defualt event loop and signals (jkonecny) +- Add abstract base classes for EventLoop and Event (jkonecny) +- Remove ScheduleScreen tests (jkonecny) +- Add tests for renderer (jkonecny) +- Extract renderer from App class to render directory (jkonecny) +- Add tests for new ScreenStack and ScreenData (jkonecny) +- Extract screen stack to its own object and data class (jkonecny) +- Modify comments in the spec file (jkonecny) +- Package is named python-simpleline (jkonecny) +- Fix spec file (jkonecny) +- Fix summary in the spec file (jkonecny) +- Fix names according to tagging (jkonecny) + +* Fri May 5 2017 Jiri Konecny - 0.1-3 +- Modify comments in the spec file + +* Thu May 4 2017 Jiri Konecny - 0.1-2 +- Drop clean section +- Drop Group, it is not needed +- Use make_build macro +- Reorder check and install sections +- Rename package to python-simpleline but rpm will be python3-simpleline + +* Fri Dec 16 2016 Jiri Konecny - 0.1-1 +- Initial package diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/setup.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/setup.py new file mode 100644 index 0000000..9534796 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/setup.py @@ -0,0 +1,43 @@ +#!/usr/bin/python3 +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from setuptools import setup, find_packages + +with open("README.md", "r") as f: + long_description = f.read() + +setup(name='simpleline', + version='1.8', + author='Jiri Konecny', + author_email='jkonecny@redhat.com', + description='Python text UI framework', + long_description=long_description, + long_description_content_type="text/markdown", + keywords='ui text library glib', + url='https://github.com/rhinstaller/python-simpleline', + packages=find_packages(include=['simpleline', 'simpleline.*']), + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: Software Development :: User Interfaces", + "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", + "Programming Language :: Python :: 3", + ], + python_requires='>=3.4') diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/__init__.py new file mode 100644 index 0000000..1d4dfc7 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/__init__.py @@ -0,0 +1,136 @@ +# Base class for Simpleline Text UI framework. +# +# Library containing the Text UI framework. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +__all__ = ["App"] + + +from simpleline.logging import setup_logging +from simpleline.errors import NothingScheduledError + +setup_logging() + + +class App(): + """This is the main class for Simpleline library. + + Do not create instance of this class. Use this class as static! + The `initialize()` method must be called before use. + + It is giving you access to the scheduler and event loop. You can have only one instance of this + class in your application. + + To create this instance call `App.initialize()` method. This method can also be used to + reset settings in the App class to start with new event loop or scheduler. + """ + __app = None + + class AppPimpl(): + + def __init__(self, scheduler, event_loop, configuration): + self.event_loop = event_loop + self.scheduler = scheduler + self.configuration = configuration + + @classmethod + def initialize(cls, scheduler=None, event_loop=None, global_configuration=None): + """Create app instance inside of this class. + + This method can be called multiple times to reset App settings. + + :param scheduler: scheduler used for rendering screens; if not specified use + `simpleline.render.screen_scheduler.ScreenScheduler`. + :type scheduler: instance of `simpleline.render.screen_scheduler.ScreenScheduler`. + + :param event_loop: event loop used for asynchronous tasks; + if not specified use `simpleline.event_loop.main_loop.MainLoop`. + :type event_loop: object based on class `simpleline.event_loop.AbstractEventLoop`. + + :param global_configuration: instance of the global configuration object; if not specified + use `simpleline.global_configuration.GlobalConfiguration` + :type global_configuration: object based on class + `simpleline.global_configuration.GlobalConfiguration` + """ + from simpleline.event_loop.main_loop import MainLoop # pylint: disable=import-outside-toplevel + from simpleline.render.screen_scheduler import ScreenScheduler # pylint: disable=import-outside-toplevel + from simpleline.global_configuration import GlobalConfiguration # pylint: disable=import-outside-toplevel + + if event_loop is None: + event_loop = MainLoop() + if scheduler is None: + scheduler = ScreenScheduler(event_loop) + if global_configuration is None: + global_configuration = GlobalConfiguration() + + cls.__app = cls.AppPimpl(scheduler, event_loop, global_configuration) + + cls._post_init() + + @classmethod + def _post_init(cls): + from simpleline.input.input_threading import InputThreadManager # pylint: disable=import-outside-toplevel + # FIXME: This should be done by more general way not by calling exact class here. + # Create new instance of InputThreadManager because it needs new event loop + InputThreadManager.create_new_instance() + + @classmethod + def is_initialized(cls): + """Is the App already initialized? + + :returns: True if the `App.initialized()` method was called, False otherwise. + """ + if cls.__app is None: + return False + + return True + + @classmethod + def get_scheduler(cls): + """Get instance of class responsible for rendering of the screen.""" + return cls.__app.scheduler + + @classmethod + def get_event_loop(cls): + """Get instance of class responsible for processing asynchronous events.""" + return cls.__app.event_loop + + @classmethod + def get_configuration(cls): + """Get application defaults configuration object.""" + return cls.__app.configuration + + @classmethod + def run(cls): + """Run event loop. + + Raise an exception if no screen is scheduled. This behavior can be changed by + `should_run_with_empty_stack` global configuration option. + + This is shortcut to `App.event_loop().run()`. + :raises NothingScheduledError: when there is no screen scheduled + """ + if not cls.__app.configuration.should_run_with_empty_stack: + # Check if the screen stack is not empty + if cls.__app.scheduler.nothing_to_render: + raise NothingScheduledError("Can't run application with the empty screen stack! " + "To avoid this please see should_run_with_empty_stack " + "global configuration option.") + App.get_event_loop().run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/errors.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/errors.py new file mode 100644 index 0000000..4532c61 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/errors.py @@ -0,0 +1,31 @@ +# Base exceptions for the Simpleline application. +# +# Base class for Simpleline Text UI framework. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# This can't be moved to __init__.py because of cyclic imports error. +# + + +class SimplelineError(Exception): + """Base exception for all other exceptions.""" + + +class NothingScheduledError(SimplelineError): + """Exception when running the loop with no screens scheduled.""" diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/__init__.py new file mode 100644 index 0000000..1b68307 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/__init__.py @@ -0,0 +1,264 @@ +# Abstract base class for Simpleline Event Loop. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +# This class can be overridden to use any existing event loop of your program. +# +# Author(s): Jiri Konecny +# + +import sys + +from abc import ABCMeta, abstractmethod +from collections import namedtuple + +from simpleline.errors import SimplelineError +from simpleline.event_loop.ticket_machine import TicketMachine +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + +__all__ = ["AbstractEventLoop", "AbstractSignal", "ExitMainLoop"] + +QuitCallback = namedtuple("QuitCallback", ["callback", "args"]) + + +class ExitMainLoop(SimplelineError): + """This exception ends the whole event loop.""" + + +class AbstractEventLoop(metaclass=ABCMeta): + + def __init__(self): + super().__init__() + self._handlers = {} + self._processed_signals = TicketMachine() + self._quit_callback = None + # end most inner loop politely by setting to False + self._run_loop = True + self._force_quit = False + + def register_signal_handler(self, signal, callback, data=None): + """Register a callback which will be called when message "event" + is encountered during process_events. + + The callback has to accept two arguments: + - the received message in the form of (type, [arguments]) + - the data registered with the handler + + :param signal: Signal class we want to react on. + :type signal: Class based on the simpleline.event_loop.AbstractSignal class. + + :param callback: The callback function. + :type callback: func(event_message, data) + + :param data: Optional data to pass to callback. + :type data: Anything. + """ + if signal not in self._handlers: + self._handlers[signal] = [] + + event_handler = self._create_event_handler(callback, data) + self._handlers[signal].append(event_handler) + + @abstractmethod + def register_signal_source(self, signal_source): + """Register source of signal for actual event queue. + + :param signal_source: Source for future signals. + :type signal_source: `simpleline.render.ui_screen.UIScreen` + """ + + @abstractmethod + def enqueue_signal(self, signal): + """Enqueue new event for processing. + + :param signal: Signal which you want to add to the event queue for processing. + :type signal: Instance based on AbstractEvent class. + """ + log.debug("New signal %s enqueued with source %s", + signal, + signal.source.__class__.__name__) + + @abstractmethod + def run(self): + """Starts the event loop.""" + log.debug("Starting main loop") + self._force_quit = False + + def force_quit(self): + """Force quit all running event loops. + + Kill all loop including inner loops (modal window). + None of the Simpleline events will be processed anymore. + """ + log.debug("Force quit called. Killing all loops!") + self._force_quit = True + + @abstractmethod + def execute_new_loop(self, signal): + """Starts the new event loop and pass `signal` in it. + + This is required for processing a modal screens. + + :param signal: Signal passed to the new event loop. + :type signal: The `AbstractSignal` based class. + """ + log.debug("Executing inner loop") + + @abstractmethod + def close_loop(self): + """Close active event loop. + + Close an event loop created by the `execute_new_loop()` method. + """ + log.debug("Closing inner loop") + + @abstractmethod + def process_signals(self, return_after=None): + """This method processes incoming async messages. + + Process signals enqueued by the `self.enqueue_signal()` method. Call handlers + registered to the signals by the `self.register_signal_handler()` method. + + When `return_after` is specified then wait to the point when this signal is processed. + NO warranty that this method will return immediately after the signal was processed! + + Without `return_after` parameter this method will return after all queued signals + with the highest priority will be processed. + + The method is NOT thread safe! + + :param return_after: Wait on this signal to be processed. + :type return_after: Class of the signal. + """ + + def set_quit_callback(self, callback, args=None): + """Call this callback when event loop quits. + + :param callback: Call this callback when event loops ends (application quit). + :type callback: Function with one parameter data `func(data)`. + + :param args: Arguments passed to the quit callback. + :type args: Anything. + """ + self._quit_callback = QuitCallback(callback, args) + + def kill_app_with_traceback(self, exception_signal, data=None): + """Print exception and screen stack and kill the application. + + :param exception_signal: ExceptionSignal encapsulating the original exception which + will be passed to the sys.excepthook method. + :type exception_signal: Instance of `simpleline.event_loop.signals.ExceptionSignal` class. + + :param data: To be usable as signal handler. + :type data: Anything will be ignored. + """ + log.debug("Unhandled error in handler raised:") + sys.excepthook(*exception_signal.exception_info) + + from simpleline import App # pylint: disable=import-outside-toplevel + stack_dump = App.get_scheduler().dump_stack() + print("") + print(stack_dump) + log.error(stack_dump) + + log.debug("Killing application!") + sys.exit(1) + + @staticmethod + def _create_event_handler(callback, data): + """Create event handler data object and return it.""" + return EventHandler(callback=callback, data=data) + + def _register_wait_on_signal(self, wait_on_signal): + """Register process waiting on signal `wait_on_signal` and return id for later checking. + + ID is returned which is then used in the `self._check_if_signal_processed()` method. + + :param wait_on_signal: Signal we are waiting for. + :type wait_on_signal: Class based on `simpleline.event_loop.AbstractSignal`. + """ + return self._processed_signals.take_ticket(wait_on_signal.__name__) + + def _mark_signal_processed(self, signal): + """Mark that processes waiting on this signal that they are able to go. + + :param signal: Signal which was processed. + :type signal: Class based on `simpleline.event_loop.AbstractSignal`. + """ + self._processed_signals.mark_line_to_go(signal.__class__.__name__) + + def _check_if_signal_processed(self, wait_on_signal, unique_id): + """Check if the signal was processed. + + :param wait_on_signal: Signal the process is waiting for. + :type wait_on_signal: Class based on `simpleline.event_loop.AbstractSignal`. + + :param unique_id: Unique id returned by the `self._register_wait_on_signal()` method. + :type unique_id: int + """ + return self._processed_signals.check_ticket(wait_on_signal.__name__, unique_id) + + +class EventHandler(): + """Data class to save event handlers.""" + + def __init__(self, callback, data): + self.callback = callback + self.data = data + + +class AbstractSignal(metaclass=ABCMeta): + """This class is base class for signals. + + .. NOTE: + Ordering and equality is based on priority. + """ + + def __init__(self, source, priority=0): + self._source = source + self._priority = priority + + def __lt__(self, other): + """Order Signal classes by priority.""" + return self._priority < other.priority + + def __eq__(self, other): + """Order Signal classes by priority.""" + return self._priority == other.priority + + def __str__(self): + """For easier logging.""" + return self.__class__.__name__ + + @property + def priority(self): + """Priority of this event. + + Values less than 0 denote higher priorities. Values greater than 0 denote lower priorities. + Events from high priority sources are always processed before events from lower priority + sources. + """ + return self._priority + + @property + def source(self): + """Source which emitted this event.""" + return self._source diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/event_queue.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/event_queue.py new file mode 100644 index 0000000..c0351d3 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/event_queue.py @@ -0,0 +1,153 @@ +# Default event queue for Simpleline application. +# +# This class is thread safe. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +from queue import PriorityQueue +from threading import Lock + +from simpleline.errors import SimplelineError + + +class EventQueueError(SimplelineError): + """Main exception for `EventQueue` class. + + Inherits from `simpleline.SimplelineError`. + """ + + +class EventQueue(): + """Class for managing signal queue. + + Responsibilities of this class are: + * sorting by priority of signals + * managing sources for this event queue + * enqueuing signals + """ + + def __init__(self): + self._queue = PriorityQueue() + self._contained_screens = set() + self._lock = Lock() + + def empty(self): + """Return true if Queue is empty. + + :return: True if empty, False otherwise. + """ + return self._queue.empty() + + def enqueue(self, signal): + """Enqueue signal to this queue. + + :param signal: Signal which should be enqueued to this queue. + :type signal: Signal class based on `simpleline.event_loop.signals.AbstractSignal`. + """ + self._queue.put(signal) + + def enqueue_if_source_belongs(self, signal, source): + """Enqueue signal to this queue if the signal source belongs to this queue. + + Enqueue the `signal` only if the `source` belongs to this queue. + See the `add_source()` method. + + :param signal: Signal which should be enqueued to this queue. + :type signal: Signal class based on `simpleline.event_loop.signals.AbstractSignal`. + :param source: Source of this signal. + :type source: Anything. + :return: True if the source belongs to this queue and signal was queued, False otherwise. + :rtype: bool + """ + if self.contains_source(source): + self._queue.put(signal) + return True + + return False + + def get(self): + """Return enqueued signal with the highest priority. + + This is FIFO implementation for the same priority. + If the queue is empty this method will wait for the input signal. + + :return: Queued signal. + :rtype: Signal based on class `simpleline.event_loop.signals.AbstractSignal`. + """ + return self._queue.get() + + def get_top_event_if_priority(self, priority): + """Return top enqueued signal if priority is equal to `priority`. Otherwise `None`. + + :param priority: Requested event priority. + :type priority: int + + :return: Queued signal if it has requested priority. Otherwise `None`. + :rtype: Signal based on class `simpleline.event_loop.signals.AbstractSignal` or `None`. + """ + event = self._queue.get() + if event.priority == priority: + return event + + self._queue.put(event) + return None + + def add_source(self, signal_source): + """Add new source of signals to this queue. + + This method is mandatory for `enqueue_if_source_belongs()` method. + The same source will be added only once. + + :param signal_source: Source of future signals. + :type signal_source: Anything which will emit signals in future. + """ + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._contained_screens.add(signal_source) + + def remove_source(self, signal_source): + """Remove signal source from this queue. + + :param signal_source: Source of future signals. + :type signal_source: Anything. + :raise: EventQueueError""" + try: + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._contained_screens.remove(signal_source) + except KeyError as e: + raise EventQueueError("Can't remove non-existing event source!") from e + + def contains_source(self, signal_source): + """Test if `signal_source` belongs to this queue. + + :param signal_source: Source of signals. + :type signal_source: Anything. + :return: True if signal source belongs to this queue. + :rtype: bool + """ + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + return signal_source in self._contained_screens diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/glib_event_loop.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/glib_event_loop.py new file mode 100644 index 0000000..25847e5 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/glib_event_loop.py @@ -0,0 +1,230 @@ +# Glib event queue used by Simpleline application. +# +# This class is thread safe. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# +from collections import namedtuple + +import gi + +from simpleline.event_loop import AbstractEventLoop, ExitMainLoop +from simpleline.event_loop.signals import ExceptionSignal +from simpleline.logging import get_simpleline_logger + +gi.require_version("GLib", "2.0") + +from gi.repository import GLib # pylint: disable=wrong-import-order, wrong-import-position + +log = get_simpleline_logger() + +CallbackArgs = namedtuple("CallbackArgs", ["signal", "source", "handlers"]) + + +__all__ = ["GLibEventLoop"] + + +class GLibEventLoop(AbstractEventLoop): + + def __init__(self): + super().__init__() + # Create first loop + loop = GLib.MainLoop() + self._event_loops = [EventLoopData(loop)] + log.debug("GLib event loop is used!") + + @property + def active_main_loop(self): + """Return GLib mainloop object.""" + return self._event_loops[-1].loop + + def register_signal_source(self, signal_source): + """Register source of signal for actual event queue. + + :param signal_source: Source for future signals. + :type signal_source: `simpleline.render.ui_screen.UIScreen` + """ + super().register_signal_source(signal_source) + loop_data = self._event_loops[-1] + loop_data.sources.add(signal_source) + + def enqueue_signal(self, signal): + """Enqueue new event for processing. + + :param signal: signal which you want to add to the event queue for processing + :type signal: instance based on AbstractEvent class + """ + if self._force_quit: + return + + super().enqueue_signal(signal) + + loop_data = self._find_loop_data_for_source(signal.source) + self._register_handlers_to_loop(loop_data.loop, signal) + + def _find_loop_data_for_source(self, source): + """Find event loop belonging to this signal source.""" + for loop_data in reversed(self._event_loops): + if source in loop_data.sources: + return loop_data + + return self._event_loops[-1] + + def _register_handlers_to_loop(self, event_loop, signal): + """Register handlers to the event loop.""" + context = event_loop.get_context() + handlers = [] + + if type(signal) in self._handlers: # pylint: disable=unidiomatic-typecheck + handlers = self._handlers[type(signal)] + elif isinstance(signal, ExceptionSignal): + handler_data = self._create_event_handler(self.kill_app_with_traceback, None) + handlers = [handler_data] + + # GLib event source which contains handler callback + # Every source can hold only one callback + source = GLib.idle_source_new() + source.set_priority(signal.priority) + data = CallbackArgs(signal, source, handlers) + + source.set_callback(self._run_handlers, data) + # attach source to the event loop + source.attach(context) + + def _run_handlers(self, data): + """Run handlers attached to this signal and clean source afterwards.""" + signal = data.signal + source = data.source + handlers = data.handlers + + if not self._force_quit: + try: + for handler in handlers: + handler.callback(signal, handler.data) + except ExitMainLoop: + self._quit_all_loops() + except Exception: # pylint: disable=broad-except + self.enqueue_signal(ExceptionSignal(self)) + + # based on GLib documentation we should clean source + # source will be removed from event loop context this way + source.destroy() + + self._mark_signal_processed(signal) + + def _quit_all_loops(self): + for loop_data in reversed(self._event_loops): + loop_data.loop.quit() + + def run(self): + """Starts the event loop.""" + super().run() + if len(self._event_loops) != 1: + raise ValueError("Can't run event loop multiple times.") + + self._event_loops[0].loop.run() + log.debug("Main loop ended. Running callback if set.") + + if self._quit_callback: + cb = self._quit_callback.callback + cb(self._quit_callback.args) + + def force_quit(self): + """Force quit all running event loops. + + Kill all loop including inner loops (modal window). + None of the Simpleline events will be processed anymore. + """ + super().force_quit() + self._quit_all_loops() + + def execute_new_loop(self, signal): + """Starts the new event loop and pass `signal` in it. + + This is required for processing a modal screens. + + :param signal: signal passed to the new event loop + :type signal: `AbstractSignal` based class + """ + super().execute_new_loop(signal) + + if self._force_quit: + return + + new_context = GLib.MainContext() + new_loop = GLib.MainLoop(new_context) + loop_data = EventLoopData(new_loop) + self._event_loops.append(loop_data) + + self.enqueue_signal(signal) + new_loop.run() + + def close_loop(self): + """Close active event loop. + + Close an event loop created by the `execute_new_loop()` method. + """ + super().close_loop() + old_loop_data = self._event_loops.pop() + old_loop_data.loop.quit() + + def process_signals(self, return_after=None): + """This method processes incoming async messages. + + Process signals en-queued by the `self.enqueue_signal()` method. Call handlers registered + to the signals by the `self.register_signal_handler()` method. + + When `return_after` is specified then wait to the point when this signal is processed. + NO warranty that this method will return immediately after the signal was processed! + + Without `return_after` parameter this method will return after all queued signals with + the highest priority will be processed. + + The method is NOT thread safe! + + :param return_after: Wait on this signal to be processed. + :type return_after: Class of the signal. + """ + super().process_signals(return_after) + loop_data = self._event_loops[-1] + + if return_after is not None: + ticket_id = self._register_wait_on_signal(return_after) + + while not self._check_if_signal_processed(return_after, ticket_id) and \ + not self._force_quit: + self._iterate_event_loop(loop_data.loop) + else: + self._iterate_event_loop(loop_data.loop) + + @staticmethod + def _iterate_event_loop(event_loop): + context = event_loop.get_context() + # This is useful for tests + wait_on_timeout = False + context.iteration(wait_on_timeout) + + +class EventLoopData(): + + def __init__(self, loop): + super().__init__() + self.loop = loop + self.sources = set() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/main_loop.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/main_loop.py new file mode 100644 index 0000000..bf64a15 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/main_loop.py @@ -0,0 +1,247 @@ +# Default event loop for Simpleline application. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from threading import Lock + +from simpleline.event_loop import AbstractEventLoop, ExitMainLoop +from simpleline.event_loop.event_queue import EventQueue +from simpleline.event_loop.signals import ExceptionSignal +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + +__all__ = ["MainLoop"] + + +class MainLoop(AbstractEventLoop): + """Default main event loop for the Simpleline. + + This event loop can be replaced by your event loop by implementing + `simpleline.event_loop.AbstractEventLoop` class. + """ + + def __init__(self): + super().__init__() + self._active_queue = EventQueue() + self._event_queues = [self._active_queue] + self._lock = Lock() + + def register_signal_source(self, signal_source): + """Register source of signal for actual event queue. + + :param signal_source: Source for future signals. + :type signal_source: `simpleline.render.ui_screen.UIScreen`. + """ + super().register_signal_source(signal_source) + self._active_queue.add_source(signal_source) + + def run(self): + """This methods starts the application. + + Do not use self.mainloop() directly as run() handles all the required exceptions + needed to keep nested mainloop working. + """ + super().run() + self._run_loop = True + + try: + self._mainloop() + except ExitMainLoop: + pass + + log.debug("Main loop ended. Running callback if set.") + + if self._quit_callback: + cb = self._quit_callback.callback + cb(self._quit_callback.args) + + def force_quit(self): + """Force quit all running event loops. + + Kill all loop including inner loops (modal window). + None of the Simpleline events will be processed anymore. + """ + super().force_quit() + self._event_queues.clear() + self._run_loop = False + + def execute_new_loop(self, signal): + """Starts the new event loop and pass `signal` in it. + + This is required for processing a modal screens. + + :param signal: Signal passed to the new event loop. + :type signal: The `AbstractSignal` based class. + """ + super().execute_new_loop(signal) + + if self._force_quit: + return + + self._active_queue = EventQueue() + + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._event_queues.append(self._active_queue) + + self.enqueue_signal(signal) + self._mainloop() + log.debug("Inner loop is closed") + + def close_loop(self): + """Close active event loop. + + Close an event loop created by the `execute_new_loop()` method. + """ + super().close_loop() + self.process_signals() + + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + self._event_queues.pop() + try: + self._active_queue = self._event_queues[-1] + except IndexError: + log.error("No more event queues to work with!") + raise ExitMainLoop() # pylint: disable=raise-missing-from + + self._run_loop = False + + def enqueue_signal(self, signal): + """Enqueue new event for processing. + + Enqueue signal to the most inner queue (nearest to the active queue) where + the `signal.source` belongs. + If it belongs nowhere enqueue it to the active one. + + This method is thread safe. + + :param signal: Event which you want to add to the event queue for processing. + :type signal: Instance based on AbstractEvent class. + """ + if self._force_quit: + return + + super().enqueue_signal(signal) + # TODO: Remove when python3-astroid 1.5.3 will be in Fedora + # pylint: disable=not-context-manager + with self._lock: + for queue in reversed(self._event_queues): + if queue.enqueue_if_source_belongs(signal, signal.source): + return + + self._active_queue.enqueue(signal) + + def _mainloop(self): + """Single mainloop. Do not use directly, start the application using run().""" + # run infinite loop + # this will always wait on input processing or similar so it should not busy waiting + while self._run_loop: + self._process_signals_loop() + + if not self._force_quit: + # set back to True to leave outer loop working + self._run_loop = True + + def process_signals(self, return_after=None): + """This method processes incoming async messages. + + Process signals en-queued by the `self.enqueue_signal()` method. Call handlers + registered to the signals by the `self.register_signal_handler()` method. + + When `return_after` is specified then wait to the point when this signal is processed. + NO warranty that this method will return immediately after the signal was processed! + + Without `return_after` parameter this method will return after all queued signals + with the highest priority will be processed. + + The method is NOT thread safe! + + :param return_after: Wait on this signal to be processed. + :type return_after: Class of the signal. + """ + super().process_signals(return_after) + if return_after is not None: + self._process_signals_with_return(return_after) + else: + self._process_signals_iteration() + + def _process_signals_with_return(self, return_after): + """Process signals until the return_after signal was processed. + + Or the loop quited. + """ + # get unique ID when waiting for the signal + unique_id = self._register_wait_on_signal(return_after) + + while self._run_loop: + signal = self._active_queue.get() + + # do the signal processing (call handlers) + self._process_signal(signal) + + # was our signal processed if yes, return this method + if self._check_if_signal_processed(return_after, unique_id): + return + + def _process_signals_iteration(self): + """Process queued signal and then return.""" + priority = None + + while not self._active_queue.empty() and self._run_loop: + if priority is None: + # take first signal to find out the highest priority in queue + signal = self._active_queue.get() + priority = signal.priority + else: + # get signal with this priority only + signal = self._active_queue.get_top_event_if_priority(priority) + + # Signal with this priority is not available anymore + if signal is None: + return + + self._process_signal(signal) + + def _process_signals_loop(self): + """Process signal until the event loop quited.""" + while self._run_loop: + signal = self._active_queue.get() + self._process_signal(signal) + + def _process_signal(self, signal): + log.debug("Processing signal %s", signal) + + self._mark_signal_processed(signal) + + if type(signal) in self._handlers: # pylint: disable=unidiomatic-typecheck + for handler_data in self._handlers[type(signal)]: + try: + handler_data.callback(signal, handler_data.data) + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + self.enqueue_signal(ExceptionSignal(self)) + elif isinstance(signal, ExceptionSignal): + self.kill_app_with_traceback(signal) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/signals.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/signals.py new file mode 100644 index 0000000..dd4a5e3 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/signals.py @@ -0,0 +1,110 @@ +# Set of default signals used inside of widgets. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from sys import exc_info +from simpleline.event_loop import AbstractSignal + +__all__ = ["ExceptionSignal", "InputReadySignal", "RenderScreenSignal", "CloseScreenSignal", + "InputReceivedSignal"] + + +class ExceptionSignal(AbstractSignal): + """Emit this signal when exception is raised. + + This class must be created inside of exception handler or `exception_info` must be specified + in creation process. + + If you register handler for this exception then the Simpleline's exception handling + is disabled! + """ + + def __init__(self, source, exception_info=None): + """Create exception signal with higher priority (-20) than other signals. + + :param source: source of this signal + :type source: class which emits this signal + + :param exception_info: if specified raise your exception, otherwise create exception here; + to create exception here it needs to be created inside of exception + handler + :type exception_info: output of `sys.exc_info()` method + """ + super().__init__(source, priority=-20) + if exception_info: + self.exception_info = exception_info + else: + self.exception_info = exc_info() + + +class InputReadySignal(AbstractSignal): + """Input from user is ready for processing.""" + def __init__(self, source, input_handler_source, data, priority=0, success=True): + """Store user input inside of this signal + + Read the data from user input in `data` attribute. + + The only way how a user should ask for input is to use InputHandler and inherited classes. + The input_handler_source param must be set but this signal instance can be attached to + another source object which is registered to a specific event loop. + + If no requester (object who uses InputHandler) is specified then source and + input_handler_source will both point to InputHandler instance. + + :param source: Source of this signal. + :type source: Any object. + + :param input_handler_source: InputHandler who is asking for input. + :type input_handler_source: The `simpleline.input.input_handler.InputHandler` based + instance. + + :param data: User input data. + :type data: str + + :param priority: Priority of this event. + :type priority: Int greater than 0. + + :param success: Was the input successful? True on successful input False otherwise. + :type success: bool + """ + super().__init__(source, priority=priority) + self.input_handler_source = input_handler_source + self.data = data + self.success = success + + +class InputReceivedSignal(AbstractSignal): + """Raw input received. + + This signal will be further processed and InputReadySignal should be enqueued soon. + Most probably you are looking for InputReadySignal instead. + """ + def __init__(self, source, data, priority=0): + super().__init__(source, priority=priority) + self.data = data + + +class RenderScreenSignal(AbstractSignal): + """Render UIScreen to terminal.""" + + +class CloseScreenSignal(AbstractSignal): + """Close current screen.""" diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/ticket_machine.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/ticket_machine.py new file mode 100644 index 0000000..6234720 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/event_loop/ticket_machine.py @@ -0,0 +1,81 @@ +# Ticket machine synchronization class. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +class TicketMachine(): + """Hold signals processed by the event loop if someone wait on them. + + This is useful when recursive process events will skip required signal. + """ + + def __init__(self): + self._lines = {} + self._counter = 0 + + def take_ticket(self, line_id): + """Take ticket (id) and go line (processing events). + + Use `check_ticket` if you are ready to go. + + :param line_id: Line where you are waiting. + :type line_id: Anything. + """ + obj_id = self._counter + if line_id not in self._lines: + self._lines[line_id] = {obj_id: False} + else: + self._lines[line_id][obj_id] = False + + self._counter += 1 + return obj_id + + def check_ticket(self, line, unique_id): + """Check if you are ready to go. + + If True the unique_id is not valid anymore. + + :param unique_id: Your id used to identify you in the line. + :type unique_id: int + + :param line: Line where you are waiting. + :type line: Anything. + + :return: True if the ticket was already marked, False otherwise + :rtype: bool + """ + if self._lines[line][unique_id]: + return self._lines[line].pop(unique_id) + + return False + + def mark_line_to_go(self, line): + """All in the `line` are ready to go. + + Mark all tickets in the line as True. + + :param line: Line which should processed. + :type line: Anything. + """ + if line in self._lines: + our_line = self._lines[line] + for key in our_line: + our_line[key] = True diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/global_configuration.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/global_configuration.py new file mode 100644 index 0000000..1fa91a7 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/global_configuration.py @@ -0,0 +1,112 @@ +# Global configuration for the whole application. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from getpass import getpass + +__all__ = ["GlobalConfiguration"] + +DEFAULT_WIDTH = 80 +DEFAULT_PASSWORD_FUNC = getpass + + +class GlobalConfiguration(): + """Class for global configuration of application defaults. + + All stored data are persistent between App.initialize() calls and can be used before this call. + """ + + def __init__(self): + self._width = DEFAULT_WIDTH + self._getpass = DEFAULT_PASSWORD_FUNC + self._run_with_empty_stack = False + + @property + def width(self): + """Get width of the application. + + :returns: int + """ + return self._width + + @width.setter + def width(self, width): + """Set width of the application. + + :param width: Number of characters which can be printed to one line. + :type width: int + """ + self._width = width + + def clear_width(self): + """Clear user defined width and set the default. + + Default: 80 characters + """ + self._width = DEFAULT_WIDTH + + @property + def password_function(self): + """Get function to get user passwords from a console. + + :returns: Function with one argument which is text representation of prompt. + """ + return self._getpass + + @password_function.setter + def password_function(self, password_func): + """Set function to get user passwords from a console. + + :param password_func: Function to get password from a command line. + :type password_func: Function with one argument which is text representation of prompt. + """ + self._getpass = password_func + + def clear_password_function(self): + """Clear user defined password function and set the default. + + Default: getpass.getpass function + """ + self._getpass = getpass + + @property + def should_run_with_empty_stack(self): + """Should test on empty screen stack when starting event loop. + + :returns: If False the App.run() call will end with an exception (default), True otherwise. + """ + return self._run_with_empty_stack + + @should_run_with_empty_stack.setter + def should_run_with_empty_stack(self, value): + """Set if the App.run() call should end with an exception when screen stack is empty. + + This can be valuable when you want to schedule a screen later by an other thread. + + :param value: If False the App.run() call will end with an exception, if True it will + run with nothing displayed. + """ + self._run_with_empty_stack = value + + def clear_should_run_with_empty_stack(self): + """Clear user defined test to run with an empty screen stack. + + Default: False + """ + self._run_with_empty_stack = False diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/__init__.py new file mode 100644 index 0000000..e632883 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/__init__.py @@ -0,0 +1,22 @@ +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from simpleline.input.input_handler import InputHandler, PasswordInputHandler + +__all__ = ["InputHandler", "PasswordInputHandler"] diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_handler.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_handler.py new file mode 100644 index 0000000..2528a01 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_handler.py @@ -0,0 +1,292 @@ +# Handle user input +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import sys + +from simpleline import App +from simpleline.event_loop.signals import InputReadySignal +from simpleline.render.widgets import TextWidget +from simpleline.input.input_threading import InputThreadManager, InputRequest + +__all__ = ["InputHandler", "PasswordInputHandler"] + + +class InputHandler(): + + def __init__(self, callback=None, source=None): + """Class to handle input from the terminal. + + This class is designed to be instantiated on place where it should be used. + The main method is `get_input()` which is non-blocking asynchronous call. It can be used + as synchronous call be calling the `wait_on_input` method. + + To get result from this class use the `value` property. + + :param callback: You can specify callback which will be called when user give input. + :type callback: Callback function with one argument which will be user input. + + :param source: Source of this input. It will be helpful in case of debugging an issue. + :type source: Class which will process an input from this InputHandler. + """ + super().__init__() + self._input = None + self._input_callback = callback + self._input_received = False + self._input_successful = False + self._skip_concurrency_check = False + self._source = source + + App.get_event_loop().register_signal_handler(InputReadySignal, + self._input_received_handler) + + def _input_received_handler(self, signal, args): + if signal.input_handler_source != self: + return + + self._input_received = True + self._input_successful = signal.success + + if not self._input_successful: + return + + self._input = signal.data + + # call async callback + if self._input_callback is not None: + cb = self._input_callback + self._input_callback = None + + cb(self._input) + + @property + def value(self): + """Return user input. + + :returns: String or None if no is input received. + """ + return self._input + + @property + def source(self): + """Get source of this input. + + :returns: Anything probably UIScreen. + """ + return self._source + + @property + def skip_concurrency_check(self): + """Is this InputHandler skipping concurrency check? + + :returns bool + """ + return self._skip_concurrency_check + + @skip_concurrency_check.setter + def skip_concurrency_check(self, value): + """Set if this InputHandler should skip concurrency check. + + Note if you skip this check, you can have unexpected behavior. Use with caution. + + :param value: True to skip the check, False if not. + """ + self._skip_concurrency_check = value + + def set_callback(self, callback): + """Set a callback to get user input asynchronously. + + :param callback: Callback called when user write their input. + :type callback: Method with 1 argument which is user input: def cb(user_input) + """ + self._input_callback = callback + + def input_received(self): + """Was user input already received? + + :returns: True if yes, False otherwise. + """ + return self._input_received + + def wait_on_input(self): + """Blocks execution till the user input is received. + + Events will works as expected during this blocking. + + Please check the `input_successful` method to test the input. + """ + # we already received input from user + if self._input_received: + return + + while not self._input_received: + App.get_event_loop().process_signals(InputReadySignal) + + def input_successful(self): + """Was input successful? + + :returns: bool + """ + return self._input_successful + + def get_input(self, prompt): + """Use prompt to ask for user input and wait (non-blocking) on user input. + + This is an asynchronous call. If you want to wait for user input then use + the `wait_on_input` method. If you want to get results asynchronously then register + callback in constructor or by the `set_callback` method. + + Check if user input was already received can be done by the `input_received` method call. + + :param prompt: Ask user what you want to get. + :type prompt: String or Prompt instance. + + :returns: User input. + :rtype: str + """ + self._clear_input() + self._invoke_input_thread(prompt) + + def _invoke_input_thread(self, prompt): + thread_object = self.create_thread_object(prompt) + InputThreadManager.get_instance().start_input_thread(thread_object, + not self._skip_concurrency_check) + + def create_thread_object(self, prompt): + """Create thread object containing all the information how to get user input. + + :returns: Instance of class inherited from `simpleline.input.InputThread`. + """ + return InputHandlerRequest(App.get_configuration().width, prompt, self) + + def _clear_input(self): + self._input_received = False + self._input = None + + +class InputHandlerRequest(InputRequest): + """This is thread object to get input from user without blocking main thread.""" + + def __init__(self, width, prompt, input_handler): + """Create request object to get input in InputThreadManager. + + :param width: Width of the screen prompt. + :type width: int + + :param prompt: Input prompt. + :type prompt: Instance of `simpleline.render.prompt.Prompt` class. + + :param input_handler: InputHandler instance which created this object. + :type input_handler: InputHandler based instance. + """ + super().__init__(input_handler, input_handler.source) + self._width = width + self._prompt = prompt + + def get_input(self): + """This method is responsible for interruptable user input. + + It is expected to be used in a thread started on demand + and returns the input via the communication Queue. + """ + # lock acquired, we can run input + try: + data = self._ask_input() + except EOFError: + data = "" + + return data + + def text_prompt(self): + widget = TextWidget(str(self._prompt)) + widget.render(self._width) + lines = widget.get_lines() + return "\n".join(lines) + " " + + def _ask_input(self): + text_prompt = self.text_prompt() + sys.stdout.write(text_prompt) + sys.stdout.flush() + + return self._get_input() + + @staticmethod + def _get_input(): + return input() + + +class PasswordInputHandler(InputHandler): + + def __init__(self, callback=None, source=None): + """Class to handle hidden password input from the terminal. + + This class is designed to be instantiated on place where it should be used. + The main method is `get_input()` which is non-blocking asynchronous call. It can be used + as synchronous call be calling the `wait_on_input` method. + + To get result from this class use the `value` property. + + :param callback: You can specify callback which will be called when user give input. + :type callback: Callback function with one argument which will be user input. + + :param source: Source of this input. It will be helpful in case of debugging an issue. + :type source: Class which will process an input from this InputHandler. + """ + super().__init__(callback=callback, source=source) + self._getpass_func = App.get_configuration().password_function + + def set_pass_func(self, getpass_func): + """Set a function for getting passwords.""" + if not getpass_func: + return + + self._getpass_func = getpass_func + + def create_thread_object(self, prompt): + """Return PasswordInputThread for getting user password.""" + return PasswordInputHandlerRequest(App.get_configuration().width, prompt, self, + self._getpass_func) + + +class PasswordInputHandlerRequest(InputHandlerRequest): + """Similar as InputHandlerRequest but don't echo user keys.""" + + def __init__(self, width, prompt, input_handler, getpass_func): + """Create request object to get password input in InputThreadManager. + + :param width: Width of the screen prompt. + :type width: int + + :param prompt: Input prompt. + :type prompt: Instance of `simpleline.render.prompt.Prompt` class. + + :param input_handler: InputHandler instance which created this object. + :type input_handler: InputHandler based instance. + + :param getpass_func: Function to get user password. + :type getpass_func: Function which gets prompt as only parameter and returns user input + string. + """ + super().__init__(width, prompt, input_handler) + self._getpass_func = getpass_func + + def _ask_input(self): + text_prompt = self.text_prompt() + + return self._getpass_func(text_prompt) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_threading.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_threading.py new file mode 100644 index 0000000..b8926c8 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/input/input_threading.py @@ -0,0 +1,238 @@ +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import threading +from abc import ABCMeta, abstractmethod + +from simpleline import App +from simpleline.logging import get_simpleline_logger +from simpleline.event_loop.signals import InputReceivedSignal, InputReadySignal + +log = get_simpleline_logger() + + +INPUT_THREAD_NAME = "SimplelineInputThread" + + +class InputThreadManager(): + """Manager object for input threads. + + This manager helps with concurrent user input (still you really shouldn't do that). + """ + + __instance = None + + def __init__(self): + super().__init__() + self._input_stack = [] + self._processing_input = False + + @classmethod + def create_new_instance(cls): + instance = InputThreadManager() + cls.__instance = instance + + instance._post_init_configuration() # pylint: disable=protected-access + + def _post_init_configuration(self): + # pylint: disable=protected-access + App.get_event_loop().register_signal_handler(InputReceivedSignal, + self.__instance._input_received_handler) + + @classmethod + def get_instance(cls): + if not cls.__instance: + cls.create_new_instance() + + return cls.__instance + + def _input_received_handler(self, signal, args): + thread_object = self._input_stack.pop() + thread_object.emit_input_ready_signal(signal.data) + + if thread_object.thread: + thread_object.thread.join() + + # wait until used object ends + for t in self._input_stack: + t.emit_failed_input_ready_signal() + if t.thread: + t.thread.join() + + # remove all other items waiting for input + self._input_stack.clear() + self._processing_input = False + + def start_input_thread(self, input_thread_object, concurrent_check=True): + """Start input thread to get user input. + + :param input_thread_object: Input thread object based on InputThread class. + :param concurrent_check: Should the concurrent thread check be fatal? (default True). + """ + self._input_stack.append(input_thread_object) + self._check_input_thread_running(concurrent_check) + self._start_user_input_async() + + def _check_input_thread_running(self, raise_concurrent_check): + if len(self._input_stack) != 1: + if not raise_concurrent_check: + log.warning("Asking for multiple inputs with concurrent check bypassed, " + "last who asked wins! Others are dropped.") + else: + msg = "" + for t in self._input_stack: + requester_source = t.requester_source or "Unknown" + msg += "Input handler: {} Input requester: {}\n".format(t.source, + requester_source) + + msg.rstrip() + + raise KeyError("Can't run multiple input threads at the same time!\n" + "Asking for input:\n" + "{}".format(msg)) + + def _start_user_input_async(self): + thread_object = self._input_stack[-1] + + if self._processing_input: + self._print_new_prompt(thread_object) + return + + thread_object.initialize_thread() + self._processing_input = True + thread_object.start_thread() + + @staticmethod + def _print_new_prompt(thread_object): + prompt = thread_object.text_prompt() + + # print new prompt + print(prompt, end="") + + +class InputRequest(metaclass=ABCMeta): + """Base input request class. + + This should be overloaded for every InputHandler class. Purpose of this class is to print + prompt and get input from user. + + The `run_input` method is the entry point for this class. Output from this method must be + a user input. + The `text_prompt` method is used to get textual representation of a prompt. This will be used + on concurrent input to replace existing prompt to get new input. + + WARNING: + The `run_input` method will run in a separate thread! + """ + + def __init__(self, source, requester_source=None): + super().__init__() + self._source = source + self._requester_source = requester_source + self.thread = None + + @property + def source(self): + """Get direct source of this input request. + + :returns: InputHandler instance. + """ + return self._source + + @property + def requester_source(self): + """Get requester -- source of this input. + + :returns: Anything probably UIScreen based instance. + """ + return self._requester_source + + def emit_input_ready_signal(self, input_data): + """Emit the InputReadySignal signal with collected input data. + + :param input_data: Input data received. + :type input_data: str + """ + handler_source = self.source + signal_source = self._get_request_source() + + new_signal = InputReadySignal(source=signal_source, input_handler_source=handler_source, + data=input_data, success=True) + App.get_event_loop().enqueue_signal(new_signal) + + def emit_failed_input_ready_signal(self): + """Emit the InputReadySignal with failed state.""" + handler_source = self.source + signal_source = self._get_request_source() + + new_signal = InputReadySignal(source=signal_source, input_handler_source=handler_source, + data="", success=False) + App.get_event_loop().enqueue_signal(new_signal) + + def _get_request_source(self): + """Get user input request source. + + That means object who is using InputHandler. + If this object is not specified then return InputHandler as a source. + """ + return self.requester_source or self.source + + def initialize_thread(self): + """Initialize thread for this input request. + + Do not call this directly! Will be called by InputThreadManager. + """ + self.thread = threading.Thread(name=INPUT_THREAD_NAME, target=self.run) + self.thread.daemon = True + + def start_thread(self): + """Start input thread. + + Do not call this directly! Will be called by InputThreadManager. + """ + self.thread.start() + + def run(self): + """Run the `run_input` method and propagate input outside. + + Do not call this method directly. It will be called by InputThreadManager. + """ + data = self.get_input() + + App.get_event_loop().enqueue_signal(InputReceivedSignal(self, data)) + + @abstractmethod + def text_prompt(self): + """Get text representation of the user prompt. + + This will be used to get high priority input. + + :returns: String representation of the prompt or None if no prompt is present. + """ + return None + + @abstractmethod + def get_input(self): + """Print prompt and get an input from user. + + ..NOTE: Overload this method in your class. + + Return this input from a function. + """ + return "" diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/logging.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/logging.py new file mode 100644 index 0000000..f22ddaa --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/logging.py @@ -0,0 +1,39 @@ +# Logging functions and methods used by Simpleline. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +import logging + + +SIMPLELINE_LOGGER = "simpleline" + + +def setup_logging(): + """Set proper logging for a library""" + log = get_simpleline_logger() + null_hd = logging.NullHandler() + log.addHandler(null_hd) + + +def get_simpleline_logger(): + """Return logging instance that can be used in the application.""" + return logging.getLogger(SIMPLELINE_LOGGER) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/__init__.py new file mode 100644 index 0000000..20125e6 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/__init__.py @@ -0,0 +1,31 @@ +# Module with classes to handle rendering and input. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from simpleline.errors import SimplelineError + + +class RenderError(SimplelineError): + """Exception raised when error in rendering happens.""" + + +class RenderUnexpectedError(RenderError): + """Exception raised when something goes really wrong.""" diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/adv_widgets.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/adv_widgets.py new file mode 100644 index 0000000..e8399b4 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/adv_widgets.py @@ -0,0 +1,253 @@ +# Advanced widgets +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import sys + +from simpleline.render import widgets +from simpleline.render.containers import WindowContainer +from simpleline.render.prompt import Prompt +from simpleline.render.screen import UIScreen, InputState +from simpleline.input.input_handler import PasswordInputHandler +from simpleline.utils.i18n import _, N_, C_ + +__all__ = ["ErrorDialog", "GetInputScreen", "GetPasswordInputScreen", "HelpScreen", + "PasswordDialog", "YesNoDialog"] + + +class ErrorDialog(UIScreen): + """Dialog screen for reporting errors to user.""" + + def __init__(self, message): + """ + :param message: the message to show to the user + :type message: str + """ + super().__init__() + self.title = N_("Error") + self._message = message + + def refresh(self, args=None): + super().refresh(args) + text = widgets.TextWidget(self._message) + self.window.add_with_separator(widgets.CenterWidget(text)) + + def prompt(self, args=None): + return Prompt(_("Press %s to exit") % Prompt.ENTER) + + def input(self, args, key): + """This dialog is closed by any input. + + And causes the program to quit. + """ + sys.exit(1) + + +class PasswordDialog(UIScreen): + """Dialog screen for password input.""" + + def __init__(self, message=None): + """ + :param message: password prompt question + :type message: string + """ + super().__init__() + self.title = N_("Password") + self._message = message or _("Enter your passphrase") + self._password = None + + def refresh(self, args=None): + super().refresh(args) + text = widgets.TextWidget(self._message) + self.window.add_with_separator(widgets.CenterWidget(text)) + + def prompt(self, args=None): + handler = PasswordInputHandler(source=self) + if self.password_func: + handler.set_pass_func(self.password_func) + + handler.get_input(_("Passphrase: ")) + handler.wait_on_input() + + if not handler.input_successful(): + return None + + self._password = handler.value + + # this may seem innocuous, but it's really a giant hack; we should + # not be calling close() from prompt(), but the input handling code + # in the TUI is such that without this very simple workaround, we + # would be forever pelting users with a prompt to enter their pw + self.close() + return None + + @property + def answer(self): + """The response can be None (no response) or the password entered.""" + return self._password + + def input(self, args, key): + if key: + self._password = key + return InputState.PROCESSED_AND_CLOSE + + return InputState.DISCARDED + + +class YesNoDialog(UIScreen): + """Dialog screen for Yes - No questions.""" + + def __init__(self, message): + """ + :param message: the message to show to the user + :type message: unicode + """ + super().__init__() + self.title = N_("Question") + self._message = message + self._response = None + + def refresh(self, args=None): + super().refresh(args) + text = widgets.TextWidget(self._message) + self.window.add_with_separator(widgets.CenterWidget(text)) + + def prompt(self, args=None): + return Prompt(_("Please respond '%(yes)s' or '%(no)s'") % { + # TRANSLATORS: 'yes' as positive reply + "yes": C_('TUI|Spoke Navigation', 'yes'), + # TRANSLATORS: 'no' as negative reply + "no": C_('TUI|Spoke Navigation', 'no') + }) + + def input(self, args, key): + # TRANSLATORS: 'yes' as positive reply + if key == C_('TUI|Spoke Navigation', 'yes'): + self._response = True + return InputState.PROCESSED_AND_CLOSE + + # TRANSLATORS: 'no' as negative reply + if key == C_('TUI|Spoke Navigation', 'no'): + self._response = False + return InputState.PROCESSED_AND_CLOSE + + return InputState.DISCARDED + + @property + def answer(self): + """The response can be True (yes), False (no) or None (no response).""" + return self._response + + +class HelpScreen(UIScreen): + """Screen to display a help message.""" + + def __init__(self, help_path): + """ + :param help_path: help file name + :type help_path: str + """ + super().__init__() + self.title = N_("Help") + self.help_path = help_path + + def refresh(self, args=None): + """ Show the help. """ + super().refresh(args) + help_message = _("The help is not available.") + + if self.help_path: + with open(self.help_path, 'r') as f: + help_message = f.read() + + self.window.add_with_separator(widgets.TextWidget(help_message)) + + def input(self, args, key): + """ Handle user input. """ + return InputState.PROCESSED_AND_CLOSE + + def prompt(self, args=None): + return Prompt(_("Press %s to return") % Prompt.ENTER) + + +class GetInputScreen(UIScreen): + """Screen for getting user input.""" + + def __init__(self, message): + """ + :param message: Prompt printed before user input. + :type message: str + """ + super().__init__() + self._message = message + self._value = None + self._conditions = [] + + @property + def value(self): + """User input.""" + return self._value + + def add_acceptance_condition(self, acceptance_function, args=None): + """Add acceptance condition to the conditions list. + + :param acceptance_function: Functions that accepts or rejects a user input. + :type acceptance_function: `function(input, args) -> bool` - function which takes + user input (string) and arguments (`args`) and return True when + input is accepted or False if rejected so we will ask for + a new input. + + :param args: Second argument for `acceptance_function` the first one will be user input. + :type args: Anything. + """ + self._conditions.append((acceptance_function, args)) + + def clear_acceptance_conditions(self): + """Clear list of the acceptance conditions.""" + self._conditions.clear() + + def refresh(self, args=None): + super().refresh(args) + self._window = WindowContainer() + + def prompt(self, args=None): + return Prompt(message=self._message) + + def input(self, args, key): + if not self._test_input(key): + return InputState.DISCARDED + + self._value = key + + return InputState.PROCESSED_AND_CLOSE + + def _test_input(self, key): + for f, args in self._conditions: + if not f(key, args): + return False + + return True + + +class GetPasswordInputScreen(GetInputScreen): + """Screen for getting user password input.""" + + def __init__(self, message): + super().__init__(message) + self.hide_user_input = True diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/containers.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/containers.py new file mode 100644 index 0000000..fb233b2 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/containers.py @@ -0,0 +1,475 @@ +# Widgets for holding other widgets. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from math import ceil + +from simpleline.render.widgets import Widget, TextWidget, SeparatorWidget + +from simpleline.logging import get_simpleline_logger + +__all__ = ["ListRowContainer", "ListColumnContainer", "WindowContainer"] + +log = get_simpleline_logger() + + +class Container(Widget): + """Base class for containers which will do positioning of the widgets.""" + + def __init__(self, items=None, numbering=True): + """Construct Container. + + :param items: List of items for positioning in this Container. Callback + can't be specified this way. + :type items: List of items for rendering. + + :param numbering: Enable/disable automatic numbering (labels) for items. + Enabled by default (True). + :type numbering: bool + """ + super().__init__() + self._key_pattern = None + self._items = [] + if items: + for i in items: + self._items.append(ContainerItem(i)) + + if numbering: + self._key_pattern = KeyPattern() + else: + self._key_pattern = None + + @property + def size(self): + """Return items count.""" + return len(self._items) + + @property + def key_pattern(self): + """Return key pattern which will be used for items numbering. + + Will return `None` if not set. + """ + return self._key_pattern + + @key_pattern.setter + def key_pattern(self, key_pattern): + """Set the key pattern object which will be used for items numbering. + + Setting `None` will stop doing numbering. + """ + self._key_pattern = key_pattern + + def add(self, item, callback=None, data=None): + """Add item to the Container. + + :param item: Add item to this container. + :type item: Could be item (based on `simpleline.render.widgets.Widget`) + or other container (based on `simpleline.render.containers.Container`). + + :param callback: Add callback for this item. This callback will be called when user + activate this `item`. + :type callback: function ``func(data)``. + + :param data: Data which will be passed to the callback. + :param data: Anything. + + :returns: ID of the item in this Container. + :rtype: int + """ + self._items.append(ContainerItem(item, callback, data)) + return len(self._items) - 1 + + def process_user_input(self, key): + """Process input from the user if any of the items in the list was called. + + This method must be called in `UIScreen.input()` method if list widget should call + the callbacks. + + :param key: Key pressed from user. + :type key: str + + :returns: True if key was processed. False otherwise. + """ + if not self._key_pattern: + return False + + if not isinstance(key, str): + return False + + res = self._key_pattern.translate_input_to_widget_id(key) + if res is not None and res >= 0: + try: + item = self._items[res] + if item.callback is not None: + item.callback(item.data) + return True + except IndexError: # container widget with this id doesn't exists + return False + + return False + + def create_number_label(self, item_id): + """Create TextWidget from KeyPattern. + + :param item_id: Create label for item with this id. + :type item_id: int + + :returns: Widget with label for the item with item_id. + :rtype: `simpleline.render.widgets.TextWidget` instance. + """ + number_widget = TextWidget(self._key_pattern.get_widget_label(item_id)) + return number_widget + + +class WindowContainer(Container): + """Base container for screens. + + This can hold other containers or Widgets for rendering. + """ + + def __init__(self, title=None): + """Construct base container for screens. + + This container doesn't have numbering support. Input other containers in it to + allow numbering and input processing. + + :param title: Title line with separator after this title. + :type title: str + """ + super().__init__(numbering=False) + self._title = title + + def add_with_separator(self, item, callback=None, data=None, blank_lines=1): + """Add widget and after widget add blank line. + + This method will call + `self.add(item, callback, data)` + `self.add_separator(lines)` + + :param item: Add item to this container. + :type item: Could be item (based on `simpleline.render.widgets.Widget`) + or other container (based on `simpleline.render.containers.Container`). + + :param callback: Add callback for this item. This callback will be called when user + activate this `item`. + :type callback: function ``func(data)``. + + :param data: Data which will be passed to the callback. + :param data: Anything. + + :param blank_lines: How many blank lines should be printed. + :type blank_lines: int greater than 0. + + :returns: ID of the item in this Container. + :rtype: int + """ + item_id = self.add(item, callback, data) + self.add_separator(blank_lines) + + return item_id + + def add_separator(self, lines=1): + """Add blank lines between widgets. + + :param lines: How many blank lines should be printed. + :type lines: int greater than 0. + """ + self.add(SeparatorWidget(lines)) + + @property + def title(self): + """Title of WindowContainer.""" + return self._title + + def render(self, width): + """Render widgets to it's internal buffer. + + :param width: the maximum width the item can use + :type width: int + + :return: nothing + """ + super().render(width) + + # set cursor position to top-left corner + self.set_cursor_position(0, 0) + + if self._title: + self._draw_title_and_separator(width) + + for item in self._items: + widget = item.widget + widget.render(width) + self.draw(widget) + + def _draw_title_and_separator(self, width): + title_widget = TextWidget(self._title) + sep = SeparatorWidget() + + title_widget.render(width) + sep.render(width) + + self.draw(title_widget) + self.draw(sep) + + +class ListRowContainer(Container): + """Place widgets in rows automatically. + + Compared to the ColumnWidget this is able to handle word wrapping correctly. + + There is numbering N) automatically for all items. To disable this feature call + `self.key_pattern = None`. If you want other numbering then look on `KeyPattern` class. + + Widgets will be placed based on the number of columns in the following way: + + 1) w1 2) w2 3) w3 + 4) w4 5) w5 6) w6 + .... + """ + + def __init__(self, columns, items=None, columns_width=None, spacing=3, numbering=True): + """Create ListWidget with specific number of columns. + + :param columns: How many columns we want. + :type columns: int, bigger than 0 + + :param items: List of items for positioning in this Container. Callback can't be + specified this way. + :type items: List of items for rendering. + + :param columns_width: Width of every column. If nothing specified the maximum width + will be distributed to columns. + :type columns_width: int or None + + :param spacing: Set the spacing between columns. + :type spacing: int + + :param numbering: Enable/disable automatic numbering (labels) for items. + Enabled by default (True). + :type numbering: bool + """ + super().__init__(items, numbering) + self._columns = columns + self._columns_width = columns_width + self._spacing = spacing + self._numbering_widgets = [] + + def render(self, width): + """Render widgets to it's internal buffer. + + :param width: the maximum width the item can use + :type width: int + + :return: nothing + """ + super().render(width) + + if self._columns_width is None: + spaces_between_columns = self._columns - 1 + sum_spacing = spaces_between_columns * self._spacing + self._columns_width = int((width - sum_spacing) / self._columns) + + ordered_map = self._get_ordered_map() + lines_per_rows = self._lines_per_every_row(ordered_map) + + # the leftmost empty column + col_pos = 0 + + for col in ordered_map: + row_pos = 0 + + # render and draw contents of column + for row_id, item_id in enumerate(col): + container = self._items[item_id] + widget = container.widget + + # set cursor to first line and leftmost empty column + self.set_cursor_position(row_pos, col_pos) + + if self._key_pattern is not None: + number_widget = self._numbering_widgets[item_id] + widget_width = len(number_widget.text) + self.draw(number_widget) + self.set_cursor_position(row_pos, col_pos + widget_width) + + self.draw(widget, block=True) + row_pos = row_pos + lines_per_rows[row_id] + + # recompute the leftmost empty column + col_pos = max((col_pos + self._columns_width), self.width) + self._spacing + + def _lines_per_every_row(self, items): + self._render_all_items() + # call `self._render_and_calculate_lines_per_rows()` method instead + lines_per_row = [] + + # go through all items and find how many lines we need for each row + # printed (because of wrapping) + for column_items in items: + for row_id, item_id in enumerate(column_items): + item = self._items[item_id] + if len(lines_per_row) <= row_id: + lines_per_row.append(0) + + lines_per_row[row_id] = max(lines_per_row[row_id], len(item.widget.get_lines())) + + return lines_per_row + + def _render_all_items(self): + for item_id, item in enumerate(self._items): + item_width = self._columns_width + + if item_width <= 0: + raise ValueError("Widget can't be rendered! Columns width is too small.") + + if self._key_pattern: + number_widget = self.create_number_label(item_id) + # render numbers before widgets + number_width = len(number_widget.text) + number_widget.render(number_width) + self._numbering_widgets.append(number_widget) + # reduce the size of widget because of the number + item_width -= number_width + + if item_width <= 0: + raise ValueError("Widget can't be rendered with numbering on! " + "Increase column width or disable numbering.") + + item.widget.render(item_width) + + def _get_ordered_map(self): + """Return list of identifiers (index) to the original item list. + + .. NOTE: Use of ``self._prepare_list()` is encouraged to create output list and + just fill up this list. + """ + # create list of columns (lists) + ordering_map = self._prepare_list() + + for item_id in range(self.size): + ordering_map[item_id % self._columns].append(item_id) + + return ordering_map + + def _prepare_list(self): + """Prepare list for items ordering to rows and columns. + + List will be prepared as ([column 1], [column 2], ...) + """ + return list(map(lambda x: [], range(0, self._columns))) + + +class ListColumnContainer(ListRowContainer): + """Place widgets in columns automatically. + + Compared to the ColumnWidget this is able to handle word wrapping correctly. + + There is numbering N) automatically for all items. To disable this feature call + `self.key_pattern = None`. If you want other numbering then look on `KeyPattern` class. + + Widgets will be placed based on the number of columns in the following way: + + 1) w1 4) w4 7) w7 + 2) w2 5) w5 8) w8 + 3) w3 6) w6 9) w9 + """ + + def _get_ordered_map(self): + ordering_map = self._prepare_list() + items_in_column = ceil(len(self._items) / self._columns) + + for item_id in range(self.size): + col_position = int(item_id // items_in_column) + ordering_map[col_position].append(item_id) + + return ordering_map + + +class KeyPattern(): + """Pattern for automatic key printing before items.""" + + def __init__(self, pattern="{:d}) ", offset=1): + """Create the pattern class. + + For enabling greater functionality than python 3 format is able to do, feel free to + override this class and use your subclass instead. + + :param pattern: Set pattern which will be called for every item. + :type pattern: Strings format method. + See https://docs.python.org/3.3/library/string.html#format-string-syntax. + + :param offset: Set the offset for numbering items. Default is 1 to start indexing + naturally for user. + :type offset: int + """ + self._pattern = pattern + self._offset = offset + + def get_widget_label(self, item_id): + """Get widget identifier for user input description. + + It should be something similar to the pattern. + + :param item_id: Position of the widget in the list. + :type item_id: int starts from 0. + """ + return self._pattern.format(item_id + self._offset) + + def translate_input_to_widget_id(self, user_input): + """Get id of the widget from the user input. + + This is reverse translation to `self.get_widget_identifier()`. + + :param user_input: Input from user: + :type user_input: str + + :return: ID of the widget in the list or None if the input can't be translated. + :rtype: int or None + """ + try: + return int(user_input) - 1 + except ValueError: + log.debug("No callback registered for user input %s", user_input) + return None + + +class ContainerItem(): + """Item used inside of containers to store widgets callbacks and data. + + Internal representation for Containers. Do not use this class directly. + """ + + def __init__(self, widget, callback=None, data=None): + """Construct WidgetContainer. + + :param widget: Any item from `simpleline.render.widgets` or `Container`. + :type widget: Class subclassing the `simpleline.render.widgets.Widget` class + or `simpleline.render.containers.Container`. + + :param callback: This callback will be called as reaction on user input. + :type callback: Function with one data parameter: `def func(data):`. + + :param data: Params which will be passed to callback. + :type data: Anything. + """ + self.widget = widget + self.callback = callback + self.data = data diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/prompt.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/prompt.py new file mode 100644 index 0000000..4c99e35 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/prompt.py @@ -0,0 +1,154 @@ +# Class for the Anaconda TUI prompt. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Vendula Poncova +# +import logging + +from simpleline.utils.i18n import N_, _ + +log = logging.getLogger("simpleline") + + +class Prompt(): + """Class to create a prompt message with options.""" + # Default message of the prompt + DEFAULT_MESSAGE = N_("Please make a selection from the above") + + # String to use in a prompt when we want users to press the key ENTER. + ENTER = N_("ENTER") + + # TRANSLATORS: 'q' to quit + QUIT_DESCRIPTION = N_("to quit") + QUIT = 'q' + + # TRANSLATORS:'c' to continue + CONTINUE_DESCRIPTION = N_("to continue") + CONTINUE = 'c' + + # TRANSLATORS:'r' to refresh + REFRESH_DESCRIPTION = N_("to refresh") + REFRESH = 'r' + + # TRANSLATORS:'h' to help + HELP_DESCRIPTION = N_("to help") + HELP = 'h' + + def __init__(self, message=DEFAULT_MESSAGE): + """ + :param message: the message of the prompt + :type message: str|None + """ + self.message = message + self.options = dict() + + def set_message(self, message): + """Set the prompt message. + + :param message: the message of the prompt + :type message: str|None + """ + self.message = message + + def add_option(self, key, description): + """Add an option to the prompt. + Causes a warning if the option already exists. + + :param key: the key for choosing the option + :type key: str + + :param description: the description of the option + :type description: str + """ + if key in self.options: + log.warning("The option '%s' does already exist in '%s'.", key, self) + + self.options[key] = description + + def update_option(self, key, description): + """Update an option in the prompt. + Causes a warning if the option does not exist. + + :param key: the key for choosing the option + :type key: str + + :param description: the description of the option + :type description: str + """ + if key not in self.options: + log.warning("The option '%s' does not exist in '%s'.", key, self) + + self.options[key] = description + + def add_refresh_option(self, description=REFRESH_DESCRIPTION): + """Add the option to refresh.""" + if Prompt.REFRESH in self.options: + self.update_option(Prompt.REFRESH, description) + else: + self.add_option(Prompt.REFRESH, description) + + def add_continue_option(self, description=CONTINUE_DESCRIPTION): + """Add the option to continue.""" + if Prompt.CONTINUE in self.options: + self.update_option(Prompt.CONTINUE, description) + else: + self.add_option(Prompt.CONTINUE, description) + + def add_quit_option(self, description=QUIT_DESCRIPTION): + """Add the option to quit.""" + if Prompt.QUIT in self.options: + self.update_option(Prompt.QUIT, description) + else: + self.add_option(Prompt.QUIT, description) + + def add_help_option(self, description=HELP_DESCRIPTION): + """Add the option to help.""" + if Prompt.HELP in self.options: + self.update_option(Prompt.HELP, description) + else: + self.add_option(Prompt.HELP, description) + + def remove_option(self, key): + """Remove an option with the given key. + + :param key: the key of the option + :type key: str + + :return: the removed option + :rtype: str|None + """ + return self.options.pop(key, None) + + def __str__(self): + """Return the string representation of the prompt.""" + if not self.message and not self.options: + return "" + + parts = [] + + if self.message: + parts.append(_(self.message)) + + if self.options: + opt_list = ["'%s' %s" % (key, _(self.options[key])) + for key in sorted(self.options.keys())] + opt_str = "[%s]" % ", ".join(opt_list) + parts.append(opt_str) + + return " ".join(parts) + ": " diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/__init__.py new file mode 100644 index 0000000..6918b28 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/__init__.py @@ -0,0 +1,313 @@ +# Base class for text window screens. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from enum import Enum + +from simpleline import App +from simpleline.render.containers import WindowContainer +from simpleline.render.prompt import Prompt +from simpleline.render.screen.signal_handler import SignalHandler +from simpleline.render.screen.input_manager import InputManager +from simpleline.utils.i18n import _ + +__all__ = ["UIScreen", "InputState"] + + +class UIScreen(SignalHandler): + """Base class representing one TUI Screen. + + Shares some API with anaconda's GUI to make it easy for devs to create similar UI + with the familiar API. + """ + + def __init__(self, title=None, screen_height=30): + """ Constructor of the TUI screen. + + :param title: Title line of the screen. + :type title: str + + :param screen_height: height of the screen (useful for printing long widgets) + :type screen_height: int (the value must be bigger than 4) + """ + self._title = title + self._screen_height = screen_height + self._screen_ready = False + + # ask for password + self._hide_user_input = False + self._password_func = None + + # do not print separator for this screen + self._no_separator = False + + # list that holds the content to be printed out + self._window = WindowContainer(self.title) + + # should the input be required after draw + self._input_required = True + + # index of the page (subset of screen) shown during show_all + # indexing starts with 0 + self._page = 0 + + self._input_manager = InputManager(ui_screen=self) + + def __str__(self): + """For easier logging.""" + return self.__class__.__name__ + + @property + def title(self): + """Screen title.""" + return self._title + + @title.setter + def title(self, title): + """Set screen title. + + Set `None` to remove title. + """ + self._title = title + + @property + def password_func(self): + """Get password function. + + This is function with one argument to get password from command line. + """ + return self._password_func + + @password_func.setter + def password_func(self, value): + """Set password function. + + :param value: Function to get password from a command line. + :type value: Function with one argument which is text representation of prompt. + """ + self._password_func = value + + @property + def screen_ready(self): + """This screen is ready for use.""" + return self._screen_ready + + @screen_ready.setter + def screen_ready(self, screen_ready): + """Set ready status for this screen.""" + self._screen_ready = screen_ready + + @property + def input_required(self): + """Return if the screen requires input.""" + return self._input_required + + @input_required.setter + def input_required(self, input_required): + """Set if the screen should require input.""" + self._input_required = input_required + + @property + def no_separator(self): + """Should we print separator for this screen? + + :returns: True to print separator before this screen (default). + False do not print separator. + """ + return self._no_separator + + @no_separator.setter + def no_separator(self, no_separator): + """Print or do not print separator. + + :param no_separator: Specify if the separator should be printed. + :type no_separator: bool (default: False). + """ + self._no_separator = no_separator + + @property + def hide_user_input(self): + """Hide typed user input. + + This is main solution how to ask for password. + + :returns: True if user input should be hidden. + False otherwise (default). + """ + return self._hide_user_input + + @hide_user_input.setter + def hide_user_input(self, hide_input): + """Should be the user input hidden. + + :param hide_input: True if user input should be hidden. + False if not (default). + :type hide_input: bool (default: False). + """ + self._hide_user_input = hide_input + + @property + def window(self): + """Return WindowContainer instance.""" + return self._window + + @window.setter + def window(self, window): + """Set base WindowContainer instance. + + :param window: Base window container containing other widgets and containers. + :type window: Instance of `simpleline.render.containers.WindowContainer` class. + """ + self._window = window + + def get_user_input(self, message, hidden=False): + """Get immediately input from the user. + + Use this with cautious. Never call this in middle of rendering or when other + input is already waiting. It is recommended to use `self.input_required` instead. + + :param message: Message prompt for the user. + :type message: str + + :param hidden: Do not echo user input (password typing). + :type hidden: bool + """ + return self._input_manager.get_input_blocking(message, hidden) + + def setup(self, args): + """Do additional setup right before this screen is used. + + It is mandatory to call this ancestor method in the child class to set ready status. + + :param args: arguments for the setup + :type args: array of values + :return: whether this screen should be scheduled or not + :rtype: bool + """ + self._screen_ready = True + App.get_event_loop().register_signal_source(self) + return True + + def refresh(self, args=None): + """Method which prepares the content desired on the screen to `self.window`. + + :param args: optional argument passed from switch_screen calls + :type args: anything + """ + self.window = WindowContainer(self._title) + + def _print_widget(self, widget): + """Prints a widget with user interaction (when needed). + + Could be longer than the screen height. + + :param widget: widget to print + :type widget: Widget instance + """ + # TODO: Work even for lower screen_height than 4 + pos = 0 + lines = widget.get_lines() + num_lines = len(lines) + + if num_lines == 0: + return + + prompt_height = 2 + real_screen_height = self._screen_height - prompt_height + + if num_lines < real_screen_height: + # widget plus prompt are shorter than screen height, just print the widget + print(u"\n".join(lines)) + return + + # long widget, print it in steps and prompt user to continue + last_line = num_lines - 1 + while pos <= last_line: + if pos + real_screen_height > last_line: + # enough space to print the rest of the widget plus regular + # prompt (2 lines) + for line in lines[pos:]: + print(line) + pos += self._screen_height - 1 + else: + # print part with a prompt to continue + for line in lines[pos:(pos + real_screen_height)]: + print(line) + custom_prompt = Prompt(_("\nPress %s to continue") % Prompt.ENTER) + self._ask_user_input_blocking(custom_prompt) + pos += real_screen_height + + def _ask_user_input_blocking(self, prompt): + return self._input_manager.get_input_blocking(prompt, False) + + def show_all(self): + """Print WindowContainer in `self.window` with all its content.""" + self.window.render(App.get_configuration().width) + self._print_widget(self.window) + + def input(self, args, key): + """Method called to process input. If the input is not handled here, return it. + + :param key: input string to process + :type key: str + :param args: optional argument passed from switch_screen calls + :type args: anything + :return: return `simpleline.render.InputState.PROCESSED` if key was handled, + `simpleline.render.InputState.DISCARDED` if the screen should not process input + on the scheduler and key if you want it to. + :rtype: `simpleline.render.InputState` enum | str + """ + return key + + def get_input_with_error_check(self, args): + """Get user input and redraw if user add too many invalid inputs. + + This method should be used only by ScreenScheduler. + + :param args: Arguments passed in when scheduling this screen. + :type args: Anything. + """ + self._input_manager.get_input(args=args) + + def prompt(self, args=None): + """Return the text to be shown as prompt or handle the prompt and return None. + + :param args: optional argument passed from switch_screen calls + :type args: anything + :return: returns an instance of Prompt with text to be shown next to the prompt + for input or None to skip further input processing + :rtype: Prompt instance|None + """ + prompt = Prompt() + prompt.add_refresh_option() + prompt.add_continue_option() + prompt.add_quit_option() + return prompt + + def closed(self): + """Callback when this screen is closed.""" + + +class InputState(Enum): + PROCESSED = 1 + PROCESSED_AND_REDRAW = 2 + PROCESSED_AND_CLOSE = 3 + DISCARDED = 0 diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/input_manager.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/input_manager.py new file mode 100644 index 0000000..dc0c220 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/input_manager.py @@ -0,0 +1,203 @@ +# Class for managing input and output for application. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from enum import Enum + +from simpleline import App +from simpleline.event_loop import ExitMainLoop +from simpleline.event_loop.signals import ExceptionSignal +from simpleline.render.prompt import Prompt +from simpleline.input import InputHandler, PasswordInputHandler + +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + + +class InputManager(): + + def __init__(self, ui_screen): + """Processor for user input. + + This class is mainly helper class for ScreenScheduler. + + :param ui_screen: Screen associated with this input manager. + :type ui_screen: The `simpleline.render.screen.UIScreen` based instance. + """ + super().__init__() + self._ui_screen = ui_screen + self._input_error_counter = 0 + self._input_error_threshold = 5 + self._input_args = None + + @property + def input_error_counter(self): + """Return how many times the user provided bad input.""" + return self._input_error_counter + + @property + def input_error_threshold_exceeded(self): + """Did the error counter pass the threshold? + + The screen should be redraw. + """ + errors = self._input_error_counter % self._input_error_threshold + return errors == 0 + + def get_input_blocking(self, message, hidden): + """Get blocking input from the user. + + :param message: Message prompt for the user. + :type message: str + + :param hidden: Do not echo user input (password typing). + :type hidden: bool + """ + if hidden: + handler = PasswordInputHandler(source=self) + if self._ui_screen.password_func: + handler.set_pass_func(self._ui_screen.password_func) + else: + handler = InputHandler(source=self) + + handler.get_input(message) + handler.wait_on_input() + return handler.value + + def get_input(self, args=None): + """Get input from user. + + :param args: Arguments passed in when UIScreen was scheduled. + :type args: Anything. + """ + prompt = self._ui_screen.prompt(args) + if not self._is_input_expected(prompt): + return + + self._input_args = args + + if not self._ui_screen.hide_user_input: + handler = InputHandler(source=self._ui_screen) + else: + handler = PasswordInputHandler(source=self._ui_screen) + if self._ui_screen.password_func: + handler.set_pass_func(self._ui_screen.password_func) + + handler.set_callback(self.process_input) + handler.get_input(prompt) + + def _is_input_expected(self, prompt): + """Check if user handled input processing some other way. + + Do nothing if user did handled user input. + + :returns: True if prompt is set and we can use it to get user input. + False if prompt is not available, which means that user handled input on their + own. + """ + # None means prompt handled the input by itself -> continue + if prompt is None: + self._input_error_counter = 0 + return False + + return True + + def process_input(self, user_input): + """Process input from the screens. + + :param user_input: User input string. + :type user_input: String. + + :raises: ExitMainLoop or any other kind of exception from screen processing. + """ + # process the input, if it wasn't processed (valid) + # increment the error counter + try: + result = self._process_input(user_input) + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + App.get_event_loop().enqueue_signal(ExceptionSignal(self)) + return + + if result.was_successful(): + self._input_error_counter = 0 + else: + self._input_error_counter += 1 + + App.get_scheduler().process_input_result(result, self.input_error_threshold_exceeded) + + def _process_input(self, key): + """Method called internally to process unhandled input key presses. + + :param key: The string entered by user. + :type key: String. + + :return: Return state result object. + :rtype: `simpleline.render.in_out_manager.UserInputResult` class. + + :raises: Anything the Screen can raise in the input processing. + """ + from simpleline.render.screen import InputState # pylint: disable=import-outside-toplevel + # delegate the handling to active screen first + key = self._ui_screen.input(self._input_args, key) + if key == InputState.PROCESSED: + return UserInputAction.NOOP + + if key == InputState.PROCESSED_AND_REDRAW: + return UserInputAction.REDRAW + + if key == InputState.PROCESSED_AND_CLOSE: + return UserInputAction.CLOSE + + if key == InputState.DISCARDED: + return UserInputAction.INPUT_ERROR + + # global refresh command + if key == Prompt.REFRESH: + return UserInputAction.REDRAW + + # global close command + if key == Prompt.CONTINUE: + return UserInputAction.CLOSE + + # global quit command + if key == Prompt.QUIT: + return UserInputAction.QUIT + + if key is None: + log.warning("Returned key from screen is None. " + "This could be missing return in a screen input method?") + + return UserInputAction.INPUT_ERROR + + +class UserInputAction(Enum): + """Store user input result.""" + INPUT_ERROR = -1 + NOOP = 0 + REDRAW = 5 + CLOSE = 6 + QUIT = 7 + + def was_successful(self): + return self != UserInputAction.INPUT_ERROR diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/signal_handler.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/signal_handler.py new file mode 100644 index 0000000..e5e1eb5 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen/signal_handler.py @@ -0,0 +1,94 @@ +# Signal handler is giving ability connect and emit to all widgets. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from simpleline import App +from simpleline.event_loop.signals import RenderScreenSignal, CloseScreenSignal + + +class SignalHandler(): + """Provides methods for handling signals anc callbacks. + + Provides main methods: + `connect()` -- connect this widget on given signal + `create_signal()` -- create signal class which can be used in the emit method + `emit()` -- emit signal given signal + """ + + def connect(self, signal, callback, data=None): + """Connect this class method with given signal. + + :param signal: signal class which you want to connect + :type signal: class based on `simpleline.event_loop.AbstractSignal` + + :param callback: the callback function + :type callback: func(event_message, data) + + :param data: Data you want to pass to the callback + :type data: Anything + """ + App.get_event_loop().register_signal_handler(signal, callback, data) + + def create_signal(self, signal_class, priority=0): + """Create signal instance usable in the emit method. + + :param signal_class: signal you want to use + :type signal_class: class based on `simpleline.event_loop.AbstractSignal` + + :param priority: priority of the signal; please look on the + `simpleline.event_loop.AbstractSignal.priority` for further info + :type priority: int + """ + return signal_class(self, priority) + + def emit(self, signal): + """Emit the signal. + + This will add `signal` to the event loop. + + :param signal: signal to emit + :type signal: instance of class based on `simpleline.event_loop.AbstractSignal` + """ + App.get_event_loop().enqueue_signal(signal) + + def create_and_emit(self, signal): + """Create the signal and emit it. + + This is basically shortcut for calling `self.create_signal` and `self.emit`. + """ + created_signal = self.create_signal(signal) + self.emit(created_signal) + + def redraw(self): + """Emit signal to initiate draw. + + Add RenderScreenSignal to the event loop. + """ + signal = self.create_signal(RenderScreenSignal) + App.get_event_loop().enqueue_signal(signal) + + def close(self): + """Emit signal to close this screen. + + Add CloseScreenSignal to the event loop. + """ + signal = self.create_signal(CloseScreenSignal) + App.get_event_loop().enqueue_signal(signal) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_handler.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_handler.py new file mode 100644 index 0000000..19655f7 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_handler.py @@ -0,0 +1,58 @@ +# Serves shortcuts for easy screen scheduling. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +from simpleline import App + + +class ScreenHandler(): + + @classmethod + def schedule_screen(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.schedule_screen()`. + """ + App.get_scheduler().schedule_screen(ui_screen=ui_screen, args=args) + + @classmethod + def replace_screen(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.replace_screen()`. + """ + App.get_scheduler().replace_screen(ui_screen=ui_screen, args=args) + + @classmethod + def push_screen(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.push_screen()`. + """ + App.get_scheduler().push_screen(ui_screen=ui_screen, args=args) + + @classmethod + def push_screen_modal(cls, ui_screen, args=None): + """Schedule screen to the active scheduler. + + See: `simpleline.render.screen_scheduler.push_screen_modal()`. + """ + App.get_scheduler().push_screen_modal(ui_screen=ui_screen, args=args) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_scheduler.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_scheduler.py new file mode 100644 index 0000000..cfc4cbf --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_scheduler.py @@ -0,0 +1,311 @@ +# Class handling rendering of the screens to console. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +import threading + + +from simpleline import App +from simpleline.event_loop import ExitMainLoop +from simpleline.event_loop.signals import ExceptionSignal, RenderScreenSignal, CloseScreenSignal +from simpleline.render import RenderUnexpectedError +from simpleline.render.screen.input_manager import UserInputAction +from simpleline.render.screen_stack import ScreenStack, ScreenData, ScreenStackEmptyException + +from simpleline.logging import get_simpleline_logger + +log = get_simpleline_logger() + +RAW_INPUT_LOCK = threading.Lock() + + +__all__ = ["ScreenScheduler"] + + +class ScreenScheduler(): + + def __init__(self, event_loop, scheduler_stack=None): + """Constructor where you can pass your own scheduler stack. + + The ScreenStack will be used automatically if scheduler stack will be None. + + :param event_loop: Event loop used for the scheduler. + :type event_loop: Class based on `simpleline.event_loop.AbstractEventLoop`. + :param scheduler_stack: Use custom scheduler stack if you need to. + :type scheduler_stack: `simpleline.screen_stack.ScreenStack` based class. + """ + self._quit_screen = None + self._event_loop = event_loop + + if scheduler_stack: + self._screen_stack = scheduler_stack + else: + self._screen_stack = ScreenStack() + self._register_handlers() + + self._first_screen_scheduled = False + + @staticmethod + def _spacer(): + return "\n".join(2 * [App.get_configuration().width * "="]) + + def _register_handlers(self): + self._event_loop.register_signal_handler(RenderScreenSignal, self._process_screen_callback) + self._event_loop.register_signal_handler(CloseScreenSignal, self._close_screen_callback) + + @property + def quit_screen(self): + """Return quit UIScreen.""" + return self._quit_screen + + @quit_screen.setter + def quit_screen(self, quit_screen): + """Set the UIScreen based instance which will be showed before the Application will quit. + + You can also use `simpleline.render.adv_widgets.YesNoDialog` or `UIScreen` based class + with the `answer` property. Without the `answer` property the application will always + close. + """ + self._quit_screen = quit_screen + + @property + def nothing_to_render(self): + """Is something for rendering in the scheduler stack? + + :return: True if the rendering stack is empty + :rtype: bool + """ + return self._screen_stack.empty() + + def dump_stack(self): + """Get string representation of actual screen stack.""" + return self._screen_stack.dump_stack() + + def schedule_screen(self, ui_screen, args=None): + """Add screen to the bottom of the stack. + + This is mostly useful at the beginning to prepare the first screen hierarchy to display. + + :param ui_screen: screen to show + :type ui_screen: UIScreen instance + :param args: optional argument, please see switch_screen for details + :type args: anything + """ + log.debug("Scheduling screen %s", ui_screen) + screen = ScreenData(ui_screen, args) + self._screen_stack.add_first(screen) + self._redraw_on_first_scheduled_screen() + + def _redraw_on_first_scheduled_screen(self): + if not self._first_screen_scheduled: + self.redraw() + self._first_screen_scheduled = True + + def replace_screen(self, ui_screen, args=None): + """Schedules a screen to replace the current one. + + :param ui_screen: screen to show + :type ui_screen: instance of UIScreen + :param args: optional argument to pass to ui's refresh and setup methods + (can be used to select what item should be displayed or so) + :type args: anything + """ + log.debug("Replacing screen %s", ui_screen) + try: + execute_new_loop = self._screen_stack.pop().execute_new_loop + except ScreenStackEmptyException as e: + raise ScreenStackEmptyException("Switch screen is not possible when there is no " + "screen scheduled!") from e + + # we have to keep the old_loop value so we stop + # dialog's mainloop if it ever uses switch_screen + screen = ScreenData(ui_screen, args, execute_new_loop) + self._screen_stack.append(screen) + self.redraw() + + def push_screen(self, ui_screen, args=None): + """Schedules a screen to show, but keeps the current one in stack to + return to, when the new one is closed. + + :param ui_screen: screen to show + :type ui_screen: UIScreen instance + :param args: optional argument + :type args: anything + """ + log.debug("Pushing screen %s to stack", ui_screen) + screen = ScreenData(ui_screen, args, False) + self._screen_stack.append(screen) + self.redraw() + + def push_screen_modal(self, ui_screen, args=None): + """Starts a new screen right away, so the caller can collect data back. + + When the new screen is closed, the caller is redisplayed. + + This method does not return until the new screen is closed. + + :param ui_screen: screen to show + :type ui_screen: UIScreen instance + :param args: optional argument, please see switch_screen for details + :type args: anything + """ + log.debug("Pushing modal screen %s to stack", ui_screen) + screen = ScreenData(ui_screen, args, True) + self._screen_stack.append(screen) + # only new events will be processed now + # the old one will wait after this event loop will be closed + self._event_loop.execute_new_loop(RenderScreenSignal(self)) + + def _close_screen_callback(self, signal, data): + self.close_screen(signal.source) + + def close_screen(self, closed_from=None): + """Close the currently displayed screen and exit it's main loop if necessary. + + Next screen from the stack is then displayed. + """ + screen = self._screen_stack.pop() + log.debug("Closing screen %s from %s", screen, closed_from) + + # User can react when screen is closing + screen.ui_screen.closed() + + if closed_from is not None and closed_from is not screen.ui_screen: + raise RenderUnexpectedError("You are trying to close screen %s from screen %s! " + "This is most probably not intentional." % + (closed_from, screen.ui_screen)) + + if screen.execute_new_loop: + self._event_loop.close_loop() + + # redraw screen if there is what to redraw + # and if it is not modal screen (modal screen parent is blocked) + if not self._screen_stack.empty() and not screen.execute_new_loop: + self.redraw() + + # we can't draw anything more. Kill the application. + if self._screen_stack.empty(): + raise ExitMainLoop() + + def redraw(self): + """Register rendering to the event loop for processing.""" + self._event_loop.enqueue_signal(RenderScreenSignal(self)) + + def _process_screen_callback(self, signal, data): + self._process_screen() + + def _process_screen(self): + """Process the current screen. + + 1) It will call setup if the screen is not already set. + 2a) If setup was success then draw the screen. + 2b) If setup wasn't successful then pop the screen and try to process next in the stack. + Continue by (1). + 3)Ask for user input if requested. + """ + top_screen = self._get_last_screen() + + log.debug("Processing screen %s", top_screen) + + # this screen is used first time (call setup() method) + if not top_screen.ui_screen.screen_ready: + if not top_screen.ui_screen.setup(top_screen.args): + # remove the screen and skip if setup went wrong + self._screen_stack.pop() + self.redraw() + log.warning("Screen %s setup wasn't successful", top_screen) + return + + # get the widget tree from the screen and show it in the screen + try: + # refresh screen content + top_screen.ui_screen.refresh(top_screen.args) + + # Screen was closed in the refresh method + if top_screen != self._get_last_screen(): + return + + # draw screen to the console + self._draw_screen(top_screen) + + if top_screen.ui_screen.input_required: + log.debug("Input is required by %s screen", top_screen) + top_screen.ui_screen.get_input_with_error_check(top_screen.args) + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + self._event_loop.enqueue_signal(ExceptionSignal(self)) + return + + def _draw_screen(self, active_screen): + """Draws the current `active_screen`. + + :param active_screen: Screen which should be draw to the console. + :type active_screen: Classed based on `simpleline.render.screen.UIScreen`. + """ + # get the widget tree from the screen and show it in the screen + try: + if not active_screen.ui_screen.no_separator: + # separate the content on the screen from the stuff we are about to display now + print(self._spacer()) + + # print UIScreen content + active_screen.ui_screen.show_all() + except ExitMainLoop: # pylint: disable=try-except-raise + raise + except Exception: # pylint: disable=broad-except + self._event_loop.enqueue_signal(ExceptionSignal(self)) + + def _get_last_screen(self): + if self._screen_stack.empty(): + raise ExitMainLoop() + + return self._screen_stack.pop(False) + + def process_input_result(self, input_result, should_redraw): + active_screen = self._get_last_screen() + + if not input_result.was_successful(): + if should_redraw: + self.redraw() + else: + log.debug("Input was not successful, ask for new input.") + active_screen.ui_screen.get_input_with_error_check(active_screen.args) + else: + if input_result == UserInputAction.NOOP: + return + + if input_result == UserInputAction.REDRAW: + self.redraw() + elif input_result == UserInputAction.CLOSE: + self.close_screen() + elif input_result == UserInputAction.QUIT: + if self.quit_screen: + self.push_screen_modal(self.quit_screen) + try: + if self.quit_screen.answer is True: + raise ExitMainLoop() + + self.redraw() + except AttributeError as e: + raise ExitMainLoop() from e + else: + raise ExitMainLoop() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_stack.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_stack.py new file mode 100644 index 0000000..9d0d7c2 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/screen_stack.py @@ -0,0 +1,117 @@ +# Classes implementation for storing and manipulating Screen stack. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +from simpleline.errors import SimplelineError + + +class ScreenStackException(SimplelineError): + """General screen stack exception.""" + + +class ScreenStackEmptyException(ScreenStackException): + """Screen stack exception when stack is empty.""" + + +class ScreenStack(): + """Managing screen stack used in `ScreenScheduler`.""" + + def __init__(self): + self._screens = [] + + def empty(self): + """Test if screen stack is empty. + + :return: True if empty. + :rtype: bool + """ + return not self._screens + + def size(self): + """Get size of the stack. + + :return: Size of the stack. + """ + return len(self._screens) + + def append(self, screen): + """Add new screen to the top of the stack. + + :param screen: Screen for the future rendering. + :type screen: Class based on `simpleline.render.ui_screen.UIScreen`. + """ + self._screens.append(screen) + + def pop(self, remove=True): + """Return top item from the stack. + + :param remove: If True (default) also remove this items from the stack. + :return: The top screen on the stack. + """ + try: + if remove: + return self._screens.pop() + + return self._screens[-1] + except IndexError as e: + raise ScreenStackEmptyException(e) from e + + def add_first(self, screen): + """Add `screen` to the bottom of the stack. + + :param screen: Add the `screen` to the bottom of the stack. + :type screen: Class based on `simpleline.render.ui_screen.UIScreen`. + """ + self._screens.insert(0, screen) + + def dump_stack(self): + """Dump screen stack structure. + + :returns: Screen stack representation. + :rtype: str + """ + msg = '======= Screen stack =======\n' + msg += '----------- TOP ------------\n' + + for screen in reversed(self._screens): + msg += str(screen) + msg += "\n" + + msg += '============================\n' + + return msg + + +class ScreenData(): + """Inner data class to store screen data.""" + + def __init__(self, ui_screen, args=None, execute_new_loop=False): + self.ui_screen = ui_screen + self.args = args + self.execute_new_loop = execute_new_loop + + def __str__(self): + msg = self.__class__.__name__ + msg += "(" + msg += ",".join((str(self.ui_screen), str(self.args), str(self.execute_new_loop))) + msg += ")" + return msg diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/widgets.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/widgets.py new file mode 100644 index 0000000..2f645a0 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/render/widgets.py @@ -0,0 +1,495 @@ +# Widgets for Text UI framework. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import functools +from textwrap import wrap +from simpleline.utils.i18n import _ +from simpleline.utils import ensure_str + +__all__ = ["Widget", "TextWidget", "SeparatorWidget", "EntryWidget", "ColumnWidget", + "CheckboxWidget", "CenterWidget"] + + +class Widget(): + + def __init__(self, max_width=None, default=None): + """Initializes base Widgets buffer. + + This class can be subclassed to create customized widgets. + + :param max_width: serves as a hint about screen size to write method with default arguments + :type max_width: int + + :param default: string containing the default content to fill the buffer with + :type default: string + """ + self._buffer = [] + if default: + self._buffer = [[c for c in l] for l in default.split("\n")] # pylint: disable=unnecessary-comprehension + self._max_width = max_width + self._cursor = (0, 0) # row, col + + @property + def height(self): + """The current height of the internal buffer.""" + return len(self._buffer) + + @property + def width(self): + """The current width of the internal buffer (id of the first empty column).""" + return functools.reduce(lambda acc, l: max(acc, len(l)), self._buffer, 0) + + def clear(self): + """Clears this widgets buffer and resets cursor.""" + self._buffer = list() + self._cursor = (0, 0) + + @property + def content(self): + """Return a list (rows) of lists (columns) with one character elements.""" + return self._buffer + + def render(self, width): + """Redraw the widget's self._buffer. + + :param width: the width of buffer requested by the caller + :type width: int + + Commonly, call render of child widgets and then draw and write + methods to copy their contents to self._buffer. + """ + self.clear() + + def get_lines(self): + """Return lines to write out in order to show this widget. + + :return: lines representing this widget + :rtype: list(str) + """ + return [str(u"".join(line)) for line in self._buffer] + + def set_cursor_position(self, row, col): + """Set cursor position. + + :param row: row id, starts with 0 at the top of the screen + :type row: int + + :param col: column id, starts with 0 on the left side of the screen + :type col: int + """ + self._cursor = (row, col) + + @property + def cursor(self): + return self._cursor + + def set_end(self): + """Set the cursor to first column in new line at the end.""" + self._cursor = (self.height, 0) + + def draw(self, w, row=None, col=None, block=False): + """Copy w widget's content to this widget's buffer at row, col position. + + :param w: widget to take content from + :type w: class Widget + + :param row: row number to start at (default is at the cursor position) + :type row: int + + :param col: column number to start at (default is at the cursor position) + :type col: int + + :param block: when printing newline, start at column col (True) or at column 0 (False) + :type block: boolean + """ + # if the starting row is not present, start at the cursor position + if row is None: + row = self._cursor[0] + + # if the starting column is not present, start at the cursor position + if col is None: + col = self._cursor[1] + + # fill up rows to accommodate for w.height + if self.height < row + w.height: + for _i in range(row + w.height - self.height): + self._buffer.append(list()) + + # append columns to accommodate for w.width + for l in range(row, row + w.height): + l_len = len(self._buffer[l]) + w_len = len(w.content[l - row]) + if l_len < col + w_len: + self._buffer[l] += ((col + w_len - l_len) * list(u" ")) + self._buffer[l][col:col + w_len] = w.content[l - row][:] + + # move the cursor to new spot + if block: + self._cursor = (row + w.height, col) + else: + self._cursor = (row + w.height, 0) + + def write(self, text, row=None, col=None, width=None, block=False, wordwrap=False): + """Emulate the typing machine writing to this widget's buffer. + + :param text: text to type + :type text: str + + :param row: row number to start at (default is at the cursor position) + :type row: int + + :param col: column number to start at (default is at the cursor position) + :type col: int + + :param width: wrap at "col" + "width" column (default is at self._max_width) + :type width: int + + :param block: when printing newline, start at column col (True) or at column 0 (False) + :type block: boolean + + :param wordwrap: wrap by words + :type wordwrap: boolean + """ + if not text: + return + + text = ensure_str(text) + if row is None: + row = self._cursor[0] + + if col is None: + col = self._cursor[1] + + if width is None and self._max_width: + width = self._max_width - col + + x = row + y = col + + if wordwrap: + text = self._wrap_words(text, width) + + # emulate typing machine + for character in text: + # FIXME: Remove the code duplication below and optimize it + # process newline + if character == "\n": + x += 1 + if block: + y = col + else: + y = 0 + + self._increase_x_buffer_size(x) + continue + + self._increase_x_buffer_size(x) + self._increase_y_buffer_size(x, y) + + self._save_character_to_buffer(x, y, character) + + # shift to the next char + y += 1 + if width is not None and y >= col + width: + x += 1 + if block: + y = col + else: + y = 0 + + self._cursor = (x, y) + + def _increase_x_buffer_size(self, x): + if x >= len(self._buffer): + for _i in range(x - len(self._buffer) + 1): + self._buffer.append(list()) + + def _increase_y_buffer_size(self, x, y): + if y >= len(self._buffer[x]): + self._buffer[x] += ((y - len(self._buffer[x]) + 1) * list(u" ")) + + def _save_character_to_buffer(self, x, y, character): + self._buffer[x][y] = character + + @staticmethod + def _wrap_words(text, width): + lines = [] + # Wrap each line separately + for line in text.split('\n'): + sublines = [] + for subline in wrap(line, width): + sublines.append(subline) + if len(subline) < width: + # line shorter than width will be wrapped by '\n' we add + sublines.append('\n') + # line with length == width will be wrapped by the width based + # wrapping logic + # end of line will be wrapped by '\n' following the line in + # original text + if sublines and sublines[-1] == '\n': + sublines.pop() + lines.append("".join(sublines)) + return '\n'.join(lines) + + +class TextWidget(Widget): + """Class to handle wrapped text output.""" + + def __init__(self, text): + """ + :param text: text to format + :type text: str + """ + super().__init__() + self._text = text + + @property + def text(self): + """Contains text of this widget.""" + return self._text + + def render(self, width): + """Renders the text widget limited to width number of columns. + + Wraps to the next line when the text is longer. + + :param width: maximum width allocated to the string + :type width: int + """ + super().render(width) + self.write(self._text, width=width, wordwrap=True) + + +class EntryWidget(TextWidget): + """This is the easy way how to generate entry items for containers. + + If the numbering in a container is turned on the output looks like: + + N) title + value + + Without numbering turned on: + + title + value + """ + + def __init__(self, title, value=None): + """ Create Entry widget instance. + + :param title: Title of this entry. + :type title: String. + + :param value: Actual value printed in second line below the title. + :type value: String. + """ + text = self._create_text(title=title, value=value) + super().__init__(text) + + @staticmethod + def _create_text(title, value): + msg = title + + if value: + msg += "\n" + msg += value + + return msg + + +class SeparatorWidget(Widget): + """Print empty line.""" + + def __init__(self, lines=1): + """Construct SeparatorWidget for printing blank lines. + + :param lines: How many lines should be blank. + :type lines: int greater than 0. + """ + super().__init__() + self._lines = lines + + def render(self, width): + """Render empty line to the buffer. + + :param width: maximum width allocated to the string + :type width: int + """ + super().render(width) + self.write("") + + def write(self, text, row=None, col=None, width=None, block=False, wordwrap=False): + """Optimize write function. + + To print just a blank line we don't need too much logic. + """ + for i in range(0, self._lines): + self._buffer.append(list()) + self._buffer[i] += u"" + self.set_cursor_position(self._lines - 1, 0) + + +class CenterWidget(Widget): + """Class to handle horizontal centering of content.""" + + def __init__(self, w): + """ + :param w: widget to center + :type w: Widget + """ + super().__init__() + self._w = w + + def render(self, width): + """Render the centered widget to internal buffer. + + :param width: maximum width the widget should use + :type width: int + """ + super().render(width) + self._w.render(width) + # make sure col is an integer + self.draw(self._w, col=(width - self._w.width) // 2) + + +class CheckboxWidget(Widget): + """Widget to show checkbox with (un)checked box, name and description.""" + + def __init__(self, key="x", title=None, text=None, completed=None): + """ + :param key: tick character to be used inside [ ] + :type key: character + + :param title: the title next to the [ ] box + :type title: str + + :param text: the description text to be shown on the second row in () + :type text: str + + :param completed: is the checkbox ticked or not? + :type completed: True|False + """ + super().__init__() + self._key = key + self._title = title + self._text = text + self._completed = completed + + def render(self, width): + """Render the widget to internal buffer. + + It should be max width characters wide. + """ + super().render(width) + + if self.completed: + checkchar = self._key + else: + checkchar = " " + + # prepare the checkbox + checkbox = TextWidget("[%s]" % checkchar) + + data = [] + + # append lines + if self.title: + data.append(TextWidget(_(self.title))) + + if self.text: + data.append(TextWidget("(%s)" % self.text)) + + # the checkbox has two columns + # [x] is one and is 3 chars wide + # text is second and can occupy width - 3 - 1 (for space) chars + cols = ColumnWidget([(3, [checkbox]), (width - 4, data)], 1) + cols.render(width) + + # transfer the column widget rendered stuff to internal buffer + self.draw(cols) + + @property + def title(self): + """Returns the first line (main title) of the checkbox.""" + return self._title + + @property + def completed(self): + """Returns the state of the checkbox, checked is True.""" + return self._completed + + @property + def text(self): + """Contains the description text from the second line.""" + return self._text + + +class ColumnWidget(Widget): + + def __init__(self, columns, spacing=0): + """Create text columns + + Deprecated. Please do not use this widget, use containers instead. + + :param columns: list containing (column width, [list of widgets to put into this column]) + :type columns: [(int, [...]), ...] + + :param spacing: number of spaces to use between columns + :type spacing: int + """ + super().__init__() + self._spacing = spacing + self._columns = columns + + def render(self, width): + """Render the widget to it's internal buffer + + :param width: the maximum width the widget can use + :type width: int + + :return: nothing + """ + super().render(width) + + # the leftmost empty column + col_pos = 0 + + # iterate over tuples (column width, column content) + for col_width, col in self._columns: + + # set cursor to first line and leftmost empty column + self.set_cursor_position(0, col_pos) + + # if requested width is None, limit the maximum to width + # and set minimum to 0 + if col_width is None: + col_max_width = width - self.cursor[1] + col_width = 0 + else: + col_max_width = col_width + + # render and draw contents of column + for item in col: + item.render(col_max_width) + self.draw(item, block=True) + + # recompute the leftmost empty column + col_pos = max((col_pos + col_width), self.width) + self._spacing diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/__init__.py new file mode 100644 index 0000000..bb1622c --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/__init__.py @@ -0,0 +1,94 @@ +# iutil.py - generic install utility functions +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import sys +import string # pylint: disable=deprecated-module +import unicodedata + + +def ensure_str(str_or_bytes, keep_none=True): + """ + Returns a str instance for given string or ``None`` if requested to keep it. + + :param str_or_bytes: string to be kept or converted to str type + :type str_or_bytes: str or bytes + :param bool keep_none: whether to keep None as it is or raise ValueError if + ``None`` is passed + :raises ValueError: if applied on an object not being of type bytes nor str + (nor NoneType if ``keep_none`` is ``False``) + """ + if keep_none and str_or_bytes is None: + return None + if isinstance(str_or_bytes, str): + return str_or_bytes + if isinstance(str_or_bytes, bytes): + return str_or_bytes.decode(sys.getdefaultencoding()) + + raise ValueError( + "str_or_bytes must be of type 'str' or 'bytes', not '%s'" % type(str_or_bytes)) + + +# Define translations between ASCII uppercase and lowercase for +# locale-independent string conversions. The tables are 256-byte string used +# with str.translate. If str.translate is used with a unicode string, +# even if the string contains only 7-bit characters, str.translate will +# raise a UnicodeDecodeError. +_ASCIIlower_table = str.maketrans(string.ascii_uppercase, string.ascii_lowercase) +_ASCIIupper_table = str.maketrans(string.ascii_lowercase, string.ascii_uppercase) + + +def _toASCII(s): + """Convert a unicode string to ASCII""" + if isinstance(s, str): + # Decompose the string using the NFK decomposition, which in addition + # to the canonical decomposition replaces characters based on + # compatibility equivalence (e.g., ROMAN NUMERAL ONE has its own code + # point but it's really just a capital I), so that we can keep as much + # of the ASCII part of the string as possible. + s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').decode("ascii") + elif not isinstance(s, bytes): + s = '' + return s + + +def lowerASCII(s): + """Convert a string to lowercase using only ASCII character definitions. + + The returned string will contain only ASCII characters. This function is + locale-independent. + """ + # XXX: Python 3 has str.maketrans() and bytes.maketrans() so we should + # ideally use one or the other depending on the type of 's'. But it turns + # out we expect this function to always return string even if given bytes. + s = ensure_str(s) + return str.translate(_toASCII(s), _ASCIIlower_table) + + +def upperASCII(s): + """Convert a string to uppercase using only ASCII character definitions. + + The returned string will contain only ASCII characters. This function is + locale-independent. + """ + # XXX: Python 3 has str.maketrans() and bytes.maketrans() so we should + # ideally use one or the other depending on the type of 's'. But it turns + # out we expect this function to always return string even if given bytes. + s = ensure_str(s) + return str.translate(_toASCII(s), _ASCIIupper_table) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/i18n.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/i18n.py new file mode 100644 index 0000000..c740c34 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/simpleline/utils/i18n.py @@ -0,0 +1,61 @@ +# Translation functions we use all over the place +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +__all__ = ["_", "N_", "P_", "C_", "CN_", "CP_"] + +import gettext + +N_ = lambda x: x +_ = lambda x: gettext.translation("python-simpleline", fallback=True).gettext(x) if x != "" else "" +P_ = lambda x, y, z: gettext.translation("python-simpleline", fallback=True).ngettext(x, y, z) + +# This is equivalent to "pgettext" in GNU gettext. The pgettext functions +# are not exported by Python, but all they really do is a stick a EOT +# character between msgctxt and msgid and check that msgctxt isn't part +# of the return value. + + +def C_(msgctxt, msgid): + ctxid = "%s\x04%s" % (msgctxt, msgid) + translation = _(ctxid) + + # If there is no translation for msgctxtmsgid, return only msgid + if translation == ctxid: + return msgid + + return translation + +# Mark as translatable with context +CN_ = lambda c, x: x + +# npgettext; i.e., gettext with plural form and context + + +def CP_(msgctxt, msgid, msgid_plural, n): + ctxid = "%s\x04%s" % (msgctxt, msgid) + translation = P_(ctxid, msgid_plural, n) + + # If the returned value is msgctxtmsgid, ngettext was trying to + # fallback to msgid. We don't add msgctxt to msgid_plural, so any other + # return value is correct. + if translation == ctxid: + return msgid + + return translation diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/__init__.py new file mode 100644 index 0000000..fb94082 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/__init__.py @@ -0,0 +1,45 @@ +# Helper functions for the test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from simpleline import App +from simpleline.global_configuration import DEFAULT_WIDTH + + +class UtilityMixin(): + + @staticmethod + def calculate_separator(width=DEFAULT_WIDTH): + separator = "\n".join(2 * [width * "="]) + separator += "\n" # print adds another newline + return separator + + def create_output_with_separators(self, screens_text): + msg = "" + for screen_txt in screens_text: + msg += self.calculate_separator() + msg += screen_txt + "\n\n" + + return msg + + @staticmethod + def schedule_screen_and_run(screen): + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/__init__.py new file mode 100644 index 0000000..7574516 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/__init__.py @@ -0,0 +1,67 @@ +# Helper functions for the GLib test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +import gi + +from simpleline import App +from simpleline.event_loop.glib_event_loop import GLibEventLoop + +gi.require_version("GLib", "2.0") + +from gi.repository import GLib # pylint: disable=wrong-import-position, wrong-import-order + + +class GLibUtilityMixin(): + + def __init__(self): + self.loop = None + self.timeout_error = False + + def _quit_loop(self, loop): + """Kill GLib loop.""" + loop.quit() + self.timeout_error = True + return True + + def create_glib_loop(self): + # clear flags + self.timeout_error = False + self.loop = GLibEventLoop() + + loop = self.loop.active_main_loop + context = loop.get_context() + + # This is prevention from running loop indefinitely + source = GLib.timeout_source_new_seconds(2) + source.set_callback(self._quit_loop, loop) + source.attach(context) + + def setup_glib(self): + self.create_glib_loop() + App.initialize(event_loop=self.loop) + + def teardown_glib(self): + if self.timeout_error: + raise AssertionError("Loop was killed by timeout!") + + def schedule_screen_and_run_with_glib(self, screen): + self.setup_glib() + + App.get_scheduler().schedule_screen(screen) + App.run() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/event_loop_glib_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/event_loop_glib_test.py new file mode 100644 index 0000000..fa3c257 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/event_loop_glib_test.py @@ -0,0 +1,37 @@ +# Event loop test classes for GLib implementation. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from . import GLibUtilityMixin +from ..main.event_loop_test import ProcessEvents_TestCase + + +class GLibProcessEvents_TestCase(ProcessEvents_TestCase, GLibUtilityMixin): + """Run all the tests in ProcessEvents test case but with GLib event loop.""" + + def tearDown(self): + super().tearDown() + self.teardown_glib() + + def create_loop(self): + self.create_glib_loop() + + +# Hack to avoid running the original class thanks to import +del ProcessEvents_TestCase diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/input_handler_glib_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/input_handler_glib_test.py new file mode 100644 index 0000000..c1ff51b --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/input_handler_glib_test.py @@ -0,0 +1,38 @@ +# Rendering screen test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +from . import GLibUtilityMixin +from ..main.input_handler_test import InputHandler_TestCase + + +class GLibInputHandler_TestCase(InputHandler_TestCase, GLibUtilityMixin): + """Run all the tests in InputHandler test case but with GLib event loop.""" + + def tearDown(self): + super().tearDown() + self.teardown_glib() + + def create_loop(self): + self.create_glib_loop() + + +# Hack to avoid running the original class thanks to import +del InputHandler_TestCase diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/render_screen_glib_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/render_screen_glib_test.py new file mode 100644 index 0000000..9a42b65 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/render_screen_glib_test.py @@ -0,0 +1,73 @@ +# Rendering screen test classes for GLib implementation. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +from . import GLibUtilityMixin +from ..main.render_screen_test import SimpleUIScreenProcessing_TestCase, \ + InputProcessing_TestCase, ScreenException_TestCase + + +class GLibSimpleUIScreenProcessing_TestCase(SimpleUIScreenProcessing_TestCase, GLibUtilityMixin): + """Run all the tests in ProcessEvents test case but with GLib event loop.""" + + def setUp(self): + super().setUp() + self.loop = None + self.timeout_error = False + + def tearDown(self): + super().tearDown() + self.teardown_glib() + + def schedule_screen_and_run(self, screen): + self.schedule_screen_and_run_with_glib(screen) + + +# Hack to avoid running the original class thanks to import +del SimpleUIScreenProcessing_TestCase + + +class GLibScreenException_TestCase(ScreenException_TestCase, GLibUtilityMixin): + + def tearDown(self): + super().tearDown() + self.teardown_glib() + + def schedule_screen_and_run(self, screen): + self.schedule_screen_and_run_with_glib(screen) + + +# Hack to avoid running the original class thanks to import +del ScreenException_TestCase + + +class GLibInputProcessing_TestCase(InputProcessing_TestCase, GLibUtilityMixin): + + def setUp(self): + super().setUp() + self.setup_glib() + + def tearDown(self): + super().tearDown() + self.teardown_glib() + + +# Hack to avoid running the original class thanks to import +del InputProcessing_TestCase diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/screen_scheduler_glib_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/screen_scheduler_glib_test.py new file mode 100644 index 0000000..93148a1 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/glib/screen_scheduler_glib_test.py @@ -0,0 +1,37 @@ +# Screen scheduling GLib test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +from . import GLibUtilityMixin +from ..main.screen_scheduler_test import ScreenScheduler_TestCase + + +class GLibScreenScheduler_TestCase(ScreenScheduler_TestCase, GLibUtilityMixin): + + def tearDown(self): + super().tearDown() + self.teardown_glib() + + def schedule_screen_and_run(self, screen): + self.schedule_screen_and_run_with_glib(screen) + + +# Hack to avoid running the original class thanks to import +del ScreenScheduler_TestCase diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/__init__.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/adv_widgets_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/adv_widgets_test.py new file mode 100644 index 0000000..03048bf --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/adv_widgets_test.py @@ -0,0 +1,118 @@ +# Advanced widgets test cases. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from unittest.mock import patch +from io import StringIO + +from simpleline.render.adv_widgets import GetInputScreen, GetPasswordInputScreen + +from .. import UtilityMixin + + +@patch('simpleline.input.input_handler.InputHandlerRequest._get_input') +@patch('sys.stdout', new_callable=StringIO) +class AdvWidgets_TestCase(unittest.TestCase, UtilityMixin): + def setUp(self): + self.correct_input = False + self.args_used = False + + def test_gettext(self, stdout_mock, stdin_mock): + prompt = "Type input" + input_text = "user input" + screen = GetInputScreen(message=prompt) + stdin_mock.return_value = input_text + + self.schedule_screen_and_run(screen) + + expected_output = self.create_output_with_separators(["%s: " % prompt]).rstrip('\n') + + self.assertEqual(expected_output, stdout_mock.getvalue()) + self.assertEqual(screen.value, input_text) + + def test_gettext_with_condition(self, stdout_mock, stdin_mock): + prompt = "Type input" + wrong_input = "wrong" + condition = lambda x, _: x != wrong_input + stdin_mock.side_effect = self.input_generator() + + screen = GetInputScreen(message=prompt) + screen.add_acceptance_condition(condition) + + self.schedule_screen_and_run(screen) + + temp_prompt = ["%s: %s: " % (prompt, prompt)] + expected_output = self.create_output_with_separators(temp_prompt).rstrip("\n") + + self.assertEqual(expected_output, stdout_mock.getvalue()) + self.assertTrue(self.correct_input) + + def test_gettext_with_condition_and_use_arg(self, stdout_mock, stdin_mock): + prompt = "Type input" + user_input = "y" + stdin_mock.return_value = user_input + + screen = GetInputScreen(message=prompt) + screen.add_acceptance_condition(self.acceptance_condition_test, "y") + + self.schedule_screen_and_run(screen) + + expected_msg = "%s: " % prompt + expected_output = self.create_output_with_separators([expected_msg]).rstrip("\n") + + self.assertEqual(expected_output, stdout_mock.getvalue()) + self.assertTrue(self.args_used) + + @patch("simpleline.global_configuration.GlobalConfiguration.password_function") + def test_getpass(self, hiden_stdin_mock, stdout_mock, stdin_mock): + prompt = "Type input" + input_text = "user input" + screen = GetPasswordInputScreen(message=prompt) + hiden_stdin_mock.return_value = input_text + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.value, input_text) + + @patch("simpleline.global_configuration.GlobalConfiguration.password_function") + def test_getpass_with_condition(self, hiden_stdin_mock, stdout_mock, stdin_mock): + prompt = "Type input" + wrong_input = "wrong" + condition = lambda x, _: x != wrong_input + hiden_stdin_mock.side_effect = self.input_generator() + + screen = GetPasswordInputScreen(message=prompt) + screen.add_acceptance_condition(condition) + + self.schedule_screen_and_run(screen) + + self.assertTrue(self.correct_input) + + def input_generator(self): + for i in ("wrong", "correct"): + if i == "correct": + self.correct_input = True + yield i + + def acceptance_condition_test(self, user_input, args): + if user_input == args: + self.args_used = True + return True diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/app_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/app_test.py new file mode 100644 index 0000000..02a5ee6 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/app_test.py @@ -0,0 +1,120 @@ +# App class test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from unittest import mock + +from simpleline import App +from simpleline.global_configuration import GlobalConfiguration +from simpleline.input.input_threading import InputThreadManager +from simpleline.render.screen_scheduler import ScreenScheduler +from simpleline.event_loop.main_loop import MainLoop +from simpleline.errors import NothingScheduledError + + +class App_TestCase(unittest.TestCase): + + def test_create_instance(self): + App.initialize() + self.assertTrue(isinstance(App.get_scheduler(), ScreenScheduler)) + self.assertTrue(isinstance(App.get_event_loop(), MainLoop)) + self.assertTrue(isinstance(App.get_configuration(), GlobalConfiguration)) + + def test_create_instance_with_custom_scheduler(self): + App.initialize(scheduler=CustomScreenScheduler(CustomEventLoop())) + self.assertTrue(isinstance(App.get_scheduler(), CustomScreenScheduler)) + + def test_create_instance_with_event_loop(self): + App.initialize(event_loop=CustomEventLoop()) + self.assertTrue(isinstance(App.get_event_loop(), CustomEventLoop)) + + def test_create_instance_with_configuration(self): + App.initialize(global_configuration=CustomGlobalConfiguration()) + self.assertTrue(isinstance(App.get_configuration(), CustomGlobalConfiguration)) + + def test_create_instance_with_custom_everything(self): + event_loop = CustomEventLoop() + App.initialize(event_loop=event_loop, + scheduler=CustomScreenScheduler(event_loop), + global_configuration=CustomGlobalConfiguration()) + + self.assertTrue(isinstance(App.get_event_loop(), CustomEventLoop)) + self.assertTrue(isinstance(App.get_scheduler(), CustomScreenScheduler)) + self.assertTrue(isinstance(App.get_configuration(), CustomGlobalConfiguration)) + + def test_reinitialize(self): + event_loop1 = CustomEventLoop() + event_loop2 = CustomEventLoop() + scheduler1 = CustomScreenScheduler(event_loop1) + scheduler2 = CustomScreenScheduler(event_loop2) + configuration1 = CustomGlobalConfiguration() + configuration2 = CustomGlobalConfiguration() + + App.initialize(event_loop=event_loop1, scheduler=scheduler1, + global_configuration=configuration1) + self._check_app_settings(event_loop1, scheduler1, configuration1) + + App.initialize(event_loop=event_loop2, scheduler=scheduler2, + global_configuration=configuration2) + self._check_app_settings(event_loop2, scheduler2, configuration2) + + App.initialize() + self.assertNotEqual(App.get_event_loop(), event_loop2) + self.assertNotEqual(App.get_scheduler(), scheduler2) + self.assertNotEqual(App.get_configuration(), configuration2) + + def test_input_thread_manager_after_initialize(self): + App.initialize() + + thread_mgr = InputThreadManager.get_instance() + + App.initialize() + + self.assertNotEqual(thread_mgr, InputThreadManager.get_instance()) + + @mock.patch('simpleline.event_loop.main_loop.MainLoop.run') + def test_run_shortcut(self, run_mock): + App.initialize() + App.get_configuration().should_run_with_empty_stack = True + App.run() + self.assertTrue(run_mock.called) + + def test_run_with_empty_screen_stack(self): + App.initialize() + with self.assertRaises(NothingScheduledError): + App.run() + + def _check_app_settings(self, event_loop, scheduler, configuration): + self.assertEqual(App.get_event_loop(), event_loop) + self.assertEqual(App.get_scheduler(), scheduler) + self.assertEqual(App.get_configuration(), configuration) + + +class CustomScreenScheduler(ScreenScheduler): + pass + + +class CustomEventLoop(MainLoop): + pass + + +class CustomGlobalConfiguration(GlobalConfiguration): + pass diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/containers_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/containers_test.py new file mode 100644 index 0000000..0c7d2de --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/containers_test.py @@ -0,0 +1,394 @@ +# Containers test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from io import StringIO +from unittest.mock import patch + +from simpleline import App +from simpleline.render.containers import WindowContainer, ListRowContainer, ListColumnContainer, \ + KeyPattern +from simpleline.render.screen import UIScreen, InputState +from simpleline.render.widgets import TextWidget + +from .widgets_test import BaseWidgets_TestCase + + +class Containers_TestCase(BaseWidgets_TestCase): + + def _test_callback(self, data): + pass + + def test_listrow_container(self): + c = ListRowContainer(columns=2, + items=[self.w2, self.w3, self.w5], + columns_width=10, + spacing=2, + numbering=False) + c.render(25) + + expected_result = [u"Test Test 2", + u"Test 3"] + res_lines = c.get_lines() + + self.evaluate_result(res_lines, expected_result) + + def test_empty(self): + c = ListRowContainer(columns=1) + + c.render(10) + result = c.get_lines() + + self.assertEqual(len(result), 0) + + def test_more_columns_than_widgets(self): + c = ListRowContainer(columns=3, items=[self.w1], columns_width=40, numbering=False) + c.render(80) + + expected_result = [u"Můj krásný dlouhý text"] + + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_listrow_wrapping(self): + # spacing is 3 by default + c = ListRowContainer(2, + [self.w1, self.w2, self.w3, self.w4], + columns_width=15, + numbering=False) + c.render(25) + + expected_result = [u"Můj krásný Test", + u"dlouhý text", + u"Test 2 Krásný dlouhý", + u" text podruhé"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_newline_wrapping(self): + widgets = [TextWidget("Hello"), TextWidget("Wrap\nthis\ntext"), TextWidget("Hi"), + TextWidget("Hello2")] + + c = ListRowContainer(3, widgets, columns_width=6, spacing=1, numbering=False) + c.render(80) + + expected_result = [u"Hello Wrap Hi", + u" this", + u" text", + u"Hello2"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_listcolumn_container(self): + c = ListColumnContainer(columns=2, + items=[self.w2, self.w3, self.w5], + columns_width=10, + spacing=2, + numbering=False) + c.render(25) + + expected_result = [u"Test Test 3", + u"Test 2"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_listcolumn_wrapping(self): + # spacing is 3 by default + c = ListColumnContainer(2, + [self.w1, self.w2, self.w3, self.w4], + columns_width=15, + numbering=False) + c.render(25) + + expected_result = [u"Můj krásný Test 2", + u"dlouhý text", + u"Test Krásný dlouhý", + u" text podruhé"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_add_new_container(self): + c = ListRowContainer(columns=2, + items=[TextWidget("Ahoj")], + columns_width=15, + spacing=0, + numbering=False) + + expected_result = [u"Ahoj"] + + c.render(80) + self.evaluate_result(c.get_lines(), expected_result) + + c.add(TextWidget("Nový widget")) + c.add(TextWidget("Hello")) + + expected_result = [u"Ahoj Nový widget", + u"Hello"] + + c.render(80) + self.evaluate_result(c.get_lines(), expected_result) + + def test_column_numbering(self): + # spacing is 3 by default + c = ListColumnContainer(2, [self.w1, self.w2, self.w3, self.w4], columns_width=16) + c.render(25) + + expected_result = [u"1) Můj krásný 3) Test 2", + u" dlouhý text", + u"2) Test 4) Krásný dlouhý", + u" text podruhé"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_row_numbering(self): + # spacing is 3 by default + c = ListRowContainer(2, [self.w1, self.w2, self.w3, self.w4], columns_width=16) + c.render(25) + + expected_result = [u"1) Můj krásný 2) Test", + u" dlouhý text", + u"3) Test 2 4) Krásný dlouhý", + u" text podruhé"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_custom_numbering(self): + # spacing is 3 by default + c = ListRowContainer(2, [self.w1, self.w2, self.w3, self.w4], columns_width=20) + c.key_pattern = KeyPattern("a {:d} a ") + c.render(25) + + expected_result = [u"a 1 a Můj krásný a 2 a Test", + u" dlouhý text", + u"a 3 a Test 2 a 4 a Krásný dlouhý", + u" text podruhé"] + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_window_container(self): + c = WindowContainer(title="Test") + + c.add(TextWidget("Body")) + c.render(10) + + expected_result = [u"Test", + u"", + u"Body"] + + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_window_container_with_multiple_items(self): + c = WindowContainer(title="Test") + + c.add(TextWidget("Body")) + c.add(TextWidget("Body second line")) + c.render(30) + + expected_result = [u"Test", + u"", + u"Body", + u"Body second line"] + + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_window_container_wrapping(self): + c = WindowContainer(title="Test") + + c.add(TextWidget("Body long line")) + c.add(TextWidget("Body")) + c.render(5) + + expected_result = [u"Test", + u"", + u"Body", + u"long", + u"line", + u"Body"] + + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_list_container_without_width(self): + column_count = 3 + spacing_width = 3 + c = ListRowContainer(column_count, spacing=spacing_width, numbering=False) + + c.add(TextWidget("AAAA")) + c.add(TextWidget("BBBB")) + c.add(TextWidget("CCCCC")) # this line is too long + c.add(TextWidget("DDDD")) + + expected_col_width = 4 + expected_spacing_sum = 2 * spacing_width # three columns so 2 spacing between them + render_width = (column_count * expected_col_width) + expected_spacing_sum + c.render(render_width) + + expected_result = [u"AAAA BBBB CCCC", + u" C", + u"DDDD"] + + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_list_container_too_small(self): + # to be able to render this container we need at least 11 width + # 8 will take only spacing and then 1 for every column + c = ListRowContainer(3, spacing=4, numbering=False) + + c.add(TextWidget("This can't be rendered.")) + c.add(TextWidget("Because spacing takes more space than maximal width.")) + c.add(TextWidget("Exception will raise.")) + + with self.assertRaisesRegex(ValueError, "Columns width is too small."): + c.render(10) + + def test_list_container_too_small_turn_off_numbering(self): + # to be able to render this container we need + # 11 width + three times numbers (3 characters) = 20 + # + # 8 will take only spacing and then 1 for every column + c = ListRowContainer(3, spacing=4, numbering=True) + + c.add(TextWidget("This can't be rendered.")) + c.add(TextWidget("Because spacing takes more space than maximal width.")) + c.add(TextWidget("Exception will raise with info to turn off numbering.")) + + with self.assertRaisesRegex(ValueError, "Increase column width or disable numbering."): + c.render(19) + + +@patch('simpleline.input.input_handler.InputHandlerRequest._get_input') +@patch('sys.stdout', new_callable=StringIO) +class ContainerInput_TestCase(unittest.TestCase): + + def setUp(self): + self._callback_id = None + self._callback_called = None + + def _prepare_callbacks(self, container, count): + for i in range(count): + container.add(TextWidget("Test"), self._callback, i + 1) + + def test_list_widget_input_processing(self, out_mock, in_mock): + # call first container callback + in_mock.return_value = "2" + + screen = ScreenWithListWidget(3) + + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(1, screen.container_callback_input) + + # TEST 0 or less as user input + + def test_list_input_processing_input_0(self, out_mock, in_mock): + c = ListRowContainer(1) + + self._prepare_callbacks(c, 3) + + self.assertFalse(c.process_user_input("0")) + + def test_list_input_processing_negative_number(self, out_mock, in_mock): + c = ListRowContainer(1) + + self._prepare_callbacks(c, 3) + + self.assertFalse(c.process_user_input("-2")) + + def test_list_input_processing_exceeded(self, out_mock, in_mock): + c = ListRowContainer(1) + + self._prepare_callbacks(c, 2) + + self.assertFalse(c.process_user_input("3")) + + def test_list_without_callback(self, out_mock, in_mock): + c = ListRowContainer(1) + + c.add(TextWidget("Test")) + + self.assertTrue(c.process_user_input("1")) + + def test_list_callback_without_data(self, out_mock, in_mock): + c = ListRowContainer(1) + + c.add(TextWidget("Test"), self._callback) + + self.assertTrue(c.process_user_input("1")) + self.assertIsNone(self._callback_called) + + def test_list_correct_input_processing(self, out_mock, in_mock): + c = ListRowContainer(1) + + self._prepare_callbacks(c, 3) + + self.assertTrue(c.process_user_input("2")) + + self.assertEqual(self._callback_called, 2) + + def test_list_wrong_input_processing(self, out_mock, in_mock): + c = ListRowContainer(1) + + self._prepare_callbacks(c, 3) + + self.assertFalse(c.process_user_input("c")) + + def test_list_input_processing_none(self, out_mock, in_mock): + c = ListRowContainer(1) + + self._prepare_callbacks(c, 2) + + self.assertFalse(c.process_user_input(None)) + + def _callback(self, data): + self._callback_called = data + + +class ScreenWithListWidget(UIScreen): + + def __init__(self, widgets_count): + super().__init__() + self._widgets_count = widgets_count + self._list_widget = None + self.container_callback_input = -1 + + def refresh(self, args=None): + super().refresh(args) + + self._list_widget = ListRowContainer(2) + for i in range(self._widgets_count): + self._list_widget.add(TextWidget("Test %s" % i), self._callback, i) + + self.window.add(self._list_widget) + + def input(self, args, key): + self.close() + if self._list_widget.process_user_input(key): + return InputState.PROCESSED + + return InputState.DISCARDED + + def _callback(self, data): + self.container_callback_input = data diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_loop_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_loop_test.py new file mode 100644 index 0000000..92cfec0 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_loop_test.py @@ -0,0 +1,310 @@ +# Event loop test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from simpleline.event_loop import AbstractSignal +from simpleline.event_loop import EventHandler +from simpleline.event_loop import ExitMainLoop +from simpleline.event_loop.main_loop import MainLoop + + +class EventLoopHandler_TestCase(unittest.TestCase): + + def callback_func(self): + pass + + def test_signal_handler_named_params(self): + data = [1, 2, "args"] + ev = EventHandler(callback=self.callback_func, data=data) + + self.assertEqual(ev.callback, self.callback_func) + self.assertEqual(ev.data, data) + + def test_signal_handler_positional_params(self): + data = [1, 3, "args"] + ev = EventHandler(self.callback_func, data) + + self.assertEqual(ev.callback, self.callback_func) + self.assertEqual(ev.data, data) + + +class ProcessEvents_TestCase(unittest.TestCase): + + def setUp(self): + self.signal_counter = 0 + self.signal_counter2 = 0 + self.signal_counter_copied = 0 + self.callback_called = False + self.callback_args = None + self.create_loop() + + def create_loop(self): + self.loop = MainLoop() + + def test_simple_register_handler(self): + self.callback_called = False + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_callback) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + + self.assertTrue(self.callback_called) + + def test_process_more_signals(self): + self.signal_counter = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_signal_counter) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + + self.assertEqual(self.signal_counter, 3) + + def test_process_signals_multiple_times(self): + self.signal_counter = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_signal_counter) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + self.assertEqual(self.signal_counter, 2) + + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + self.assertEqual(self.signal_counter, 4) + + def test_wait_on_signal(self): + self.signal_counter = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, + self._handler_signal_counter) + loop.register_signal_handler(TestSignal2, + self._handler_process_events_then_register_testsignal, + loop) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal2()) + loop.process_signals(return_after=TestSignal2) + self.assertEqual(self.signal_counter, 1) + + loop.process_signals() + self.assertEqual(self.signal_counter, 2) + + def test_wait_on_signal_skipped_by_inner_process_events(self): + self.signal_counter = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, + self._handler_signal_counter) + # run process signals recursively in this handler which will skip processing + loop.register_signal_handler(TestSignal2, + self._handler_process_events_then_register_testsignal, + loop) + loop.enqueue_signal(TestSignal2()) + loop.enqueue_signal(TestSignal()) + # new signal will be registered in handler method but that shouldn't be processed + # because it should end on the first signal even when it was skipped + loop.process_signals(return_after=TestSignal) + + self.assertEqual(self.signal_counter, 1) + + def test_multiple_handlers_to_signal(self): + self.signal_counter = 0 + self.signal_counter2 = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_signal_counter) + loop.register_signal_handler(TestSignal, self._handler_signal_counter2) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + + self.assertEqual(self.signal_counter, 2) + self.assertEqual(self.signal_counter2, 2) + + def test_priority_signal_processing(self): + self.signal_counter = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_signal_counter) + loop.register_signal_handler(TestPrioritySignal, self._handler_signal_counter) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + # should be processed as first signal because of priority + loop.enqueue_signal(TestPrioritySignal()) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + self.assertEqual(self.signal_counter, 1) + + # process rest of the signals + loop.process_signals() + self.assertEqual(self.signal_counter, 4) + + def test_low_priority_signal_processing(self): + self.signal_counter = 0 + self.signal_counter_copied = 0 + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_signal_counter) + loop.register_signal_handler(TestLowPrioritySignal, self._handler_signal_copy_counter) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestLowPrioritySignal()) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal()) + loop.process_signals() + self.assertEqual(self.signal_counter, 3) + + # process the low priority signal + loop.process_signals() + self.assertEqual(self.signal_counter_copied, 3) + + def test_quit_callback(self): + self.callback_called = False + self.callback_args = None + msg = "Test data" + + loop = self.loop + loop.set_quit_callback(self._handler_quit_callback, args=msg) + loop.register_signal_handler(TestSignal, self._handler_raise_ExitMainLoop_exception) + loop.enqueue_signal(TestSignal()) + loop.run() + + self.assertTrue(self.callback_called) + self.assertEqual(msg, self.callback_args) + + def test_force_quit(self): + self.callback_called = False + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_callback) + loop.register_signal_handler(TestSignal2, self._handler_force_quit_exception) + loop.enqueue_signal(TestSignal2()) + loop.enqueue_signal(TestSignal()) + loop.run() + + self.assertFalse(self.callback_called) + + def test_force_quit_recursive_loop(self): + self.callback_called = False + + loop = self.loop + loop.register_signal_handler(TestSignal, + self._handler_start_inner_loop_and_enqueue_event, + TestSignal3()) + loop.register_signal_handler(TestSignal2, + self._handler_callback) + loop.register_signal_handler(TestSignal3, + self._handler_force_quit_exception) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal2()) + loop.run() + + self.assertFalse(self.callback_called) + + def test_force_quit_when_waiting_on_signal(self): + self.callback_called = False + + loop = self.loop + loop.register_signal_handler(TestSignal, self._handler_force_quit_exception) + loop.register_signal_handler(TestSignal2, self._handler_callback) + loop.enqueue_signal(TestSignal()) + loop.enqueue_signal(TestSignal2()) + + # FIXME: Find a better way how to detect infinite loop + # if force quit won't work properly this will hang up + loop.process_signals(return_after=TestSignal3) + + self.assertFalse(self.callback_called) + + # HANDLERS FOR TESTING + def _handler_callback(self, signal, data): + self.callback_called = True + + def _handler_quit_callback(self, args): + self.callback_called = True + self.callback_args = args + + def _handler_signal_counter(self, signal, data): + self.signal_counter += 1 + + def _handler_signal_counter2(self, signal, data): + self.signal_counter2 += 1 + + def _handler_signal_copy_counter(self, signal, data): + self.signal_counter_copied = self.signal_counter + + @staticmethod + def _handler_process_events_then_register_testsignal(signal, data): + event_loop = data + event_loop.process_signals() + # This shouldn't be processed + event_loop.enqueue_signal(TestSignal()) + + def _handler_start_inner_loop_and_enqueue_event(self, signal, data): + self.loop.execute_new_loop(data) + + @staticmethod + def _handler_raise_ExitMainLoop_exception(signal, data): + raise ExitMainLoop() + + def _handler_force_quit_exception(self, signal, data): + self.loop.force_quit() + + +# TESTING EVENTS +class TestSignal(AbstractSignal): + + def __init__(self): + # ignore source + super().__init__(None) + + +class TestSignal2(AbstractSignal): + + def __init__(self): + # ignore source + super().__init__(None) + + +class TestSignal3(AbstractSignal): + + def __init__(self): + # ignore source + super().__init__(None) + + +class TestPrioritySignal(AbstractSignal): + + def __init__(self): + # ignore source + super().__init__(None, -10) + + +class TestLowPrioritySignal(AbstractSignal): + + def __init__(self): + # ignore source + super().__init__(None, 20) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_queue_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_queue_test.py new file mode 100644 index 0000000..7707658 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/event_queue_test.py @@ -0,0 +1,105 @@ +# Event queue test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import unittest + +from unittest.mock import MagicMock + +from simpleline.event_loop.event_queue import EventQueue, EventQueueError +from simpleline.event_loop.signals import AbstractSignal + + +class EventQueue_TestCase(unittest.TestCase): + + def setUp(self): + self.e = EventQueue() + + def test_queue_is_empty(self): + self.assertTrue(self.e.empty()) + + def test_enqueue(self): + fake_signal = MagicMock() + + self.e.enqueue(fake_signal) + self.assertFalse(self.e.empty()) + + self.assertEqual(fake_signal, self.e.get()) + self.assertTrue(self.e.empty()) + + def test_enqueue_priority(self): + signal_low_priority = TestSignal(priority=10) + signal_high_priority = TestSignal(priority=0) + + self.e.enqueue(signal_low_priority) + self.e.enqueue(signal_high_priority) + + self.assertEqual(signal_high_priority, self.e.get()) + self.assertEqual(signal_low_priority, self.e.get()) + + # Test adding signals in different order (result shouldn't change) + self.e.enqueue(signal_high_priority) + self.e.enqueue(signal_low_priority) + + self.assertEqual(signal_high_priority, self.e.get()) + self.assertEqual(signal_low_priority, self.e.get()) + + def test_adding_event_source(self): + fake_source = MagicMock() + self.e.add_source(fake_source) + + self.assertTrue(self.e.contains_source(fake_source)) + + def test_removing_event_source(self): + fake_source = MagicMock() + self.e.add_source(fake_source) + + self.e.remove_source(fake_source) + + self.assertFalse(self.e.contains_source(fake_source)) + + def test_remove_empty_source(self): + with self.assertRaises(EventQueueError): + self.e.remove_source(MagicMock()) + + def test_enqueue_if_source_belongs(self): + source = MagicMock() + signal = TestSignal(source=source) + + self.e.add_source(source) + self.assertTrue(self.e.enqueue_if_source_belongs(signal, source)) + self.assertEqual(signal, self.e.get()) + + def test_enqueue_if_source_does_not_belong(self): + signal = TestSignal() + signal_low_priority = TestSignal(priority=25) + + # the get method will wait if nothing present so adding low priority signal below + # give us check if the queue is really empty + self.e.enqueue(signal_low_priority) + + self.assertFalse(self.e.enqueue_if_source_belongs(signal, MagicMock())) + self.assertEqual(signal_low_priority, self.e.get()) + + +class TestSignal(AbstractSignal): + + def __init__(self, source=None, priority=20): # pylint: disable=useless-super-delegation + super().__init__(source, priority) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/global_configuration_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/global_configuration_test.py new file mode 100644 index 0000000..4af5fad --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/global_configuration_test.py @@ -0,0 +1,84 @@ +# GlobalConfiguration class test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from unittest.mock import MagicMock + +from simpleline import App +from simpleline.global_configuration import DEFAULT_WIDTH, DEFAULT_PASSWORD_FUNC + + +class GlobalConfiguration_TestCase(unittest.TestCase): + + def tearDown(self): + App.initialize() + + def _check_default_width(self, width=DEFAULT_WIDTH): + self.assertEqual(App.get_configuration().width, width) + + def _check_default_password_function(self, password_func=None): + if password_func: + self.assertEqual(App.get_configuration().password_function, password_func) + else: + self.assertEqual(App.get_configuration().password_function, DEFAULT_PASSWORD_FUNC) + + def test_clear_width(self): + self._check_default_width() + + test_width = 150 + + App.get_configuration().width = test_width + self._check_default_width(test_width) + + App.get_configuration().clear_width() + self._check_default_width() + + def test_width(self): + self._check_default_width() + + App.initialize() + App.get_configuration().width = 100 + self._check_default_width(100) + + App.initialize() + self._check_default_width() + + def test_password_function(self): + self._check_default_password_function() + + test_mock = MagicMock() + App.initialize() + App.get_configuration().password_function = test_mock + self._check_default_password_function(test_mock) + + App.initialize() + self._check_default_password_function() + + def test_clear_password_function(self): + self._check_default_password_function() + + test_func = MagicMock() + + App.get_configuration().password_function = test_func + self._check_default_password_function(test_func) + + App.get_configuration().clear_password_function() + self._check_default_password_function() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/input_handler_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/input_handler_test.py new file mode 100644 index 0000000..9e466b1 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/input_handler_test.py @@ -0,0 +1,247 @@ +# Rendering screen test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import unittest + +from unittest.mock import Mock, patch +from threading import Barrier, current_thread, Event + +from io import StringIO + +from simpleline import App +from simpleline.event_loop.main_loop import MainLoop +from simpleline.input.input_handler import InputHandler, PasswordInputHandler +from simpleline.render.prompt import Prompt + + +@patch('sys.stdout', new_callable=StringIO) +@patch('simpleline.input.input_handler.InputHandlerRequest._get_input') +class InputHandler_TestCase(unittest.TestCase): + + def create_loop(self): + self.loop = MainLoop() + + def setUp(self): + super().setUp() + self.create_loop() + App.initialize(event_loop=self.loop) + + self._callback_called = False + self._callback_input = "" + + self._callback_called2 = False + self._callback_input2 = "" + + self._thread_barrier = Barrier(2, timeout=3) + self._thread_event_wait_for_inner = Event() + self._thread_event_wait_for_outer = Event() + self._threads = [] + + def tearDown(self): + super().tearDown() + self._thread_event_wait_for_outer.set() + + for t in self._threads: + t.join() + + # process InputReceivedSignal + App.get_event_loop().process_signals() + # process InputReadySignal + App.get_event_loop().process_signals() + + def test_async_input(self, input_mock, output_mock): + input_mock.return_value = 'a' + + h = InputHandler() + h.get_input(Prompt(message="ABC")) + h.wait_on_input() + + self.assertEqual(h.value, 'a') + + def test_input_received(self, input_mock, output_mock): + input_mock.return_value = 'a' + + h = InputHandler() + + self.assertFalse(h.input_received()) + + h.get_input(Prompt(message="ABC")) + h.wait_on_input() + + self.assertTrue(h.input_received()) + + def test_input_callback(self, input_mock, output_mock): + input_value = 'abc' + input_mock.return_value = input_value + + h = InputHandler() + h.set_callback(self._test_callback) + h.get_input(Prompt(message="ABC")) + h.wait_on_input() + + self.assertTrue(self._callback_called) + self.assertEqual(self._callback_input, input_value) + self.assertEqual(h.value, input_value) + + def test_concurrent_input(self, input_mock, output_mock): + input_mock.side_effect = self._wait_for_concurrent_call + + h = InputHandler() + h.set_callback(self._test_callback) + h2 = InputHandler() + h2.set_callback(self._test_callback2) + + with self.assertRaisesRegex(KeyError, r'.*Input handler:.*InputHandler object' + r'.*Input requester: Unknown' + r'.*Input handler:.*InputHandler object' + r'.*Input requester: Unknown.*'): + h.get_input(Prompt(message="ABC")) + self._thread_event_wait_for_inner.wait() + h2.get_input(Prompt(message="ABC")) + + self.assertFalse(self._callback_called) + self.assertEqual(self._callback_input, "") + self.assertEqual(h.value, None) + + self.assertFalse(self._callback_called2) + self.assertEqual(self._callback_input2, "") + self.assertEqual(h2.value, None) + + def test_concurrent_input_with_source(self, input_mock, output_mock): + input_mock.side_effect = self._wait_for_concurrent_call + source1 = Mock() + source2 = Mock() + + h = InputHandler(source=source1) + h2 = InputHandler(source=source2) + h.set_callback(self._test_callback) + h2.set_callback(self._test_callback2) + + with self.assertRaisesRegex(KeyError, r'.*Input handler:.*InputHandler object' + r'.*Input requester:.*Mock' + r'.*Input handler:.*InputHandler object' + r'.*Input requester:.*Mock.*'): + h.get_input(Prompt(message="ABC")) + self._thread_event_wait_for_inner.wait() + h2.get_input(Prompt(message="ABC")) + + self.assertFalse(self._callback_called) + self.assertEqual(self._callback_input, "") + self.assertEqual(h.value, None) + + self.assertFalse(self._callback_called2) + self.assertEqual(self._callback_input2, "") + self.assertEqual(h2.value, None) + + def test_concurrent_input_without_check(self, input_mock, output_mock): + input_mock.side_effect = self._wait_for_concurrent_call + + h = InputHandler() + h2 = InputHandler() + h.set_callback(self._test_callback) + h2.set_callback(self._test_callback2) + h2.skip_concurrency_check = True + h.skip_concurrency_check = True + + h.get_input(Prompt(message="ABC")) + self._thread_event_wait_for_inner.wait() + h2.get_input(Prompt(message="ABC")) + self._thread_event_wait_for_outer.set() + + h.wait_on_input() + h2.wait_on_input() + + self.assertFalse(self._callback_called) + self.assertFalse(h.input_successful()) + + self.assertTrue(self._callback_called2) + self.assertTrue(h2.input_successful()) + self.assertEqual(self._callback_input2, "thread 0") + self.assertEqual(h2.value, "thread 0") + + def _wait_for_concurrent_call(self): + ret = "thread {}".format(len(self._threads)) + self._threads.append(current_thread()) + self._thread_event_wait_for_inner.set() + self._thread_event_wait_for_outer.wait() + return ret + + def _test_callback(self, user_input): + self._callback_called = True + self._callback_input = user_input + + def _test_callback2(self, user_input): + self._callback_called2 = True + self._callback_input2 = user_input + + +@patch('sys.stdout', new_callable=StringIO) +@patch('simpleline.global_configuration.GlobalConfiguration.password_function') +class PasswordInputHandler_TestCase(unittest.TestCase): + + def create_loop(self): + self.loop = MainLoop() + + def setUp(self): + super().setUp() + self.create_loop() + App.initialize(event_loop=self.loop) + + self._callback_called = False + self._callback_input = "" + + def test_async_input(self, input_mock, output_mock): + input_mock.return_value = 'a' + + h = PasswordInputHandler() + h.get_input(Prompt(message="ABC")) + h.wait_on_input() + + self.assertEqual(h.value, 'a') + + def test_input_received(self, input_mock, output_mock): + input_mock.return_value = 'a' + + h = PasswordInputHandler() + + self.assertFalse(h.input_received()) + + h.get_input(Prompt(message="ABC")) + h.wait_on_input() + + self.assertTrue(h.input_received()) + + def test_input_callback(self, input_mock, output_mock): + input_value = 'abc' + input_mock.return_value = input_value + + h = PasswordInputHandler() + h.set_callback(self._test_callback) + h.get_input(Prompt(message="ABC")) + h.wait_on_input() + + self.assertTrue(self._callback_called) + self.assertEqual(self._callback_input, input_value) + self.assertEqual(h.value, input_value) + + def _test_callback(self, user_input): + self._callback_called = True + self._callback_input = user_input diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/prompt_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/prompt_test.py new file mode 100644 index 0000000..a5751a5 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/prompt_test.py @@ -0,0 +1,135 @@ +# Prompt test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import unittest + +from simpleline.render.prompt import Prompt + + +class Prompt_TestCase(unittest.TestCase): + def test_prompt_message(self): + p = Prompt() + + self.assertEqual(p.message, Prompt.DEFAULT_MESSAGE) + + p.set_message("Brand new message") + self.assertEqual(p.message, "Brand new message") + + p.set_message(u"Žluťoučký kůň") + self.assertEqual(p.message, u"Žluťoučký kůň") + + p2 = Prompt("Default prompt text") + self.assertEqual(p2.message, "Default prompt text") + + def test_add_options(self): + p = Prompt() + + # add new option + p.add_option("R", "refresh") + self.assertTrue("R" in p.options) + self.assertEqual(p.options["R"], "refresh") + + # add option over the existing option should trigger warning message + with self.assertLogs("simpleline", level="WARNING"): + p.add_option("R", "another refresh") + + # update existing option + p.update_option("R", "new refresh option") + self.assertEqual(p.options["R"], "new refresh option") + + # update non existing option should trigger warning + with self.assertLogs("simpleline", level="WARNING"): + p.update_option("N", "non existing option") + + p = Prompt() + p.add_option("N", "new option") + # remove option + ret = p.remove_option("N") + self.assertFalse("N" in p.options) + self.assertEqual(ret, "new option") + + # remove non-existing option + ret = p.remove_option("non-existing") + self.assertIsNone(ret) + + def _check_default_option(self, prompt, key, value): + self.assertEqual(len(prompt.options), 1) + self.assertEqual(prompt.options[key], value) + + def test_refresh_option(self): + # refresh option + p = Prompt() + p.add_refresh_option() + self._check_default_option(p, Prompt.REFRESH, Prompt.REFRESH_DESCRIPTION) + + # test add with description + p = Prompt() + p.add_refresh_option("Other refresh") + self._check_default_option(p, Prompt.REFRESH, "Other refresh") + + # change existing description + p.add_refresh_option("New refresh") + self._check_default_option(p, Prompt.REFRESH, "New refresh") + + def test_continue_option(self): + # continue option + p = Prompt() + p.add_continue_option() + self._check_default_option(p, Prompt.CONTINUE, Prompt.CONTINUE_DESCRIPTION) + + # test add with description + p = Prompt() + p.add_continue_option("Other continue") + self._check_default_option(p, Prompt.CONTINUE, "Other continue") + + # change existing description + p.add_continue_option("New continue") + self._check_default_option(p, Prompt.CONTINUE, "New continue") + + def test_quit_option(self): + # quit option + p = Prompt() + p.add_quit_option() + self._check_default_option(p, Prompt.QUIT, Prompt.QUIT_DESCRIPTION) + + # test add with description + p = Prompt() + p.add_quit_option("Other quit") + self._check_default_option(p, Prompt.QUIT, "Other quit") + + # change existing description + p.add_quit_option("New quit") + self._check_default_option(p, Prompt.QUIT, "New quit") + + def test_help_option(self): + # help option + p = Prompt() + p.add_help_option() + self._check_default_option(p, Prompt.HELP, Prompt.HELP_DESCRIPTION) + + # test add with description + p = Prompt() + p.add_help_option("Other help") + self._check_default_option(p, Prompt.HELP, "Other help") + + # change existing description + p.add_help_option("New help") + self._check_default_option(p, Prompt.HELP, "New help") diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/render_screen_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/render_screen_test.py new file mode 100644 index 0000000..c27a951 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/render_screen_test.py @@ -0,0 +1,564 @@ +# Rendering screen test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import unittest +from io import StringIO +from unittest import mock + +from simpleline import App +from simpleline.render import RenderUnexpectedError +from simpleline.render.screen import UIScreen, InputState + +from .. import UtilityMixin + + +def _fake_input(queue_instance, prompt): + queue_instance.put("a") + + +@mock.patch('sys.stdout', new_callable=StringIO) +class SeparatorPrinting_TestCase(unittest.TestCase, UtilityMixin): + + def setUp(self): + App.initialize() + + def test_separator(self, stdout_mock): + ui_screen = EmptyScreen() + + self.schedule_screen_and_run(ui_screen) + + self.assertEqual(self.calculate_separator(), stdout_mock.getvalue()) + + def test_other_width_separator(self, stdout_mock): + ui_screen = EmptyScreen() + width = 60 + + App.get_configuration().width = width + App.get_scheduler().schedule_screen(ui_screen) + App.run() + + self.assertEqual(self.calculate_separator(width), stdout_mock.getvalue()) + + def test_zero_width_no_separator(self, stdout_mock): + ui_screen = EmptyScreen() + width = 0 + + App.get_configuration().width = width + App.get_scheduler().schedule_screen(ui_screen) + App.run() + + self.assertEqual("\n\n", stdout_mock.getvalue()) + + def test_no_separator_when_screen_setup_fails(self, stdout_mock): + ui_screen = TestScreenSetupFail() + + App.initialize() + App.get_scheduler().schedule_screen(ui_screen) + App.run() + + self.assertEqual("", stdout_mock.getvalue()) + + def test_no_separator(self, stdout_mock): + print_text = "testing" + screen = NoSeparatorScreen(print_text) + + self.schedule_screen_and_run(screen) + self.schedule_screen_and_run(screen) + + expected_output = print_text + "\n" + print_text + "\n" + + self.assertEqual(expected_output, stdout_mock.getvalue()) + + +class SimpleUIScreenFeatures_TestCase(unittest.TestCase): + + def test_close_screen(self): + screen = UIScreen() + + App.initialize() + App.get_scheduler().schedule_screen(screen) + # Program will quit in close_screen when stack is empty + App.get_scheduler().schedule_screen(UIScreen()) + screen.close() + + def test_close_screen_closed_from_other_source_error(self): + App.initialize() + App.get_scheduler().schedule_screen(UIScreen()) + with self.assertRaises(RenderUnexpectedError): + App.get_scheduler().close_screen(closed_from=mock.MagicMock()) + + def test_failed_screen_setup(self): + screen = FailedSetupScreen() + + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() + + +@mock.patch('sys.stdout', new_callable=StringIO) +class SimpleUIScreenProcessing_TestCase(unittest.TestCase, UtilityMixin): + + def setUp(self): + self._default_separator = self.calculate_separator(80) + + def test_screen_event_loop_processing(self, _): + ui_screen = EmptyScreen() + + self.schedule_screen_and_run(ui_screen) + + self.assertTrue(ui_screen.is_closed) + + def test_running_empty_loop(self, _): + App.initialize() + loop = App.get_event_loop() + loop.process_signals() + + def test_screen_event_loop_processing_with_two_screens(self, _): + first_screen = EmptyScreen() + screen = EmptyScreen() + + App.initialize() + App.get_scheduler().schedule_screen(first_screen) + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(first_screen) + self.assertTrue(screen) + + def test_screen_title_rendering(self, stdout_mock): + screen = NoInputScreen() + screen.title = u"TestTitle" + + self.schedule_screen_and_run(screen) + + out = self._default_separator + out += "TestTitle\n\n" + self.assertEqual(stdout_mock.getvalue(), out) + + +@mock.patch('sys.stdout', new_callable=StringIO) +@mock.patch('simpleline.event_loop.AbstractEventLoop.kill_app_with_traceback') +class ScreenException_TestCase(unittest.TestCase, UtilityMixin): + + def setUp(self): + self._force_quit_called = False + + # The original method calls sys.exit(1) so we don't need to test this functionality + def force_quit_mock(self, signal, data=None): + self._force_quit_called = True + loop = App.get_event_loop() + loop.force_quit() + + def test_raise_exception_in_refresh(self, mock_kill_app, _): + screen = ExceptionTestScreen(ExceptionTestScreen.REFRESH) + mock_kill_app.side_effect = self.force_quit_mock + + self.schedule_screen_and_run(screen) + self.assertTrue(self._force_quit_called) + + def test_raise_exception_in_rendering(self, mock_kill_app, _): + screen = ExceptionTestScreen(ExceptionTestScreen.REDRAW) + mock_kill_app.side_effect = self.force_quit_mock + + self.schedule_screen_and_run(screen) + self.assertTrue(self._force_quit_called) + + +@mock.patch('sys.stdout', new_callable=StringIO) +@mock.patch('simpleline.input.input_handler.InputHandlerRequest._get_input') +class InputProcessing_TestCase(unittest.TestCase): + + def setUp(self): + App.initialize() + + def test_basic_input(self, input_mock, mock_stdout): + input_mock.return_value = "a" + screen = InputScreen() + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(screen.input_processed) + + def test_process_input_and_redraw(self, input_mock, mock_stdout): + input_mock.return_value = "a" + screen = InputStateRedrawScreen() + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(screen.refreshed) + + def test_process_input_and_close(self, input_mock, mock_stdout): + input_mock.return_value = "a" + screen = InputStateCloseScreen() + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(screen.input_processed) + + def test_quit_input(self, mock_stdin, mock_stdout): + mock_stdin.return_value = "q" + screen = UIScreen() + + App.get_scheduler().schedule_screen(screen) + App.run() + + def test_continue_input(self, mock_stdin, mock_stdout): + mock_stdin.return_value = "c" + screen = UIScreen() + screen2 = EmptyScreen() + + App.get_scheduler().schedule_screen(screen) + App.get_scheduler().schedule_screen(screen2) + App.run() + + self.assertTrue(screen.screen_ready) + self.assertTrue(screen.screen_ready) + + def test_refresh_input(self, mock_stdin, mock_stdout): + mock_stdin.return_value = "r" + screen = RefreshTestScreen() + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(screen.input_processed) + + def test_refresh_on_input_error(self, mock_stdin, mock_stdout): + mock_stdin.return_value = "q" + threshold = 5 + screen = InputErrorTestScreen(threshold) + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(screen.render_counter, 2) + self.assertEqual(screen.error_counter, threshold) + + def test_multiple_refresh_on_input_error(self, mock_stdin, mock_stdout): + mock_stdin.return_value = "q" + threshold = 12 + screen = InputErrorTestScreen(threshold) + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(screen.render_counter, 3) + self.assertEqual(screen.error_counter, threshold) + + def test_no_refresh_when_prompt_is_none(self, mock_stdin, mock_stdout): + mock_stdin.return_value = "q" + threshold = 5 + screen = InputErrorDynamicPromptTestScreen(threshold, not_return_prompt_on=3) + + App.get_scheduler().schedule_screen(screen) + App.run() + + # first draw and manual redraw when prompt is None + self.assertEqual(screen.render_counter, 2) + self.assertTrue(screen.input_skipped) + self.assertEqual(screen.error_counter, threshold) + + def test_input_no_prompt(self, mock_stdin, mock_stdout): + screen = InputWithNoPrompt() + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(screen.prompt_entered) + + @mock.patch('simpleline.event_loop.main_loop.MainLoop.process_signals') + def test_custom_getpass(self, mock_stdin, mock_stdout, process_signals): + prompt = mock.MagicMock() + ret = "test" + screen = TestScreenWithPassFunc(prompt, ret) + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertTrue(screen.pass_called) + self.assertEqual(screen.pass_prompt.rstrip(), str(prompt)) + + def test_blocking_input(self, mock_stdin, mock_stdout): + prompt_message = "test prompt" + ret = "blocking test" + mock_stdin.return_value = ret + screen = BlockingInputTestScreen(prompt_message, False) + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(screen.input_returned, ret) + + out = mock_stdout.getvalue() + out = out.split("\n")[-1].strip() + self.assertEqual(out, prompt_message) + + @mock.patch('simpleline.global_configuration.GlobalConfiguration.password_function') + def test_blocking_password_input(self, mock_getpass, mock_stdin, mock_stdout): + prompt_message = "test prompt" + ret = "blocking test" + mock_getpass.return_value = ret + screen = BlockingInputTestScreen(prompt_message, True) + + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(screen.input_returned, ret) + + out = mock_stdout.getvalue() + # can't check for prompt because that is printed by getpass func which is mocked + self.assertGreater(len(out), 1) + + +# HELPER CLASSES + +class EmptyScreen(UIScreen): + + def __init__(self): + super().__init__() + self.is_closed = False + EmptyScreen.title = "" + self.input_required = False + + def show_all(self): + self.close() + + def closed(self): + self.is_closed = True + + +class TestScreenSetupFail(UIScreen): + + def __init__(self): + super().__init__() + self.input_required = False + + def setup(self, args): + super().setup(args) + return False + + +class TestScreenWithPassFunc(UIScreen): + + def __init__(self, prompt, return_value): + super().__init__() + self.pass_prompt = "" + self.pass_called = False + self.password_func = self._test_getpass + self.hide_user_input = True + self._prompt = prompt + self._return_value = return_value + + def prompt(self, args=None): + return self._prompt + + def _test_getpass(self, prompt): + self.pass_prompt = prompt + self.pass_called = True + return self._return_value + + def input(self, args, key): + return InputState.PROCESSED_AND_CLOSE + + +class InputErrorTestScreen(UIScreen): + + def __init__(self, error_threshold=5): + super().__init__() + self.error_counter = 0 + self.render_counter = 0 + self._error_threshold = error_threshold + + def input(self, args, key): + if self.error_counter == self._error_threshold: + # let "q" propagate to quit + return key + + self.error_counter += 1 + return InputState.DISCARDED + + def show_all(self): + self.render_counter += 1 + + +class InputErrorDynamicPromptTestScreen(InputErrorTestScreen): + + def __init__(self, error_threshold=5, not_return_prompt_on=2): + super().__init__(error_threshold=error_threshold) + self._not_return_prompt_on = not_return_prompt_on + self.input_skipped = False + + def prompt(self, args=None): + if self.error_counter == self._not_return_prompt_on and not self.input_skipped: + self.input_skipped = True + self.redraw() + return None + + return super().prompt(args) + + +class InputWithNoPrompt(UIScreen): + + def __init__(self): + super().__init__() + self.prompt_entered = False + self.input_required = True + + def prompt(self, args=None): + self.prompt_entered = True + self.close() + # do not process input - it was processed here by user + return None + + +class RefreshTestScreen(UIScreen): + + def __init__(self): + super().__init__() + self.input_processed = False + + def input(self, args, key): + self.input_processed = True + return key + + def refresh(self, args=None): + super().refresh(args) + if self.input_processed: + self.close() + self.input_required = False + return + + +class FailedSetupScreen(UIScreen): + + def setup(self, args): + super().setup(args) + return False + + +class NoSeparatorScreen(UIScreen): + + def __init__(self, print_string): + super().__init__() + self.input_required = False + self.no_separator = True + self._print_string = print_string + + def show_all(self): + print(self._print_string) + self.close() + + +class NoInputScreen(UIScreen): + + def __init__(self): + super().__init__() + self.input_required = False + + def show_all(self): + super().show_all() + self.close() + + +class InputScreen(UIScreen): + + def __init__(self): + super().__init__() + self.input_processed = False + + def input(self, args, key): + if key == "a": + self.input_processed = True + self.close() + return InputState.PROCESSED + + +class InputStateCloseScreen(UIScreen): + + def __init__(self): + super().__init__() + self.input_processed = False + + def input(self, args, key): + self.input_processed = not self.input_processed + return InputState.PROCESSED_AND_CLOSE + + +class InputStateRedrawScreen(UIScreen): + + def __init__(self): + super().__init__() + self._refreshing = False + self.refreshed = False + + def input(self, args, key): + if not self._refreshing: + self._refreshing = True + return InputState.PROCESSED_AND_REDRAW + + self.refreshed = True + return InputState.PROCESSED_AND_CLOSE + + +class ExceptionTestScreen(UIScreen): + """Raising an exception in some place of processing.""" + + REFRESH = 0 + REDRAW = 1 + + def __init__(self, where): + super().__init__() + self._where = where + self.input_required = False + + def refresh(self, args=None): + super().refresh() + if self._where == self.REFRESH: + raise TestRefreshException("Refresh test exception happened!") + + def show_all(self): + super().show_all() + if self._where == self.REDRAW: + raise TestRedrawException("Redraw test exception happened!") + + +class BlockingInputTestScreen(EmptyScreen): + + def __init__(self, prompt_message, hidden): + super().__init__() + self._prompt_message = prompt_message + self._hidden = hidden + self.input_returned = None + + def show_all(self): + self.input_returned = self.get_user_input(self._prompt_message, self._hidden) + super().show_all() + + +class TestRefreshException(Exception): + pass + + +class TestRedrawException(Exception): + pass diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/scheduler_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/scheduler_test.py new file mode 100644 index 0000000..bd4837b --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/scheduler_test.py @@ -0,0 +1,181 @@ +# Screen scheduler test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + +import unittest + +from unittest import mock + +from simpleline.event_loop.main_loop import MainLoop +from simpleline.render.screen import UIScreen +from simpleline.render.screen_scheduler import ScreenScheduler +from simpleline.render.screen_stack import ScreenStack, ScreenStackEmptyException + + +class Scheduler_TestCase(unittest.TestCase): + + def setUp(self): + self.stack = None + self.scheduler = None + + def create_scheduler_with_stack(self): + self.stack = ScreenStack() + self.scheduler = ScreenScheduler(event_loop=mock.MagicMock(), scheduler_stack=self.stack) + + def pop_last_item(self, remove=True): + return self.stack.pop(remove) + + def test_create_scheduler(self): + scheduler = ScreenScheduler(MainLoop()) + self.assertTrue(isinstance(scheduler._screen_stack, ScreenStack)) # pylint: disable=protected-access + + def test_scheduler_quit_screen(self): + def test_callback(): + pass + scheduler = ScreenScheduler(MainLoop()) + self.assertEqual(scheduler.quit_screen, None) + scheduler.quit_screen = test_callback + self.assertEqual(scheduler.quit_screen, test_callback) + + def test_nothing_to_render(self): + self.create_scheduler_with_stack() + + self.assertTrue(self.scheduler.nothing_to_render) + self.assertTrue(self.stack.empty()) + + self.scheduler.schedule_screen(UIScreen()) + self.assertFalse(self.scheduler.nothing_to_render) + self.assertFalse(self.stack.empty()) + + def test_schedule_screen(self): + self.create_scheduler_with_stack() + + screen = UIScreen() + self.scheduler.schedule_screen(screen) + test_screen = self.pop_last_item(False) + self.assertEqual(test_screen.ui_screen, screen) + self.assertEqual(test_screen.args, None) # empty field - no arguments + self.assertFalse(test_screen.execute_new_loop) + + # Schedule another screen, new one will be added to the bottom of the stack + new_screen = UIScreen() + self.scheduler.schedule_screen(new_screen) + # Here should still be the old screen + self.assertEqual(self.pop_last_item().ui_screen, screen) + # After removing the first we would find the second screen + self.assertEqual(self.pop_last_item().ui_screen, new_screen) + + def test_replace_screen_with_empty_stack(self): + self.create_scheduler_with_stack() + + with self.assertRaises(ScreenStackEmptyException): + self.scheduler.replace_screen(UIScreen()) + + def test_replace_screen(self): + self.create_scheduler_with_stack() + + old_screen = UIScreen() + screen = UIScreen() + self.scheduler.schedule_screen(old_screen) + self.scheduler.replace_screen(screen) + self.assertEqual(self.pop_last_item(False).ui_screen, screen) + + new_screen = UIScreen() + self.scheduler.replace_screen(new_screen) + self.assertEqual(self.pop_last_item().ui_screen, new_screen) + # The old_screen was replaced so the stack is empty now + self.assertTrue(self.stack.empty()) + + def test_replace_screen_with_args(self): + self.create_scheduler_with_stack() + + old_screen = UIScreen() + screen = UIScreen() + self.scheduler.schedule_screen(old_screen) + self.scheduler.replace_screen(screen, "test") + test_screen = self.pop_last_item() + self.assertEqual(test_screen.ui_screen, screen) + self.assertEqual(test_screen.args, "test") + # The old_screen was replaced so the stack is empty now + self.assertTrue(self.stack.empty()) + + def test_switch_screen_with_empty_stack(self): + self.create_scheduler_with_stack() + + screen = UIScreen() + self.scheduler.push_screen(screen) + self.assertEqual(self.pop_last_item().ui_screen, screen) + + def test_switch_screen(self): + self.create_scheduler_with_stack() + + screen = UIScreen() + new_screen = UIScreen() + + self.scheduler.schedule_screen(screen) + self.scheduler.push_screen(new_screen) + + test_screen = self.pop_last_item() + self.assertEqual(test_screen.ui_screen, new_screen) + self.assertEqual(test_screen.args, None) + self.assertEqual(test_screen.execute_new_loop, False) + + # We popped the new_screen so the old screen should stay here + self.assertEqual(self.pop_last_item().ui_screen, screen) + self.assertTrue(self.stack.empty()) + + def test_switch_screen_with_args(self): + self.create_scheduler_with_stack() + + screen = UIScreen() + self.scheduler.push_screen(screen, args="test") + self.assertEqual(self.pop_last_item(False).ui_screen, screen) + self.assertEqual(self.pop_last_item().args, "test") + + @mock.patch('simpleline.render.screen_scheduler.ScreenScheduler._draw_screen') + def test_switch_screen_modal_empty_stack(self, _): + self.create_scheduler_with_stack() + + screen = UIScreen() + self.scheduler.push_screen_modal(screen) + self.assertEqual(self.pop_last_item().ui_screen, screen) + + @mock.patch('simpleline.render.screen_scheduler.ScreenScheduler._draw_screen') + def test_switch_screen_modal(self, _): + self.create_scheduler_with_stack() + + screen = UIScreen() + new_screen = UIScreen() + self.scheduler.schedule_screen(screen) + self.scheduler.push_screen_modal(new_screen) + + test_screen = self.pop_last_item() + self.assertEqual(test_screen.ui_screen, new_screen) + self.assertEqual(test_screen.args, None) + self.assertEqual(test_screen.execute_new_loop, True) + + @mock.patch('simpleline.render.screen_scheduler.ScreenScheduler._draw_screen') + def test_switch_screen_modal_with_args(self, _): + self.create_scheduler_with_stack() + + screen = UIScreen() + self.scheduler.push_screen_modal(screen, args="test") + self.assertEqual(self.pop_last_item(False).ui_screen, screen) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_scheduler_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_scheduler_test.py new file mode 100644 index 0000000..b4f3c48 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_scheduler_test.py @@ -0,0 +1,207 @@ +# Screen scheduling test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from io import StringIO +from unittest import mock + +from simpleline.render.screen import UIScreen +from simpleline.render.screen_handler import ScreenHandler + +from .. import UtilityMixin + + +@mock.patch('sys.stdout', new_callable=StringIO) +class ScreenScheduler_TestCase(unittest.TestCase, UtilityMixin): + + def test_replace_screen(self, _): + replace_screen = ShowedCounterScreen() + screen = ShowedCounterScreen(replace_screen=replace_screen) + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.counter, 1) + self.assertEqual(replace_screen.counter, 1) + + def test_switch_screen(self, _): + switched_screen = ShowedCounterScreen() + screen = ShowedCounterScreen(switched_screen) + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.counter, 2) + self.assertEqual(switched_screen.counter, 1) + + def test_switch_screen_modal_in_render(self, _): + modal_screen = ModalTestScreen() + screen = ModalTestScreen(modal_screen_render=modal_screen) + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.copied_modal_counter, ModalTestScreen.AFTER_MODAL_RENDER) + self.assertEqual(modal_screen.copied_modal_counter, ModalTestScreen.BEFORE_MODAL_RENDER) + + def test_switch_screen_modal_in_refresh(self, _): + modal_screen = ModalTestScreen() + screen = ModalTestScreen(modal_screen_refresh=modal_screen) + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.copied_modal_counter, ModalTestScreen.AFTER_MODAL_REFRESH) + self.assertEqual(modal_screen.copied_modal_counter, ModalTestScreen.BEFORE_MODAL_REFRESH) + + def test_switch_screen_modal_refresh_and_render(self, _): + modal_refresh = ModalTestScreen() + modal_render = ModalTestScreen() + screen = ModalTestScreen(modal_screen_refresh=modal_refresh, + modal_screen_render=modal_render) + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.copied_modal_counter, ModalTestScreen.AFTER_MODAL_RENDER) + self.assertEqual(modal_refresh.copied_modal_counter, ModalTestScreen.BEFORE_MODAL_REFRESH) + self.assertEqual(modal_render.copied_modal_counter, ModalTestScreen.BEFORE_MODAL_RENDER) + + def test_switch_screen_modal_render_recursive(self, _): + modal_render_inner = ModalTestScreen() + modal_render_outer = ModalTestScreen(modal_screen_render=modal_render_inner) + screen = ModalTestScreen(modal_screen_render=modal_render_outer) + + self.schedule_screen_and_run(screen) + + self.assertEqual(screen.copied_modal_counter, ModalTestScreen.AFTER_MODAL_RENDER) + # outer modal screen has AFTER_MODAL_RENDER because it was set before by inner loop + self.assertEqual(modal_render_outer.copied_modal_counter, + ModalTestScreen.AFTER_MODAL_RENDER) + self.assertEqual(modal_render_inner.copied_modal_counter, + ModalTestScreen.BEFORE_MODAL_RENDER) + + @mock.patch('simpleline.input.input_handler.InputHandlerRequest._get_input') + def test_switch_screen_modal_input_order(self, mock_input, mock_stdout): + modal_screen = InputAndDrawScreen("Modal") + parent_screen = EmitDrawThenCreateModal(modal_screen, msg="Parent") + mock_input.return_value = "c" + expected = ["Modal", # modal needs to be printed first + "Parent", # draw enqueued draw signal -- manually registered in refresh() + "Parent"] # draw because modal screen was closed + + self.schedule_screen_and_run(parent_screen) + + self.maxDiff = None + self.assertEqual(self.create_output_with_separators(expected), mock_stdout.getvalue()) + + +class ShowedCounterScreen(UIScreen): + + def __init__(self, switch_to_screen=None, replace_screen=None): + super().__init__() + self._switch_to_screen = switch_to_screen + self._replace_screen = replace_screen + self.counter = 0 + self.input_required = False + + def show_all(self): + super().show_all() + self.counter += 1 + if self._switch_to_screen is not None: + ScreenHandler.push_screen(self._switch_to_screen) + self._switch_to_screen = None + elif self._replace_screen is not None: + ScreenHandler.replace_screen(self._replace_screen) + self._replace_screen = None + else: + self.close() + + +class ModalTestScreen(UIScreen): + """Test if the modal screen is really modal and stops the execution in a place where + we start the modal screen. + + This class have checkpoints which increment class variable counter. This counter is + copied in the modal instance to the local variable self.copied_modal_counter. + In the end we should check if the instance modal counter have the correct value, which is + before the modal screen was started (1). + """ + + INIT = 0 + BEFORE_MODAL_REFRESH = 1 + AFTER_MODAL_REFRESH = 2 + BEFORE_MODAL_RENDER = 3 + AFTER_MODAL_RENDER = 4 + + modal_counter = 0 + + def __init__(self, modal_screen_render=None, modal_screen_refresh=None): + super().__init__() + self._modal_screen_render = modal_screen_render + self._modal_screen_refresh = modal_screen_refresh + self.copied_modal_counter = 0 + self.input_required = False + ModalTestScreen.modal_counter = self.INIT + + def refresh(self, args=None): + super().refresh(args) + if self._modal_screen_refresh is not None: + # Start a new modal screen + ModalTestScreen.modal_counter = self.BEFORE_MODAL_REFRESH + ScreenHandler.push_screen_modal(self._modal_screen_refresh) + ModalTestScreen.modal_counter = self.AFTER_MODAL_REFRESH + + def show_all(self): + super().show_all() + if self._modal_screen_render is not None: + # Start new modal screen + ModalTestScreen.modal_counter = self.BEFORE_MODAL_RENDER + ScreenHandler.push_screen_modal(self._modal_screen_render) + ModalTestScreen.modal_counter = self.AFTER_MODAL_RENDER + + self.copied_modal_counter = ModalTestScreen.modal_counter + self.close() + + +class EmitDrawThenCreateModal(UIScreen): + + def __init__(self, refresh_screen, msg): + super().__init__() + self._refresh_screen = refresh_screen + self.title = msg + self.input_required = False + + def refresh(self, args=None): + super().refresh(args) + if self._refresh_screen: + self.redraw() + ScreenHandler.push_screen_modal(self._refresh_screen) + self._refresh_screen = None + else: + self.close() + + +class InputAndDrawScreen(UIScreen): + + def __init__(self, msg): + super().__init__() + self.title = msg + self.input_required = False + + def refresh(self, args=None): + super().refresh(args) + self.close() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_stack_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_stack_test.py new file mode 100644 index 0000000..a5012f3 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/screen_stack_test.py @@ -0,0 +1,162 @@ +# Screen stack test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# +# Author(s): Jiri Konecny +# + + +import unittest + +from simpleline.render.screen import UIScreen +from simpleline.render.screen_stack import ScreenStack, ScreenData, ScreenStackEmptyException + + +class ScreenStack_TestCase(unittest.TestCase): + + def test_append_screen(self): + stack = ScreenStack() + stack.append(ScreenData(None)) + + def test_is_empty(self): + stack = ScreenStack() + self.assertTrue(stack.empty()) + stack.append(ScreenData(None)) + self.assertFalse(stack.empty()) + + def test_pop(self): + stack = ScreenStack() + with self.assertRaises(ScreenStackEmptyException): + stack.pop() + + with self.assertRaises(ScreenStackEmptyException): + stack.pop(False) + + # stack.pop(True) will remove the item + stack.append(ScreenData(None)) + stack.pop(True) + with self.assertRaises(ScreenStackEmptyException): + stack.pop() + + # stack.pop() should behave the same as stack.pop(True) + stack.append(ScreenData(None)) + stack.pop() + with self.assertRaises(ScreenStackEmptyException): + stack.pop() + + stack.append(ScreenData(None)) + stack.pop(False) + stack.pop(True) + + def test_add_first(self): + stack = ScreenStack() + + screen_data = ScreenData(None) + stack.add_first(screen_data) + self.assertEqual(stack.pop(False), screen_data) + + # Add new Screen data to the end + new_screen_data = ScreenData(None) + stack.add_first(new_screen_data) + # First the old screen data should be there + self.assertEqual(stack.pop(), screen_data) + # Second should be the new screen data + self.assertEqual(stack.pop(), new_screen_data) + + def test_size(self): + stack = ScreenStack() + self.assertEqual(stack.size(), 0) + + stack.append(ScreenData(None)) + self.assertEqual(stack.size(), 1) + + stack.append(ScreenData(None)) + self.assertEqual(stack.size(), 2) + + # Remove from stack + stack.pop() + self.assertEqual(stack.size(), 1) + stack.pop() + self.assertEqual(stack.size(), 0) + + # Add first when stack has items + stack.append(ScreenData(None)) + stack.append(ScreenData(None)) + self.assertEqual(stack.size(), 2) + stack.add_first(ScreenData(None)) + self.assertEqual(stack.size(), 3) + + def test_stack_dump(self): + stack = ScreenStack() + + stack.append(ScreenData(TestScreen1())) + stack.append(ScreenData(TestScreen2())) + + dump = stack.dump_stack() + dump = dump.replace('\n', '') + self.assertRegex(dump, r"TestScreen2.*TestScreen1") + + +class ScreenData_TestCase(unittest.TestCase): + + def setUp(self): + self.ui_screen = None + + def _prepare(self): + self.ui_screen = UIScreen() + + def _screen_check(self, test_screen, ui_screen, args, execute_new_loop): + self._prepare() + self.assertEqual(test_screen.ui_screen, ui_screen) + self.assertEqual(test_screen.args, args) + self.assertEqual(test_screen.execute_new_loop, execute_new_loop) + + def test_screen_data(self): + self._prepare() + screen = ScreenData(self.ui_screen) + self._screen_check(screen, self.ui_screen, None, False) + + def test_screen_data_with_args(self): + self._prepare() + screen = ScreenData(ui_screen=self.ui_screen, args=1) + self._screen_check(screen, self.ui_screen, 1, False) + + array = [2, "a"] + screen2 = ScreenData(ui_screen=self.ui_screen, args=array) + self._screen_check(screen2, self.ui_screen, array, False) + + def test_screen_data_with_execute_loop(self): + self._prepare() + screen = ScreenData(self.ui_screen, execute_new_loop=True) + self._screen_check(screen, self.ui_screen, None, True) + + screen2 = ScreenData(self.ui_screen, execute_new_loop=False) + self._screen_check(screen2, self.ui_screen, None, False) + + def test_screen_data_with_args_and_execute_loop(self): + self._prepare() + screen = ScreenData(self.ui_screen, "test", True) + self._screen_check(screen, self.ui_screen, "test", True) + + +class TestScreen1(UIScreen): + pass + + +class TestScreen2(UIScreen): + pass diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/signal_handler_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/signal_handler_test.py new file mode 100644 index 0000000..e03187c --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/signal_handler_test.py @@ -0,0 +1,113 @@ +# Signal handler test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + + +import unittest + +from unittest.mock import patch, MagicMock + +from simpleline import App +from simpleline.event_loop.signals import RenderScreenSignal, AbstractSignal +from simpleline.render.screen import UIScreen + + +class SignalHandler_TestCase(unittest.TestCase): + + def setUp(self): + self.callback_called = False + self.priority = 0 + + def _callback(self, signal, data): + self.callback_called = True + signal.test_attribute = True + + def test_basic_connect(self): + connect_screen = UIScreen() + + App.initialize(scheduler=MagicMock()) + connect_screen.connect(TestSignal, self._callback) + App.get_event_loop().enqueue_signal(TestSignal(self)) + App.get_event_loop().process_signals() + + self.assertTrue(self.callback_called) + + def test_create_signal(self): + connect_screen = UIScreen() + + App.initialize(scheduler=MagicMock()) + signal = connect_screen.create_signal(TestSignal, priority=20) + + self.assertEqual(signal.priority, 20) + self.assertTrue(isinstance(signal, TestSignal)) + # source is set by create_signal + self.assertEqual(signal.source, connect_screen) + + def test_emit(self): + connect_screen = UIScreen() + + App.initialize(scheduler=MagicMock()) + connect_screen.connect(TestSignal, self._callback) + connect_screen.emit(TestSignal(self)) + App.get_event_loop().process_signals() + + self.assertTrue(self.callback_called) + + @patch('sys.stdout') + def test_connect_react_on_rendering(self, _): + connect_test_screen = TestRenderConnectHandler() + screen2 = EmptyScreen() + + App.initialize() + App.get_scheduler().schedule_screen(connect_test_screen) + App.get_scheduler().schedule_screen(screen2) + App.run() + + self.assertTrue(connect_test_screen.callback_called) + + +class TestRenderConnectHandler(UIScreen): + + def __init__(self): + super().__init__() + self.callback_called = False + self.input_required = False + + def refresh(self, args=None): + super().refresh(args) + self.connect(RenderScreenSignal, self._callback) + self.close() + + def _callback(self, signal, args): + self.callback_called = True + + +class EmptyScreen(UIScreen): + + def __init__(self): + super().__init__() + self.input_required = False + + def show_all(self): + super().show_all() + self.close() + + +class TestSignal(AbstractSignal): + pass diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/ticket_machine_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/ticket_machine_test.py new file mode 100644 index 0000000..7f45a22 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/ticket_machine_test.py @@ -0,0 +1,106 @@ +# Widgets test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +from unittest import TestCase + +from simpleline.event_loop.ticket_machine import TicketMachine + + +class TicketMachine_TestCase(TestCase): + + def setUp(self): + self._tickets = TicketMachine() + + def test_take_ticket(self): + line_id = 0 + t = self._tickets.take_ticket(line_id) + self.assertEqual(t, 0) + t2 = self._tickets.take_ticket(line_id) + self.assertNotEqual(t, t2) + + def test_check_ticket(self): + line_id = 0 + t = self._tickets.take_ticket(line_id) + + self.assertFalse(self._tickets.check_ticket(line_id, t)) + + self._tickets.mark_line_to_go(line_id) + + self.assertTrue(self._tickets.check_ticket(line_id, t)) + + def test_mark_multiple_tickets(self): + line_id = 0 + + t1 = self._tickets.take_ticket(line_id) + t2 = self._tickets.take_ticket(line_id) + t3 = self._tickets.take_ticket(line_id) + t4 = self._tickets.take_ticket(line_id) + + self._tickets.mark_line_to_go(line_id) + self.assertTrue(self._tickets.check_ticket(line_id, t1)) + self.assertTrue(self._tickets.check_ticket(line_id, t2)) + self.assertTrue(self._tickets.check_ticket(line_id, t3)) + self.assertTrue(self._tickets.check_ticket(line_id, t4)) + + def test_mark_one_of_lines(self): + line_id1 = "a" + line_id2 = "b" + + t1 = self._tickets.take_ticket(line_id1) + t2 = self._tickets.take_ticket(line_id1) + t3 = self._tickets.take_ticket(line_id2) + t4 = self._tickets.take_ticket(line_id2) + + self._tickets.mark_line_to_go(line_id1) + + self.assertTrue(self._tickets.check_ticket(line_id1, t1)) + self.assertTrue(self._tickets.check_ticket(line_id1, t2)) + self.assertFalse(self._tickets.check_ticket(line_id2, t3)) + self.assertFalse(self._tickets.check_ticket(line_id2, t4)) + + def text_check_re_using(self): + line_id = "a" + + t1 = self._tickets.take_ticket(line_id) + t2 = self._tickets.take_ticket(line_id) + t3 = self._tickets.take_ticket(line_id) + + self._tickets.mark_line_to_go(line_id) + + self.assertTrue(self._tickets.check_ticket(line_id, t1)) + self.assertTrue(self._tickets.check_ticket(line_id, t2)) + + # it needs to be False when you check it again + self.assertFalse(self._tickets.check_ticket(line_id, t1)) + self.assertFalse(self._tickets.check_ticket(line_id, t2)) + + # take new ticket and mark the line again + + t4 = self._tickets.take_ticket(line_id) + + self._tickets.mark_line_to_go(line_id) + + # old checked tickets should be invalid now + self.assertFalse(self._tickets.check_ticket(line_id, t1)) + self.assertFalse(self._tickets.check_ticket(line_id, t2)) + # old not checked ticket should work + self.assertTrue(self._tickets.check_ticket(line_id, t3)) + # new tickets should work + self.assertTrue(self._tickets.check_ticket(line_id, t4)) diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/widgets_test.py b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/widgets_test.py new file mode 100644 index 0000000..fedb7c8 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/main/widgets_test.py @@ -0,0 +1,335 @@ +# Widgets test classes. +# +# This file is part of Simpleline Text UI library. +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Simpleline is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Simpleline is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Simpleline. If not, see . +# + +import unittest + +from io import StringIO +from unittest.mock import patch + +from simpleline import App +from simpleline.render.prompt import Prompt +from simpleline.render.screen import UIScreen +from simpleline.render.widgets import TextWidget, SeparatorWidget, CheckboxWidget, CenterWidget, \ + ColumnWidget, EntryWidget + + +class BaseWidgets_TestCase(unittest.TestCase): + """Base class containing helper functions.""" + def setUp(self): + self.w1 = TextWidget(u"Můj krásný dlouhý text") + self.w2 = TextWidget(u"Test") + self.w3 = TextWidget(u"Test 2") + self.w4 = TextWidget(u"Krásný dlouhý text podruhé") + self.w5 = TextWidget(u"Test 3") + self.w6 = TextWidget("The rescue environment will now attempt " + "to find your Linux installation and mount it under " + "the directory : bla. You can then make any changes " + "required to your system. Choose '1' to proceed with " + "this step.\nYou can choose to mount your file " + "systems read-only instead of read-write by choosing " + "'2'.\nIf for some reason this process does not work " + "choose '3' to skip directly to a shell.\n\n") + self.w7 = TextWidget("Wrapping toooooooooooooooooooooooooooooooooooooooooooo" + "oooooooooooooooooooooooooooooooooooooooooooooooooooooo long word.") + self.w8 = TextWidget("Text that would be wrapped exactly at the screen width should" + " have special test. This one.") + + def evaluate_result(self, test_result, expected_result): + self.assertEqual(len(test_result), len(expected_result)) + for i in range(0, len(test_result)): # pylint: disable=consider-using-enumerate + self.assertEqual(test_result[i], expected_result[i]) + + +class Widgets_TestCase(BaseWidgets_TestCase): + + def test_separator_widget(self): + w = SeparatorWidget() + w.render(80) + + res_lines = w.get_lines() + + expected_result = [u""] + + self.evaluate_result(res_lines, expected_result) + + def test_separator_widget_multiline(self): + w = SeparatorWidget(3) + w.render(80) + + res_lines = w.get_lines() + + expected_result = [u"", + u"", + u""] + + self.evaluate_result(res_lines, expected_result) + + def test_column_widget(self): + # Test column text + c = ColumnWidget([(20, [self.w1, self.w2, self.w3]), + (25, [self.w4, self.w5]), + (15, [self.w1, self.w2, self.w3])], spacing=3) + c.render(80) + res_lines = c.get_lines() + + expected_result = [u"Můj krásný dlouhý Krásný dlouhý text Můj krásný", + u"text podruhé dlouhý text", + u"Test Test 3 Test", + u"Test 2 Test 2"] + self.evaluate_result(res_lines, expected_result) + + def test_column_wrapping(self): + # Test column wrapping text + c = ColumnWidget([(15, [self.w1, self.w2, self.w3]), (10, [self.w4, self.w5])], spacing=1) + c.render(80) + + expected_result = [u"Můj krásný Krásný", + u"dlouhý text dlouhý", + u"Test text", + u"Test 2 podruhé", + u" Test 3"] + + res_lines = c.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_multiline_text(self): + self.w6.render(80) + expected_result = [ + "The rescue environment will now attempt to find your Linux installation and", + "mount it under the directory : bla. You can then make any changes required to", + "your system. Choose '1' to proceed with this step.", + "You can choose to mount your file systems read-only instead of read-write by", + "choosing '2'.", + "If for some reason this process does not work choose '3' to skip directly to a", + "shell.", + "", + ""] + res_lines = self.w6.get_lines() + self.evaluate_result(res_lines, expected_result) + + def test_wrapping(self): + # wrap long text + self.w7.render(80) + expected_result = [ + "Wrapping toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", + "oooooooooooooooooooooooooooo long word."] + res_lines = self.w7.get_lines() + + self.assertEqual(len(res_lines), len(expected_result)) + for i in range(0, len(res_lines)): # pylint: disable=consider-using-enumerate + self.assertEqual(res_lines[i], expected_result[i]) + + self.w8.render(80) + # pylint: disable=line-too-long + expected_result = ["Text that would be wrapped exactly at the screen width should have special test.", + "This one."] + res_lines = self.w8.get_lines() + + self.evaluate_result(res_lines, expected_result) + + def test_checkbox(self): + checkbox = CheckboxWidget(title="Test Title", text="Description") + + checkbox.render(80) + + expected_result = [u"[ ] Test Title", + u" (Description)"] + + self.evaluate_result(checkbox.get_lines(), expected_result) + + def test_completed_checkbox(self): + checkbox = CheckboxWidget(title="Title", text="Description", completed=True) + + checkbox.render(80) + + expected_result = [u"[x] Title", + u" (Description)"] + + self.evaluate_result(checkbox.get_lines(), expected_result) + + def test_key_checkbox(self): + checkbox = CheckboxWidget(key="o", title="Title", text="Description", completed=True) + + checkbox.render(80) + + expected_result = [u"[o] Title", + u" (Description)"] + + self.evaluate_result(checkbox.get_lines(), expected_result) + + def test_empty_checkbox(self): + checkbox = CheckboxWidget() + + checkbox.render(80) + + expected_result = [u"[ ]"] + + self.evaluate_result(checkbox.get_lines(), expected_result) + + def test_checkbox_wrapping(self): + checkbox = CheckboxWidget(title="Title", text="Testing\nwrapping") + + checkbox.render(80) + + expected_result = [u"[ ] Title", + u" (Testing", + u" wrapping)"] + + self.evaluate_result(checkbox.get_lines(), expected_result) + + def test_center_widget(self): + w = CenterWidget(self.w2) + + w.render(10) + + expected_result = [u" Test"] + + self.evaluate_result(w.get_lines(), expected_result) + + def test_entry_widget(self): + title = "Title" + value = "Value" + w = EntryWidget(title=title, value=value) + + w.render(30) + + expected_result = [title, + value] + + self.evaluate_result(w.get_lines(), expected_result) + + def test_entry_too_long(self): + title = "Title too long" + value = "Value also too long" + w = EntryWidget(title=title, value=value) + + w.render(10) + + expected_result = [u"Title too", + u"long", + u"Value also", + u"too long"] + + self.evaluate_result(w.get_lines(), expected_result) + + def test_entry_value_empty(self): + title = "Title" + w = EntryWidget(title=title) + + w.render(20) + + expected_result = [title] + + self.evaluate_result(w.get_lines(), expected_result=expected_result) + + +@patch('simpleline.input.input_handler.InputHandlerRequest._get_input') +@patch('sys.stdout', new_callable=StringIO) +class WidgetProcessing_TestCase(unittest.TestCase): + + @staticmethod + def _calculate_spacer(): + # this calculation is taken from scheduler for default width '80' + return '\n'.join(2 * [80 * '=']) + + def _expected_output(self, text, widget_height=20): + + # two lines are always added to the printed size + prompt_height = 2 + real_widget_height = widget_height - prompt_height + + lines = text.split('\n') + + # add Press ENTER... to the text + if len(lines) - 1 >= real_widget_height: + lines.insert(real_widget_height, "\nPress %s to continue: \n" % Prompt.ENTER) + + msg = self._calculate_spacer() + '\n' + msg += "\n".join(lines) + msg += "\n" + return msg + + def test_draw_simple_widget(self, out_mock, in_mock): + widget_text = "Test" + screen = ScreenWithWidget(widget_text) + + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(self._expected_output(widget_text), out_mock.getvalue()) + + def test_widget_multiline(self, out_mock, in_mock): + widget_text = "Testing output\n\n\nAgain..." + screen = ScreenWithWidget(widget_text) + + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(self._expected_output(widget_text), out_mock.getvalue()) + + def test_widget_too_high(self, out_mock, in_mock): + in_mock.return_value = "\n" + in_mock.side_effect = lambda: print('\n') + + widget_text = ("Line\n" + "Line2\n" + "Line3\n" + "Line4\n" + "Line5") + # Screen height take into account also 2 lines for prompt + screen = ScreenWithWidget(widget_text, height=6) + + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(self._expected_output(widget_text, widget_height=6), out_mock.getvalue()) + + def test_widget_is_exactly_height_to_print(self, out_mock, in_mock): + widget_text = ("Line\n" + "Line2\n" + "Line3\n" + "Line4") + # Screen height take into account also 2 lines for prompt + screen = ScreenWithWidget(widget_text, height=6) + + App.initialize() + App.get_scheduler().schedule_screen(screen) + App.run() + + self.assertEqual(self._expected_output(widget_text, widget_height=6), out_mock.getvalue()) + + +class ScreenWithWidget(UIScreen): + + def __init__(self, msg, height=25): + super().__init__(screen_height=height) + self._msg = msg + self.input_required = False + + def refresh(self, args=None): + super().refresh(args) + self.window.add(TextWidget(self._msg)) + + def show_all(self): + super().show_all() + self.close() diff --git a/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/run_test.sh b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/run_test.sh new file mode 100755 index 0000000..029a8a6 --- /dev/null +++ b/pkgbuilds/python-simpleline/src/python-simpleline-simpleline-1.8/tests/units/run_test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +if [ -z $PYTHON ]; then + PYTHON=python3 +fi + +SCRIPT_DIR=$(dirname $0) + +$PYTHON -m unittest discover -v -s $SCRIPT_DIR/../ -p '*_test.py' diff --git a/setup-aur.sh b/setup-aur.sh index 10409f2..c421318 100755 --- a/setup-aur.sh +++ b/setup-aur.sh @@ -160,6 +160,24 @@ for pkg in "${AUR_PACKAGES[@]}"; do success "$pkg build OK" done +# ------------------------------------------------------------ +# PKGBUILD locaux FWS (deps Anaconda packagées maison, pkgbuilds/) +# cf. portage de l'installateur Anaconda sur Arch. +# ------------------------------------------------------------ +LOCAL_PKGBUILDS_DIR="$SCRIPT_DIR/pkgbuilds" +if [ -d "$LOCAL_PKGBUILDS_DIR" ]; then + for dir in "$LOCAL_PKGBUILDS_DIR"/*/; do + [ -f "$dir/PKGBUILD" ] || continue + name="$(basename "$dir")" + info "Build local $name…" + cp -a "$dir" "$BUILD_DIR/$name" + chown -R "$BUILD_USER:$BUILD_USER" "$BUILD_DIR/$name" + su - "$BUILD_USER" -c "cd $BUILD_DIR/$name && makepkg -sf --noconfirm" \ + || error "Build local $name échoué" + success "$name build OK" + done +fi + # ============================================================ step "4/4 — Création du repo pacman local fws-local" # ============================================================ @@ -171,6 +189,16 @@ for pkg in "${AUR_PACKAGES[@]}"; do || error "Paquet $pkg introuvable dans $BUILD_DIR/$pkg" done +# PKGBUILD locaux FWS +if [ -d "$LOCAL_PKGBUILDS_DIR" ]; then + for dir in "$LOCAL_PKGBUILDS_DIR"/*/; do + [ -f "$dir/PKGBUILD" ] || continue + name="$(basename "$dir")" + cp "$BUILD_DIR/$name"/*.pkg.tar.zst "$LOCAL_REPO/" \ + || error "Paquet local $name introuvable" + done +fi + repo-add "$LOCAL_REPO/fws-local.db.tar.gz" "$LOCAL_REPO"/*.pkg.tar.zst \ || error "repo-add a échoué" success "Repo local prêt : $LOCAL_REPO"