fractal-server 2.15.0a4__tar.gz → 2.15.1__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 (237) hide show
  1. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/PKG-INFO +1 -1
  2. fractal_server-2.15.1/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/security.py +2 -2
  4. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/user_settings.py +2 -2
  5. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/dataset.py +3 -3
  6. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/job.py +6 -6
  7. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/task.py +5 -4
  8. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/task_group.py +2 -2
  9. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/workflowtask.py +5 -4
  10. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +22 -0
  11. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task_collection.py +5 -13
  12. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task_collection_pixi.py +7 -13
  13. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task_group.py +3 -0
  14. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +10 -0
  15. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +39 -14
  16. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +8 -1
  17. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/config.py +29 -1
  18. fractal_server-2.15.1/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +264 -0
  19. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/collect_pixi.py +21 -0
  20. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/reactivate_pixi.py +21 -0
  21. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/collect_pixi.py +22 -2
  22. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +20 -3
  23. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +1 -1
  24. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/pixi_2_install.sh +11 -2
  25. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +1 -5
  26. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/pyproject.toml +2 -2
  27. fractal_server-2.15.0a4/fractal_server/__init__.py +0 -1
  28. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/LICENSE +0 -0
  29. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/README.md +0 -0
  30. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/__main__.py +0 -0
  31. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/alembic.ini +0 -0
  32. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/__init__.py +0 -0
  33. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/db/__init__.py +0 -0
  34. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/__init__.py +0 -0
  35. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/linkusergroup.py +0 -0
  36. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/linkuserproject.py +0 -0
  37. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/__init__.py +0 -0
  38. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/accounting.py +0 -0
  39. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/history.py +0 -0
  40. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/project.py +0 -0
  41. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/models/v2/workflow.py +0 -0
  42. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/__init__.py +0 -0
  43. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/__init__.py +0 -0
  44. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  45. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  46. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  47. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/job.py +0 -0
  48. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/project.py +0 -0
  49. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/task.py +0 -0
  50. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  51. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
  52. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/__init__.py +0 -0
  53. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  54. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  55. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  56. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  57. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
  58. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
  59. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  60. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/history.py +0 -0
  61. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/images.py +0 -0
  62. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/job.py +0 -0
  63. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  64. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/project.py +0 -0
  65. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  66. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/submit.py +0 -0
  67. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task.py +0 -0
  68. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  69. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
  70. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
  71. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  72. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  73. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  74. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/__init__.py +0 -0
  75. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  76. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/current_user.py +0 -0
  77. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/group.py +0 -0
  78. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/login.py +0 -0
  79. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/oauth.py +0 -0
  80. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/register.py +0 -0
  81. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/router.py +0 -0
  82. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/auth/users.py +0 -0
  83. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/aux/__init__.py +0 -0
  84. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/aux/_job.py +0 -0
  85. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/aux/_runner.py +0 -0
  86. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  87. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/routes/pagination.py +0 -0
  88. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/__init__.py +0 -0
  89. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/components.py +0 -0
  90. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/exceptions.py +0 -0
  91. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/__init__.py +0 -0
  92. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/base_runner.py +0 -0
  93. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/call_command_wrapper.py +0 -0
  94. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/local/__init__.py +0 -0
  95. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/local/get_local_config.py +0 -0
  96. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/local/runner.py +0 -0
  97. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
  98. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
  99. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
  100. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/remote.py +0 -0
  101. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  102. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
  103. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  104. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_ssh/runner.py +0 -0
  105. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_ssh/tar_commands.py +0 -0
  106. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
  107. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  108. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/executors/slurm_sudo/runner.py +0 -0
  109. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/filenames.py +0 -0
  110. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  111. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/shutdown.py +0 -0
  112. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/task_files.py +0 -0
  113. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/__init__.py +0 -0
  114. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/_local.py +0 -0
  115. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/_slurm_ssh.py +0 -0
  116. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/_slurm_sudo.py +0 -0
  117. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/db_tools.py +0 -0
  118. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  119. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  120. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/runner.py +0 -0
  121. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  122. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/submit_workflow.py +0 -0
  123. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/v2/task_interface.py +0 -0
  124. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/runner/versions.py +0 -0
  125. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/__init__.py +0 -0
  126. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/user.py +0 -0
  127. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/user_group.py +0 -0
  128. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/user_settings.py +0 -0
  129. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/__init__.py +0 -0
  130. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/accounting.py +0 -0
  131. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/dataset.py +0 -0
  132. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/dumps.py +0 -0
  133. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/history.py +0 -0
  134. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/job.py +0 -0
  135. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/manifest.py +0 -0
  136. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/project.py +0 -0
  137. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  138. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/task.py +0 -0
  139. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  140. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/task_group.py +0 -0
  141. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/workflow.py +0 -0
  142. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  143. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/security/__init__.py +0 -0
  144. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/security/signup_email.py +0 -0
  145. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/app/user_settings.py +0 -0
  146. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/data_migrations/2_14_10.py +0 -0
  147. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/data_migrations/README.md +0 -0
  148. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/data_migrations/tools.py +0 -0
  149. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/exceptions.py +0 -0
  150. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/gunicorn_fractal.py +0 -0
  151. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/images/__init__.py +0 -0
  152. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/images/models.py +0 -0
  153. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/images/status_tools.py +0 -0
  154. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/images/tools.py +0 -0
  155. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/logger.py +0 -0
  156. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/main.py +0 -0
  157. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/env.py +0 -0
  158. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/naming_convention.py +0 -0
  159. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  160. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  161. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  162. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  163. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  164. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  165. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  166. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  167. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  168. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  169. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  170. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  171. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  172. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
  173. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  174. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  175. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  176. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  177. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
  178. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  179. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  180. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  181. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  182. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  183. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  184. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  185. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  186. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
  187. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  188. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  189. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  190. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  191. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  192. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  193. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  194. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  195. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  196. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  197. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  198. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/py.typed +0 -0
  199. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/ssh/__init__.py +0 -0
  200. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/ssh/_fabric.py +0 -0
  201. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/string_tools.py +0 -0
  202. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/syringe.py +0 -0
  203. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/__init__.py +0 -0
  204. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/utils.py +0 -0
  205. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/__init__.py +0 -0
  206. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/__init__.py +0 -0
  207. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/_utils.py +0 -0
  208. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/collect.py +0 -0
  209. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  210. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
  211. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  212. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  213. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  214. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  215. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  216. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
  217. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  218. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  219. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  220. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  221. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  222. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  223. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  224. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/utils_background.py +0 -0
  225. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/utils_database.py +0 -0
  226. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  227. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/utils_pixi.py +0 -0
  228. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  229. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/tasks/v2/utils_templates.py +0 -0
  230. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/types/__init__.py +0 -0
  231. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/types/validators/__init__.py +0 -0
  232. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/types/validators/_common_validators.py +0 -0
  233. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/types/validators/_filter_validators.py +0 -0
  234. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  235. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/urls.py +0 -0
  236. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/fractal_server/utils.py +0 -0
  237. {fractal_server-2.15.0a4 → fractal_server-2.15.1}/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.0a4
3
+ Version: 2.15.1
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.1"
@@ -15,8 +15,8 @@ from typing import Optional
15
15
  from pydantic import ConfigDict
16
16
  from pydantic import EmailStr
17
17
  from sqlalchemy import Column
18
+ from sqlalchemy.dialects.postgresql import JSONB
18
19
  from sqlalchemy.types import DateTime
19
- from sqlalchemy.types import JSON
20
20
  from sqlmodel import Field
21
21
  from sqlmodel import Relationship
22
22
  from sqlmodel import SQLModel
@@ -124,5 +124,5 @@ class UserGroup(SQLModel, table=True):
124
124
  sa_column=Column(DateTime(timezone=True), nullable=False),
125
125
  )
126
126
  viewer_paths: list[str] = Field(
127
- sa_column=Column(JSON, server_default="[]", nullable=False)
127
+ sa_column=Column(JSONB, server_default="[]", nullable=False)
128
128
  )
@@ -1,5 +1,5 @@
1
1
  from sqlalchemy import Column
2
- from sqlalchemy.types import JSON
2
+ from sqlalchemy.dialects.postgresql import JSONB
3
3
  from sqlmodel import Field
4
4
  from sqlmodel import SQLModel
5
5
 
@@ -25,7 +25,7 @@ class UserSettings(SQLModel, table=True):
25
25
 
26
26
  id: int | None = Field(default=None, primary_key=True)
27
27
  slurm_accounts: list[str] = Field(
28
- sa_column=Column(JSON, server_default="[]", nullable=False)
28
+ sa_column=Column(JSONB, server_default="[]", nullable=False)
29
29
  )
30
30
  ssh_host: str | None = None
31
31
  ssh_username: str | None = None
@@ -3,8 +3,8 @@ from typing import Any
3
3
 
4
4
  from pydantic import ConfigDict
5
5
  from sqlalchemy import Column
6
+ from sqlalchemy.dialects.postgresql import JSONB
6
7
  from sqlalchemy.types import DateTime
7
- from sqlalchemy.types import JSON
8
8
  from sqlmodel import Field
9
9
  from sqlmodel import Relationship
10
10
  from sqlmodel import SQLModel
@@ -24,7 +24,7 @@ class DatasetV2(SQLModel, table=True):
24
24
  )
25
25
 
26
26
  history: list[dict[str, Any]] = Field(
27
- sa_column=Column(JSON, server_default="[]", nullable=False)
27
+ sa_column=Column(JSONB, server_default="[]", nullable=False)
28
28
  )
29
29
 
30
30
  timestamp_created: datetime = Field(
@@ -34,7 +34,7 @@ class DatasetV2(SQLModel, table=True):
34
34
 
35
35
  zarr_dir: str
36
36
  images: list[dict[str, Any]] = Field(
37
- sa_column=Column(JSON, server_default="[]", nullable=False)
37
+ sa_column=Column(JSONB, server_default="[]", nullable=False)
38
38
  )
39
39
 
40
40
  @property
@@ -3,8 +3,8 @@ from typing import Any
3
3
 
4
4
  from pydantic import ConfigDict
5
5
  from sqlalchemy import Column
6
+ from sqlalchemy.dialects.postgresql import JSONB
6
7
  from sqlalchemy.types import DateTime
7
- from sqlalchemy.types import JSON
8
8
  from sqlmodel import Field
9
9
  from sqlmodel import SQLModel
10
10
 
@@ -31,13 +31,13 @@ class JobV2(SQLModel, table=True):
31
31
  slurm_account: str | None = None
32
32
 
33
33
  dataset_dump: dict[str, Any] = Field(
34
- sa_column=Column(JSON, nullable=False)
34
+ sa_column=Column(JSONB, nullable=False)
35
35
  )
36
36
  workflow_dump: dict[str, Any] = Field(
37
- sa_column=Column(JSON, nullable=False)
37
+ sa_column=Column(JSONB, nullable=False)
38
38
  )
39
39
  project_dump: dict[str, Any] = Field(
40
- sa_column=Column(JSON, nullable=False)
40
+ sa_column=Column(JSONB, nullable=False)
41
41
  )
42
42
 
43
43
  worker_init: str | None = None
@@ -57,8 +57,8 @@ class JobV2(SQLModel, table=True):
57
57
  log: str | None = None
58
58
 
59
59
  attribute_filters: AttributeFilters = Field(
60
- sa_column=Column(JSON, nullable=False, server_default="{}")
60
+ sa_column=Column(JSONB, nullable=False, server_default="{}")
61
61
  )
62
62
  type_filters: dict[str, bool] = Field(
63
- sa_column=Column(JSON, nullable=False, server_default="{}")
63
+ sa_column=Column(JSONB, nullable=False, server_default="{}")
64
64
  )
@@ -1,7 +1,8 @@
1
1
  from typing import Any
2
2
 
3
3
  from sqlalchemy import Column
4
- from sqlalchemy.types import JSON
4
+ from sqlalchemy.dialects.postgresql import JSON
5
+ from sqlalchemy.dialects.postgresql import JSONB
5
6
  from sqlmodel import Field
6
7
  from sqlmodel import SQLModel
7
8
 
@@ -33,8 +34,8 @@ class TaskV2(SQLModel, table=True):
33
34
  docs_info: str | None = None
34
35
  docs_link: str | None = None
35
36
 
36
- input_types: dict[str, bool] = Field(sa_column=Column(JSON), default={})
37
- output_types: dict[str, bool] = Field(sa_column=Column(JSON), default={})
37
+ input_types: dict[str, bool] = Field(sa_column=Column(JSONB), default={})
38
+ output_types: dict[str, bool] = Field(sa_column=Column(JSONB), default={})
38
39
 
39
40
  taskgroupv2_id: int = Field(foreign_key="taskgroupv2.id")
40
41
 
@@ -42,5 +43,5 @@ class TaskV2(SQLModel, table=True):
42
43
  modality: str | None = None
43
44
  authors: str | None = None
44
45
  tags: list[str] = Field(
45
- sa_column=Column(JSON, server_default="[]", nullable=False)
46
+ sa_column=Column(JSONB, server_default="[]", nullable=False)
46
47
  )
@@ -2,8 +2,8 @@ from datetime import datetime
2
2
  from datetime import timezone
3
3
 
4
4
  from sqlalchemy import Column
5
+ from sqlalchemy.dialects.postgresql import JSONB
5
6
  from sqlalchemy.types import DateTime
6
- from sqlalchemy.types import JSON
7
7
  from sqlmodel import Field
8
8
  from sqlmodel import Relationship
9
9
  from sqlmodel import SQLModel
@@ -35,7 +35,7 @@ class TaskGroupV2(SQLModel, table=True):
35
35
  pip_extras: str | None = None
36
36
  pinned_package_versions: dict[str, str] = Field(
37
37
  sa_column=Column(
38
- JSON,
38
+ JSONB,
39
39
  server_default="{}",
40
40
  default={},
41
41
  nullable=True,
@@ -2,7 +2,8 @@ from typing import Any
2
2
 
3
3
  from pydantic import ConfigDict
4
4
  from sqlalchemy import Column
5
- from sqlalchemy.types import JSON
5
+ from sqlalchemy.dialects.postgresql import JSON
6
+ from sqlalchemy.dialects.postgresql import JSONB
6
7
  from sqlmodel import Field
7
8
  from sqlmodel import Relationship
8
9
  from sqlmodel import SQLModel
@@ -24,14 +25,14 @@ class WorkflowTaskV2(SQLModel, table=True):
24
25
  sa_column=Column(JSON), default=None
25
26
  )
26
27
  args_parallel: dict[str, Any] | None = Field(
27
- sa_column=Column(JSON), default=None
28
+ sa_column=Column(JSONB), default=None
28
29
  )
29
30
  args_non_parallel: dict[str, Any] | None = Field(
30
- sa_column=Column(JSON), default=None
31
+ sa_column=Column(JSONB), default=None
31
32
  )
32
33
 
33
34
  type_filters: dict[str, bool] = Field(
34
- sa_column=Column(JSON, nullable=False, server_default="{}")
35
+ sa_column=Column(JSONB, nullable=False, server_default="{}")
35
36
  )
36
37
 
37
38
  # Task
@@ -333,6 +333,28 @@ async def _verify_non_duplication_group_constraint(
333
333
  )
334
334
 
335
335
 
336
+ async def _verify_non_duplication_group_path(
337
+ path: str | None,
338
+ db: AsyncSession,
339
+ ) -> None:
340
+ """
341
+ Verify uniqueness of non-`None` `TaskGroupV2.path`
342
+ """
343
+ if path is None:
344
+ return
345
+ stm = select(TaskGroupV2.id).where(TaskGroupV2.path == path)
346
+ res = await db.execute(stm)
347
+ duplicate_ids = res.scalars().all()
348
+ if duplicate_ids:
349
+ raise HTTPException(
350
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
351
+ detail=(
352
+ f"Other TaskGroups already have {path=}: "
353
+ f"{sorted(duplicate_ids)}."
354
+ ),
355
+ )
356
+
357
+
336
358
  async def _add_warnings_to_workflow_tasks(
337
359
  wftask_list: list[WorkflowTaskV2], user_id: int, db: AsyncSession
338
360
  ) -> list[dict[str, Any]]:
@@ -13,7 +13,6 @@ from fastapi import UploadFile
13
13
  from pydantic import BaseModel
14
14
  from pydantic import model_validator
15
15
  from pydantic import ValidationError
16
- from sqlmodel import select
17
16
 
18
17
  from .....config import get_settings
19
18
  from .....logger import reset_logger_handlers
@@ -31,6 +30,7 @@ from ...aux.validate_user_settings import validate_user_settings
31
30
  from ._aux_functions_task_lifecycle import get_package_version_from_pypi
32
31
  from ._aux_functions_tasks import _get_valid_user_group_id
33
32
  from ._aux_functions_tasks import _verify_non_duplication_group_constraint
33
+ from ._aux_functions_tasks import _verify_non_duplication_group_path
34
34
  from ._aux_functions_tasks import _verify_non_duplication_user_constraint
35
35
  from fractal_server.app.models import UserOAuth
36
36
  from fractal_server.app.models.v2 import TaskGroupActivityV2
@@ -291,18 +291,10 @@ async def collect_tasks_pip(
291
291
  version=task_group_attrs["version"],
292
292
  db=db,
293
293
  )
294
-
295
- # Verify that task-group path is unique
296
- stm = select(TaskGroupV2).where(TaskGroupV2.path == task_group_path)
297
- res = await db.execute(stm)
298
- for conflicting_task_group in res.scalars().all():
299
- raise HTTPException(
300
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
301
- detail=(
302
- f"Another task-group already has path={task_group_path}.\n"
303
- f"{conflicting_task_group=}"
304
- ),
305
- )
294
+ await _verify_non_duplication_group_path(
295
+ path=task_group_attrs["path"],
296
+ db=db,
297
+ )
306
298
 
307
299
  # On-disk checks
308
300
 
@@ -9,7 +9,6 @@ from fastapi import HTTPException
9
9
  from fastapi import Response
10
10
  from fastapi import status
11
11
  from fastapi import UploadFile
12
- from sqlmodel import select
13
12
 
14
13
  from fractal_server.app.db import AsyncSession
15
14
  from fractal_server.app.db import get_async_db
@@ -22,6 +21,9 @@ from fractal_server.app.routes.api.v2._aux_functions_tasks import (
22
21
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
23
22
  _verify_non_duplication_group_constraint,
24
23
  )
24
+ from fractal_server.app.routes.api.v2._aux_functions_tasks import (
25
+ _verify_non_duplication_group_path,
26
+ )
25
27
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
26
28
  _verify_non_duplication_user_constraint,
27
29
  )
@@ -156,18 +158,10 @@ async def collect_task_pixi(
156
158
  version=task_group_attrs["version"],
157
159
  db=db,
158
160
  )
159
-
160
- # NOTE: to be removed with issue #2634
161
- stm = select(TaskGroupV2).where(TaskGroupV2.path == task_group_path)
162
- res = await db.execute(stm)
163
- for conflicting_task_group in res.scalars().all():
164
- raise HTTPException(
165
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
166
- detail=(
167
- f"Another task-group already has path={task_group_path}.\n"
168
- f"{conflicting_task_group=}"
169
- ),
170
- )
161
+ await _verify_non_duplication_group_path(
162
+ path=task_group_attrs["path"],
163
+ db=db,
164
+ )
171
165
 
172
166
  if settings.FRACTAL_RUNNER_BACKEND != "slurm_ssh":
173
167
  if Path(task_group_path).exists():
@@ -12,6 +12,7 @@ from pydantic.types import AwareDatetime
12
12
  from sqlmodel import or_
13
13
  from sqlmodel import select
14
14
 
15
+ from ._aux_functions_task_lifecycle import check_no_ongoing_activity
15
16
  from ._aux_functions_tasks import _get_task_group_full_access
16
17
  from ._aux_functions_tasks import _get_task_group_read_access
17
18
  from ._aux_functions_tasks import _verify_non_duplication_group_constraint
@@ -216,6 +217,8 @@ async def delete_task_group(
216
217
  db=db,
217
218
  )
218
219
 
220
+ await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
221
+
219
222
  stm = select(WorkflowTaskV2).where(
220
223
  WorkflowTaskV2.task_id.in_({task.id for task in task_group.task_list})
221
224
  )
@@ -48,6 +48,8 @@ class _SlurmConfigSet(BaseModel):
48
48
  constraint:
49
49
  gres:
50
50
  time:
51
+ exclude:
52
+ nodelist:
51
53
  account:
52
54
  extra_lines:
53
55
  """
@@ -59,6 +61,8 @@ class _SlurmConfigSet(BaseModel):
59
61
  mem: int | str | None = None
60
62
  constraint: str | None = None
61
63
  gres: str | None = None
64
+ exclude: str | None = None
65
+ nodelist: str | None = None
62
66
  time: str | None = None
63
67
  account: str | None = None
64
68
  extra_lines: list[str] | None = None
@@ -227,6 +231,8 @@ class SlurmConfig(BaseModel):
227
231
  account: Corresponds to SLURM option.
228
232
  gpus: Corresponds to SLURM option.
229
233
  time: Corresponds to SLURM option (WARNING: not fully supported).
234
+ nodelist: Corresponds to SLURM option.
235
+ exclude: Corresponds to SLURM option.
230
236
  prefix: Prefix of configuration lines in SLURM submission scripts.
231
237
  shebang_line: Shebang line for SLURM submission scripts.
232
238
  extra_lines: Additional lines to include in SLURM submission scripts.
@@ -268,6 +274,8 @@ class SlurmConfig(BaseModel):
268
274
  gpus: str | None = None
269
275
  time: str | None = None
270
276
  account: str | None = None
277
+ nodelist: str | None = None
278
+ exclude: str | None = None
271
279
 
272
280
  # Free-field attribute for extra lines to be added to the SLURM job
273
281
  # preamble
@@ -361,6 +369,8 @@ class SlurmConfig(BaseModel):
361
369
  "gpus",
362
370
  "time",
363
371
  "account",
372
+ "exclude",
373
+ "nodelist",
364
374
  ]:
365
375
  value = getattr(self, key)
366
376
  if value is not None:
@@ -182,33 +182,53 @@ class BaseSlurmRunner(BaseRunner):
182
182
  def _mkdir_remote_folder(self, folder: str) -> None:
183
183
  raise NotImplementedError("Implement in child class.")
184
184
 
185
- def _submit_single_sbatch(
185
+ def _enrich_slurm_config(
186
186
  self,
187
- *,
188
- base_command: str,
189
- slurm_job: SlurmJob,
190
187
  slurm_config: SlurmConfig,
191
- ) -> str:
192
- logger.debug("[_submit_single_sbatch] START")
188
+ ) -> SlurmConfig:
189
+ """
190
+ Return an enriched `SlurmConfig` object
193
191
 
194
- # Include SLURM account in `slurm_config`. Note: we make this change
195
- # here, rather than exposing a new argument of `get_slurm_config`,
196
- # because it's a backend-specific argument while `get_slurm_config` has
197
- # a generic interface.
192
+ Include `self.account` and `self.common_script_lines` into a
193
+ `SlurmConfig` object. Extracting this logic into an independent
194
+ class method is useful to fix issue #2659 (which was due to
195
+ performing this same operation multiple times rather than once).
196
+
197
+ Args:
198
+ slurm_config: The original `SlurmConfig` object.
199
+
200
+ Returns:
201
+ A new, up-to-date, `SlurmConfig` object.
202
+ """
203
+
204
+ new_slurm_config = slurm_config.model_copy()
205
+
206
+ # Include SLURM account in `slurm_config`.
198
207
  if self.slurm_account is not None:
199
- slurm_config.account = self.slurm_account
208
+ new_slurm_config.account = self.slurm_account
200
209
 
201
210
  # Include common_script_lines in extra_lines
202
211
  if len(self.common_script_lines) > 0:
203
212
  logger.debug(
204
213
  f"Add {self.common_script_lines} to "
205
- f"{slurm_config.extra_lines=}."
214
+ f"{new_slurm_config.extra_lines=}."
206
215
  )
207
- current_extra_lines = slurm_config.extra_lines or []
208
- slurm_config.extra_lines = (
216
+ current_extra_lines = new_slurm_config.extra_lines or []
217
+ new_slurm_config.extra_lines = (
209
218
  current_extra_lines + self.common_script_lines
210
219
  )
211
220
 
221
+ return new_slurm_config
222
+
223
+ def _submit_single_sbatch(
224
+ self,
225
+ *,
226
+ base_command: str,
227
+ slurm_job: SlurmJob,
228
+ slurm_config: SlurmConfig,
229
+ ) -> str:
230
+ logger.debug("[_submit_single_sbatch] START")
231
+
212
232
  for task in slurm_job.tasks:
213
233
  # Write input file
214
234
  if self.slurm_runner_type == "ssh":
@@ -508,6 +528,9 @@ class BaseSlurmRunner(BaseRunner):
508
528
  user_id: int,
509
529
  ) -> tuple[Any, Exception]:
510
530
  logger.debug("[submit] START")
531
+
532
+ config = self._enrich_slurm_config(config)
533
+
511
534
  try:
512
535
  workdir_local = task_files.wftask_subfolder_local
513
536
  workdir_remote = task_files.wftask_subfolder_remote
@@ -649,6 +672,8 @@ class BaseSlurmRunner(BaseRunner):
649
672
  input images, while for compound tasks these can differ.
650
673
  """
651
674
 
675
+ config = self._enrich_slurm_config(config)
676
+
652
677
  logger.debug(f"[multisubmit] START, {len(list_parameters)=}")
653
678
  try:
654
679
  if self.is_shutdown():
@@ -125,7 +125,14 @@ def get_slurm_config_internal(
125
125
  )
126
126
  logger.error(error_msg)
127
127
  raise SlurmConfigError(error_msg)
128
- for key in ["time", "gres", "gpus", "constraint"]:
128
+ for key in [
129
+ "time",
130
+ "gres",
131
+ "gpus",
132
+ "constraint",
133
+ "nodelist",
134
+ "exclude",
135
+ ]:
129
136
  value = wftask_meta.get(key, None)
130
137
  if value is not None:
131
138
  slurm_dict[key] = value
@@ -65,8 +65,36 @@ class MailSettings(BaseModel):
65
65
 
66
66
 
67
67
  class PixiSettings(BaseModel):
68
- default_version: str
68
+ """
69
+ Configuration for Pixi task collection
70
+
71
+ See https://pixi.sh/latest/reference/cli/pixi/install/#config-options for
72
+ `pixi install` concurrency options.
73
+ See https://docs.rs/tokio/latest/tokio/#cpu-bound-tasks-and-blocking-code
74
+ for `tokio` configuration.
75
+
76
+ versions:
77
+ Available `pixi` versions and their `PIXI_HOME` folders.
78
+ default_version:
79
+ Default `pixi` version to use for task collection - must be one
80
+ of `versions` keys.
81
+ PIXI_CONCURRENT_SOLVES:
82
+ Value of `--concurrent-solves` for `pixi install`.
83
+ PIXI_CONCURRENT_DOWNLOADS:
84
+ Value of `--concurrent-downloads for `pixi install`.
85
+ TOKIO_WORKER_THREADS:
86
+ From tokio docs, "The core threads are where all asynchronous code
87
+ runs, and Tokio will by default spawn one for each CPU core. You can
88
+ use the environment variable TOKIO_WORKER_THREADS to override the
89
+ default value."
90
+ """
91
+
69
92
  versions: DictStrStr
93
+ default_version: str
94
+
95
+ PIXI_CONCURRENT_SOLVES: int = 4
96
+ PIXI_CONCURRENT_DOWNLOADS: int = 4
97
+ TOKIO_WORKER_THREADS: int = 2
70
98
 
71
99
  @model_validator(mode="after")
72
100
  def check_pixi_settings(self):