fractal-server 2.15.10a2__tar.gz → 2.15.10a3__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 (242) hide show
  1. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/PKG-INFO +1 -1
  2. fractal_server-2.15.10a3/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/task_group.py +0 -32
  4. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +67 -0
  5. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +22 -0
  6. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +1 -1
  7. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task_group.py +0 -38
  8. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +69 -0
  9. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/runner.py +10 -0
  10. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/submit_workflow.py +33 -44
  11. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/task_group.py +1 -0
  12. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/__init__.py +1 -0
  13. fractal_server-2.15.10a3/fractal_server/tasks/v2/local/delete.py +76 -0
  14. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/__init__.py +1 -0
  15. fractal_server-2.15.10a3/fractal_server/tasks/v2/ssh/delete.py +115 -0
  16. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/utils_background.py +3 -1
  17. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/pyproject.toml +2 -2
  18. fractal_server-2.15.10a2/fractal_server/__init__.py +0 -1
  19. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/LICENSE +0 -0
  20. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/README.md +0 -0
  21. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/__main__.py +0 -0
  22. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/alembic.ini +0 -0
  23. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/__init__.py +0 -0
  24. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/db/__init__.py +0 -0
  25. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/__init__.py +0 -0
  26. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/linkusergroup.py +0 -0
  27. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/linkuserproject.py +0 -0
  28. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/security.py +0 -0
  29. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/user_settings.py +0 -0
  30. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/__init__.py +0 -0
  31. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/accounting.py +0 -0
  32. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/dataset.py +0 -0
  33. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/history.py +0 -0
  34. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/job.py +0 -0
  35. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/project.py +0 -0
  36. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/task.py +0 -0
  37. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/task_group.py +0 -0
  38. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/workflow.py +0 -0
  39. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/models/v2/workflowtask.py +0 -0
  40. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/__init__.py +0 -0
  41. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/__init__.py +0 -0
  42. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  43. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  44. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  45. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/job.py +0 -0
  46. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/project.py +0 -0
  47. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/admin/v2/task.py +0 -0
  48. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/__init__.py +0 -0
  49. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  50. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  51. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  52. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
  53. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
  54. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  55. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/history.py +0 -0
  56. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/images.py +0 -0
  57. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/job.py +0 -0
  58. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  59. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/project.py +0 -0
  60. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  61. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/submit.py +0 -0
  62. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task.py +0 -0
  63. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
  64. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  65. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task_collection_pixi.py +0 -0
  66. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
  67. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  68. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  69. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  70. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/__init__.py +0 -0
  71. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  72. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/current_user.py +0 -0
  73. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/group.py +0 -0
  74. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/login.py +0 -0
  75. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/oauth.py +0 -0
  76. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/register.py +0 -0
  77. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/router.py +0 -0
  78. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/auth/users.py +0 -0
  79. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/aux/__init__.py +0 -0
  80. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/aux/_job.py +0 -0
  81. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/aux/_runner.py +0 -0
  82. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  83. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/routes/pagination.py +0 -0
  84. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/__init__.py +0 -0
  85. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/components.py +0 -0
  86. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/exceptions.py +0 -0
  87. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/__init__.py +0 -0
  88. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/base_runner.py +0 -0
  89. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/call_command_wrapper.py +0 -0
  90. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/local/__init__.py +0 -0
  91. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/local/get_local_config.py +0 -0
  92. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/local/runner.py +0 -0
  93. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
  94. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
  95. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
  96. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +0 -0
  97. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +0 -0
  98. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +0 -0
  99. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/remote.py +0 -0
  100. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  101. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
  102. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  103. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_ssh/runner.py +0 -0
  104. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_ssh/tar_commands.py +0 -0
  105. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
  106. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  107. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/executors/slurm_sudo/runner.py +0 -0
  108. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/filenames.py +0 -0
  109. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  110. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/shutdown.py +0 -0
  111. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/task_files.py +0 -0
  112. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/__init__.py +0 -0
  113. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/_local.py +0 -0
  114. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/_slurm_ssh.py +0 -0
  115. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/_slurm_sudo.py +0 -0
  116. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/db_tools.py +0 -0
  117. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  118. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  119. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  120. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/v2/task_interface.py +0 -0
  121. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/runner/versions.py +0 -0
  122. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/__init__.py +0 -0
  123. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/user.py +0 -0
  124. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/user_group.py +0 -0
  125. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/user_settings.py +0 -0
  126. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/__init__.py +0 -0
  127. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/accounting.py +0 -0
  128. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/dataset.py +0 -0
  129. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/dumps.py +0 -0
  130. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/history.py +0 -0
  131. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/job.py +0 -0
  132. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/manifest.py +0 -0
  133. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/project.py +0 -0
  134. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  135. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/task.py +0 -0
  136. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  137. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/workflow.py +0 -0
  138. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  139. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/security/__init__.py +0 -0
  140. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/security/signup_email.py +0 -0
  141. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/app/user_settings.py +0 -0
  142. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/config.py +0 -0
  143. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/data_migrations/2_14_10.py +0 -0
  144. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/data_migrations/README.md +0 -0
  145. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/data_migrations/tools.py +0 -0
  146. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/exceptions.py +0 -0
  147. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/gunicorn_fractal.py +0 -0
  148. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/images/__init__.py +0 -0
  149. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/images/models.py +0 -0
  150. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/images/status_tools.py +0 -0
  151. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/images/tools.py +0 -0
  152. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/logger.py +0 -0
  153. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/main.py +0 -0
  154. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/env.py +0 -0
  155. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/naming_convention.py +0 -0
  156. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  157. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  158. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
  159. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  160. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
  161. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  162. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  163. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  164. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  165. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  166. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  167. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  168. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  169. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  170. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  171. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
  172. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  173. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  174. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  175. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  176. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
  177. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  178. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
  179. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  180. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  181. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  182. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  183. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  184. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  185. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  186. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
  187. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
  188. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  189. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  190. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  191. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  192. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  193. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  194. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  195. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  196. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  197. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  198. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  199. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/py.typed +0 -0
  200. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/ssh/__init__.py +0 -0
  201. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/ssh/_fabric.py +0 -0
  202. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/string_tools.py +0 -0
  203. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/syringe.py +0 -0
  204. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/__init__.py +0 -0
  205. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/utils.py +0 -0
  206. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/__init__.py +0 -0
  207. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/_utils.py +0 -0
  208. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/collect.py +0 -0
  209. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
  210. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  211. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
  212. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  213. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
  214. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  215. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  216. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
  217. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  218. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
  219. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  220. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
  221. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  222. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  223. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  224. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  225. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  226. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  227. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
  228. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
  229. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
  230. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/utils_database.py +0 -0
  231. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  232. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/utils_pixi.py +0 -0
  233. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  234. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/tasks/v2/utils_templates.py +0 -0
  235. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/types/__init__.py +0 -0
  236. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/types/validators/__init__.py +0 -0
  237. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/types/validators/_common_validators.py +0 -0
  238. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/types/validators/_filter_validators.py +0 -0
  239. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  240. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/urls.py +0 -0
  241. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/utils.py +0 -0
  242. {fractal_server-2.15.10a2 → fractal_server-2.15.10a3}/fractal_server/zip_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fractal-server
3
- Version: 2.15.10a2
3
+ Version: 2.15.10a3
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License: BSD-3-Clause
6
6
  Author: Tommaso Comparin
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.15.10a3"
@@ -1,7 +1,6 @@
1
1
  from fastapi import APIRouter
2
2
  from fastapi import Depends
3
3
  from fastapi import HTTPException
4
- from fastapi import Response
5
4
  from fastapi import status
6
5
  from pydantic.types import AwareDatetime
7
6
  from sqlalchemy.sql.operators import is_
@@ -13,7 +12,6 @@ from fractal_server.app.db import get_async_db
13
12
  from fractal_server.app.models import UserOAuth
14
13
  from fractal_server.app.models.v2 import TaskGroupActivityV2
15
14
  from fractal_server.app.models.v2 import TaskGroupV2
16
- from fractal_server.app.models.v2 import WorkflowTaskV2
17
15
  from fractal_server.app.routes.auth import current_active_superuser
18
16
  from fractal_server.app.routes.auth._aux_auth import (
19
17
  _verify_user_belongs_to_group,
@@ -161,33 +159,3 @@ async def patch_task_group(
161
159
  await db.commit()
162
160
  await db.refresh(task_group)
163
161
  return task_group
164
-
165
-
166
- @router.delete("/{task_group_id}/", status_code=204)
167
- async def delete_task_group(
168
- task_group_id: int,
169
- user: UserOAuth = Depends(current_active_superuser),
170
- db: AsyncSession = Depends(get_async_db),
171
- ):
172
- task_group = await db.get(TaskGroupV2, task_group_id)
173
- if task_group is None:
174
- raise HTTPException(
175
- status_code=status.HTTP_404_NOT_FOUND,
176
- detail=f"TaskGroupV2 {task_group_id} not found",
177
- )
178
-
179
- stm = select(WorkflowTaskV2).where(
180
- WorkflowTaskV2.task_id.in_({task.id for task in task_group.task_list})
181
- )
182
- res = await db.execute(stm)
183
- workflow_tasks = res.scalars().all()
184
- if workflow_tasks != []:
185
- raise HTTPException(
186
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
187
- detail=f"TaskV2 {workflow_tasks[0].task_id} is still in use",
188
- )
189
-
190
- await db.delete(task_group)
191
- await db.commit()
192
-
193
- return Response(status_code=status.HTTP_204_NO_CONTENT)
@@ -12,6 +12,9 @@ from fractal_server.app.models.v2 import TaskGroupActivityV2
12
12
  from fractal_server.app.routes.api.v2._aux_functions_task_lifecycle import (
13
13
  check_no_ongoing_activity,
14
14
  )
15
+ from fractal_server.app.routes.api.v2._aux_functions_task_lifecycle import (
16
+ check_no_related_workflowtask,
17
+ )
15
18
  from fractal_server.app.routes.api.v2._aux_functions_task_lifecycle import (
16
19
  check_no_submitted_job,
17
20
  )
@@ -31,8 +34,10 @@ from fractal_server.logger import set_logger
31
34
  from fractal_server.ssh._fabric import SSHConfig
32
35
  from fractal_server.syringe import Inject
33
36
  from fractal_server.tasks.v2.local import deactivate_local
37
+ from fractal_server.tasks.v2.local import delete_local
34
38
  from fractal_server.tasks.v2.local import reactivate_local
35
39
  from fractal_server.tasks.v2.ssh import deactivate_ssh
40
+ from fractal_server.tasks.v2.ssh import delete_ssh
36
41
  from fractal_server.tasks.v2.ssh import reactivate_ssh
37
42
  from fractal_server.utils import get_timestamp
38
43
 
@@ -258,3 +263,65 @@ async def reactivate_task_group(
258
263
  )
259
264
  response.status_code = status.HTTP_202_ACCEPTED
260
265
  return task_group_activity
266
+
267
+
268
+ @router.post("/{task_group_id}/delete/", status_code=202)
269
+ async def delete_task_group(
270
+ task_group_id: int,
271
+ background_tasks: BackgroundTasks,
272
+ response: Response,
273
+ superuser: UserOAuth = Depends(current_active_superuser),
274
+ db: AsyncSession = Depends(get_async_db),
275
+ ):
276
+ task_group = await _get_task_group_or_404(
277
+ task_group_id=task_group_id, db=db
278
+ )
279
+ await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
280
+ await check_no_submitted_job(task_group_id=task_group_id, db=db)
281
+ await check_no_related_workflowtask(task_group=task_group, db=db)
282
+
283
+ task_group_activity = TaskGroupActivityV2(
284
+ user_id=task_group.user_id,
285
+ taskgroupv2_id=task_group.id,
286
+ status=TaskGroupActivityStatusV2.PENDING,
287
+ action=TaskGroupActivityActionV2.DELETE,
288
+ pkg_name=task_group.pkg_name,
289
+ version=(task_group.version or "N/A"),
290
+ timestamp_started=get_timestamp(),
291
+ )
292
+ db.add(task_group_activity)
293
+ await db.commit()
294
+
295
+ settings = Inject(get_settings)
296
+ if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
297
+ # Validate user settings (backend-specific)
298
+ task_owner = await db.get(UserOAuth, task_group.user_id)
299
+ task_owner_settings = await validate_user_settings(
300
+ user=task_owner, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
301
+ )
302
+ # Use appropriate FractalSSH object
303
+ ssh_config = SSHConfig(
304
+ user=task_owner_settings.ssh_username,
305
+ host=task_owner_settings.ssh_host,
306
+ key_path=task_owner_settings.ssh_private_key_path,
307
+ )
308
+
309
+ background_tasks.add_task(
310
+ delete_ssh,
311
+ task_group_id=task_group.id,
312
+ task_group_activity_id=task_group_activity.id,
313
+ ssh_config=ssh_config,
314
+ tasks_base_dir=task_owner_settings.ssh_tasks_dir,
315
+ )
316
+ else:
317
+ background_tasks.add_task(
318
+ delete_local,
319
+ task_group_id=task_group.id,
320
+ task_group_activity_id=task_group_activity.id,
321
+ )
322
+ logger.debug(
323
+ "Admin task group deletion endpoint: start deletion "
324
+ "and return task_group_activity"
325
+ )
326
+ response.status_code = status.HTTP_202_ACCEPTED
327
+ return task_group_activity
@@ -8,6 +8,7 @@ from sqlmodel import select
8
8
  from fractal_server.app.db import AsyncSession
9
9
  from fractal_server.app.models.v2 import JobV2
10
10
  from fractal_server.app.models.v2 import TaskGroupActivityV2
11
+ from fractal_server.app.models.v2 import TaskGroupV2
11
12
  from fractal_server.app.models.v2 import TaskV2
12
13
  from fractal_server.app.models.v2 import WorkflowTaskV2
13
14
  from fractal_server.app.models.v2 import WorkflowV2
@@ -203,3 +204,24 @@ async def check_no_submitted_job(
203
204
  "submitted jobs use its tasks."
204
205
  ),
205
206
  )
207
+
208
+
209
+ async def check_no_related_workflowtask(
210
+ *,
211
+ task_group: TaskGroupV2,
212
+ db: AsyncSession,
213
+ ) -> None:
214
+ """
215
+ Raises an HTTPException if any of the tasks in the TaskGroup are referenced
216
+ by an existing WorkflowTask.
217
+ """
218
+ stm = select(WorkflowTaskV2).where(
219
+ WorkflowTaskV2.task_id.in_([task.id for task in task_group.task_list])
220
+ )
221
+ res = await db.execute(stm)
222
+ bad_wftask = res.scalars().first()
223
+ if bad_wftask is not None:
224
+ raise HTTPException(
225
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
226
+ detail=f"TaskV2 {bad_wftask.task_id} is still in use",
227
+ )
@@ -243,7 +243,7 @@ async def _get_collection_task_group_activity_status_message(
243
243
  )
244
244
  elif len(task_group_activity_list) == 1:
245
245
  msg = (
246
- "\nNote:"
246
+ "\nNote: "
247
247
  "There exists another task-group collection "
248
248
  f"(activity ID={task_group_activity_list[0].id}) for "
249
249
  f"this task group (ID={task_group_id}), with status "
@@ -3,7 +3,6 @@ import itertools
3
3
  from fastapi import APIRouter
4
4
  from fastapi import Depends
5
5
  from fastapi import HTTPException
6
- from fastapi import Response
7
6
  from fastapi import status
8
7
  from packaging.version import InvalidVersion
9
8
  from packaging.version import parse
@@ -12,7 +11,6 @@ from pydantic.types import AwareDatetime
12
11
  from sqlmodel import or_
13
12
  from sqlmodel import select
14
13
 
15
- from ._aux_functions_task_lifecycle import check_no_ongoing_activity
16
14
  from ._aux_functions_tasks import _get_task_group_full_access
17
15
  from ._aux_functions_tasks import _get_task_group_read_access
18
16
  from ._aux_functions_tasks import _verify_non_duplication_group_constraint
@@ -23,7 +21,6 @@ from fractal_server.app.models import LinkUserGroup
23
21
  from fractal_server.app.models import UserOAuth
24
22
  from fractal_server.app.models.v2 import TaskGroupActivityV2
25
23
  from fractal_server.app.models.v2 import TaskGroupV2
26
- from fractal_server.app.models.v2 import WorkflowTaskV2
27
24
  from fractal_server.app.routes.auth import current_active_user
28
25
  from fractal_server.app.routes.auth._aux_auth import _get_default_usergroup_id
29
26
  from fractal_server.app.routes.auth._aux_auth import (
@@ -199,41 +196,6 @@ async def get_task_group(
199
196
  return task_group
200
197
 
201
198
 
202
- @router.delete("/{task_group_id}/", status_code=204)
203
- async def delete_task_group(
204
- task_group_id: int,
205
- user: UserOAuth = Depends(current_active_user),
206
- db: AsyncSession = Depends(get_async_db),
207
- ):
208
- """
209
- Delete single TaskGroup
210
- """
211
-
212
- task_group = await _get_task_group_full_access(
213
- task_group_id=task_group_id,
214
- user_id=user.id,
215
- db=db,
216
- )
217
-
218
- await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
219
-
220
- stm = select(WorkflowTaskV2).where(
221
- WorkflowTaskV2.task_id.in_({task.id for task in task_group.task_list})
222
- )
223
- res = await db.execute(stm)
224
- workflow_tasks = res.scalars().all()
225
- if workflow_tasks != []:
226
- raise HTTPException(
227
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
228
- detail=f"TaskV2 {workflow_tasks[0].task_id} is still in use",
229
- )
230
-
231
- await db.delete(task_group)
232
- await db.commit()
233
-
234
- return Response(status_code=status.HTTP_204_NO_CONTENT)
235
-
236
-
237
199
  @router.patch("/{task_group_id}/", response_model=TaskGroupReadV2)
238
200
  async def patch_task_group(
239
201
  task_group_id: int,
@@ -7,6 +7,7 @@ from fastapi import status
7
7
 
8
8
  from ...aux.validate_user_settings import validate_user_settings
9
9
  from ._aux_functions_task_lifecycle import check_no_ongoing_activity
10
+ from ._aux_functions_task_lifecycle import check_no_related_workflowtask
10
11
  from ._aux_functions_task_lifecycle import check_no_submitted_job
11
12
  from ._aux_functions_tasks import _get_task_group_full_access
12
13
  from fractal_server.app.db import AsyncSession
@@ -25,10 +26,12 @@ from fractal_server.ssh._fabric import SSHConfig
25
26
  from fractal_server.syringe import Inject
26
27
  from fractal_server.tasks.v2.local import deactivate_local
27
28
  from fractal_server.tasks.v2.local import deactivate_local_pixi
29
+ from fractal_server.tasks.v2.local import delete_local
28
30
  from fractal_server.tasks.v2.local import reactivate_local
29
31
  from fractal_server.tasks.v2.local import reactivate_local_pixi
30
32
  from fractal_server.tasks.v2.ssh import deactivate_ssh
31
33
  from fractal_server.tasks.v2.ssh import deactivate_ssh_pixi
34
+ from fractal_server.tasks.v2.ssh import delete_ssh
32
35
  from fractal_server.tasks.v2.ssh import reactivate_ssh
33
36
  from fractal_server.tasks.v2.ssh import reactivate_ssh_pixi
34
37
  from fractal_server.utils import get_timestamp
@@ -281,3 +284,69 @@ async def reactivate_task_group(
281
284
  )
282
285
  response.status_code = status.HTTP_202_ACCEPTED
283
286
  return task_group_activity
287
+
288
+
289
+ @router.post(
290
+ "/{task_group_id}/delete/",
291
+ status_code=202,
292
+ )
293
+ async def delete_task_group(
294
+ task_group_id: int,
295
+ background_tasks: BackgroundTasks,
296
+ response: Response,
297
+ user: UserOAuth = Depends(current_active_user),
298
+ db: AsyncSession = Depends(get_async_db),
299
+ ) -> TaskGroupActivityV2Read:
300
+ """
301
+ Deletion of task-group from db and file system
302
+ """
303
+
304
+ task_group = await _get_task_group_full_access(
305
+ task_group_id=task_group_id,
306
+ user_id=user.id,
307
+ db=db,
308
+ )
309
+ await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
310
+ await check_no_related_workflowtask(task_group=task_group, db=db)
311
+
312
+ task_group_activity = TaskGroupActivityV2(
313
+ user_id=task_group.user_id,
314
+ taskgroupv2_id=task_group.id,
315
+ status=TaskGroupActivityStatusV2.PENDING,
316
+ action=TaskGroupActivityActionV2.DELETE,
317
+ pkg_name=task_group.pkg_name,
318
+ version=(task_group.version or "N/A"),
319
+ timestamp_started=get_timestamp(),
320
+ )
321
+ db.add(task_group_activity)
322
+ await db.commit()
323
+
324
+ settings = Inject(get_settings)
325
+ if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
326
+ # Validate user settings (backend-specific)
327
+ user_settings = await validate_user_settings(
328
+ user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
329
+ )
330
+ # User appropriate FractalSSH object
331
+ ssh_config = SSHConfig(
332
+ user=user_settings.ssh_username,
333
+ host=user_settings.ssh_host,
334
+ key_path=user_settings.ssh_private_key_path,
335
+ )
336
+
337
+ background_tasks.add_task(
338
+ delete_ssh,
339
+ task_group_id=task_group.id,
340
+ task_group_activity_id=task_group_activity.id,
341
+ ssh_config=ssh_config,
342
+ tasks_base_dir=user_settings.ssh_tasks_dir,
343
+ )
344
+ else:
345
+ background_tasks.add_task(
346
+ delete_local,
347
+ task_group_id=task_group.id,
348
+ task_group_activity_id=task_group_activity.id,
349
+ )
350
+
351
+ response.status_code = status.HTTP_202_ACCEPTED
352
+ return task_group_activity
@@ -194,6 +194,16 @@ def execute_tasks_v2(
194
194
  db.refresh(history_run)
195
195
  history_run_id = history_run.id
196
196
 
197
+ # Refresh `job.executor_error_log`, to avoid a spurious value left
198
+ # over from a previous task
199
+ job_db = db.get(JobV2, job_id)
200
+ job_db.executor_error_log = None
201
+ logger.debug(
202
+ f"Resetting `JobV2[{job_id}].executor_error_log` to None."
203
+ )
204
+ db.merge(job_db)
205
+ db.commit()
206
+
197
207
  # TASK EXECUTION (V2)
198
208
  try:
199
209
  if task.type in [
@@ -244,6 +244,7 @@ def submit_workflow(
244
244
  logger.debug(f"job.first_task_index: {job.first_task_index}")
245
245
  logger.debug(f"job.last_task_index: {job.last_task_index}")
246
246
  logger.debug(f'START workflow "{workflow.name}"')
247
+ job_working_dir = job.working_dir
247
248
 
248
249
  try:
249
250
  if FRACTAL_RUNNER_BACKEND == "local":
@@ -267,19 +268,6 @@ def submit_workflow(
267
268
  f"Invalid runner backend {FRACTAL_RUNNER_BACKEND=}"
268
269
  )
269
270
 
270
- # "The Session.close() method does not prevent the Session from being
271
- # used again. The Session itself does not actually have a distinct
272
- # “closed” state; it merely means the Session will release all database
273
- # connections and ORM objects."
274
- # (https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.close).
275
- #
276
- # We close the session before the (possibly long) process_workflow
277
- # call, to make sure all DB connections are released. The reason why we
278
- # are not using a context manager within the try block is that we also
279
- # need access to db_sync in the except branches.
280
- db_sync = next(DB.get_sync_db())
281
- db_sync.close()
282
-
283
271
  process_workflow(
284
272
  workflow=workflow,
285
273
  dataset=dataset,
@@ -303,47 +291,48 @@ def submit_workflow(
303
291
  logger.debug(f'END workflow "{workflow.name}"')
304
292
 
305
293
  # Update job DB entry
306
- job = db_sync.get(JobV2, job_id) # refetch, in case it was updated
307
- job.status = JobStatusTypeV2.DONE
308
- job.end_timestamp = get_timestamp()
309
- with log_file_path.open("r") as f:
310
- logs = f.read()
311
- job.log = logs
312
- db_sync.merge(job)
313
- db_sync.commit()
294
+ with next(DB.get_sync_db()) as db_sync:
295
+ job = db_sync.get(JobV2, job_id)
296
+ job.status = JobStatusTypeV2.DONE
297
+ job.end_timestamp = get_timestamp()
298
+ with log_file_path.open("r") as f:
299
+ logs = f.read()
300
+ job.log = logs
301
+ db_sync.merge(job)
302
+ db_sync.commit()
314
303
 
315
304
  except JobExecutionError as e:
316
305
  logger.debug(f'FAILED workflow "{workflow.name}", JobExecutionError.')
317
306
  logger.info(f'Workflow "{workflow.name}" failed (JobExecutionError).')
318
-
319
- fail_job(
320
- db=db_sync,
321
- job=job,
322
- log_msg=(
323
- f"JOB ERROR in Fractal job {job.id}:\n"
324
- f"TRACEBACK:\n{e.assemble_error()}"
325
- ),
326
- logger_name=logger_name,
327
- )
307
+ with next(DB.get_sync_db()) as db_sync:
308
+ job = db_sync.get(JobV2, job_id)
309
+ fail_job(
310
+ db=db_sync,
311
+ job=job,
312
+ log_msg=(
313
+ f"JOB ERROR in Fractal job {job.id}:\n"
314
+ f"TRACEBACK:\n{e.assemble_error()}"
315
+ ),
316
+ logger_name=logger_name,
317
+ )
328
318
 
329
319
  except Exception:
330
320
  logger.debug(f'FAILED workflow "{workflow.name}", unknown error.')
331
321
  logger.info(f'Workflow "{workflow.name}" failed (unkwnon error).')
332
322
 
333
323
  current_traceback = traceback.format_exc()
334
- fail_job(
335
- db=db_sync,
336
- job=job,
337
- log_msg=(
338
- f"UNKNOWN ERROR in Fractal job {job.id}\n"
339
- f"TRACEBACK:\n{current_traceback}"
340
- ),
341
- logger_name=logger_name,
342
- )
324
+ with next(DB.get_sync_db()) as db_sync:
325
+ job = db_sync.get(JobV2, job_id)
326
+ fail_job(
327
+ db=db_sync,
328
+ job=job,
329
+ log_msg=(
330
+ f"UNKNOWN ERROR in Fractal job {job.id}\n"
331
+ f"TRACEBACK:\n{current_traceback}"
332
+ ),
333
+ logger_name=logger_name,
334
+ )
343
335
 
344
336
  finally:
345
337
  reset_logger_handlers(logger)
346
- # refetch, in case it is not already available
347
- job = db_sync.get(JobV2, job_id)
348
- db_sync.close()
349
- _zip_folder_to_file_and_remove(folder=job.working_dir)
338
+ _zip_folder_to_file_and_remove(folder=job_working_dir)
@@ -31,6 +31,7 @@ class TaskGroupActivityActionV2(StrEnum):
31
31
  COLLECT = "collect"
32
32
  DEACTIVATE = "deactivate"
33
33
  REACTIVATE = "reactivate"
34
+ DELETE = "delete"
34
35
 
35
36
 
36
37
  class TaskGroupCreateV2(BaseModel):
@@ -2,5 +2,6 @@ from .collect import collect_local # noqa
2
2
  from .collect_pixi import collect_local_pixi # noqa
3
3
  from .deactivate import deactivate_local # noqa
4
4
  from .deactivate_pixi import deactivate_local_pixi # noqa
5
+ from .delete import delete_local # noqa
5
6
  from .reactivate import reactivate_local # noqa
6
7
  from .reactivate_pixi import reactivate_local_pixi # noqa
@@ -0,0 +1,76 @@
1
+ import shutil
2
+ from pathlib import Path
3
+ from tempfile import TemporaryDirectory
4
+
5
+ from fractal_server.app.db import get_sync_db
6
+ from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
7
+ from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
8
+ from fractal_server.logger import reset_logger_handlers
9
+ from fractal_server.logger import set_logger
10
+ from fractal_server.tasks.utils import get_log_path
11
+ from fractal_server.tasks.v2.utils_background import add_commit_refresh
12
+ from fractal_server.tasks.v2.utils_background import fail_and_cleanup
13
+ from fractal_server.tasks.v2.utils_background import (
14
+ get_activity_and_task_group,
15
+ )
16
+ from fractal_server.tasks.v2.utils_background import get_current_log
17
+ from fractal_server.utils import get_timestamp
18
+
19
+
20
+ def delete_local(
21
+ *,
22
+ task_group_activity_id: int,
23
+ task_group_id: int,
24
+ ) -> None:
25
+ LOGGER_NAME = f"{__name__}.ID{task_group_activity_id}"
26
+
27
+ with TemporaryDirectory() as tmpdir:
28
+ log_file_path = get_log_path(Path(tmpdir))
29
+
30
+ logger = set_logger(
31
+ logger_name=LOGGER_NAME,
32
+ log_file_path=log_file_path,
33
+ )
34
+ logger.debug("START")
35
+ with next(get_sync_db()) as db:
36
+ db_objects_ok, task_group, activity = get_activity_and_task_group(
37
+ task_group_activity_id=task_group_activity_id,
38
+ task_group_id=task_group_id,
39
+ db=db,
40
+ logger_name=LOGGER_NAME,
41
+ )
42
+ if not db_objects_ok:
43
+ return
44
+
45
+ try:
46
+ activity.status = TaskGroupActivityStatusV2.ONGOING
47
+ activity.log = get_current_log(log_file_path)
48
+ activity = add_commit_refresh(obj=activity, db=db)
49
+
50
+ db.commit()
51
+ db.delete(task_group)
52
+ logger.debug("Task group removed from database.")
53
+
54
+ if task_group.origin != TaskGroupV2OriginEnum.OTHER:
55
+ logger.debug(f"Removing {task_group.path=}.")
56
+ shutil.rmtree(task_group.path)
57
+ logger.debug(f"{task_group.path=} removed.")
58
+
59
+ activity.status = TaskGroupActivityStatusV2.OK
60
+ activity.log = get_current_log(log_file_path)
61
+ activity.timestamp_ended = get_timestamp()
62
+ activity = add_commit_refresh(obj=activity, db=db)
63
+
64
+ logger.debug("END")
65
+
66
+ except Exception as delete_e:
67
+ fail_and_cleanup(
68
+ task_group=task_group,
69
+ task_group_activity=activity,
70
+ logger_name=LOGGER_NAME,
71
+ log_file_path=log_file_path,
72
+ exception=delete_e,
73
+ db=db,
74
+ )
75
+ finally:
76
+ reset_logger_handlers(logger)
@@ -2,5 +2,6 @@ from .collect import collect_ssh # noqa
2
2
  from .collect_pixi import collect_ssh_pixi # noqa
3
3
  from .deactivate import deactivate_ssh # noqa
4
4
  from .deactivate_pixi import deactivate_ssh_pixi # noqa
5
+ from .delete import delete_ssh # noqa
5
6
  from .reactivate import reactivate_ssh # noqa
6
7
  from .reactivate_pixi import reactivate_ssh_pixi # noqa