labtasker 0.2.6__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. {labtasker-0.2.6 → labtasker-0.2.8}/PKG-INFO +9 -11
  2. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/__init__.py +1 -1
  3. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/api_models.py +2 -1
  4. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/config.py +4 -3
  5. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/client_api.py +9 -1
  6. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/api.py +2 -0
  7. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/config.py +1 -1
  8. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/context.py +5 -0
  9. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/job_runner.py +2 -5
  10. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/logging.py +2 -0
  11. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/query_transpiler.py +10 -10
  12. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/database.py +5 -2
  13. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/endpoints.py +1 -0
  14. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker.egg-info/SOURCES.txt +1 -35
  15. {labtasker-0.2.6 → labtasker-0.2.8}/pyproject.toml +11 -13
  16. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_task.py +1 -3
  17. labtasker-0.2.8/tests/test_client/test_core/test_event/test_event_listener_entity_data.py +108 -0
  18. {labtasker-0.2.6 → labtasker-0.2.8}/tox.ini +1 -1
  19. labtasker-0.2.6/.coveragerc +0 -5
  20. labtasker-0.2.6/.dockerignore +0 -11
  21. labtasker-0.2.6/.flake8 +0 -20
  22. labtasker-0.2.6/.gitattributes +0 -217
  23. labtasker-0.2.6/.gitignore +0 -189
  24. labtasker-0.2.6/.gitmodules +0 -8
  25. labtasker-0.2.6/.pre-commit-config.yaml +0 -24
  26. labtasker-0.2.6/.pytest.ini +0 -9
  27. labtasker-0.2.6/.python-version +0 -6
  28. labtasker-0.2.6/Dockerfile +0 -25
  29. labtasker-0.2.6/PRIVACY.md +0 -1
  30. labtasker-0.2.6/demo/advanced/custom_resolver/submit_job.py +0 -11
  31. labtasker-0.2.6/demo/advanced/custom_resolver/w.py +0 -38
  32. labtasker-0.2.6/demo/advanced/custom_resolver/wo.py +0 -29
  33. labtasker-0.2.6/demo/advanced/event_system/email_on_task_failure.py +0 -67
  34. labtasker-0.2.6/demo/advanced/event_system/send_email.py +0 -46
  35. labtasker-0.2.6/demo/advanced/event_system/sim_unstable_job.py +0 -27
  36. labtasker-0.2.6/demo/advanced/event_system/submit.sh +0 -10
  37. labtasker-0.2.6/demo/basic/bash_demo/job_main.py +0 -23
  38. labtasker-0.2.6/demo/basic/bash_demo/run_job.sh +0 -8
  39. labtasker-0.2.6/demo/basic/bash_demo/submit_job.sh +0 -13
  40. labtasker-0.2.6/demo/basic/python_demo/run_job.py +0 -25
  41. labtasker-0.2.6/demo/basic/python_demo/submit_job.py +0 -9
  42. labtasker-0.2.6/docker/mongodb/init.d/init-keyfile.sh +0 -29
  43. labtasker-0.2.6/docker/mongodb/post-init.d/init-mongo.sh +0 -53
  44. labtasker-0.2.6/docker-compose.yml +0 -90
  45. labtasker-0.2.6/script_tests/test_ban_datetime_now/allowed.py +0 -80
  46. labtasker-0.2.6/script_tests/test_ban_datetime_now/disallowed.py +0 -129
  47. labtasker-0.2.6/script_tests/test_ban_datetime_now/test_ban.py +0 -138
  48. labtasker-0.2.6/scripts/asciinema_adjust_timestamp.py +0 -38
  49. labtasker-0.2.6/scripts/check_version.py +0 -59
  50. labtasker-0.2.6/scripts/datetime_now_checker.py +0 -268
  51. labtasker-0.2.6/scripts/get_vendored.py +0 -137
  52. labtasker-0.2.6/server.example.env +0 -24
  53. labtasker-0.2.6/tests/test_client/test_core/test_event/test_event_integration.py +0 -0
  54. {labtasker-0.2.6 → labtasker-0.2.8}/LICENSE +0 -0
  55. {labtasker-0.2.6 → labtasker-0.2.8}/MANIFEST.in +0 -0
  56. {labtasker-0.2.6 → labtasker-0.2.8}/README.md +0 -0
  57. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/__main__.py +0 -0
  58. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/__init__.py +0 -0
  59. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/__init__.py +0 -0
  60. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/cli.py +0 -0
  61. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/event.py +0 -0
  62. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/init.py +0 -0
  63. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/loop.py +0 -0
  64. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/queue.py +0 -0
  65. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/task.py +0 -0
  66. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/cli/worker.py +0 -0
  67. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/__init__.py +0 -0
  68. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cli_utils.py +0 -0
  69. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/LabCmd.g4 +0 -0
  70. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/LabCmdLexer.g4 +0 -0
  71. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/__init__.py +0 -0
  72. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/generated/LabCmd.py +0 -0
  73. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/generated/LabCmdLexer.py +0 -0
  74. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/generated/LabCmdListener.py +0 -0
  75. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/generated/__init__.py +0 -0
  76. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/cmd_parser/parser.py +0 -0
  77. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/events.py +0 -0
  78. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/exceptions.py +0 -0
  79. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/heartbeat.py +0 -0
  80. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/paths.py +0 -0
  81. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/plugin_utils.py +0 -0
  82. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/resolver/__init__.py +0 -0
  83. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/resolver/models.py +0 -0
  84. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/resolver/utils.py +0 -0
  85. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/utils.py +0 -0
  86. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/core/version_checker.py +0 -0
  87. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/templates/labtasker_root/.gitignore +0 -0
  88. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/templates/labtasker_root/client.toml +0 -0
  89. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/client/templates/labtasker_root/logs/.gitkeep +0 -0
  90. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/constants.py +0 -0
  91. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/filtering.py +0 -0
  92. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/security.py +0 -0
  93. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/__init__.py +0 -0
  94. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/cli.py +0 -0
  95. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/config.py +0 -0
  96. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/db_utils.py +0 -0
  97. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/dependencies.py +0 -0
  98. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/embedded_db.py +0 -0
  99. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/event_manager.py +0 -0
  100. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/fsm.py +0 -0
  101. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/server/logging.py +0 -0
  102. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/utils.py +0 -0
  103. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/README.txt +0 -0
  104. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/__init__.py +0 -0
  105. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/BufferedTokenStream.py +0 -0
  106. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/CommonTokenFactory.py +0 -0
  107. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/CommonTokenStream.py +0 -0
  108. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/FileStream.py +0 -0
  109. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/InputStream.py +0 -0
  110. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/IntervalSet.py +0 -0
  111. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/LL1Analyzer.py +0 -0
  112. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/Lexer.py +0 -0
  113. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/ListTokenSource.py +0 -0
  114. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/Parser.py +0 -0
  115. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/ParserInterpreter.py +0 -0
  116. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/ParserRuleContext.py +0 -0
  117. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/PredictionContext.py +0 -0
  118. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/Recognizer.py +0 -0
  119. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/RuleContext.py +0 -0
  120. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/StdinStream.py +0 -0
  121. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/Token.py +0 -0
  122. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/TokenStreamRewriter.py +0 -0
  123. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/Utils.py +0 -0
  124. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/__init__.py +0 -0
  125. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/_pygrun.py +0 -0
  126. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATN.py +0 -0
  127. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNConfig.py +0 -0
  128. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNConfigSet.py +0 -0
  129. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNDeserializationOptions.py +0 -0
  130. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNDeserializer.py +0 -0
  131. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNSimulator.py +0 -0
  132. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNState.py +0 -0
  133. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ATNType.py +0 -0
  134. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/LexerATNSimulator.py +0 -0
  135. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/LexerAction.py +0 -0
  136. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/LexerActionExecutor.py +0 -0
  137. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/ParserATNSimulator.py +0 -0
  138. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/PredictionMode.py +0 -0
  139. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/SemanticContext.py +0 -0
  140. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/Transition.py +0 -0
  141. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/atn/__init__.py +0 -0
  142. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/dfa/DFA.py +0 -0
  143. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/dfa/DFASerializer.py +0 -0
  144. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/dfa/DFAState.py +0 -0
  145. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/dfa/__init__.py +0 -0
  146. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/error/DiagnosticErrorListener.py +0 -0
  147. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/error/ErrorListener.py +0 -0
  148. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/error/ErrorStrategy.py +0 -0
  149. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/error/Errors.py +0 -0
  150. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/error/__init__.py +0 -0
  151. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/Chunk.py +0 -0
  152. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/ParseTreeMatch.py +0 -0
  153. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/ParseTreePattern.py +0 -0
  154. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/ParseTreePatternMatcher.py +0 -0
  155. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/RuleTagToken.py +0 -0
  156. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/TokenTagToken.py +0 -0
  157. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/Tree.py +0 -0
  158. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/Trees.py +0 -0
  159. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/tree/__init__.py +0 -0
  160. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/xpath/XPath.py +0 -0
  161. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/xpath/XPathLexer.py +0 -0
  162. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/antlr4/xpath/__init__.py +0 -0
  163. {labtasker-0.2.6 → labtasker-0.2.8}/labtasker/vendor/vendor.txt +0 -0
  164. {labtasker-0.2.6 → labtasker-0.2.8}/setup.cfg +0 -0
  165. {labtasker-0.2.6 → labtasker-0.2.8}/tests/__init__.py +0 -0
  166. {labtasker-0.2.6 → labtasker-0.2.8}/tests/conftest.py +0 -0
  167. {labtasker-0.2.6 → labtasker-0.2.8}/tests/demo_pager_iterator.py +0 -0
  168. {labtasker-0.2.6 → labtasker-0.2.8}/tests/dummy_jobs/job_1.py +0 -0
  169. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/__init__.py +0 -0
  170. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/database/__init__.py +0 -0
  171. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/database/mock.py +0 -0
  172. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/database/real.py +0 -0
  173. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/logging.py +0 -0
  174. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/mock_datetime_now.py +0 -0
  175. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/server/__init__.py +0 -0
  176. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/server/async_app.py +0 -0
  177. {labtasker-0.2.6 → labtasker-0.2.8}/tests/fixtures/server/sync_app.py +0 -0
  178. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_api_models.py +0 -0
  179. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/__init__.py +0 -0
  180. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/conftest.py +0 -0
  181. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/__init__.py +0 -0
  182. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/conftest.py +0 -0
  183. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_basic.py +0 -0
  184. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_config.py +0 -0
  185. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_event.py +0 -0
  186. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_init.py +0 -0
  187. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_loop.py +0 -0
  188. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_queue.py +0 -0
  189. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_cli/test_worker.py +0 -0
  190. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/__init__.py +0 -0
  191. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_cli_utils.py +0 -0
  192. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_event/__init__.py +0 -0
  193. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_event/test_concurrency_job_flow_event.py +0 -0
  194. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_event/test_event_listener_basic.py +0 -0
  195. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_event/test_various_actions.py +0 -0
  196. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_event/utils.py +0 -0
  197. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_heartbeat.py +0 -0
  198. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_job_runner.py +0 -0
  199. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_logging.py +0 -0
  200. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_loop_internal_error_handler.py +0 -0
  201. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_pager_iterator.py +0 -0
  202. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_parser.py +0 -0
  203. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_query_transpiler/__init__.py +0 -0
  204. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_query_transpiler/conftest.py +0 -0
  205. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_query_transpiler/test_behavior.py +0 -0
  206. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_query_transpiler/test_matching.py +0 -0
  207. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_query_transpiler/test_utils.py +0 -0
  208. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_query_transpiler/utils.py +0 -0
  209. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_resolver.py +0 -0
  210. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_concurrency/__init__.py +0 -0
  211. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_concurrency/run_concurrent.py +0 -0
  212. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_concurrency/test_runner_concurrency_success_failure.py +0 -0
  213. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_concurrency/test_runner_high_concurrency.py +0 -0
  214. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_timeout/__init__.py +0 -0
  215. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_timeout/conftest.py +0 -0
  216. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_timeout/test_job_runner_timeout.py +0 -0
  217. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_timeout/test_job_runner_with_resolver_timeout.py +0 -0
  218. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_runner_with_resolver.py +0 -0
  219. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_server_notification_and_client_version.py +0 -0
  220. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_client/test_core/test_version_checker.py +0 -0
  221. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_filtering/__init__.py +0 -0
  222. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_filtering/exception_utils.py +0 -0
  223. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_filtering/test_exception_filtering.py +0 -0
  224. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_mock_time.py +0 -0
  225. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_security.py +0 -0
  226. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/__init__.py +0 -0
  227. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/conftest.py +0 -0
  228. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_database/__init__.py +0 -0
  229. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_database/conftest.py +0 -0
  230. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_database/test_database_basic.py +0 -0
  231. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_database/test_fetch_extra_filter.py +0 -0
  232. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_database/test_query_dict_to_mongo_filter.py +0 -0
  233. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_database/test_required_field_fetching.py +0 -0
  234. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_db_utils/__init__.py +0 -0
  235. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_db_utils/test_arg_match.py +0 -0
  236. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_db_utils/test_keys_to_query_dict.py +0 -0
  237. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_db_utils/test_keys_to_query_dict_deepest.py +0 -0
  238. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_db_utils/test_keys_to_query_dict_topmost.py +0 -0
  239. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_embedded_db.py +0 -0
  240. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_endpoint/__init__.py +0 -0
  241. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_endpoint/test_event_basic.py +0 -0
  242. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_endpoint/test_server.py +0 -0
  243. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_endpoint/test_server_async.py +0 -0
  244. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_endpoint/test_server_async_ping.py +0 -0
  245. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_fsm.py +0 -0
  246. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_server/test_get_verified_queue_dependency.py +0 -0
  247. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_utils/__init__.py +0 -0
  248. {labtasker-0.2.6 → labtasker-0.2.8}/tests/test_utils/test_utils.py +0 -0
  249. {labtasker-0.2.6 → labtasker-0.2.8}/tests/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labtasker
3
- Version: 0.2.6
3
+ Version: 0.2.8
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
@@ -11,29 +11,27 @@ Classifier: Intended Audience :: Science/Research
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
14
  Classifier: Programming Language :: Python :: 3.10
17
15
  Classifier: Programming Language :: Python :: 3.11
18
16
  Classifier: Programming Language :: Python :: 3.12
19
17
  Classifier: Programming Language :: Python :: 3.13
20
- Requires-Python: <4.0,>=3.8.1
18
+ Requires-Python: <4.0,>=3.10
21
19
  Description-Content-Type: text/markdown
22
20
  License-File: LICENSE
23
21
  Requires-Dist: pymongo<5.0.0,>=4.0.0
24
- Requires-Dist: fastapi<0.116.0,>=0.115.0
25
- Requires-Dist: uvicorn[standard]<0.35.0,>=0.15.0
26
- Requires-Dist: click<9.0.0,>=8.1.0
22
+ Requires-Dist: fastapi<0.117.0,>=0.115.0
23
+ Requires-Dist: uvicorn[standard]<0.36.0,>=0.15.0
24
+ Requires-Dist: click<9.0.0,>=8.2.0
27
25
  Requires-Dist: passlib<2.0.0,>=1.7.0
28
26
  Requires-Dist: pydantic-settings<3.0.0,>=2.8.0
29
27
  Requires-Dist: httpx[socks]<0.29.0,>=0.28.0
30
- Requires-Dist: typer<0.16.0,>=0.15.0
28
+ Requires-Dist: typer<0.17.0,>=0.16.0
31
29
  Requires-Dist: loguru<0.8.0,>=0.7.0
32
30
  Requires-Dist: ruamel-yaml<0.19.0,>=0.18.10
33
31
  Requires-Dist: pyyaml<7.0.0,>=6.0.0
34
32
  Requires-Dist: tomlkit<0.14.0,>=0.13.2
35
33
  Requires-Dist: importlib-metadata<9.0.0,>=8.5.0
36
- Requires-Dist: packaging<25.0,>=24.2
34
+ Requires-Dist: packaging<26.0,>=24.2
37
35
  Requires-Dist: sse-starlette<3.0.0,>=2.1.3
38
36
  Requires-Dist: httpx-sse<0.5.0,>=0.4.0
39
37
  Requires-Dist: stamina<26.0.0,>=25.1.0
@@ -52,9 +50,9 @@ Requires-Dist: flake8<8.0.0,>=7.0.0; extra == "dev"
52
50
  Requires-Dist: pre-commit<5.0.0,>=3.0.0; extra == "dev"
53
51
  Requires-Dist: freezegun<2.0.0,>=1.5.0; extra == "dev"
54
52
  Requires-Dist: pytest-docker<4.0.0,>=3.0.0; extra == "dev"
55
- Requires-Dist: pytest-asyncio<0.27.0,>=0.24.0; extra == "dev"
53
+ Requires-Dist: pytest-asyncio<1.1.0,>=0.24.0; extra == "dev"
56
54
  Requires-Dist: asgi-lifespan<3.0.0,>=2.1.0; extra == "dev"
57
- Requires-Dist: tox<4.26.0,>=4.24.0; extra == "dev"
55
+ Requires-Dist: tox<4.28.0,>=4.24.0; extra == "dev"
58
56
  Requires-Dist: pytest-dependency<0.7.0,>=0.6.0; extra == "dev"
59
57
  Requires-Dist: pytest-sugar<2.0.0,>=1.0.0; extra == "dev"
60
58
  Provides-Extra: doc
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.6"
1
+ __version__ = "0.2.8"
2
2
 
3
3
  from labtasker.client.client_api import *
4
4
  from labtasker.client.core.config import get_client_config
@@ -126,6 +126,7 @@ class TaskFetchRequest(BaseRequestModel):
126
126
  start_heartbeat: bool = True
127
127
  required_fields: Optional[List[str]] = None
128
128
  extra_filter: Optional[Dict[str, Any]] = None
129
+ cmd: Optional[Union[str, List[str]]] = None
129
130
 
130
131
 
131
132
  class Task(
@@ -149,7 +150,7 @@ class Task(
149
150
  priority: int
150
151
  metadata: Dict
151
152
  args: Dict
152
- cmd: Union[str, List[str]]
153
+ cmd: Optional[Union[str, List[str]]]
153
154
  summary: Dict
154
155
  worker_id: Optional[str]
155
156
 
@@ -48,9 +48,10 @@ def config(
48
48
  # 1.1 Copy existing configuration to the temporary file (if it exists)
49
49
  config_path = get_labtasker_client_config_path()
50
50
  if config_path.exists():
51
- with open(config_path, "rb") as existing_config, open(
52
- temp_file_path, "wb"
53
- ) as temp_file:
51
+ with (
52
+ open(config_path, "rb") as existing_config,
53
+ open(temp_file_path, "wb") as temp_file,
54
+ ):
54
55
  temp_file.write(existing_config.read())
55
56
 
56
57
  # 1.2 Open the temporary file in the editor and validate changes
@@ -1,7 +1,12 @@
1
1
  from typing import Any, Dict, List, Optional, Union
2
2
 
3
3
  from labtasker.client.core.api import * # noqa: F403
4
- from labtasker.client.core.context import current_task_id, current_worker_id, task_info
4
+ from labtasker.client.core.context import (
5
+ current_task_id,
6
+ current_worker_id,
7
+ is_enabled,
8
+ task_info,
9
+ )
5
10
  from labtasker.client.core.events import EventListener, connect_events
6
11
  from labtasker.client.core.exceptions import LabtaskerTypeError, LabtaskerValueError
7
12
  from labtasker.client.core.job_runner import (
@@ -10,6 +15,7 @@ from labtasker.client.core.job_runner import (
10
15
  set_loop_internal_error_handler,
11
16
  set_prompt_on_task_failure,
12
17
  )
18
+ from labtasker.client.core.paths import get_labtasker_log_dir
13
19
  from labtasker.client.core.resolver import (
14
20
  Required,
15
21
  get_params_from_function,
@@ -29,6 +35,8 @@ __all__ = [
29
35
  "task_info",
30
36
  "current_task_id",
31
37
  "current_worker_id",
38
+ "is_enabled",
39
+ "get_labtasker_log_dir",
32
40
  # event api
33
41
  "connect_events",
34
42
  "EventListener",
@@ -195,6 +195,7 @@ def fetch_task(
195
195
  required_fields: Optional[List[str]] = None,
196
196
  extra_filter: Optional[Dict[str, Any]] = None,
197
197
  client: Optional[httpx.Client] = None,
198
+ cmd: Optional[Union[str, List[str]]] = None,
198
199
  ) -> TaskFetchResponse:
199
200
  """Fetch the next available task from the queue."""
200
201
  if client is None:
@@ -212,6 +213,7 @@ def fetch_task(
212
213
  start_heartbeat=start_heartbeat,
213
214
  required_fields=required_fields,
214
215
  extra_filter=extra_filter,
216
+ cmd=cmd,
215
217
  ).model_dump()
216
218
  response = client.post("/api/v1/queues/me/tasks/next", json=payload)
217
219
  if response.status_code == HTTP_403_FORBIDDEN:
@@ -99,7 +99,7 @@ def requires_client_config(
99
99
  if not _config and not get_labtasker_client_config_path().exists():
100
100
  stderr_console.print(
101
101
  "[bold red]Error:[/bold red] Configuration not initialized. "
102
- "Run [orange1]`labtasker config`[/orange1] to initialize configuration."
102
+ "Run [orange1]`labtasker init`[/orange1] to initialize configuration."
103
103
  )
104
104
  raise typer.Exit(-1)
105
105
 
@@ -52,3 +52,8 @@ def set_current_task_id(task_id: str):
52
52
  def set_current_worker_id(worker_id: Optional[str]):
53
53
  os.environ["LABTASKER_WORKER_ID"] = worker_id if worker_id else ""
54
54
  _current_worker_id.set(worker_id)
55
+
56
+
57
+ def is_enabled() -> bool:
58
+ """Whether current script is executed under Labtasker context."""
59
+ return current_worker_id() is not None
@@ -183,6 +183,7 @@ def loop_run(
183
183
  start_heartbeat=True,
184
184
  required_fields=required_fields,
185
185
  extra_filter=extra_filter,
186
+ cmd=cmd,
186
187
  )
187
188
  if not resp.found: # task run complete
188
189
  logger.info(
@@ -190,11 +191,7 @@ def loop_run(
190
191
  )
191
192
  break
192
193
 
193
- # update the "cmd" field of the current task, and get the updated task info
194
- task = update_tasks(
195
- [TaskUpdateRequest(task_id=resp.task.task_id, cmd=cmd)], # noqa
196
- reset_pending=False,
197
- ).content[0]
194
+ task = resp.task
198
195
 
199
196
  logger.info(
200
197
  f"Prepared to run task {task.task_id} with args {task.args}."
@@ -18,12 +18,14 @@ stderr_console = Console(markup=True, stderr=True)
18
18
  LOGGER_FORMAT = (
19
19
  "<green>[{time:YYYY-MM-DD HH:mm:ss.SSS}]</green>"
20
20
  "[<level>{level: <8}</level>]"
21
+ "[<cyan>{name}</cyan>]"
21
22
  " - <level>{message}</level>"
22
23
  )
23
24
 
24
25
  DEBUG_LOGGER_FORMAT = (
25
26
  "<green>[{time:YYYY-MM-DD HH:mm:ss.SSS}]</green>"
26
27
  "[<level>{level: <8}</level>]"
28
+ "[<cyan>{name}</cyan>]"
27
29
  "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
28
30
  )
29
31
 
@@ -706,8 +706,8 @@ class QueryTranspiler(ast.NodeVisitor):
706
706
  # Python 3.8 and earlier uses an Index node
707
707
  if isinstance(node.slice, ast.Index):
708
708
  # Extract the value from the Index node
709
- if isinstance(node.slice.value, ast.Constant):
710
- index = node.slice.value.value
709
+ if isinstance(node.slice.value, ast.Constant): # type: ignore[attr-defined]
710
+ index = node.slice.value.value # type: ignore[attr-defined]
711
711
  # Type check: only allow string and integer subscripts
712
712
  if isinstance(index, (str, int)):
713
713
  return f"{value}.{index}"
@@ -719,16 +719,16 @@ class QueryTranspiler(ast.NodeVisitor):
719
719
  exception=QueryTranspilerValueError,
720
720
  )
721
721
  # Handle negative indexing with unary operations
722
- elif isinstance(node.slice.value, ast.UnaryOp) and isinstance(
723
- node.slice.value.op, ast.USub
722
+ elif isinstance(node.slice.value, ast.UnaryOp) and isinstance( # type: ignore[attr-defined]
723
+ node.slice.value.op, ast.USub # type: ignore[attr-defined]
724
724
  ):
725
725
  # Get the operand value if possible
726
726
  operand_info = ""
727
727
  try:
728
- if isinstance(node.slice.value.operand, ast.Constant):
729
- operand_info = f" (value: -{node.slice.value.operand.value})"
730
- elif isinstance(node.slice.value.operand, ast.Name):
731
- operand_info = f" (variable: -{node.slice.value.operand.id})"
728
+ if isinstance(node.slice.value.operand, ast.Constant): # type: ignore[attr-defined]
729
+ operand_info = f" (value: -{node.slice.value.operand.value!s})" # type: ignore[attr-defined]
730
+ elif isinstance(node.slice.value.operand, ast.Name): # type: ignore[attr-defined]
731
+ operand_info = f" (variable: -{node.slice.value.operand.id})" # type: ignore[attr-defined]
732
732
  except AttributeError:
733
733
  pass
734
734
 
@@ -742,7 +742,7 @@ class QueryTranspiler(ast.NodeVisitor):
742
742
  self._report_error(
743
743
  # More specific node location
744
744
  node=node.slice.value, # type: ignore
745
- msg=f"Unsupported index value type: {type(node.slice.value).__name__}",
745
+ msg=f"Unsupported index value type: {type(node.slice.value).__name__}", # type: ignore[attr-defined]
746
746
  exception=QueryTranspilerValueError,
747
747
  )
748
748
 
@@ -769,7 +769,7 @@ class QueryTranspiler(ast.NodeVisitor):
769
769
  operand_info = ""
770
770
  try:
771
771
  if isinstance(node.slice.operand, ast.Constant):
772
- operand_info = f" (value: -{node.slice.operand.value})"
772
+ operand_info = f" (value: -{node.slice.operand.value})" # type: ignore[str-bytes-safe]
773
773
  elif isinstance(node.slice.operand, ast.Name):
774
774
  operand_info = f" (variable: -{node.slice.operand.id})"
775
775
  except AttributeError:
@@ -521,6 +521,7 @@ class DBService:
521
521
  start_heartbeat: bool = True,
522
522
  required_fields: Optional[List[str]] = None,
523
523
  extra_filter: Optional[Dict[str, Any]] = None,
524
+ cmd: Optional[Union[str, List[str]]] = None,
524
525
  ) -> Optional[Mapping[str, Any]]:
525
526
  """
526
527
  Fetch next available task from queue.
@@ -538,6 +539,7 @@ class DBService:
538
539
  start_heartbeat (bool): Whether to start heartbeat.
539
540
  required_fields (list, optional): Which fields are required. If None, no constraint is put on which fields should exist in args dict.
540
541
  extra_filter (Dict[str, Any], optional): Additional filter criteria for the task.
542
+ cmd (Optional[Union[str, List[str]]]): The command that runs the job.
541
543
  """
542
544
  task_timeout = parse_timeout(eta_max) if eta_max else None
543
545
 
@@ -611,6 +613,7 @@ class DBService:
611
613
  "last_heartbeat": now if start_heartbeat else None,
612
614
  "last_modified": now,
613
615
  "worker_id": worker_id,
616
+ "cmd": cmd,
614
617
  }
615
618
  }
616
619
 
@@ -741,7 +744,7 @@ class DBService:
741
744
  )
742
745
 
743
746
  for event_handle in event_handles:
744
- event_handle.update_fsm_event(task, commit=True)
747
+ event_handle.commit()
745
748
 
746
749
  return True
747
750
 
@@ -774,7 +777,7 @@ class DBService:
774
777
  )
775
778
 
776
779
  for event_handle in event_handles:
777
- event_handle.update_fsm_event(task, commit=True)
780
+ event_handle.commit()
778
781
  return True
779
782
 
780
783
  def _report_task_status(
@@ -263,6 +263,7 @@ def fetch_task(
263
263
  start_heartbeat=task_request.start_heartbeat,
264
264
  required_fields=task_request.required_fields,
265
265
  extra_filter=task_request.extra_filter,
266
+ cmd=task_request.cmd,
266
267
  )
267
268
 
268
269
  if not task:
@@ -1,35 +1,8 @@
1
- .coveragerc
2
- .dockerignore
3
- .flake8
4
- .gitattributes
5
- .gitignore
6
- .gitmodules
7
- .pre-commit-config.yaml
8
- .pytest.ini
9
- .python-version
10
- Dockerfile
11
1
  LICENSE
12
2
  MANIFEST.in
13
- PRIVACY.md
14
3
  README.md
15
- docker-compose.yml
16
4
  pyproject.toml
17
- server.example.env
18
5
  tox.ini
19
- demo/advanced/custom_resolver/submit_job.py
20
- demo/advanced/custom_resolver/w.py
21
- demo/advanced/custom_resolver/wo.py
22
- demo/advanced/event_system/email_on_task_failure.py
23
- demo/advanced/event_system/send_email.py
24
- demo/advanced/event_system/sim_unstable_job.py
25
- demo/advanced/event_system/submit.sh
26
- demo/basic/bash_demo/job_main.py
27
- demo/basic/bash_demo/run_job.sh
28
- demo/basic/bash_demo/submit_job.sh
29
- demo/basic/python_demo/run_job.py
30
- demo/basic/python_demo/submit_job.py
31
- docker/mongodb/init.d/init-keyfile.sh
32
- docker/mongodb/post-init.d/init-mongo.sh
33
6
  labtasker/__init__.py
34
7
  labtasker/__main__.py
35
8
  labtasker/api_models.py
@@ -149,13 +122,6 @@ labtasker/vendor/antlr4/tree/__init__.py
149
122
  labtasker/vendor/antlr4/xpath/XPath.py
150
123
  labtasker/vendor/antlr4/xpath/XPathLexer.py
151
124
  labtasker/vendor/antlr4/xpath/__init__.py
152
- script_tests/test_ban_datetime_now/allowed.py
153
- script_tests/test_ban_datetime_now/disallowed.py
154
- script_tests/test_ban_datetime_now/test_ban.py
155
- scripts/asciinema_adjust_timestamp.py
156
- scripts/check_version.py
157
- scripts/datetime_now_checker.py
158
- scripts/get_vendored.py
159
125
  tests/__init__.py
160
126
  tests/conftest.py
161
127
  tests/demo_pager_iterator.py
@@ -199,8 +165,8 @@ tests/test_client/test_core/test_server_notification_and_client_version.py
199
165
  tests/test_client/test_core/test_version_checker.py
200
166
  tests/test_client/test_core/test_event/__init__.py
201
167
  tests/test_client/test_core/test_event/test_concurrency_job_flow_event.py
202
- tests/test_client/test_core/test_event/test_event_integration.py
203
168
  tests/test_client/test_core/test_event/test_event_listener_basic.py
169
+ tests/test_client/test_core/test_event/test_event_listener_entity_data.py
204
170
  tests/test_client/test_core/test_event/test_various_actions.py
205
171
  tests/test_client/test_core/test_event/utils.py
206
172
  tests/test_client/test_core/test_query_transpiler/__init__.py
@@ -1,22 +1,20 @@
1
1
  [build-system]
2
- requires = ["setuptools>=45", "wheel", "setuptools_scm>=6.2"]
2
+ requires = ["setuptools>=45", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "labtasker"
7
- version = "0.2.6"
7
+ version = "0.2.8"
8
8
  description = "A task queue system for lab experiments"
9
9
  authors = [{ name = "Your Name", email = "your.email@example.com" }]
10
10
  license = { text = "Apache License 2.0" }
11
11
  readme = "README.md"
12
- requires-python = ">=3.8.1,<4.0"
12
+ requires-python = ">=3.10,<4.0"
13
13
  classifiers = [
14
14
  "Intended Audience :: Science/Research",
15
15
  "License :: OSI Approved :: Apache Software License",
16
16
  "Operating System :: OS Independent",
17
17
  "Programming Language :: Python :: 3",
18
- "Programming Language :: Python :: 3.8",
19
- "Programming Language :: Python :: 3.9",
20
18
  "Programming Language :: Python :: 3.10",
21
19
  "Programming Language :: Python :: 3.11",
22
20
  "Programming Language :: Python :: 3.12",
@@ -25,19 +23,19 @@ classifiers = [
25
23
 
26
24
  dependencies = [
27
25
  "pymongo (>=4.0.0,<5.0.0)",
28
- "fastapi (>=0.115.0,<0.116.0)",
29
- "uvicorn[standard] (>=0.15.0,<0.35.0)",
30
- "click (>=8.1.0,<9.0.0)",
26
+ "fastapi (>=0.115.0,<0.117.0)",
27
+ "uvicorn[standard] (>=0.15.0,<0.36.0)",
28
+ "click (>=8.2.0,<9.0.0)",
31
29
  "passlib (>=1.7.0,<2.0.0)",
32
30
  "pydantic-settings (>=2.8.0,<3.0.0)",
33
31
  "httpx[socks] (>=0.28.0,<0.29.0)",
34
- "typer (>=0.15.0,<0.16.0)",
32
+ "typer (>=0.16.0,<0.17.0)",
35
33
  "loguru (>=0.7.0,<0.8.0)",
36
34
  "ruamel-yaml (>=0.18.10,<0.19.0)",
37
35
  "pyyaml (>=6.0.0,<7.0.0)",
38
36
  "tomlkit (>=0.13.2,<0.14.0)",
39
37
  "importlib-metadata (>=8.5.0,<9.0.0)",
40
- "packaging (>=24.2,<25.0)",
38
+ "packaging (>=24.2,<26.0)",
41
39
  "sse-starlette (>=2.1.3,<3.0.0)",
42
40
  "httpx-sse (>=0.4.0,<0.5.0)",
43
41
  "stamina (>=25.1.0,<26.0.0)",
@@ -59,9 +57,9 @@ dev = [
59
57
  "pre-commit (>=3.0.0,<5.0.0)",
60
58
  "freezegun (>=1.5.0,<2.0.0)",
61
59
  "pytest-docker (>=3.0.0,<4.0.0)",
62
- "pytest-asyncio (>=0.24.0,<0.27.0)",
60
+ "pytest-asyncio (>=0.24.0,<1.1.0)",
63
61
  "asgi-lifespan (>=2.1.0,<3.0.0)",
64
- "tox (>=4.24.0,<4.26.0)",
62
+ "tox (>=4.24.0,<4.28.0)",
65
63
  "pytest-dependency (>=0.6.0,<0.7.0)",
66
64
  "pytest-sugar (>=1.0.0,<2.0.0)",
67
65
  ]
@@ -130,7 +128,7 @@ disable_error_code = [
130
128
  "no-redef",
131
129
  "import-untyped"
132
130
  ]
133
- python_version = "3.8"
131
+ python_version = "3.10"
134
132
  warn_unused_configs = true
135
133
  ignore_missing_imports = true
136
134
  show_error_codes = true
@@ -18,9 +18,7 @@ from labtasker.server.fsm import TaskState
18
18
  from labtasker.utils import get_current_time
19
19
  from tests.test_client.test_cli.test_queue import cli_create_queue_from_config
20
20
 
21
- runner = CliRunner(
22
- mix_stderr=False
23
- ) # mix_stderr must be set to False to access result.stderr
21
+ runner = CliRunner()
24
22
 
25
23
  # Mark the entire file as e2e, integration and unit tests
26
24
  pytestmark = [
@@ -0,0 +1,108 @@
1
+ """
2
+ End-to-end tests for the EventListener class that checks entity data.
3
+ """
4
+
5
+ import threading
6
+ import time
7
+
8
+ import pytest
9
+
10
+ from labtasker import Required, create_queue, loop, submit_task
11
+ from labtasker.api_models import EventResponse
12
+ from labtasker.client.core.events import connect_events
13
+ from tests.fixtures.logging import silence_logger
14
+ from tests.test_client.test_core.test_event.utils import dump_events
15
+
16
+ pytestmark = [
17
+ pytest.mark.e2e,
18
+ pytest.mark.usefixtures("silence_logger"),
19
+ ]
20
+
21
+
22
+ @pytest.fixture(autouse=True)
23
+ def setup_queue(client_config, db_fixture):
24
+ # relies on db_fixture so that DB is cleaned up after each test
25
+ return create_queue(
26
+ queue_name=client_config.queue.queue_name,
27
+ password=client_config.queue.password.get_secret_value(),
28
+ metadata={"tag": "test"},
29
+ )
30
+
31
+
32
+ def test_event_listener_entity_data():
33
+ """Test the basic flow of events when tasks are submitted and processed."""
34
+ job_finish_event = threading.Event()
35
+ listener = connect_events(timeout=5)
36
+
37
+ def jobflow_thread():
38
+ try:
39
+ # Submit tasks to generate events
40
+ task_id = submit_task(
41
+ task_name="test_task",
42
+ args={"foo": "bar"},
43
+ max_retries=1, # only 1 attempt
44
+ ).task_id
45
+
46
+ @loop()
47
+ def dummy(foo=Required()):
48
+ time.sleep(0.5)
49
+ raise RuntimeError # crash task
50
+
51
+ dummy() # fetch and run tasks
52
+ except Exception as e:
53
+ pytest.fail(f"Error in jobflow thread: {e}")
54
+ finally:
55
+ job_finish_event.set()
56
+
57
+ jobflow_thread = threading.Thread(target=jobflow_thread, daemon=True)
58
+
59
+ time.sleep(1) # wait for the listener to start
60
+ jobflow_thread.start()
61
+
62
+ # Wait for job to finish with timeout
63
+ job_finish_event.wait(timeout=10)
64
+ # Give some time for all events to be processed
65
+ time.sleep(2)
66
+ listener.stop()
67
+
68
+ # Check that we received the expected events
69
+ received_events = dump_events(listener)
70
+
71
+ expected_transition_sequence = [
72
+ # 1 job creation events
73
+ ("created", "pending"),
74
+ # worker creation event
75
+ ("created", "active"),
76
+ # 1 running and failure events
77
+ ("pending", "running"),
78
+ # worker fail() event result in either active -> active or active -> crashed
79
+ ("active", "active"),
80
+ # task fail() event
81
+ ("running", "failed"),
82
+ ]
83
+
84
+ assert len(received_events) == len(
85
+ expected_transition_sequence
86
+ ), f"Not enough events, got {len(received_events)} / {len(expected_transition_sequence)}"
87
+
88
+ # Verify event transitions match expected sequence
89
+ for i, event_resp in enumerate(received_events):
90
+ event_resp: EventResponse
91
+ from_state, to_state = expected_transition_sequence[i]
92
+ assert (
93
+ event_resp.event.old_state == from_state
94
+ ), f"Event {i} has wrong from_state: {event_resp.event.old_state}, expected {from_state}"
95
+ assert (
96
+ event_resp.event.new_state == to_state
97
+ ), f"Event {i} has wrong to_state: {event_resp.event.new_state}, expected {to_state}"
98
+
99
+ print(f"Event data: {event_resp.event.entity_data}")
100
+
101
+ # assert cmd in pending -> running event
102
+ assert received_events[2].event.entity_data["cmd"], "Cmd is missing"
103
+
104
+ # assert summary in running -> failed event
105
+ assert received_events[-1].event.entity_data["summary"], "Summary is missing"
106
+
107
+ # Join threads to clean up
108
+ jobflow_thread.join(timeout=3)
@@ -1,5 +1,5 @@
1
1
  [tox]
2
- envlist = py{38,39,310,311,312,313}-{unit,integration,e2e}
2
+ envlist = py{310,311,312,313}-{unit,integration,e2e}
3
3
  isolated_build = True
4
4
 
5
5
  [testenv]
@@ -1,5 +0,0 @@
1
- [run]
2
- omit =
3
- # skip those auto-generated codes by antlr
4
- labtasker/client/core/cmd_parser/generated
5
- labtasker/vendor/*
@@ -1,11 +0,0 @@
1
- # exclude all,
2
- **
3
-
4
- # except
5
- !pyproject.toml
6
- !MANIFEST.in
7
- !setup.py
8
- !labtasker/
9
-
10
- # also exclude run caches
11
- **/__pycache__/
labtasker-0.2.6/.flake8 DELETED
@@ -1,20 +0,0 @@
1
- [flake8]
2
- max-line-length = 88
3
- extend-ignore = E203, E501, C901, E402, W503, F405
4
- exclude =
5
- .git,
6
- __pycache__,
7
- build,
8
- dist,
9
- *.egg-info,
10
- .venv,
11
- .tox,
12
- .mypy_cache,
13
- .pytest_cache,
14
- labtasker/client/core/cmd_parser/generated,
15
- labtasker/vendor
16
- per-file-ignores =
17
- __init__.py:F401,F403
18
- tests/*:F841,F811,F401,S101
19
- script_tests/*:F841,F811,F401,S101
20
- max-complexity = 10