fractal-server 2.14.6__tar.gz → 2.14.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 (221) hide show
  1. {fractal_server-2.14.6 → fractal_server-2.14.8}/PKG-INFO +1 -1
  2. fractal_server-2.14.8/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/history.py +1 -0
  4. fractal_server-2.14.8/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +42 -0
  5. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/history.py +63 -73
  6. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/task_version_update.py +23 -47
  7. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +21 -0
  8. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_ssh/runner.py +2 -0
  9. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_sudo/runner.py +1 -1
  10. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/_slurm_ssh.py +4 -2
  11. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/_slurm_sudo.py +1 -1
  12. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/runner.py +1 -0
  13. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/submit_workflow.py +5 -1
  14. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/__init__.py +1 -1
  15. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/history.py +13 -2
  16. fractal_server-2.14.8/fractal_server/data_migrations/2_14_6.py +48 -0
  17. fractal_server-2.14.8/fractal_server/images/image_status.py +85 -0
  18. fractal_server-2.14.8/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +42 -0
  19. {fractal_server-2.14.6 → fractal_server-2.14.8}/pyproject.toml +2 -2
  20. fractal_server-2.14.6/fractal_server/__init__.py +0 -1
  21. {fractal_server-2.14.6 → fractal_server-2.14.8}/LICENSE +0 -0
  22. {fractal_server-2.14.6 → fractal_server-2.14.8}/README.md +0 -0
  23. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/__main__.py +0 -0
  24. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/alembic.ini +0 -0
  25. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/__init__.py +0 -0
  26. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/db/__init__.py +0 -0
  27. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/__init__.py +0 -0
  28. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/linkusergroup.py +0 -0
  29. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/linkuserproject.py +0 -0
  30. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/security.py +0 -0
  31. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/user_settings.py +0 -0
  32. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/__init__.py +0 -0
  33. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/accounting.py +0 -0
  34. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/dataset.py +0 -0
  35. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/job.py +0 -0
  36. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/project.py +0 -0
  37. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/task.py +0 -0
  38. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/task_group.py +0 -0
  39. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/workflow.py +0 -0
  40. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/models/v2/workflowtask.py +0 -0
  41. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/__init__.py +0 -0
  42. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/__init__.py +0 -0
  43. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  44. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  45. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  46. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/job.py +0 -0
  47. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/project.py +0 -0
  48. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/task.py +0 -0
  49. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  50. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
  51. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/__init__.py +0 -0
  52. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  53. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  54. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  55. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  56. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  57. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  58. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/images.py +0 -0
  59. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/job.py +0 -0
  60. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  61. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/project.py +0 -0
  62. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  63. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/submit.py +0 -0
  64. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/task.py +0 -0
  65. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
  66. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  67. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  68. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
  69. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  70. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  71. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  72. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/__init__.py +0 -0
  73. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  74. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/current_user.py +0 -0
  75. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/group.py +0 -0
  76. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/login.py +0 -0
  77. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/oauth.py +0 -0
  78. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/register.py +0 -0
  79. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/router.py +0 -0
  80. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/auth/users.py +0 -0
  81. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/aux/__init__.py +0 -0
  82. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/aux/_job.py +0 -0
  83. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/aux/_runner.py +0 -0
  84. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  85. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/routes/pagination.py +0 -0
  86. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/__init__.py +0 -0
  87. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/components.py +0 -0
  88. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/exceptions.py +0 -0
  89. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/__init__.py +0 -0
  90. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/base_runner.py +0 -0
  91. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/call_command_wrapper.py +0 -0
  92. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/local/__init__.py +0 -0
  93. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/local/get_local_config.py +0 -0
  94. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/local/runner.py +0 -0
  95. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
  96. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
  97. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
  98. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +0 -0
  99. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +0 -0
  100. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/remote.py +0 -0
  101. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  102. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
  103. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  104. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_ssh/tar_commands.py +0 -0
  105. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
  106. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  107. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/filenames.py +0 -0
  108. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  109. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/shutdown.py +0 -0
  110. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/task_files.py +0 -0
  111. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/__init__.py +0 -0
  112. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/_local.py +0 -0
  113. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/db_tools.py +0 -0
  114. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  115. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  116. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  117. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/v2/task_interface.py +0 -0
  118. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/runner/versions.py +0 -0
  119. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/__init__.py +0 -0
  120. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/user.py +0 -0
  121. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/user_group.py +0 -0
  122. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/user_settings.py +0 -0
  123. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/accounting.py +0 -0
  124. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/dataset.py +0 -0
  125. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/dumps.py +0 -0
  126. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/job.py +0 -0
  127. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/manifest.py +0 -0
  128. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/project.py +0 -0
  129. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  130. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/task.py +0 -0
  131. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  132. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/task_group.py +0 -0
  133. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/workflow.py +0 -0
  134. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  135. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/security/__init__.py +0 -0
  136. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/security/signup_email.py +0 -0
  137. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/app/user_settings.py +0 -0
  138. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/config.py +0 -0
  139. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/data_migrations/README.md +0 -0
  140. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/data_migrations/tools.py +0 -0
  141. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/gunicorn_fractal.py +0 -0
  142. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/images/__init__.py +0 -0
  143. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/images/models.py +0 -0
  144. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/images/tools.py +0 -0
  145. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/logger.py +0 -0
  146. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/main.py +0 -0
  147. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/env.py +0 -0
  148. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/naming_convention.py +0 -0
  149. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  150. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  151. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  152. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  153. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  154. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  155. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  156. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  157. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  158. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  159. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  160. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  161. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  162. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  163. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  164. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  165. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  166. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  167. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  168. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  169. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  170. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  171. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  172. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  173. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  174. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  175. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  176. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  177. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  178. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  179. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  180. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  181. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  182. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  183. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  184. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  185. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/py.typed +0 -0
  186. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/ssh/__init__.py +0 -0
  187. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/ssh/_fabric.py +0 -0
  188. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/string_tools.py +0 -0
  189. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/syringe.py +0 -0
  190. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/__init__.py +0 -0
  191. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/utils.py +0 -0
  192. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/__init__.py +0 -0
  193. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/local/__init__.py +0 -0
  194. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/local/_utils.py +0 -0
  195. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/local/collect.py +0 -0
  196. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  197. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  198. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  199. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  200. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  201. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  202. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  203. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  204. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  205. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  206. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  207. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  208. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  209. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/utils_background.py +0 -0
  210. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/utils_database.py +0 -0
  211. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  212. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  213. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/tasks/v2/utils_templates.py +0 -0
  214. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/types/__init__.py +0 -0
  215. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/types/validators/__init__.py +0 -0
  216. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/types/validators/_common_validators.py +0 -0
  217. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/types/validators/_filter_validators.py +0 -0
  218. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  219. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/urls.py +0 -0
  220. {fractal_server-2.14.6 → fractal_server-2.14.8}/fractal_server/utils.py +0 -0
  221. {fractal_server-2.14.6 → fractal_server-2.14.8}/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.14.6
3
+ Version: 2.14.8
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.14.8"
@@ -27,6 +27,7 @@ class HistoryRun(SQLModel, table=True):
27
27
  ondelete="SET NULL",
28
28
  )
29
29
  job_id: int = Field(foreign_key="jobv2.id")
30
+ task_id: int | None = Field(foreign_key="taskv2.id", ondelete="SET NULL")
30
31
 
31
32
  workflowtask_dump: dict[str, Any] = Field(
32
33
  sa_column=Column(JSONB, nullable=False),
@@ -0,0 +1,42 @@
1
+ from typing import Any
2
+
3
+
4
+ def get_new_workflow_task_meta(
5
+ *,
6
+ old_workflow_task_meta: dict | None,
7
+ old_task_meta: dict | None,
8
+ new_task_meta: dict | None,
9
+ ) -> dict[str, Any]:
10
+ """
11
+ Prepare new meta field based on old/new tasks and old workflow task.
12
+ """
13
+
14
+ # When the whole `old_workflow_task_meta` is user-provided, use it
15
+ # as the outcome
16
+ if old_task_meta is None:
17
+ return old_workflow_task_meta
18
+
19
+ # When `old_workflow_task_meta` is unset, use the new-task meta as default.
20
+ if old_workflow_task_meta is None:
21
+ return new_task_meta
22
+
23
+ if new_task_meta is None:
24
+ new_task_meta = {}
25
+
26
+ # Find properties that were added to the old defaults
27
+ additions = {
28
+ k: v
29
+ for k, v in old_workflow_task_meta.items()
30
+ if v != old_task_meta.get(k)
31
+ }
32
+ # Find properties that were removed from the old defaults
33
+ removals = old_task_meta.keys() - old_workflow_task_meta.keys()
34
+
35
+ # Add `additions` and remove `removals`.
36
+ new_workflowtask_meta = {
37
+ k: v
38
+ for k, v in (new_task_meta | additions).items()
39
+ if k not in removals
40
+ }
41
+
42
+ return new_workflowtask_meta
@@ -23,6 +23,7 @@ from fractal_server.app.models import UserOAuth
23
23
  from fractal_server.app.models.v2 import HistoryImageCache
24
24
  from fractal_server.app.models.v2 import HistoryRun
25
25
  from fractal_server.app.models.v2 import HistoryUnit
26
+ from fractal_server.app.models.v2 import TaskV2
26
27
  from fractal_server.app.routes.auth import current_active_user
27
28
  from fractal_server.app.routes.pagination import get_pagination_params
28
29
  from fractal_server.app.routes.pagination import PaginationRequest
@@ -31,9 +32,11 @@ from fractal_server.app.schemas.v2 import HistoryRunRead
31
32
  from fractal_server.app.schemas.v2 import HistoryRunReadAggregated
32
33
  from fractal_server.app.schemas.v2 import HistoryUnitRead
33
34
  from fractal_server.app.schemas.v2 import HistoryUnitStatus
34
- from fractal_server.app.schemas.v2 import HistoryUnitStatusQuery
35
+ from fractal_server.app.schemas.v2 import HistoryUnitStatusWithUnset
35
36
  from fractal_server.app.schemas.v2 import ImageLogsRequest
36
37
  from fractal_server.app.schemas.v2 import SingleImageWithStatus
38
+ from fractal_server.images.image_status import enrich_image_list
39
+ from fractal_server.images.image_status import IMAGE_STATUS_KEY
37
40
  from fractal_server.images.tools import aggregate_attributes
38
41
  from fractal_server.images.tools import aggregate_types
39
42
  from fractal_server.images.tools import filter_image_list
@@ -60,7 +63,6 @@ def check_historyrun_related_to_dataset_and_wftask(
60
63
 
61
64
 
62
65
  class ImageWithStatusPage(PaginationResponse[SingleImageWithStatus]):
63
-
64
66
  attributes: dict[str, list[Any]]
65
67
  types: list[str]
66
68
 
@@ -77,7 +79,6 @@ async def get_workflow_tasks_statuses(
77
79
  user: UserOAuth = Depends(current_active_user),
78
80
  db: AsyncSession = Depends(get_async_db),
79
81
  ) -> JSONResponse:
80
-
81
82
  # Access control
82
83
  workflow = await _get_workflow_check_owner(
83
84
  project_id=project_id,
@@ -150,7 +151,6 @@ async def get_history_run_list(
150
151
  user: UserOAuth = Depends(current_active_user),
151
152
  db: AsyncSession = Depends(get_async_db),
152
153
  ) -> list[HistoryRunReadAggregated]:
153
-
154
154
  # Access control
155
155
  await get_wftask_check_owner(
156
156
  project_id=project_id,
@@ -199,7 +199,36 @@ async def get_history_run_list(
199
199
  for run_id, unit_status, count in unit_counts:
200
200
  count_map[run_id][f"num_{unit_status}_units"] = count
201
201
 
202
- runs = [dict(**run.model_dump(), **count_map[run.id]) for run in runs]
202
+ res = await db.execute(
203
+ select(
204
+ TaskV2.id,
205
+ TaskV2.version,
206
+ TaskV2.args_schema_parallel,
207
+ TaskV2.args_schema_non_parallel,
208
+ ).where(
209
+ TaskV2.id.in_(
210
+ [run.task_id for run in runs if run.task_id is not None]
211
+ )
212
+ )
213
+ )
214
+
215
+ task_args = {
216
+ _id: {
217
+ "version": version,
218
+ "args_schema_parallel": parallel,
219
+ "args_schema_non_parallel": non_parallel,
220
+ }
221
+ for _id, version, parallel, non_parallel in res.all()
222
+ }
223
+
224
+ runs = [
225
+ dict(
226
+ **run.model_dump(),
227
+ **count_map[run.id],
228
+ **task_args.get(run.task_id, {}),
229
+ )
230
+ for run in runs
231
+ ]
203
232
 
204
233
  return runs
205
234
 
@@ -215,7 +244,6 @@ async def get_history_run_units(
215
244
  db: AsyncSession = Depends(get_async_db),
216
245
  pagination: PaginationRequest = Depends(get_pagination_params),
217
246
  ) -> PaginationResponse[HistoryUnitRead]:
218
-
219
247
  # Access control
220
248
  await get_wftask_check_owner(
221
249
  project_id=project_id,
@@ -271,12 +299,11 @@ async def get_history_images(
271
299
  dataset_id: int,
272
300
  workflowtask_id: int,
273
301
  request_body: ImageQuery,
274
- unit_status: HistoryUnitStatusQuery | None = None,
302
+ unit_status: HistoryUnitStatusWithUnset | None = None,
275
303
  user: UserOAuth = Depends(current_active_user),
276
304
  db: AsyncSession = Depends(get_async_db),
277
305
  pagination: PaginationRequest = Depends(get_pagination_params),
278
306
  ) -> ImageWithStatusPage:
279
-
280
307
  # Access control and object retrieval
281
308
  wftask = await get_wftask_check_owner(
282
309
  project_id=project_id,
@@ -318,99 +345,62 @@ async def get_history_images(
318
345
  actual_filters.update(type_filters_patch)
319
346
  logger.debug(f"{prefix} {actual_filters=}")
320
347
  # (1D) Get all matching images from the dataset
348
+
321
349
  pre_filtered_dataset_images = filter_image_list(
322
350
  images=dataset.images,
323
351
  type_filters=inferred_dataset_type_filters,
324
352
  )
353
+
354
+ full_images_list = await enrich_image_list(
355
+ dataset_id=dataset_id,
356
+ workflowtask_id=workflowtask_id,
357
+ images=pre_filtered_dataset_images,
358
+ db=db,
359
+ )
360
+
361
+ if unit_status is not None:
362
+ request_body.attribute_filters[IMAGE_STATUS_KEY] = unit_status
363
+
325
364
  filtered_dataset_images = filter_image_list(
326
- pre_filtered_dataset_images,
365
+ full_images_list,
327
366
  type_filters=request_body.type_filters,
328
367
  attribute_filters=request_body.attribute_filters,
329
368
  )
330
369
  logger.debug(f"{prefix} {len(dataset.images)=}")
331
370
  logger.debug(f"{prefix} {len(filtered_dataset_images)=}")
332
- # (1E) Extract the list of URLs for filtered images
333
- filtered_dataset_images_url = list(
334
- img["zarr_url"] for img in filtered_dataset_images
335
- )
336
-
337
- # (2) Get `(zarr_url, status)` pairs for all images that have already
338
- # been processed, and
339
- # (3) When relevant, find images that have not been processed
340
- base_stmt = (
341
- select(HistoryImageCache.zarr_url, HistoryUnit.status)
342
- .join(HistoryUnit)
343
- .where(HistoryImageCache.dataset_id == dataset_id)
344
- .where(HistoryImageCache.workflowtask_id == workflowtask_id)
345
- .where(HistoryImageCache.latest_history_unit_id == HistoryUnit.id)
346
- .where(HistoryImageCache.zarr_url.in_(filtered_dataset_images_url))
347
- )
348
-
349
- if unit_status in [HistoryUnitStatusQuery.UNSET, None]:
350
- stmt = base_stmt.order_by(HistoryImageCache.zarr_url)
351
- res = await db.execute(stmt)
352
- list_processed_url_status = res.all()
353
- list_processed_url = list(
354
- item[0] for item in list_processed_url_status
355
- )
356
- list_non_processed_url_status = list(
357
- (url, None)
358
- for url in filtered_dataset_images_url
359
- if url not in list_processed_url
360
- )
361
- if unit_status == HistoryUnitStatusQuery.UNSET:
362
- list_processed_url_status = []
363
- else:
364
- stmt = base_stmt.where(HistoryUnit.status == unit_status).order_by(
365
- HistoryImageCache.zarr_url
366
- )
367
- res = await db.execute(stmt)
368
- list_processed_url_status = res.all()
369
- list_non_processed_url_status = []
370
-
371
- logger.debug(f"{prefix} {len(list_processed_url_status)=}")
372
- logger.debug(f"{prefix} {len(list_non_processed_url_status)=}")
373
-
374
- # (3) Combine outputs from 1 and 2
375
- full_list_url_status = (
376
- list_processed_url_status + list_non_processed_url_status
377
- )
378
- logger.debug(f"{prefix} {len(full_list_url_status)=}")
379
371
 
380
372
  attributes = aggregate_attributes(pre_filtered_dataset_images)
381
373
  types = aggregate_types(pre_filtered_dataset_images)
382
374
 
383
- sorted_list_url_status = sorted(
384
- full_list_url_status,
385
- key=lambda url_status: url_status[0],
386
- )
387
- logger.debug(f"{prefix} {len(sorted_list_url_status)=}")
388
-
389
375
  # Final list of objects
390
376
 
391
- total_count = len(sorted_list_url_status)
377
+ total_count = len(filtered_dataset_images)
392
378
  page_size = pagination.page_size or total_count
393
-
394
- paginated_list_url_status = sorted_list_url_status[
379
+ sorted_images_list = sorted(
380
+ filtered_dataset_images,
381
+ key=lambda image: image["zarr_url"],
382
+ )
383
+ paginated_images_list = sorted_images_list[
395
384
  (pagination.page - 1) * page_size : pagination.page * page_size
396
385
  ]
397
386
 
398
- # Aggregate information to create 'SingleImageWithStatus'
399
- items = [
387
+ # FIXME: This is only for backwards-compatibility. To remove when we
388
+ # update the webclient
389
+ paginated_images_list = [
400
390
  {
401
- **filtered_dataset_images[
402
- filtered_dataset_images_url.index(url_status[0])
403
- ],
404
- "status": url_status[1],
391
+ **img,
392
+ "status": (
393
+ lambda x: None if x == HistoryUnitStatusWithUnset.UNSET else x
394
+ )(img["attributes"].pop(IMAGE_STATUS_KEY)),
405
395
  }
406
- for url_status in paginated_list_url_status
396
+ for img in paginated_images_list
407
397
  ]
408
398
 
409
399
  return dict(
410
400
  current_page=pagination.page,
411
401
  page_size=page_size,
412
402
  total_count=total_count,
413
- items=items,
403
+ items=paginated_images_list,
414
404
  attributes=attributes,
415
405
  types=types,
416
406
  )
@@ -17,12 +17,12 @@ from ....models import LinkUserGroup
17
17
  from ....models.v2 import TaskV2
18
18
  from ._aux_functions import _get_workflow_check_owner
19
19
  from ._aux_functions import _get_workflow_task_check_owner
20
+ from ._aux_functions_task_version_update import get_new_workflow_task_meta
20
21
  from ._aux_functions_tasks import _check_type_filters_compatibility
21
22
  from ._aux_functions_tasks import _get_task_group_or_404
22
23
  from ._aux_functions_tasks import _get_task_read_access
23
24
  from fractal_server.app.models import UserOAuth
24
25
  from fractal_server.app.models.v2 import TaskGroupV2
25
- from fractal_server.app.models.v2 import WorkflowTaskV2
26
26
  from fractal_server.app.routes.auth import current_active_user
27
27
  from fractal_server.app.schemas.v2 import WorkflowTaskReadV2
28
28
  from fractal_server.app.schemas.v2 import WorkflowTaskReplaceV2
@@ -181,7 +181,7 @@ async def replace_workflowtask(
181
181
  ) -> WorkflowTaskReadV2:
182
182
 
183
183
  # Get objects from database
184
- old_wftask, workflow = await _get_workflow_task_check_owner(
184
+ workflow_task, workflow = await _get_workflow_task_check_owner(
185
185
  project_id=project_id,
186
186
  workflow_id=workflow_id,
187
187
  workflow_task_id=workflow_task_id,
@@ -197,14 +197,14 @@ async def replace_workflowtask(
197
197
 
198
198
  # Preliminary checks
199
199
  if not _is_type_update_valid(
200
- old_type=old_wftask.task_type,
200
+ old_type=workflow_task.task_type,
201
201
  new_type=new_task.type,
202
202
  ):
203
203
  raise HTTPException(
204
204
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
205
205
  detail=(
206
206
  "Cannot change task type from "
207
- f"{old_wftask.task_type} to {new_task.type}."
207
+ f"{workflow_task.task_type} to {new_task.type}."
208
208
  ),
209
209
  )
210
210
 
@@ -220,51 +220,27 @@ async def replace_workflowtask(
220
220
  )
221
221
  _check_type_filters_compatibility(
222
222
  task_input_types=new_task.input_types,
223
- wftask_type_filters=old_wftask.type_filters,
223
+ wftask_type_filters=workflow_task.type_filters,
224
224
  )
225
225
 
226
- # Task arguments
227
- if replace.args_non_parallel is None:
228
- _args_non_parallel = old_wftask.args_non_parallel
229
- else:
230
- _args_non_parallel = replace.args_non_parallel
231
- if replace.args_parallel is None:
232
- _args_parallel = old_wftask.args_parallel
233
- else:
234
- _args_parallel = replace.args_parallel
235
-
236
- # If user's changes to `meta_non_parallel` are compatible with new task,
237
- # keep them; else, get `meta_non_parallel` from new task
238
- if (
239
- old_wftask.meta_non_parallel != old_wftask.task.meta_non_parallel
240
- ) and (old_wftask.task.meta_non_parallel == new_task.meta_non_parallel):
241
- _meta_non_parallel = old_wftask.meta_non_parallel
242
- else:
243
- _meta_non_parallel = new_task.meta_non_parallel
244
- # Same for `meta_parallel`
245
- if (old_wftask.meta_parallel != old_wftask.task.meta_parallel) and (
246
- old_wftask.task.meta_parallel == new_task.meta_parallel
247
- ):
248
- _meta_parallel = old_wftask.meta_parallel
249
- else:
250
- _meta_parallel = new_task.meta_parallel
251
-
252
- new_workflow_task = WorkflowTaskV2(
253
- task_id=new_task.id,
254
- task_type=new_task.type,
255
- task=new_task,
256
- # old-task values
257
- type_filters=old_wftask.type_filters,
258
- # possibly new values
259
- args_non_parallel=_args_non_parallel,
260
- args_parallel=_args_parallel,
261
- meta_non_parallel=_meta_non_parallel,
262
- meta_parallel=_meta_parallel,
226
+ workflow_task.task_id = new_task.id
227
+ workflow_task.task_type = new_task.type
228
+ workflow_task.meta_non_parallel = get_new_workflow_task_meta(
229
+ old_task_meta=workflow_task.task.meta_non_parallel,
230
+ old_workflow_task_meta=workflow_task.meta_non_parallel,
231
+ new_task_meta=new_task.meta_non_parallel,
232
+ )
233
+ workflow_task.meta_parallel = get_new_workflow_task_meta(
234
+ old_task_meta=workflow_task.task.meta_parallel,
235
+ old_workflow_task_meta=workflow_task.meta_parallel,
236
+ new_task_meta=new_task.meta_parallel,
263
237
  )
238
+ if replace.args_non_parallel is not None:
239
+ workflow_task.args_non_parallel = replace.args_non_parallel
240
+ if replace.args_parallel is not None:
241
+ workflow_task.args_parallel = replace.args_parallel
264
242
 
265
- workflow_task_order = old_wftask.order
266
- workflow.task_list.remove(old_wftask)
267
- workflow.task_list.insert(workflow_task_order, new_workflow_task)
243
+ db.add(workflow_task)
268
244
  await db.commit()
269
- await db.refresh(new_workflow_task)
270
- return new_workflow_task
245
+ await db.refresh(workflow_task)
246
+ return workflow_task
@@ -73,6 +73,7 @@ class BaseSlurmRunner(BaseRunner):
73
73
  jobs: dict[str, SlurmJob]
74
74
  python_worker_interpreter: str
75
75
  slurm_runner_type: Literal["ssh", "sudo"]
76
+ slurm_account: str | None = None
76
77
 
77
78
  def __init__(
78
79
  self,
@@ -83,6 +84,7 @@ class BaseSlurmRunner(BaseRunner):
83
84
  common_script_lines: list[str] | None = None,
84
85
  user_cache_dir: str | None = None,
85
86
  poll_interval: int | None = None,
87
+ slurm_account: str | None = None,
86
88
  ):
87
89
  self.slurm_runner_type = slurm_runner_type
88
90
  self.root_dir_local = root_dir_local
@@ -91,6 +93,7 @@ class BaseSlurmRunner(BaseRunner):
91
93
  self._check_slurm_account()
92
94
  self.user_cache_dir = user_cache_dir
93
95
  self.python_worker_interpreter = python_worker_interpreter
96
+ self.slurm_account = slurm_account
94
97
 
95
98
  settings = Inject(get_settings)
96
99
 
@@ -185,6 +188,24 @@ class BaseSlurmRunner(BaseRunner):
185
188
  ) -> str:
186
189
  logger.debug("[_submit_single_sbatch] START")
187
190
 
191
+ # Include SLURM account in `slurm_config`. Note: we make this change
192
+ # here, rather than exposing a new argument of `get_slurm_config`,
193
+ # because it's a backend-specific argument while `get_slurm_config` has
194
+ # a generic interface.
195
+ if self.slurm_account is not None:
196
+ slurm_config.account = self.slurm_account
197
+
198
+ # Include common_script_lines in extra_lines
199
+ if len(self.common_script_lines) > 0:
200
+ logger.debug(
201
+ f"Add {self.common_script_lines} to "
202
+ f"{slurm_config.extra_lines=}."
203
+ )
204
+ current_extra_lines = slurm_config.extra_lines or []
205
+ slurm_config.extra_lines = (
206
+ current_extra_lines + self.common_script_lines
207
+ )
208
+
188
209
  for task in slurm_job.tasks:
189
210
  # Write input file
190
211
  if self.slurm_runner_type == "ssh":
@@ -30,6 +30,7 @@ class SlurmSSHRunner(BaseSlurmRunner):
30
30
  user_cache_dir: str | None = None,
31
31
  poll_interval: int | None = None,
32
32
  # Specific
33
+ slurm_account: str | None = None,
33
34
  fractal_ssh: FractalSSH,
34
35
  ) -> None:
35
36
  """
@@ -49,6 +50,7 @@ class SlurmSSHRunner(BaseSlurmRunner):
49
50
  user_cache_dir=user_cache_dir,
50
51
  poll_interval=poll_interval,
51
52
  python_worker_interpreter=settings.FRACTAL_SLURM_WORKER_PYTHON,
53
+ slurm_account=slurm_account,
52
54
  )
53
55
 
54
56
  def _mkdir_local_folder(self, folder: str) -> None:
@@ -63,7 +63,6 @@ class SudoSlurmRunner(BaseSlurmRunner):
63
63
  """
64
64
 
65
65
  self.slurm_user = slurm_user
66
- self.slurm_account = slurm_account
67
66
  settings = Inject(get_settings)
68
67
 
69
68
  super().__init__(
@@ -76,6 +75,7 @@ class SudoSlurmRunner(BaseSlurmRunner):
76
75
  python_worker_interpreter=(
77
76
  settings.FRACTAL_SLURM_WORKER_PYTHON or sys.executable
78
77
  ),
78
+ slurm_account=slurm_account,
79
79
  )
80
80
 
81
81
  def _mkdir_local_folder(self, folder: str) -> None:
@@ -43,10 +43,11 @@ def process_workflow(
43
43
  logger_name: str,
44
44
  job_attribute_filters: AttributeFilters,
45
45
  job_type_filters: dict[str, bool],
46
+ user_id: int,
47
+ # SLURM-ssh-specific
46
48
  fractal_ssh: FractalSSH,
49
+ slurm_account: str | None = None,
47
50
  worker_init: str | None = None,
48
- user_id: int,
49
- **kwargs, # not used
50
51
  ) -> None:
51
52
  """
52
53
  Process workflow (SLURM backend public interface)
@@ -79,6 +80,7 @@ def process_workflow(
79
80
  fractal_ssh=fractal_ssh,
80
81
  root_dir_local=workflow_dir_local,
81
82
  root_dir_remote=workflow_dir_remote,
83
+ slurm_account=slurm_account,
82
84
  common_script_lines=worker_init,
83
85
  ) as runner:
84
86
  execute_tasks_v2(
@@ -39,7 +39,7 @@ def process_workflow(
39
39
  job_attribute_filters: AttributeFilters,
40
40
  job_type_filters: dict[str, bool],
41
41
  user_id: int,
42
- # Slurm-specific
42
+ # SLURM-sudo-specific
43
43
  user_cache_dir: str | None = None,
44
44
  slurm_user: str | None = None,
45
45
  slurm_account: str | None = None,
@@ -153,6 +153,7 @@ def execute_tasks_v2(
153
153
  dataset_id=dataset.id,
154
154
  workflowtask_id=wftask.id,
155
155
  job_id=job_id,
156
+ task_id=wftask.task.id,
156
157
  workflowtask_dump=workflowtask_dump,
157
158
  task_group_dump=task_group_dump,
158
159
  num_available_images=num_available_images,
@@ -236,6 +236,7 @@ def submit_workflow(
236
236
  elif FRACTAL_RUNNER_BACKEND == "slurm_ssh":
237
237
  logger.debug(f"ssh_user: {user_settings.ssh_username}")
238
238
  logger.debug(f"base dir: {user_settings.ssh_tasks_dir}")
239
+ logger.debug(f"slurm_account: {job.slurm_account}")
239
240
  logger.debug(f"worker_init: {worker_init}")
240
241
  logger.debug(f"job.id: {job.id}")
241
242
  logger.debug(f"job.working_dir: {job.working_dir}")
@@ -257,7 +258,10 @@ def submit_workflow(
257
258
  )
258
259
  elif FRACTAL_RUNNER_BACKEND == "slurm_ssh":
259
260
  process_workflow = slurm_ssh_process_workflow
260
- backend_specific_kwargs = dict(fractal_ssh=fractal_ssh)
261
+ backend_specific_kwargs = dict(
262
+ fractal_ssh=fractal_ssh,
263
+ slurm_account=job.slurm_account,
264
+ )
261
265
  else:
262
266
  raise RuntimeError(
263
267
  f"Invalid runner backend {FRACTAL_RUNNER_BACKEND=}"
@@ -14,7 +14,7 @@ from .history import HistoryRunRead # noqa F401
14
14
  from .history import HistoryRunReadAggregated # noqa F401
15
15
  from .history import HistoryUnitRead # noqa F401
16
16
  from .history import HistoryUnitStatus # noqa F401
17
- from .history import HistoryUnitStatusQuery # noqa F401
17
+ from .history import HistoryUnitStatusWithUnset # noqa F401
18
18
  from .history import ImageLogsRequest # noqa F401
19
19
  from .history import SingleImageWithStatus # noqa F401
20
20
  from .job import JobCreateV2 # noqa F401
@@ -24,12 +24,19 @@ class HistoryUnitStatus(StrEnum):
24
24
  FAILED = "failed"
25
25
 
26
26
 
27
- class HistoryUnitStatusQuery(StrEnum):
27
+ class HistoryUnitStatusWithUnset(StrEnum):
28
+ """
29
+ Available status for history queries
30
+
31
+ Attributes:
32
+ SUBMITTED:
33
+ DONE:
34
+ FAILED:
35
+ """
28
36
 
29
37
  SUBMITTED = "submitted"
30
38
  DONE = "done"
31
39
  FAILED = "failed"
32
-
33
40
  UNSET = "unset"
34
41
 
35
42
 
@@ -63,6 +70,9 @@ class HistoryRunReadAggregated(BaseModel):
63
70
  num_submitted_units: int
64
71
  num_done_units: int
65
72
  num_failed_units: int
73
+ args_schema_parallel: dict[str, Any] | None = None
74
+ args_schema_non_parallel: dict[str, Any] | None = None
75
+ version: str | None = None
66
76
 
67
77
  @field_serializer("timestamp_started")
68
78
  def serialize_datetime(v: datetime) -> str:
@@ -75,5 +85,6 @@ class ImageLogsRequest(BaseModel):
75
85
  zarr_url: str
76
86
 
77
87
 
88
+ # FIXME: remove this when we update the webclient
78
89
  class SingleImageWithStatus(SingleImage):
79
90
  status: HistoryUnitStatus | None = None
@@ -0,0 +1,48 @@
1
+ import logging
2
+
3
+ from sqlmodel import select
4
+
5
+ from fractal_server.app.db import get_sync_db
6
+ from fractal_server.app.models import HistoryRun
7
+ from fractal_server.app.models import TaskV2
8
+ from fractal_server.app.models import WorkflowTaskV2
9
+
10
+ logger = logging.getLogger("fix_db")
11
+ logger.setLevel(logging.INFO)
12
+
13
+
14
+ def fix_db():
15
+ logger.info("START execution of fix_db function")
16
+
17
+ with next(get_sync_db()) as db:
18
+
19
+ stm = select(HistoryRun).order_by(HistoryRun.id)
20
+ history_runs = db.execute(stm).scalars().all()
21
+
22
+ for hr in history_runs:
23
+ logger.info(f"HistoryRun[{hr.id}] START")
24
+
25
+ wft = db.get(WorkflowTaskV2, hr.workflowtask_id)
26
+ if wft is None:
27
+ logger.warning(
28
+ f"WorkflowTaskV2[{hr.workflowtask_id}] not found. "
29
+ "Trying to use HistoryRun.workflowtask_dump"
30
+ )
31
+ task_id = hr.workflowtask_dump.get("task_id")
32
+ if task_id is not None and db.get(TaskV2, task_id) is not None:
33
+ hr.task_id = task_id
34
+ else:
35
+ logger.warning(f"TaskV2[{task_id}] not found")
36
+ else:
37
+ hr.task_id = wft.task_id
38
+ logger.info(
39
+ f"HistoryRun[{hr.id}].task_id set to {wft.task_id}"
40
+ )
41
+
42
+ db.add(hr)
43
+ logger.info(f"HistoryRun[{hr.id}] END")
44
+
45
+ db.commit()
46
+ logger.info("Changes committed.")
47
+
48
+ logger.info("END execution of fix_db function")