labtasker 0.2.4__tar.gz → 0.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {labtasker-0.2.4 → labtasker-0.2.6}/.coveragerc +1 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/.flake8 +2 -1
- {labtasker-0.2.4 → labtasker-0.2.6}/.gitmodules +2 -2
- {labtasker-0.2.4 → labtasker-0.2.6}/.pre-commit-config.yaml +2 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/PKG-INFO +14 -15
- {labtasker-0.2.4 → labtasker-0.2.6}/README.md +9 -9
- {labtasker-0.2.4 → labtasker-0.2.6}/docker-compose.yml +1 -1
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/__init__.py +1 -1
- labtasker-0.2.6/labtasker/client/cli/loop.py +266 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cli_utils.py +5 -1
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/generated/LabCmd.py +2 -3
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/generated/LabCmdLexer.py +2 -3
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/generated/LabCmdListener.py +1 -1
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/parser.py +18 -12
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/job_runner.py +10 -7
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/logging.py +1 -1
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/database.py +0 -1
- labtasker-0.2.6/labtasker/vendor/README.txt +8 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/BufferedTokenStream.py +302 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/CommonTokenFactory.py +61 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/CommonTokenStream.py +87 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/FileStream.py +27 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/InputStream.py +87 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/IntervalSet.py +180 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/LL1Analyzer.py +173 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/Lexer.py +329 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/ListTokenSource.py +144 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/Parser.py +580 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/ParserInterpreter.py +170 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/ParserRuleContext.py +186 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/PredictionContext.py +629 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/Recognizer.py +147 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/RuleContext.py +227 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/StdinStream.py +11 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/Token.py +155 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/TokenStreamRewriter.py +255 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/Utils.py +33 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/__init__.py +21 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/_pygrun.py +171 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATN.py +132 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNConfig.py +159 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNConfigSet.py +212 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNDeserializationOptions.py +24 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNDeserializer.py +446 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNSimulator.py +47 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNState.py +264 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ATNType.py +17 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/LexerATNSimulator.py +570 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/LexerAction.py +298 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/LexerActionExecutor.py +143 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/ParserATNSimulator.py +1661 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/PredictionMode.py +499 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/SemanticContext.py +330 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/Transition.py +268 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/atn/__init__.py +1 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/dfa/DFA.py +133 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/dfa/DFASerializer.py +73 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/dfa/DFAState.py +126 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/dfa/__init__.py +1 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/error/DiagnosticErrorListener.py +107 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/error/ErrorListener.py +72 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/error/ErrorStrategy.py +709 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/error/Errors.py +173 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/error/__init__.py +1 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/Chunk.py +30 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/ParseTreeMatch.py +118 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/ParseTreePattern.py +72 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/ParseTreePatternMatcher.py +374 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/RuleTagToken.py +50 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/TokenTagToken.py +47 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/Tree.py +191 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/tree/Trees.py +111 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/xpath/XPath.py +269 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/xpath/XPathLexer.py +95 -0
- labtasker-0.2.6/labtasker/vendor/antlr4/xpath/__init__.py +1 -0
- labtasker-0.2.6/labtasker/vendor/vendor.txt +1 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker.egg-info/SOURCES.txt +63 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/pyproject.toml +35 -8
- labtasker-0.2.6/scripts/get_vendored.py +137 -0
- labtasker-0.2.6/tests/dummy_jobs/job_1.py +39 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_loop.py +51 -2
- labtasker-0.2.6/tests/test_server/test_db_utils/__init__.py +0 -0
- labtasker-0.2.6/tests/test_server/test_endpoint/__init__.py +0 -0
- labtasker-0.2.6/tests/test_utils/__init__.py +0 -0
- labtasker-0.2.4/labtasker/client/cli/loop.py +0 -185
- labtasker-0.2.4/tests/dummy_jobs/job_1.py +0 -27
- {labtasker-0.2.4 → labtasker-0.2.6}/.dockerignore +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/.gitattributes +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/.gitignore +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/.pytest.ini +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/.python-version +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/Dockerfile +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/LICENSE +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/MANIFEST.in +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/PRIVACY.md +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/custom_resolver/submit_job.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/custom_resolver/w.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/custom_resolver/wo.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/event_system/email_on_task_failure.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/event_system/send_email.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/event_system/sim_unstable_job.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/advanced/event_system/submit.sh +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/basic/bash_demo/job_main.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/basic/bash_demo/run_job.sh +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/basic/bash_demo/submit_job.sh +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/basic/python_demo/run_job.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/demo/basic/python_demo/submit_job.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/docker/mongodb/init.d/init-keyfile.sh +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/docker/mongodb/post-init.d/init-mongo.sh +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/__main__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/api_models.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/cli.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/config.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/event.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/init.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/queue.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/task.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/cli/worker.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/client_api.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/api.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/LabCmd.g4 +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/LabCmdLexer.g4 +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/generated/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/config.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/context.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/events.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/exceptions.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/heartbeat.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/paths.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/plugin_utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/query_transpiler.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/resolver/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/resolver/models.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/resolver/utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/version_checker.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/templates/labtasker_root/.gitignore +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/templates/labtasker_root/client.toml +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/templates/labtasker_root/logs/.gitkeep +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/constants.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/filtering.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/security.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/cli.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/config.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/db_utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/dependencies.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/embedded_db.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/endpoints.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/event_manager.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/fsm.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/server/logging.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/labtasker/utils.py +0 -0
- {labtasker-0.2.4/tests → labtasker-0.2.6/labtasker/vendor}/__init__.py +0 -0
- {labtasker-0.2.4/tests/fixtures → labtasker-0.2.6/labtasker/vendor/antlr4/tree}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/script_tests/test_ban_datetime_now/allowed.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/script_tests/test_ban_datetime_now/disallowed.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/script_tests/test_ban_datetime_now/test_ban.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/scripts/asciinema_adjust_timestamp.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/scripts/check_version.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/scripts/datetime_now_checker.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/server.example.env +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/setup.cfg +0 -0
- {labtasker-0.2.4/tests/test_client → labtasker-0.2.6/tests}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/conftest.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/demo_pager_iterator.py +0 -0
- {labtasker-0.2.4/tests/test_client/test_cli → labtasker-0.2.6/tests/fixtures}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/database/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/database/mock.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/database/real.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/logging.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/mock_datetime_now.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/server/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/server/async_app.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/fixtures/server/sync_app.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_api_models.py +0 -0
- {labtasker-0.2.4/tests/test_client/test_core → labtasker-0.2.6/tests/test_client}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/conftest.py +0 -0
- {labtasker-0.2.4/tests/test_client/test_core/test_event → labtasker-0.2.6/tests/test_client/test_cli}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/conftest.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_basic.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_config.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_event.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_init.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_queue.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_task.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_cli/test_worker.py +0 -0
- {labtasker-0.2.4/tests/test_client/test_core/test_query_transpiler → labtasker-0.2.6/tests/test_client/test_core}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_cli_utils.py +0 -0
- {labtasker-0.2.4/tests/test_client/test_core/test_runner_concurrency → labtasker-0.2.6/tests/test_client/test_core/test_event}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_event/test_concurrency_job_flow_event.py +0 -0
- /labtasker-0.2.4/tests/test_client/test_core/test_runner_timeout/__init__.py → /labtasker-0.2.6/tests/test_client/test_core/test_event/test_event_integration.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_event/test_event_listener_basic.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_event/test_various_actions.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_event/utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_heartbeat.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_job_runner.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_logging.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_loop_internal_error_handler.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_pager_iterator.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_parser.py +0 -0
- {labtasker-0.2.4/tests/test_filtering → labtasker-0.2.6/tests/test_client/test_core/test_query_transpiler}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_query_transpiler/conftest.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_query_transpiler/test_behavior.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_query_transpiler/test_matching.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_query_transpiler/test_utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_query_transpiler/utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_resolver.py +0 -0
- {labtasker-0.2.4/tests/test_server → labtasker-0.2.6/tests/test_client/test_core/test_runner_concurrency}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_concurrency/run_concurrent.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_concurrency/test_runner_concurrency_success_failure.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_concurrency/test_runner_high_concurrency.py +0 -0
- {labtasker-0.2.4/tests/test_server/test_database → labtasker-0.2.6/tests/test_client/test_core/test_runner_timeout}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_timeout/conftest.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_timeout/test_job_runner_timeout.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_timeout/test_job_runner_with_resolver_timeout.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_runner_with_resolver.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_server_notification_and_client_version.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_client/test_core/test_version_checker.py +0 -0
- {labtasker-0.2.4/tests/test_server/test_db_utils → labtasker-0.2.6/tests/test_filtering}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_filtering/exception_utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_filtering/test_exception_filtering.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_mock_time.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_security.py +0 -0
- {labtasker-0.2.4/tests/test_server/test_endpoint → labtasker-0.2.6/tests/test_server}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/conftest.py +0 -0
- {labtasker-0.2.4/tests/test_utils → labtasker-0.2.6/tests/test_server/test_database}/__init__.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_database/conftest.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_database/test_database_basic.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_database/test_fetch_extra_filter.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_database/test_query_dict_to_mongo_filter.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_database/test_required_field_fetching.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_db_utils/test_arg_match.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_db_utils/test_keys_to_query_dict.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_db_utils/test_keys_to_query_dict_deepest.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_db_utils/test_keys_to_query_dict_topmost.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_embedded_db.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_endpoint/test_event_basic.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_endpoint/test_server.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_endpoint/test_server_async.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_endpoint/test_server_async_ping.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_fsm.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_server/test_get_verified_queue_dependency.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/test_utils/test_utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tests/utils.py +0 -0
- {labtasker-0.2.4 → labtasker-0.2.6}/tox.ini +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[submodule "plugins/labtasker_plugin_task_count"]
|
|
2
2
|
path = plugins/labtasker_plugin_task_count
|
|
3
|
-
url = https://github.com/
|
|
3
|
+
url = https://github.com/luocfprime/labtasker-plugin-task-count.git
|
|
4
4
|
branch = main
|
|
5
5
|
[submodule "plugins/labtasker_plugin_script_generate"]
|
|
6
6
|
path = plugins/labtasker_plugin_script_generate
|
|
7
|
-
url = https://github.com/
|
|
7
|
+
url = https://github.com/luocfprime/labtasker-plugin-script-generate.git
|
|
8
8
|
branch = main
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: labtasker
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: A task queue system for lab experiments
|
|
5
5
|
Author-email: Your Name <your.email@example.com>
|
|
6
6
|
License: Apache License 2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Documentation, https://
|
|
9
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://github.com/luocfprime/labtasker
|
|
8
|
+
Project-URL: Documentation, https://luocfprime.github.io/labtasker
|
|
9
|
+
Project-URL: Repository, https://github.com/luocfprime/labtasker.git
|
|
10
10
|
Classifier: Intended Audience :: Science/Research
|
|
11
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
@@ -20,13 +20,11 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
20
|
Requires-Python: <4.0,>=3.8.1
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: python-dotenv<2.0.0,>=1.0.1
|
|
24
23
|
Requires-Dist: pymongo<5.0.0,>=4.0.0
|
|
25
24
|
Requires-Dist: fastapi<0.116.0,>=0.115.0
|
|
26
25
|
Requires-Dist: uvicorn[standard]<0.35.0,>=0.15.0
|
|
27
26
|
Requires-Dist: click<9.0.0,>=8.1.0
|
|
28
27
|
Requires-Dist: passlib<2.0.0,>=1.7.0
|
|
29
|
-
Requires-Dist: antlr4-python3-runtime<5.0.0,>=4.13.0
|
|
30
28
|
Requires-Dist: pydantic-settings<3.0.0,>=2.8.0
|
|
31
29
|
Requires-Dist: httpx[socks]<0.29.0,>=0.28.0
|
|
32
30
|
Requires-Dist: typer<0.16.0,>=0.15.0
|
|
@@ -43,6 +41,7 @@ Requires-Dist: noneprompt<0.2.0,>=0.1.9
|
|
|
43
41
|
Requires-Dist: mongomock<4.4.0,>=4.3.0
|
|
44
42
|
Requires-Dist: jsonpickle<5.0.0,>=4.0.2
|
|
45
43
|
Requires-Dist: mslex<2.0.0,>=1.3.0
|
|
44
|
+
Requires-Dist: pexpect<5.0.0,>=4.9.0
|
|
46
45
|
Provides-Extra: dev
|
|
47
46
|
Requires-Dist: pytest<9.0.0,>=8.0.0; extra == "dev"
|
|
48
47
|
Requires-Dist: pytest-cov<7.0.0,>=5.0.0; extra == "dev"
|
|
@@ -69,11 +68,11 @@ Dynamic: license-file
|
|
|
69
68
|
|
|
70
69
|
<p align="center"><em>Make your ML experiment wrapper scripts smarter with...</em></p>
|
|
71
70
|
<h1 align="center" style="font-size: 40px;"> <a href="">Labtasker</a></h1>
|
|
72
|
-
<p align="center"><a href="https://
|
|
71
|
+
<p align="center"><a href="https://luocfprime.github.io/labtasker/latest/install/install/">Install</a> • <a href="https://luocfprime.github.io/labtasker/latest/guide/basic/">Tutorial / Demo</a> • <a href="https://luocfprime.github.io/labtasker/latest/">Documentation</a> • <a href="https://luocfprime.github.io/labtasker/latest/faq/">FAQs</a> • <a href="https://github.com/luocfprime/labtasker/releases">Releases</a></p>
|
|
73
72
|
|
|
74
73
|
<p align="center">
|
|
75
|
-
<img src="https://github.com/
|
|
76
|
-
<a href="https://codecov.io/gh/
|
|
74
|
+
<img src="https://github.com/luocfprime/labtasker/actions/workflows/unit-test-matrix.yml/badge.svg" alt="unit-test-matrix" />
|
|
75
|
+
<a href="https://codecov.io/gh/luocfprime/labtasker"><img src="https://codecov.io/gh/luocfprime/labtasker/graph/badge.svg?token=KQFBV3QRPY" alt="codecov" /></a>
|
|
77
76
|
<img src="https://img.shields.io/badge/Python-3.8%20|%203.9%20|%203.10%20|%203.11%20|%203.12%20|%203.13-blue" alt="Python version" />
|
|
78
77
|
<a href="https://pypi.org/project/labtasker/"><img src="https://img.shields.io/pypi/v/labtasker" alt="PyPI" /></a>
|
|
79
78
|
</p>
|
|
@@ -91,7 +90,7 @@ parallelization, dynamic task prioritization, failure handling, halfway resume,
|
|
|
91
90
|
|
|
92
91
|

|
|
93
92
|
|
|
94
|
-
🐳 For detailed examples and concepts, check out the [documentation](https://
|
|
93
|
+
🐳 For detailed examples and concepts, check out the [documentation](https://luocfprime.github.io/labtasker/).
|
|
95
94
|
|
|
96
95
|
## 🧪️ A Quick Demo
|
|
97
96
|
|
|
@@ -103,7 +102,7 @@ such as sending emails on task failure.
|
|
|
103
102
|

|
|
104
103
|
|
|
105
104
|
For more detailed steps, please refer to the content in
|
|
106
|
-
the [Tutorial / Demo](https://
|
|
105
|
+
the [Tutorial / Demo](https://luocfprime.github.io/labtasker/latest/guide/basic/).
|
|
107
106
|
|
|
108
107
|
## ⚡️ Features
|
|
109
108
|
|
|
@@ -133,7 +132,7 @@ the [Tutorial / Demo](https://fkcptlst.github.io/labtasker/latest/guide/basic/).
|
|
|
133
132
|
> [!NOTE]
|
|
134
133
|
> You need a running Labtasker server to use the client tools.
|
|
135
134
|
> Simply use the installed Python CLI `labtasker-server serve` or use docker-compose to deploy the server.
|
|
136
|
-
> See [deployment instructions](https://
|
|
135
|
+
> See [deployment instructions](https://luocfprime.github.io/labtasker/latest/install/deployment/).
|
|
137
136
|
|
|
138
137
|
### 1. Install via PyPI
|
|
139
138
|
|
|
@@ -145,7 +144,7 @@ pip install 'labtasker[plugins]'
|
|
|
145
144
|
### 2. Install the Latest Version from GitHub
|
|
146
145
|
|
|
147
146
|
```bash
|
|
148
|
-
pip install git+https://github.com/
|
|
147
|
+
pip install git+https://github.com/luocfprime/labtasker.git
|
|
149
148
|
```
|
|
150
149
|
|
|
151
150
|
## 🚀 Quick Start
|
|
@@ -165,13 +164,13 @@ labtasker init
|
|
|
165
164
|
Then, use `labtasker submit` to submit tasks and use `labtasker loop` to run tasks across any number of workers.
|
|
166
165
|
|
|
167
166
|
> [!TIP]
|
|
168
|
-
> If you think manually writing 2 scripts for submit and run is laborious, you can checkout the [labtasker-plugin-script-generate](https://github.com/
|
|
167
|
+
> If you think manually writing 2 scripts for submit and run is laborious, you can checkout the [labtasker-plugin-script-generate](https://github.com/luocfprime/labtasker-plugin-script-generate).
|
|
169
168
|
> It automatically generate 2 scripts based on the script you provided.
|
|
170
169
|
|
|
171
170
|
## 📚 Documentation
|
|
172
171
|
|
|
173
172
|
For detailed information on demo, tutorial, deployment, usage, please refer to
|
|
174
|
-
the [documentation](https://
|
|
173
|
+
the [documentation](https://luocfprime.github.io/labtasker/).
|
|
175
174
|
|
|
176
175
|
## 🔒 License
|
|
177
176
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<p align="center"><em>Make your ML experiment wrapper scripts smarter with...</em></p>
|
|
2
2
|
<h1 align="center" style="font-size: 40px;"> <a href="">Labtasker</a></h1>
|
|
3
|
-
<p align="center"><a href="https://
|
|
3
|
+
<p align="center"><a href="https://luocfprime.github.io/labtasker/latest/install/install/">Install</a> • <a href="https://luocfprime.github.io/labtasker/latest/guide/basic/">Tutorial / Demo</a> • <a href="https://luocfprime.github.io/labtasker/latest/">Documentation</a> • <a href="https://luocfprime.github.io/labtasker/latest/faq/">FAQs</a> • <a href="https://github.com/luocfprime/labtasker/releases">Releases</a></p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<img src="https://github.com/
|
|
7
|
-
<a href="https://codecov.io/gh/
|
|
6
|
+
<img src="https://github.com/luocfprime/labtasker/actions/workflows/unit-test-matrix.yml/badge.svg" alt="unit-test-matrix" />
|
|
7
|
+
<a href="https://codecov.io/gh/luocfprime/labtasker"><img src="https://codecov.io/gh/luocfprime/labtasker/graph/badge.svg?token=KQFBV3QRPY" alt="codecov" /></a>
|
|
8
8
|
<img src="https://img.shields.io/badge/Python-3.8%20|%203.9%20|%203.10%20|%203.11%20|%203.12%20|%203.13-blue" alt="Python version" />
|
|
9
9
|
<a href="https://pypi.org/project/labtasker/"><img src="https://img.shields.io/pypi/v/labtasker" alt="PyPI" /></a>
|
|
10
10
|
</p>
|
|
@@ -22,7 +22,7 @@ parallelization, dynamic task prioritization, failure handling, halfway resume,
|
|
|
22
22
|
|
|
23
23
|

|
|
24
24
|
|
|
25
|
-
🐳 For detailed examples and concepts, check out the [documentation](https://
|
|
25
|
+
🐳 For detailed examples and concepts, check out the [documentation](https://luocfprime.github.io/labtasker/).
|
|
26
26
|
|
|
27
27
|
## 🧪️ A Quick Demo
|
|
28
28
|
|
|
@@ -34,7 +34,7 @@ such as sending emails on task failure.
|
|
|
34
34
|

|
|
35
35
|
|
|
36
36
|
For more detailed steps, please refer to the content in
|
|
37
|
-
the [Tutorial / Demo](https://
|
|
37
|
+
the [Tutorial / Demo](https://luocfprime.github.io/labtasker/latest/guide/basic/).
|
|
38
38
|
|
|
39
39
|
## ⚡️ Features
|
|
40
40
|
|
|
@@ -64,7 +64,7 @@ the [Tutorial / Demo](https://fkcptlst.github.io/labtasker/latest/guide/basic/).
|
|
|
64
64
|
> [!NOTE]
|
|
65
65
|
> You need a running Labtasker server to use the client tools.
|
|
66
66
|
> Simply use the installed Python CLI `labtasker-server serve` or use docker-compose to deploy the server.
|
|
67
|
-
> See [deployment instructions](https://
|
|
67
|
+
> See [deployment instructions](https://luocfprime.github.io/labtasker/latest/install/deployment/).
|
|
68
68
|
|
|
69
69
|
### 1. Install via PyPI
|
|
70
70
|
|
|
@@ -76,7 +76,7 @@ pip install 'labtasker[plugins]'
|
|
|
76
76
|
### 2. Install the Latest Version from GitHub
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
pip install git+https://github.com/
|
|
79
|
+
pip install git+https://github.com/luocfprime/labtasker.git
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
## 🚀 Quick Start
|
|
@@ -96,13 +96,13 @@ labtasker init
|
|
|
96
96
|
Then, use `labtasker submit` to submit tasks and use `labtasker loop` to run tasks across any number of workers.
|
|
97
97
|
|
|
98
98
|
> [!TIP]
|
|
99
|
-
> If you think manually writing 2 scripts for submit and run is laborious, you can checkout the [labtasker-plugin-script-generate](https://github.com/
|
|
99
|
+
> If you think manually writing 2 scripts for submit and run is laborious, you can checkout the [labtasker-plugin-script-generate](https://github.com/luocfprime/labtasker-plugin-script-generate).
|
|
100
100
|
> It automatically generate 2 scripts based on the script you provided.
|
|
101
101
|
|
|
102
102
|
## 📚 Documentation
|
|
103
103
|
|
|
104
104
|
For detailed information on demo, tutorial, deployment, usage, please refer to
|
|
105
|
-
the [documentation](https://
|
|
105
|
+
the [documentation](https://luocfprime.github.io/labtasker/).
|
|
106
106
|
|
|
107
107
|
## 🔒 License
|
|
108
108
|
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""Implements `labtasker loop xxx`"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from collections import defaultdict
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List, Optional
|
|
10
|
+
|
|
11
|
+
import pexpect
|
|
12
|
+
import typer
|
|
13
|
+
from typing_extensions import Annotated
|
|
14
|
+
|
|
15
|
+
from labtasker.client.cli.cli import app
|
|
16
|
+
from labtasker.client.core.cli_utils import (
|
|
17
|
+
cli_utils_decorator,
|
|
18
|
+
eta_max_validation,
|
|
19
|
+
parse_filter,
|
|
20
|
+
)
|
|
21
|
+
from labtasker.client.core.cmd_parser import cmd_interpolate
|
|
22
|
+
from labtasker.client.core.config import get_client_config
|
|
23
|
+
from labtasker.client.core.context import task_info
|
|
24
|
+
from labtasker.client.core.exceptions import CmdParserError, _LabtaskerJobFailed
|
|
25
|
+
from labtasker.client.core.job_runner import loop_run
|
|
26
|
+
from labtasker.client.core.logging import (
|
|
27
|
+
logger,
|
|
28
|
+
set_verbose,
|
|
29
|
+
stderr_console,
|
|
30
|
+
verbose_print,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class InfiniteDefaultDict(defaultdict):
|
|
35
|
+
|
|
36
|
+
def __getitem__(self, key):
|
|
37
|
+
if key not in self:
|
|
38
|
+
self[key] = InfiniteDefaultDict()
|
|
39
|
+
return super().__getitem__(key)
|
|
40
|
+
|
|
41
|
+
def get(self, key, default=None):
|
|
42
|
+
if key not in self:
|
|
43
|
+
self[key] = InfiniteDefaultDict()
|
|
44
|
+
return super().get(key, default)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _check_pty_available(opt: bool) -> bool:
|
|
48
|
+
if opt and os.name == "nt":
|
|
49
|
+
stderr_console.print(
|
|
50
|
+
"[bold orange1]Warning:[/bold orange1] PTY is not available on Windows. "
|
|
51
|
+
"Disabling PTY support."
|
|
52
|
+
)
|
|
53
|
+
return False
|
|
54
|
+
return opt
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _stream_child_output(child) -> None:
|
|
58
|
+
"""Stream the output of a pexpect child in real-time, supporting progress bars."""
|
|
59
|
+
try:
|
|
60
|
+
while True:
|
|
61
|
+
try:
|
|
62
|
+
output = child.read_nonblocking(size=1024, timeout=0.1)
|
|
63
|
+
if output:
|
|
64
|
+
# keep \r
|
|
65
|
+
sys.stdout.write(output)
|
|
66
|
+
sys.stdout.flush()
|
|
67
|
+
except pexpect.TIMEOUT:
|
|
68
|
+
continue
|
|
69
|
+
except pexpect.EOF:
|
|
70
|
+
break
|
|
71
|
+
finally:
|
|
72
|
+
child.close()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _run_with_pty(cmd, shell_exec=None, use_shell=False):
|
|
76
|
+
"""Run a command with PTY support for interactive programs."""
|
|
77
|
+
if use_shell:
|
|
78
|
+
shell_exec = shell_exec or "/bin/sh"
|
|
79
|
+
child = pexpect.spawn(shell_exec, ["-c", cmd], encoding="utf-8")
|
|
80
|
+
else:
|
|
81
|
+
child = pexpect.spawn(cmd[0], cmd[1:], encoding="utf-8")
|
|
82
|
+
|
|
83
|
+
_stream_child_output(child)
|
|
84
|
+
|
|
85
|
+
return child.exitstatus
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _run_with_subprocess(cmd, shell_exec=None, use_shell=False):
|
|
89
|
+
"""Run a command using standard subprocess approach."""
|
|
90
|
+
with subprocess.Popen(
|
|
91
|
+
args=cmd,
|
|
92
|
+
stdin=subprocess.PIPE,
|
|
93
|
+
stdout=subprocess.PIPE,
|
|
94
|
+
stderr=subprocess.PIPE,
|
|
95
|
+
text=True,
|
|
96
|
+
executable=shell_exec,
|
|
97
|
+
shell=use_shell,
|
|
98
|
+
) as process:
|
|
99
|
+
while True:
|
|
100
|
+
output = process.stdout.readline()
|
|
101
|
+
error = process.stderr.readline()
|
|
102
|
+
|
|
103
|
+
if output:
|
|
104
|
+
sys.stdout.write(output.strip())
|
|
105
|
+
sys.stdout.flush()
|
|
106
|
+
if error:
|
|
107
|
+
sys.stderr.write(error.strip())
|
|
108
|
+
sys.stderr.flush()
|
|
109
|
+
|
|
110
|
+
# Break when process completes and streams are empty
|
|
111
|
+
if process.poll() is not None and not output and not error:
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
return process.returncode
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@app.command()
|
|
118
|
+
@cli_utils_decorator
|
|
119
|
+
def loop(
|
|
120
|
+
cmd: Annotated[
|
|
121
|
+
List[str],
|
|
122
|
+
typer.Argument(
|
|
123
|
+
...,
|
|
124
|
+
help="Command to run. Supports argument interpolation using %(arg_name) syntax. Example: `python main.py '%(input_file)' '%(output_dir)'`",
|
|
125
|
+
),
|
|
126
|
+
] = None,
|
|
127
|
+
option_cmd: str = typer.Option(
|
|
128
|
+
None,
|
|
129
|
+
"--command",
|
|
130
|
+
"--cmd",
|
|
131
|
+
"-c",
|
|
132
|
+
help="Specify the command to run with shell=True. Supports the same argument interpolation the same way as the positional argument. Except you need to quote the entire command.",
|
|
133
|
+
),
|
|
134
|
+
script_path: Optional[Path] = typer.Option(
|
|
135
|
+
None,
|
|
136
|
+
exists=True,
|
|
137
|
+
readable=True,
|
|
138
|
+
help="Path to a script file that contains the command to execute. The script will run with '%(...)' placeholders replaced by the retrieved task arguments.",
|
|
139
|
+
),
|
|
140
|
+
executable: Optional[str] = typer.Option(
|
|
141
|
+
None,
|
|
142
|
+
"--executable",
|
|
143
|
+
help="Specify the shell executable to run the command with.",
|
|
144
|
+
),
|
|
145
|
+
extra_filter: Optional[str] = typer.Option(
|
|
146
|
+
None,
|
|
147
|
+
"--extra-filter",
|
|
148
|
+
"-f",
|
|
149
|
+
help='Filter tasks using MongoDB query syntax (e.g., \'{"metadata.tag": {"$in": ["a", "b"]}}\') or Python expression (e.g., \'metadata.tag in ["a", "b"] and priority == 10\').',
|
|
150
|
+
),
|
|
151
|
+
worker_id: Optional[str] = typer.Option(
|
|
152
|
+
None,
|
|
153
|
+
help="Assign a specific worker ID to run the tasks under.",
|
|
154
|
+
),
|
|
155
|
+
eta_max: Optional[str] = typer.Option(
|
|
156
|
+
None,
|
|
157
|
+
callback=eta_max_validation,
|
|
158
|
+
help="Maximum estimated time for task completion (e.g. '1h', '1h30m', '50s'). After which the task will be considered timed out.",
|
|
159
|
+
),
|
|
160
|
+
heartbeat_timeout: Optional[float] = typer.Option(
|
|
161
|
+
None,
|
|
162
|
+
help="Time in seconds before a task is considered stalled if no heartbeat is received.",
|
|
163
|
+
),
|
|
164
|
+
use_pty: bool = typer.Option(
|
|
165
|
+
os.name == "posix", # enabled by default on POSIX systems
|
|
166
|
+
callback=_check_pty_available,
|
|
167
|
+
help="Use pseudo terminal on POSIX systems for better interactive program support.",
|
|
168
|
+
),
|
|
169
|
+
verbose: bool = typer.Option( # noqa
|
|
170
|
+
False,
|
|
171
|
+
"--verbose",
|
|
172
|
+
"-v",
|
|
173
|
+
help="Enable verbose output.",
|
|
174
|
+
callback=set_verbose,
|
|
175
|
+
is_eager=True,
|
|
176
|
+
),
|
|
177
|
+
):
|
|
178
|
+
"""Process tasks from the queue by repeatedly running a command with task arguments.
|
|
179
|
+
|
|
180
|
+
The command uses template syntax to insert task arguments. For example:
|
|
181
|
+
|
|
182
|
+
labtasker loop -- python process.py --input '%(input_file)' --output '%(output_dir)'
|
|
183
|
+
|
|
184
|
+
This will fetch tasks with 'input_file' and 'output_dir' arguments and run the command
|
|
185
|
+
with those values substituted. Tasks are processed until the queue is empty.
|
|
186
|
+
"""
|
|
187
|
+
# Ensure only one of [CMD], [--command], or [--script-path] is specified
|
|
188
|
+
cmd_sources = [cmd, option_cmd, script_path]
|
|
189
|
+
cmd_sources = list(filter(None, cmd_sources)) # Remove None values dynamically
|
|
190
|
+
if len(cmd_sources) > 1:
|
|
191
|
+
raise typer.BadParameter(
|
|
192
|
+
"Only one of [CMD], [--command], or [--script-path] can be specified. Choose one."
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# 1. Assign from cmd or option_cmd
|
|
196
|
+
input_cmd = cmd or option_cmd
|
|
197
|
+
|
|
198
|
+
# 2. Assign from script_path if provided
|
|
199
|
+
if script_path and input_cmd is None:
|
|
200
|
+
with open(script_path, "r") as f:
|
|
201
|
+
input_cmd = f.read().strip()
|
|
202
|
+
|
|
203
|
+
# 3. Try reading from stdin if shell mode is enabled
|
|
204
|
+
if not input_cmd and not sys.stdin.isatty():
|
|
205
|
+
input_cmd = sys.stdin.read().strip()
|
|
206
|
+
|
|
207
|
+
# Final validation: ensure a command is present
|
|
208
|
+
if not input_cmd:
|
|
209
|
+
raise typer.BadParameter(
|
|
210
|
+
"Command cannot be empty. Specify via positional argument [CMD] or `--command` or `--script-path`."
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
parsed_filter = parse_filter(extra_filter)
|
|
214
|
+
verbose_print(f"Parsed filter: {json.dumps(parsed_filter, indent=4)}")
|
|
215
|
+
|
|
216
|
+
if heartbeat_timeout is None:
|
|
217
|
+
heartbeat_timeout = get_client_config().task.heartbeat_interval * 3
|
|
218
|
+
|
|
219
|
+
# Generate required fields dict
|
|
220
|
+
dummy_variable_table = InfiniteDefaultDict()
|
|
221
|
+
try:
|
|
222
|
+
_, queried_keys = cmd_interpolate(input_cmd, dummy_variable_table)
|
|
223
|
+
except (CmdParserError, KeyError, TypeError) as e:
|
|
224
|
+
raise typer.BadParameter(f"Command error with exception {e}")
|
|
225
|
+
|
|
226
|
+
required_fields = list(queried_keys)
|
|
227
|
+
|
|
228
|
+
logger.info(f"Got command: {input_cmd}")
|
|
229
|
+
|
|
230
|
+
@loop_run(
|
|
231
|
+
required_fields=required_fields,
|
|
232
|
+
extra_filter=parsed_filter,
|
|
233
|
+
worker_id=worker_id,
|
|
234
|
+
eta_max=eta_max,
|
|
235
|
+
heartbeat_timeout=heartbeat_timeout,
|
|
236
|
+
pass_args_dict=True,
|
|
237
|
+
)
|
|
238
|
+
def run_cmd(args):
|
|
239
|
+
interpolated_cmd, _ = cmd_interpolate(input_cmd, args)
|
|
240
|
+
logger.info(f"Prepared to run interpolated command: {interpolated_cmd}")
|
|
241
|
+
|
|
242
|
+
use_shell = isinstance(interpolated_cmd, str)
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
if use_pty:
|
|
246
|
+
# Use pexpect with PTY on POSIX systems
|
|
247
|
+
exit_code = _run_with_pty(interpolated_cmd, executable, use_shell)
|
|
248
|
+
else:
|
|
249
|
+
# Standard subprocess approach for non-PTY execution
|
|
250
|
+
exit_code = _run_with_subprocess(
|
|
251
|
+
interpolated_cmd, executable, use_shell
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
if exit_code != 0:
|
|
255
|
+
raise _LabtaskerJobFailed(
|
|
256
|
+
f"Job process finished with non-zero exit code: {exit_code}"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
except Exception as e:
|
|
260
|
+
raise _LabtaskerJobFailed(f"Error running command: {str(e)}")
|
|
261
|
+
|
|
262
|
+
logger.info(f"Task {task_info().task_id} ended.")
|
|
263
|
+
|
|
264
|
+
run_cmd()
|
|
265
|
+
|
|
266
|
+
logger.info("Loop ended.")
|
|
@@ -635,7 +635,11 @@ def make_a_choice(
|
|
|
635
635
|
default=default,
|
|
636
636
|
keyboard_interrupt_default=keyboard_interrupt_default,
|
|
637
637
|
)
|
|
638
|
-
|
|
638
|
+
|
|
639
|
+
try:
|
|
640
|
+
return asyncio.run(prompt.prompt_async())
|
|
641
|
+
except Exception: # EOFError: # e.g. closed connection under special circumstances
|
|
642
|
+
return default
|
|
639
643
|
|
|
640
644
|
|
|
641
645
|
ls_format_iter = {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# Generated from labtasker/client/core/cmd_parser/generated/LabCmd.g4 by ANTLR 4.13.2
|
|
2
2
|
# encoding: utf-8
|
|
3
|
-
import
|
|
3
|
+
from labtasker.vendor.antlr4 import *
|
|
4
4
|
from io import StringIO
|
|
5
|
-
|
|
6
|
-
from antlr4 import *
|
|
5
|
+
import sys
|
|
7
6
|
|
|
8
7
|
if sys.version_info[1] > 5:
|
|
9
8
|
from typing import TextIO
|
{labtasker-0.2.4 → labtasker-0.2.6}/labtasker/client/core/cmd_parser/generated/LabCmdLexer.py
RENAMED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Generated from labtasker/client/core/cmd_parser/generated/LabCmdLexer.g4 by ANTLR 4.13.2
|
|
2
|
-
import
|
|
2
|
+
from labtasker.vendor.antlr4 import *
|
|
3
3
|
from io import StringIO
|
|
4
|
-
|
|
5
|
-
from antlr4 import *
|
|
4
|
+
import sys
|
|
6
5
|
|
|
7
6
|
if sys.version_info[1] > 5:
|
|
8
7
|
from typing import TextIO
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Dict, List, Set, Tuple, Union
|
|
3
3
|
|
|
4
|
-
from antlr4 import CommonTokenStream, InputStream, ParserRuleContext, ParseTreeWalker
|
|
5
|
-
from antlr4.error.ErrorListener import ErrorListener
|
|
6
4
|
from rich import print
|
|
7
5
|
from rich.console import Console
|
|
8
6
|
from rich.text import Text
|
|
@@ -17,6 +15,13 @@ from labtasker.client.core.exceptions import (
|
|
|
17
15
|
CmdTypeError,
|
|
18
16
|
)
|
|
19
17
|
from labtasker.client.core.logging import stderr_console
|
|
18
|
+
from labtasker.vendor.antlr4 import (
|
|
19
|
+
CommonTokenStream,
|
|
20
|
+
InputStream,
|
|
21
|
+
ParserRuleContext,
|
|
22
|
+
ParseTreeWalker,
|
|
23
|
+
)
|
|
24
|
+
from labtasker.vendor.antlr4.error.ErrorListener import ErrorListener
|
|
20
25
|
|
|
21
26
|
# Posix quote and windows quote
|
|
22
27
|
if os.name == "nt":
|
|
@@ -158,10 +163,10 @@ def format_print_error(
|
|
|
158
163
|
|
|
159
164
|
|
|
160
165
|
class CmdListener(LabCmdListener):
|
|
161
|
-
def __init__(self, variable_table,
|
|
166
|
+
def __init__(self, variable_table, use_quote: bool):
|
|
162
167
|
super().__init__()
|
|
163
168
|
self.variable_table = variable_table
|
|
164
|
-
self.
|
|
169
|
+
self.use_quote = use_quote
|
|
165
170
|
|
|
166
171
|
self.result_str = ""
|
|
167
172
|
self.args = set()
|
|
@@ -191,12 +196,15 @@ class CmdListener(LabCmdListener):
|
|
|
191
196
|
|
|
192
197
|
if isinstance(self.variable, dict):
|
|
193
198
|
# convert dict into bash string
|
|
194
|
-
|
|
199
|
+
# reverse quotes simplifies the conventional Python string representation
|
|
200
|
+
if self.use_quote:
|
|
195
201
|
self.result_str += quote(reverse_quotes(str(self.variable)))
|
|
196
202
|
else:
|
|
197
203
|
self.result_str += reverse_quotes(str(self.variable))
|
|
198
204
|
else:
|
|
199
|
-
self.result_str +=
|
|
205
|
+
self.result_str += (
|
|
206
|
+
quote(str(self.variable)) if self.use_quote else str(self.variable)
|
|
207
|
+
)
|
|
200
208
|
|
|
201
209
|
self.variable = None
|
|
202
210
|
|
|
@@ -290,9 +298,7 @@ def cmd_interpolate(
|
|
|
290
298
|
interpolated_cmd = []
|
|
291
299
|
involved_keys = set()
|
|
292
300
|
for c in cmd:
|
|
293
|
-
interpolated_str, keys = interpolate_str(
|
|
294
|
-
c, variable_table, quote_dict=False
|
|
295
|
-
)
|
|
301
|
+
interpolated_str, keys = interpolate_str(c, variable_table, use_quote=False)
|
|
296
302
|
interpolated_cmd.append(interpolated_str)
|
|
297
303
|
involved_keys.update(keys)
|
|
298
304
|
|
|
@@ -300,14 +306,14 @@ def cmd_interpolate(
|
|
|
300
306
|
|
|
301
307
|
|
|
302
308
|
def interpolate_str(
|
|
303
|
-
input_str: str, variable_table: Dict[str, Any],
|
|
309
|
+
input_str: str, variable_table: Dict[str, Any], use_quote: bool = True
|
|
304
310
|
) -> Tuple[str, Set[str]]:
|
|
305
311
|
"""
|
|
306
312
|
|
|
307
313
|
Args:
|
|
308
314
|
input_str:
|
|
309
315
|
variable_table:
|
|
310
|
-
|
|
316
|
+
use_quote: quote dict or strings using shlex.quote
|
|
311
317
|
|
|
312
318
|
Returns:
|
|
313
319
|
interpolated str, involved keys
|
|
@@ -325,7 +331,7 @@ def interpolate_str(
|
|
|
325
331
|
try:
|
|
326
332
|
tree = parser.command()
|
|
327
333
|
# Walk the parse tree with the custom listener
|
|
328
|
-
listener = CmdListener(variable_table=variable_table,
|
|
334
|
+
listener = CmdListener(variable_table=variable_table, use_quote=use_quote)
|
|
329
335
|
walker = ParseTreeWalker()
|
|
330
336
|
walker.walk(listener, tree)
|
|
331
337
|
except CmdParserError as e:
|
|
@@ -233,12 +233,15 @@ def loop_run(
|
|
|
233
233
|
# B. Ignore: Reset task to back to PENDING with retries count set to 0, as if this crashed run never happened
|
|
234
234
|
|
|
235
235
|
# 1. log exception
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
236
|
+
if isinstance(e, KeyboardInterrupt):
|
|
237
|
+
logger.warning("KeyboardInterrupt detected")
|
|
238
|
+
else:
|
|
239
|
+
logger.error(f"Task {current_task_id()} failed")
|
|
240
|
+
if not isinstance(e, _LabtaskerJobFailed):
|
|
241
|
+
stderr_console.print_exception(
|
|
242
|
+
# hide traceback from internals
|
|
243
|
+
suppress=[labtasker]
|
|
244
|
+
)
|
|
242
245
|
|
|
243
246
|
# 2. ask the user
|
|
244
247
|
_next_action = "report" # one of ["report", "ignore"]
|
|
@@ -256,7 +259,7 @@ def loop_run(
|
|
|
256
259
|
),
|
|
257
260
|
]
|
|
258
261
|
choice = make_a_choice(
|
|
259
|
-
question="Task failed with the above
|
|
262
|
+
question="Task interrupted or failed with the above info. You have 10 seconds to make a choice:",
|
|
260
263
|
options=choices,
|
|
261
264
|
# if timed out while waiting for user input, we assume the user is not present and report this crash by default
|
|
262
265
|
default=choices[0],
|