fractal-server 2.0.0a3__tar.gz → 2.0.0a5__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 (166) hide show
  1. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/PKG-INFO +7 -7
  2. fractal_server-2.0.0a5/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/admin/v2.py +7 -2
  4. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/task_collection.py +10 -0
  5. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/__init__.py +6 -2
  6. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/_aux_functions.py +12 -8
  7. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/submit.py +3 -4
  8. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/task_collection.py +11 -1
  9. fractal_server-2.0.0a5/fractal_server/app/routes/api/v2/task_legacy.py +59 -0
  10. fractal_server-2.0.0a5/fractal_server/app/runner/__init__.py +0 -0
  11. fractal_server-2.0.0a5/fractal_server/app/runner/executors/__init__.py +0 -0
  12. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/executor.py +0 -2
  13. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_common.py +1 -1
  14. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_local/__init__.py +2 -1
  15. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_slurm/__init__.py +4 -2
  16. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_slurm/_submit_setup.py +2 -2
  17. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/__init__.py +3 -3
  18. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_local/__init__.py +11 -16
  19. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_slurm/__init__.py +4 -2
  20. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_slurm/_submit_setup.py +2 -3
  21. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/deduplicate_list.py +2 -1
  22. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/handle_failed_job.py +9 -7
  23. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/runner.py +19 -0
  24. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/task_interface.py +4 -2
  25. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/_validators.py +22 -0
  26. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/__init__.py +1 -0
  27. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/dumps.py +1 -1
  28. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/task.py +32 -1
  29. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/task_collection.py +4 -0
  30. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/workflowtask.py +38 -9
  31. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/images/__init__.py +1 -0
  32. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/images/models.py +48 -1
  33. fractal_server-2.0.0a5/fractal_server/py.typed +0 -0
  34. fractal_server-2.0.0a5/fractal_server/tasks/v1/__init__.py +0 -0
  35. fractal_server-2.0.0a5/fractal_server/tasks/v2/__init__.py +0 -0
  36. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/pyproject.toml +20 -18
  37. fractal_server-2.0.0a3/fractal_server/__init__.py +0 -1
  38. fractal_server-2.0.0a3/fractal_server/app/schemas/json_schemas/manifest.json +0 -81
  39. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/LICENSE +0 -0
  40. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/README.md +0 -0
  41. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/__main__.py +0 -0
  42. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/alembic.ini +0 -0
  43. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/__init__.py +0 -0
  44. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/db/__init__.py +0 -0
  45. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/__init__.py +0 -0
  46. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/linkuserproject.py +0 -0
  47. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/security.py +0 -0
  48. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/state.py +0 -0
  49. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v1/__init__.py +0 -0
  50. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v1/dataset.py +0 -0
  51. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v1/job.py +0 -0
  52. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v1/project.py +0 -0
  53. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v1/task.py +0 -0
  54. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v1/workflow.py +0 -0
  55. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/__init__.py +0 -0
  56. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/dataset.py +0 -0
  57. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/job.py +0 -0
  58. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/project.py +0 -0
  59. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/task.py +0 -0
  60. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/workflow.py +0 -0
  61. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/models/v2/workflowtask.py +0 -0
  62. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/__init__.py +0 -0
  63. {fractal_server-2.0.0a3/fractal_server/app/routes/aux → fractal_server-2.0.0a5/fractal_server/app/routes/admin}/__init__.py +0 -0
  64. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/admin/v1.py +0 -0
  65. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/__init__.py +0 -0
  66. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/__init__.py +0 -0
  67. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/_aux_functions.py +0 -0
  68. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/dataset.py +0 -0
  69. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/job.py +0 -0
  70. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/project.py +0 -0
  71. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/task.py +0 -0
  72. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/workflow.py +0 -0
  73. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v1/workflowtask.py +0 -0
  74. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  75. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/images.py +0 -0
  76. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/job.py +0 -0
  77. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/project.py +0 -0
  78. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/task.py +0 -0
  79. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  80. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  81. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/auth.py +0 -0
  82. /fractal_server-2.0.0a3/fractal_server/py.typed → /fractal_server-2.0.0a5/fractal_server/app/routes/aux/__init__.py +0 -0
  83. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/aux/_job.py +0 -0
  84. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/routes/aux/_runner.py +0 -0
  85. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/.gitignore +0 -0
  86. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/async_wrap.py +0 -0
  87. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/components.py +0 -0
  88. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/exceptions.py +0 -0
  89. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/__init__.py +0 -0
  90. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/_batching.py +0 -0
  91. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/_check_jobs_status.py +0 -0
  92. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/_executor_wait_thread.py +0 -0
  93. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/_slurm_config.py +0 -0
  94. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/_subprocess_run_as_user.py +0 -0
  95. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/executors/slurm/remote.py +0 -0
  96. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/filenames.py +0 -0
  97. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  98. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/task_files.py +0 -0
  99. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/__init__.py +0 -0
  100. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_local/_local_config.py +0 -0
  101. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_local/_submit_setup.py +0 -0
  102. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_local/executor.py +0 -0
  103. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -0
  104. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/common.py +0 -0
  105. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v1/handle_failed_job.py +0 -0
  106. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_local/_local_config.py +0 -0
  107. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_local/_submit_setup.py +0 -0
  108. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_local/executor.py +0 -0
  109. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/_slurm/get_slurm_config.py +0 -0
  110. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  111. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  112. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
  113. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/runner/v2/v1_compat.py +0 -0
  114. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/__init__.py +0 -0
  115. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/state.py +0 -0
  116. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/user.py +0 -0
  117. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/__init__.py +0 -0
  118. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/applyworkflow.py +0 -0
  119. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/dataset.py +0 -0
  120. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/dumps.py +0 -0
  121. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/manifest.py +0 -0
  122. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/project.py +0 -0
  123. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/task.py +0 -0
  124. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/task_collection.py +0 -0
  125. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v1/workflow.py +0 -0
  126. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/dataset.py +0 -0
  127. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/job.py +0 -0
  128. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/manifest.py +0 -0
  129. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/project.py +0 -0
  130. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/schemas/v2/workflow.py +0 -0
  131. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/app/security/__init__.py +0 -0
  132. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/config.py +0 -0
  133. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/data_migrations/README.md +0 -0
  134. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/images/tools.py +0 -0
  135. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/logger.py +0 -0
  136. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/main.py +0 -0
  137. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/README +0 -0
  138. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/env.py +0 -0
  139. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/script.py.mako +0 -0
  140. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  141. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  142. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  143. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  144. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  145. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  146. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  147. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  148. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  149. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  150. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  151. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  152. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/d71e732236cd_v2.py +0 -0
  153. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  154. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  155. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  156. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/syringe.py +0 -0
  157. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/__init__.py +0 -0
  158. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/endpoint_operations.py +0 -0
  159. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/utils.py +0 -0
  160. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/v1/_TaskCollectPip.py +0 -0
  161. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/v1/background_operations.py +0 -0
  162. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/v1/get_collection_data.py +0 -0
  163. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/v2/_TaskCollectPip.py +0 -0
  164. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/v2/background_operations.py +0 -0
  165. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/tasks/v2/get_collection_data.py +0 -0
  166. {fractal_server-2.0.0a3 → fractal_server-2.0.0a5}/fractal_server/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.0.0a3
3
+ Version: 2.0.0a5
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -16,21 +16,21 @@ Classifier: Programming Language :: Python :: 3.12
16
16
  Provides-Extra: gunicorn
17
17
  Provides-Extra: postgres
18
18
  Requires-Dist: aiosqlite (>=0.19.0,<0.20.0)
19
- Requires-Dist: alembic (>=1.9.1,<2.0.0)
19
+ Requires-Dist: alembic (>=1.13.1,<2.0.0)
20
20
  Requires-Dist: asyncpg (>=0.29.0,<0.30.0) ; extra == "postgres"
21
21
  Requires-Dist: bcrypt (==4.0.1)
22
- Requires-Dist: cloudpickle (>=2.2.1,<2.3.0)
22
+ Requires-Dist: cloudpickle (>=3.0.0,<3.1.0)
23
23
  Requires-Dist: clusterfutures (>=0.5,<0.6)
24
- Requires-Dist: fastapi (>=0.109.0,<0.110.0)
24
+ Requires-Dist: fastapi (>=0.110.0,<0.111.0)
25
25
  Requires-Dist: fastapi-users[oauth] (>=12.1.0,<13.0.0)
26
26
  Requires-Dist: gunicorn (>=21.2.0,<22.0.0) ; extra == "gunicorn"
27
27
  Requires-Dist: packaging (>=23.2,<24.0)
28
28
  Requires-Dist: psycopg2 (>=2.9.5,<3.0.0) ; extra == "postgres"
29
29
  Requires-Dist: pydantic (>=1.10.8,<2)
30
- Requires-Dist: python-dotenv (>=0.21.0,<0.22.0)
30
+ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
31
31
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
32
- Requires-Dist: sqlmodel (>=0.0.14,<0.0.15)
33
- Requires-Dist: uvicorn (>=0.27.0,<0.28.0)
32
+ Requires-Dist: sqlmodel (>=0.0.16,<0.0.17)
33
+ Requires-Dist: uvicorn (>=0.29.0,<0.30.0)
34
34
  Project-URL: Changelog, https://github.com/fractal-analytics-platform/fractal-server/blob/main/CHANGELOG.md
35
35
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
36
36
  Project-URL: Repository, https://github.com/fractal-analytics-platform/fractal-server
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.0.0a5"
@@ -12,6 +12,7 @@ from fastapi import HTTPException
12
12
  from fastapi import Response
13
13
  from fastapi import status
14
14
  from fastapi.responses import StreamingResponse
15
+ from pydantic import BaseModel
15
16
  from sqlmodel import select
16
17
 
17
18
  from ....config import get_settings
@@ -279,13 +280,17 @@ async def download_job_logs(
279
280
  )
280
281
 
281
282
 
283
+ class TaskCompatibility(BaseModel):
284
+ is_v2_compatible: bool
285
+
286
+
282
287
  @router_admin_v2.patch(
283
288
  "/task-v1/{task_id}/",
284
289
  status_code=status.HTTP_200_OK,
285
290
  )
286
291
  async def flag_task_v1_as_v2_compatible(
287
292
  task_id: int,
288
- is_v2_compatible: bool,
293
+ compatibility: TaskCompatibility,
289
294
  user: User = Depends(current_active_superuser),
290
295
  db: AsyncSession = Depends(get_async_db),
291
296
  ) -> Response:
@@ -297,7 +302,7 @@ async def flag_task_v1_as_v2_compatible(
297
302
  detail=f"Task {task_id} not found",
298
303
  )
299
304
 
300
- task.is_v2_compatible = is_v2_compatible
305
+ task.is_v2_compatible = compatibility.is_v2_compatible
301
306
  await db.commit()
302
307
  await db.close()
303
308
 
@@ -140,6 +140,16 @@ async def collect_tasks_pip(
140
140
  f"Original error: {e}"
141
141
  ),
142
142
  )
143
+ except ValidationError as e:
144
+ await db.close()
145
+ raise HTTPException(
146
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
147
+ detail=(
148
+ "Cannot collect package. Possible reason: an old version "
149
+ "of the same package has already been collected. "
150
+ f"Original error: {e}"
151
+ ),
152
+ )
143
153
  task_collect_status.info = "Already installed"
144
154
  state = State(data=task_collect_status.sanitised_dict())
145
155
  response.status_code == status.HTTP_200_OK
@@ -10,6 +10,7 @@ from .project import router as project_router_v2
10
10
  from .submit import router as submit_job_router_v2
11
11
  from .task import router as task_router_v2
12
12
  from .task_collection import router as task_collection_router_v2
13
+ from .task_legacy import router as task_legacy_router_v2
13
14
  from .workflow import router as workflow_router_v2
14
15
  from .workflowtask import router as workflowtask_router_v2
15
16
 
@@ -19,10 +20,13 @@ router_api_v2.include_router(dataset_router_v2, tags=["V2 Dataset"])
19
20
  router_api_v2.include_router(job_router_v2, tags=["V2 Job"])
20
21
  router_api_v2.include_router(images_routes_v2, tags=["V2 Images"])
21
22
  router_api_v2.include_router(project_router_v2, tags=["V2 Project"])
22
- router_api_v2.include_router(submit_job_router_v2, tags=["V2 Submit Job"])
23
- router_api_v2.include_router(task_router_v2, prefix="/task", tags=["V2 Task"])
23
+ router_api_v2.include_router(submit_job_router_v2, tags=["V2 Job"])
24
24
  router_api_v2.include_router(
25
25
  task_collection_router_v2, prefix="/task", tags=["V2 Task Collection"]
26
26
  )
27
+ router_api_v2.include_router(task_router_v2, prefix="/task", tags=["V2 Task"])
28
+ router_api_v2.include_router(
29
+ task_legacy_router_v2, prefix="/task-legacy", tags=["V2 Task Legacy"]
30
+ )
27
31
  router_api_v2.include_router(workflow_router_v2, tags=["V2 Workflow"])
28
32
  router_api_v2.include_router(workflowtask_router_v2, tags=["V2 WorkflowTask"])
@@ -39,7 +39,6 @@ async def _get_project_check_owner(
39
39
  project_id:
40
40
  user_id:
41
41
  db:
42
- version:
43
42
 
44
43
  Returns:
45
44
  The project object
@@ -382,8 +381,8 @@ async def _get_task_check_owner(
382
381
  def _get_submitted_jobs_statement() -> SelectOfScalar:
383
382
  """
384
383
  Returns:
385
- A sqlmodel statement that selects all `ApplyWorkflow`s with
386
- `ApplyWorkflow.status` equal to `submitted`.
384
+ A sqlmodel statement that selects all `Job`s with
385
+ `Job.status` equal to `submitted`.
387
386
  """
388
387
  stm = select(JobV2).where(JobV2.status == JobStatusTypeV1.SUBMITTED)
389
388
  return stm
@@ -406,11 +405,16 @@ async def _workflow_insert_task(
406
405
  Insert a new WorkflowTask into Workflow.task_list
407
406
 
408
407
  Args:
409
- task_id: TBD
410
- args: TBD
411
- meta: TBD
412
- order: TBD
413
- db: TBD
408
+ workflow_id:
409
+ task_id:
410
+ is_legacy_task:
411
+ order:
412
+ meta_parallel:
413
+ meta_non_parallel:
414
+ args_non_parallel:
415
+ args_parallel:
416
+ input_filters:
417
+ db:
414
418
  """
415
419
  db_workflow = await db.get(WorkflowV2, workflow_id)
416
420
  if db_workflow is None:
@@ -148,7 +148,7 @@ async def apply_workflow(
148
148
  if len(user.slurm_accounts) > 0:
149
149
  job_create.slurm_account = user.slurm_accounts[0]
150
150
 
151
- # Add new ApplyWorkflow object to DB
151
+ # Add new Job object to DB
152
152
  job = JobV2(
153
153
  project_id=project_id,
154
154
  dataset_id=dataset_id,
@@ -192,9 +192,8 @@ async def apply_workflow(
192
192
  raise HTTPException(
193
193
  status_code=status.HTTP_429_TOO_MANY_REQUESTS,
194
194
  detail=(
195
- f"The endpoint 'POST /api/v2/project/{project_id}/workflow/"
196
- f"{workflow_id}/apply/' "
197
- "was called several times within an interval of less "
195
+ f"The endpoint 'POST /api/v2/project/{project_id}/job/submit/'"
196
+ " was called several times within an interval of less "
198
197
  f"than {settings.FRACTAL_API_SUBMIT_RATE_LIMIT} seconds, using"
199
198
  " the same foreign keys. If it was intentional, please wait "
200
199
  "and try again."
@@ -137,7 +137,17 @@ async def collect_tasks_pip(
137
137
  detail=(
138
138
  "Cannot collect package. Possible reason: another "
139
139
  "collection of the same package is in progress. "
140
- f"Original error: {e}"
140
+ f"Original FileNotFoundError: {e}"
141
+ ),
142
+ )
143
+ except ValidationError as e:
144
+ await db.close()
145
+ raise HTTPException(
146
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
147
+ detail=(
148
+ "Cannot collect package. Possible reason: an old version "
149
+ "of the same package has already been collected. "
150
+ f"Original ValidationError: {e}"
141
151
  ),
142
152
  )
143
153
  task_collect_status.info = "Already installed"
@@ -0,0 +1,59 @@
1
+ from fastapi import APIRouter
2
+ from fastapi import Depends
3
+ from fastapi import HTTPException
4
+ from fastapi import status
5
+ from sqlmodel import select
6
+
7
+ from .....logger import set_logger
8
+ from ....db import AsyncSession
9
+ from ....db import get_async_db
10
+ from ....models.v1 import Task as TaskV1
11
+ from ....schemas.v2 import TaskLegacyReadV2
12
+ from ....security import current_active_user
13
+ from ....security import User
14
+
15
+ router = APIRouter()
16
+
17
+ logger = set_logger(__name__)
18
+
19
+
20
+ @router.get("/", response_model=list[TaskLegacyReadV2])
21
+ async def get_list_task_legacy(
22
+ args_schema: bool = True,
23
+ only_v2_compatible: bool = False,
24
+ user: User = Depends(current_active_user),
25
+ db: AsyncSession = Depends(get_async_db),
26
+ ) -> list[TaskLegacyReadV2]:
27
+ """
28
+ Get list of available legacy tasks
29
+ """
30
+ stm = select(TaskV1)
31
+ if only_v2_compatible:
32
+ stm = stm.where(TaskV1.is_v2_compatible)
33
+ res = await db.execute(stm)
34
+ task_list = res.scalars().all()
35
+ await db.close()
36
+ if args_schema is False:
37
+ for task in task_list:
38
+ setattr(task, "args_schema", None)
39
+
40
+ return task_list
41
+
42
+
43
+ @router.get("/{task_id}/", response_model=TaskLegacyReadV2)
44
+ async def get_task_legacy(
45
+ task_id: int,
46
+ user: User = Depends(current_active_user),
47
+ db: AsyncSession = Depends(get_async_db),
48
+ ) -> TaskLegacyReadV2:
49
+ """
50
+ Get info on a specific legacy task
51
+ """
52
+ task = await db.get(TaskV1, task_id)
53
+ await db.close()
54
+ if not task:
55
+ raise HTTPException(
56
+ status_code=status.HTTP_404_NOT_FOUND,
57
+ detail=f"TaskV1[{task_id}] not found",
58
+ )
59
+ return task
@@ -417,8 +417,6 @@ class FractalSlurmExecutor(SlurmExecutor):
417
417
  A `TaskFiles` object; if `None`, use
418
418
  `self.get_default_task_files()`.
419
419
 
420
- Returns:
421
- An iterator of results.
422
420
  """
423
421
 
424
422
  def _result_or_cancel(fut):
@@ -207,7 +207,7 @@ def call_single_task(
207
207
  with task_files.metadiff.open("r") as f_metadiff:
208
208
  diff_metadata = json.load(f_metadiff)
209
209
  except FileNotFoundError as e:
210
- logger.error(
210
+ logger.warning(
211
211
  f"Skip collection of updated metadata. Original error: {str(e)}"
212
212
  )
213
213
  diff_metadata = {}
@@ -49,7 +49,8 @@ def _process_workflow(
49
49
 
50
50
  Schedules the workflow using a `FractalThreadPoolExecutor`.
51
51
 
52
- Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
52
+ Cf.
53
+ [process_workflow][fractal_server.app.runner.v1._local.process_workflow]
53
54
  for the call signature.
54
55
  """
55
56
 
@@ -66,7 +66,8 @@ def _process_workflow(
66
66
  workflow working dir and user to impersonate. It then schedules the
67
67
  workflow tasks and returns the output dataset metadata.
68
68
 
69
- Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
69
+ Cf.
70
+ [process_workflow][fractal_server.app.runner.v1._local.process_workflow]
70
71
 
71
72
  Returns:
72
73
  output_dataset_metadata: Metadata of the output dataset
@@ -132,7 +133,8 @@ async def process_workflow(
132
133
  """
133
134
  Process workflow (SLURM backend public interface)
134
135
 
135
- Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
136
+ Cf.
137
+ [process_workflow][fractal_server.app.runner.v1._local.process_workflow]
136
138
  """
137
139
 
138
140
  # Set values of first_task_index and last_task_index
@@ -12,7 +12,7 @@
12
12
  """
13
13
  Submodule to define _slurm_submit_setup, which is also the reference
14
14
  implementation of `submit_setup_call` in
15
- [fractal_server.app.runner._common][]).
15
+ [fractal_server.app.runner.v1._common][]).
16
16
  """
17
17
  from pathlib import Path
18
18
 
@@ -38,7 +38,7 @@ def _slurm_submit_setup(
38
38
 
39
39
  For now, this is the reference implementation for the argument
40
40
  `submit_setup_call` of
41
- [fractal_server.app.runner._common.execute_tasks][].
41
+ [fractal_server.app.runner.v1._common.execute_tasks][].
42
42
 
43
43
  Arguments:
44
44
  wftask:
@@ -248,7 +248,7 @@ async def submit_workflow(
248
248
  job,
249
249
  dataset,
250
250
  workflow,
251
- logger,
251
+ logger_name=logger_name,
252
252
  failed_wftask=failed_wftask,
253
253
  )
254
254
  latest_filters = assemble_filters_failed_job(job)
@@ -283,7 +283,7 @@ async def submit_workflow(
283
283
  job,
284
284
  dataset,
285
285
  workflow,
286
- logger,
286
+ logger_name=logger_name,
287
287
  )
288
288
  latest_filters = assemble_filters_failed_job(job)
289
289
  if latest_filters is not None:
@@ -313,7 +313,7 @@ async def submit_workflow(
313
313
  job,
314
314
  dataset,
315
315
  workflow,
316
- logger,
316
+ logger_name=logger_name,
317
317
  )
318
318
  latest_filters = assemble_filters_failed_job(job)
319
319
  if latest_filters is not None:
@@ -45,7 +45,8 @@ def _process_workflow(
45
45
 
46
46
  Schedules the workflow using a `FractalThreadPoolExecutor`.
47
47
 
48
- Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
48
+ Cf.
49
+ [process_workflow][fractal_server.app.runner.v2._local.process_workflow]
49
50
  for the call signature.
50
51
  """
51
52
 
@@ -91,21 +92,21 @@ async def process_workflow(
91
92
  Args:
92
93
  workflow:
93
94
  The workflow to be run
94
- input_paths:
95
- The paths to the input files to pass to the first task of the
96
- workflow
97
- output_path:
98
- The destination path for the last task of the workflow
99
- input_metadata:
100
- Initial metadata, passed to the first task
101
- logger_name:
102
- Name of the logger to log information on the run to
95
+ dataset:
96
+ Initial dataset.
103
97
  workflow_dir:
104
98
  Working directory for this run.
105
99
  workflow_dir_user:
106
100
  Working directory for this run, on the user side. This argument is
107
101
  present for compatibility with the standard backend interface, but
108
102
  for the `local` backend it cannot be different from `workflow_dir`.
103
+ first_task_index:
104
+ Positional index of the first task to execute; if `None`, start
105
+ from `0`.
106
+ last_task_index:
107
+ Positional index of the last task to execute; if `None`, proceed
108
+ until the last task.
109
+ logger_name: Logger name
109
110
  slurm_user:
110
111
  Username to impersonate to run the workflow. This argument is
111
112
  present for compatibility with the standard backend interface, but
@@ -123,12 +124,6 @@ async def process_workflow(
123
124
  to the backend executor. This argument is present for compatibility
124
125
  with the standard backend interface, but is ignored in the `local`
125
126
  backend.
126
- first_task_index:
127
- Positional index of the first task to execute; if `None`, start
128
- from `0`.
129
- last_task_index:
130
- Positional index of the last task to execute; if `None`, proceed
131
- until the last task.
132
127
 
133
128
  Raises:
134
129
  TaskExecutionError: wrapper for errors raised during tasks' execution
@@ -56,7 +56,8 @@ def _process_workflow(
56
56
  workflow working dir and user to impersonate. It then schedules the
57
57
  workflow tasks and returns the new dataset attributes
58
58
 
59
- Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
59
+ Cf.
60
+ [process_workflow][fractal_server.app.runner.v2._local.process_workflow]
60
61
 
61
62
  Returns:
62
63
  new_dataset_attributes:
@@ -112,7 +113,8 @@ async def process_workflow(
112
113
  """
113
114
  Process workflow (SLURM backend public interface)
114
115
 
115
- Cf. [process_workflow][fractal_server.app.runner._local.process_workflow]
116
+ Cf.
117
+ [process_workflow][fractal_server.app.runner.v2._local.process_workflow]
116
118
  """
117
119
 
118
120
  # Set values of first_task_index and last_task_index
@@ -11,8 +11,7 @@
11
11
  # Zurich.
12
12
  """
13
13
  Submodule to define _slurm_submit_setup, which is also the reference
14
- implementation of `submit_setup_call` in
15
- [fractal_server.app.runner._common][]).
14
+ implementation of `submit_setup_call`.
16
15
  """
17
16
  from pathlib import Path
18
17
  from typing import Literal
@@ -40,7 +39,7 @@ def _slurm_submit_setup(
40
39
 
41
40
  For now, this is the reference implementation for the argument
42
41
  `submit_setup_call` of
43
- [fractal_server.app.runner._common.execute_tasks][].
42
+ [fractal_server.app.runner.v2.runner][].
44
43
 
45
44
  Arguments:
46
45
  wftask:
@@ -1,9 +1,10 @@
1
1
  from typing import TypeVar
2
2
 
3
3
  from ....images import SingleImage
4
+ from ....images import SingleImageTaskOutput
4
5
  from .task_interface import InitArgsModel
5
6
 
6
- T = TypeVar("T", SingleImage, InitArgsModel)
7
+ T = TypeVar("T", SingleImage, SingleImageTaskOutput, InitArgsModel)
7
8
 
8
9
 
9
10
  def deduplicate_list(
@@ -32,7 +32,7 @@ def assemble_history_failed_job(
32
32
  job: JobV2,
33
33
  dataset: DatasetV2,
34
34
  workflow: WorkflowV2,
35
- logger: logging.Logger,
35
+ logger_name: Optional[str] = None,
36
36
  failed_wftask: Optional[WorkflowTaskV2] = None,
37
37
  ) -> list[dict[str, Any]]:
38
38
  """
@@ -40,12 +40,12 @@ def assemble_history_failed_job(
40
40
 
41
41
  Args:
42
42
  job:
43
- The failed `ApplyWorkflow` object.
44
- output_dataset:
45
- The `dataset` associated to `job`.
43
+ The failed `JobV2` object.
44
+ dataset:
45
+ The `DatasetV2` object associated to `job`.
46
46
  workflow:
47
- The `workflow` associated to `job`.
48
- logger: A logger instance.
47
+ The `WorkflowV2` object associated to `job`.
48
+ logger_name: A logger name.
49
49
  failed_wftask:
50
50
  If set, append it to `history` during step 3; if `None`, infer
51
51
  it by comparing the job task list and the one in
@@ -53,9 +53,11 @@ def assemble_history_failed_job(
53
53
 
54
54
  Returns:
55
55
  The new value of `history`, to be merged into
56
- `output_dataset.meta`.
56
+ `dataset.meta`.
57
57
  """
58
58
 
59
+ logger = logging.getLogger(logger_name)
60
+
59
61
  # The final value of the history attribute should include up to three
60
62
  # parts, coming from: the database, the temporary file, the failed-task
61
63
  # information.
@@ -157,6 +157,20 @@ def execute_tasks_v2(
157
157
  updated_types.update(image["types"])
158
158
  updated_types.update(task.output_types)
159
159
 
160
+ # Unset attributes with None value
161
+ updated_attributes = {
162
+ key: value
163
+ for key, value in updated_attributes.items()
164
+ if value is not None
165
+ }
166
+
167
+ # Validate new image
168
+ SingleImage(
169
+ zarr_url=image["zarr_url"],
170
+ types=updated_types,
171
+ attributes=updated_attributes,
172
+ )
173
+
160
174
  # Update image in the dataset image list
161
175
  tmp_images[original_index]["attributes"] = updated_attributes
162
176
  tmp_images[original_index]["types"] = updated_types
@@ -182,6 +196,11 @@ def execute_tasks_v2(
182
196
  updated_types = copy(original_img["types"])
183
197
  # Update image attributes/types with task output and manifest
184
198
  updated_attributes.update(image["attributes"])
199
+ updated_attributes = {
200
+ key: value
201
+ for key, value in updated_attributes.items()
202
+ if value is not None
203
+ }
185
204
  updated_types.update(image["types"])
186
205
  updated_types.update(task.output_types)
187
206
  new_image = dict(
@@ -3,7 +3,7 @@ from typing import Any
3
3
  from pydantic import BaseModel
4
4
  from pydantic import Field
5
5
 
6
- from ....images import SingleImage
6
+ from ....images import SingleImageTaskOutput
7
7
  from fractal_server.images import Filters
8
8
 
9
9
 
@@ -11,7 +11,9 @@ class TaskOutput(BaseModel):
11
11
  class Config:
12
12
  extra = "forbid"
13
13
 
14
- image_list_updates: list[SingleImage] = Field(default_factory=list)
14
+ image_list_updates: list[SingleImageTaskOutput] = Field(
15
+ default_factory=list
16
+ )
15
17
  image_list_removals: list[str] = Field(default_factory=list)
16
18
  filters: Filters = Field(default_factory=Filters)
17
19
 
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  from datetime import datetime
3
3
  from datetime import timezone
4
+ from typing import Any
4
5
 
5
6
 
6
7
  def valstr(attribute: str, accept_none: bool = False):
@@ -27,6 +28,27 @@ def valstr(attribute: str, accept_none: bool = False):
27
28
  return val
28
29
 
29
30
 
31
+ def valdictkeys(attribute: str):
32
+ def val(d: dict[str, Any]):
33
+ """
34
+ Apply valstr to every key of the dictionary, and fail if there are
35
+ identical keys.
36
+ """
37
+ if d is not None:
38
+ old_keys = list(d.keys())
39
+ new_keys = [valstr(f"{attribute}[{key}]")(key) for key in old_keys]
40
+ if len(new_keys) != len(set(new_keys)):
41
+ raise ValueError(
42
+ f"Dictionary contains multiple identical keys: {d}."
43
+ )
44
+ for old_key, new_key in zip(old_keys, new_keys):
45
+ if new_key != old_key:
46
+ d[new_key] = d.pop(old_key)
47
+ return d
48
+
49
+ return val
50
+
51
+
30
52
  def valint(attribute: str, min_val: int = 1):
31
53
  """
32
54
  Check that an integer attribute (e.g. if it is meant to be the ID of a
@@ -17,6 +17,7 @@ from .project import ProjectUpdateV2 # noqa F401
17
17
  from .task import TaskCreateV2 # noqa F401
18
18
  from .task import TaskExportV2 # noqa F401
19
19
  from .task import TaskImportV2 # noqa F401
20
+ from .task import TaskLegacyReadV2 # noqa F401
20
21
  from .task import TaskReadV2 # noqa F401
21
22
  from .task import TaskUpdateV2 # noqa F401
22
23
  from .task_collection import TaskCollectPipV2 # noqa F401
@@ -5,7 +5,7 @@ Dump models differ from their Read counterpart in that:
5
5
  * They may only include a subset of the Read attributes.
6
6
 
7
7
  These models are used in at least two situations:
8
- 1. In the "*_dump" attributes of ApplyWorkflow models;
8
+ 1. In the "*_dump" attributes of Job models;
9
9
  2. In the `_DatasetHistoryItem.workflowtask` model, to trim its size.
10
10
  """
11
11
  from typing import Optional