fractal-server 2.7.1__tar.gz → 2.8.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 (236) hide show
  1. {fractal_server-2.7.1 → fractal_server-2.8.1}/PKG-INFO +11 -8
  2. {fractal_server-2.7.1 → fractal_server-2.8.1}/README.md +10 -7
  3. fractal_server-2.8.1/fractal_server/__init__.py +1 -0
  4. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/user_settings.py +1 -0
  5. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/task.py +15 -0
  6. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/dataset.py +39 -6
  7. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/task.py +2 -5
  8. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/task_collection.py +14 -42
  9. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/task_collection_custom.py +3 -3
  10. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/_validators.py +1 -1
  11. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/user_settings.py +18 -0
  12. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/dataset.py +6 -4
  13. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/task_collection.py +31 -12
  14. fractal_server-2.8.1/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +39 -0
  15. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/string_tools.py +10 -3
  16. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/utils.py +0 -31
  17. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v1/background_operations.py +11 -11
  18. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v1/endpoint_operations.py +5 -5
  19. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v1/utils.py +2 -2
  20. fractal_server-2.8.1/fractal_server/tasks/v2/collection_local.py +357 -0
  21. fractal_server-2.7.1/fractal_server/tasks/v2/background_operations_ssh.py → fractal_server-2.8.1/fractal_server/tasks/v2/collection_ssh.py +108 -102
  22. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v2/templates/_1_create_venv.sh +0 -8
  23. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v2/templates/_2_preliminary_pip_operations.sh +2 -2
  24. fractal_server-2.8.1/fractal_server/tasks/v2/templates/_3_pip_install.sh +49 -0
  25. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v2/templates/_5_pip_show.sh +5 -5
  26. fractal_server-2.8.1/fractal_server/tasks/v2/utils_background.py +209 -0
  27. fractal_server-2.8.1/fractal_server/tasks/v2/utils_package_names.py +77 -0
  28. fractal_server-2.7.1/fractal_server/tasks/v2/utils.py → fractal_server-2.8.1/fractal_server/tasks/v2/utils_python_interpreter.py +0 -26
  29. fractal_server-2.8.1/fractal_server/tasks/v2/utils_templates.py +59 -0
  30. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/utils.py +48 -3
  31. {fractal_server-2.7.1 → fractal_server-2.8.1}/pyproject.toml +2 -2
  32. fractal_server-2.7.1/fractal_server/__init__.py +0 -1
  33. fractal_server-2.7.1/fractal_server/tasks/v2/_venv_pip.py +0 -198
  34. fractal_server-2.7.1/fractal_server/tasks/v2/background_operations.py +0 -456
  35. fractal_server-2.7.1/fractal_server/tasks/v2/templates/_3_pip_install.sh +0 -28
  36. {fractal_server-2.7.1 → fractal_server-2.8.1}/LICENSE +0 -0
  37. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/__main__.py +0 -0
  38. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/alembic.ini +0 -0
  39. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/__init__.py +0 -0
  40. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/db/__init__.py +0 -0
  41. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/__init__.py +0 -0
  42. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/linkusergroup.py +0 -0
  43. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/linkuserproject.py +0 -0
  44. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/security.py +0 -0
  45. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/__init__.py +0 -0
  46. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/dataset.py +0 -0
  47. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/job.py +0 -0
  48. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/project.py +0 -0
  49. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/state.py +0 -0
  50. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/task.py +0 -0
  51. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v1/workflow.py +0 -0
  52. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/__init__.py +0 -0
  53. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/collection_state.py +0 -0
  54. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/dataset.py +0 -0
  55. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/job.py +0 -0
  56. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/project.py +0 -0
  57. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/workflow.py +0 -0
  58. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/models/v2/workflowtask.py +0 -0
  59. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/__init__.py +0 -0
  60. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/__init__.py +0 -0
  61. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/v1.py +0 -0
  62. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  63. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/v2/job.py +0 -0
  64. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/v2/project.py +0 -0
  65. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/v2/task.py +0 -0
  66. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  67. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/__init__.py +0 -0
  68. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/__init__.py +0 -0
  69. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/_aux_functions.py +0 -0
  70. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/dataset.py +0 -0
  71. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/job.py +0 -0
  72. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/project.py +0 -0
  73. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/task.py +0 -0
  74. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/task_collection.py +0 -0
  75. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/workflow.py +0 -0
  76. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v1/workflowtask.py +0 -0
  77. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  78. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  79. /fractal_server-2.7.1/fractal_server/tasks/v2/endpoint_operations.py → /fractal_server-2.8.1/fractal_server/app/routes/api/v2/_aux_functions_task_collection.py +0 -0
  80. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  81. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/images.py +0 -0
  82. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/job.py +0 -0
  83. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/project.py +0 -0
  84. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/status.py +0 -0
  85. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/submit.py +0 -0
  86. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  87. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  88. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  89. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  90. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/__init__.py +0 -0
  91. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  92. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/current_user.py +0 -0
  93. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/group.py +0 -0
  94. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/login.py +0 -0
  95. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/oauth.py +0 -0
  96. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/register.py +0 -0
  97. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/router.py +0 -0
  98. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/auth/users.py +0 -0
  99. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/aux/__init__.py +0 -0
  100. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/aux/_job.py +0 -0
  101. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/aux/_runner.py +0 -0
  102. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  103. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/.gitignore +0 -0
  104. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/__init__.py +0 -0
  105. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/async_wrap.py +0 -0
  106. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/components.py +0 -0
  107. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/compress_folder.py +0 -0
  108. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/exceptions.py +0 -0
  109. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/__init__.py +0 -0
  110. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/__init__.py +0 -0
  111. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/_batching.py +0 -0
  112. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/_slurm_config.py +0 -0
  113. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/remote.py +0 -0
  114. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -0
  115. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -0
  116. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -0
  117. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/ssh/executor.py +0 -0
  118. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -0
  119. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -0
  120. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -0
  121. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/sudo/_subprocess_run_as_user.py +0 -0
  122. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -0
  123. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/extract_archive.py +0 -0
  124. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/filenames.py +0 -0
  125. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/run_subprocess.py +0 -0
  126. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  127. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/shutdown.py +0 -0
  128. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/task_files.py +0 -0
  129. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/__init__.py +0 -0
  130. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_common.py +0 -0
  131. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_local/__init__.py +0 -0
  132. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_local/_local_config.py +0 -0
  133. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_local/_submit_setup.py +0 -0
  134. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_local/executor.py +0 -0
  135. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_slurm/__init__.py +0 -0
  136. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_slurm/_submit_setup.py +0 -0
  137. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -0
  138. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/common.py +0 -0
  139. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v1/handle_failed_job.py +0 -0
  140. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/__init__.py +0 -0
  141. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local/__init__.py +0 -0
  142. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local/_local_config.py +0 -0
  143. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local/_submit_setup.py +0 -0
  144. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local/executor.py +0 -0
  145. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -0
  146. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -0
  147. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -0
  148. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_local_experimental/executor.py +0 -0
  149. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_slurm_common/__init__.py +0 -0
  150. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +0 -0
  151. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_slurm_ssh/__init__.py +0 -0
  152. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -0
  153. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_slurm_sudo/__init__.py +0 -0
  154. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -0
  155. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  156. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/handle_failed_job.py +0 -0
  157. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  158. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/runner.py +0 -0
  159. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  160. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
  161. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/v2/task_interface.py +0 -0
  162. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/runner/versions.py +0 -0
  163. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/__init__.py +0 -0
  164. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/user.py +0 -0
  165. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/user_group.py +0 -0
  166. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/__init__.py +0 -0
  167. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/applyworkflow.py +0 -0
  168. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/dataset.py +0 -0
  169. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/dumps.py +0 -0
  170. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/manifest.py +0 -0
  171. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/project.py +0 -0
  172. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/state.py +0 -0
  173. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/task.py +0 -0
  174. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/task_collection.py +0 -0
  175. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v1/workflow.py +0 -0
  176. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/__init__.py +0 -0
  177. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/dumps.py +0 -0
  178. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/job.py +0 -0
  179. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/manifest.py +0 -0
  180. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/project.py +0 -0
  181. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/status.py +0 -0
  182. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/task.py +0 -0
  183. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/task_group.py +0 -0
  184. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/workflow.py +0 -0
  185. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  186. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/security/__init__.py +0 -0
  187. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/app/user_settings.py +0 -0
  188. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/config.py +0 -0
  189. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/data_migrations/README.md +0 -0
  190. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/data_migrations/tools.py +0 -0
  191. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/gunicorn_fractal.py +0 -0
  192. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/images/__init__.py +0 -0
  193. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/images/models.py +0 -0
  194. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/images/tools.py +0 -0
  195. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/logger.py +0 -0
  196. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/main.py +0 -0
  197. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/README +0 -0
  198. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/env.py +0 -0
  199. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/naming_convention.py +0 -0
  200. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/script.py.mako +0 -0
  201. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  202. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  203. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  204. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  205. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  206. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  207. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  208. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  209. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  210. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  211. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  212. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  213. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  214. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  215. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  216. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  217. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  218. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  219. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  220. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  221. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  222. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  223. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  224. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/py.typed +0 -0
  225. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/ssh/__init__.py +0 -0
  226. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/ssh/_fabric.py +0 -0
  227. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/syringe.py +0 -0
  228. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/__init__.py +0 -0
  229. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v1/_TaskCollectPip.py +0 -0
  230. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v1/__init__.py +0 -0
  231. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v1/get_collection_data.py +0 -0
  232. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v2/__init__.py +0 -0
  233. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v2/database_operations.py +0 -0
  234. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/tasks/v2/templates/_4_pip_freeze.sh +0 -0
  235. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/urls.py +0 -0
  236. {fractal_server-2.7.1 → fractal_server-2.8.1}/fractal_server/zip_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.7.1
3
+ Version: 2.8.1
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -37,15 +37,20 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  # Fractal Server
39
39
 
40
+ <p align="center">
41
+ <img src="https://github.com/user-attachments/assets/16e9cf11-d47d-4db8-a9b1-f5349e4175b7" alt="Fractal server" width="400">
42
+ </p>
43
+
40
44
  [![PyPI version](https://img.shields.io/pypi/v/fractal-server?color=gree)](https://pypi.org/project/fractal-server/)
45
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
41
46
  [![CI Status](https://github.com/fractal-analytics-platform/fractal-server/actions/workflows/ci.yml/badge.svg)](https://github.com/fractal-analytics-platform/fractal-server/actions/workflows/ci.yml?query=branch%3Amain)
42
47
  [![Coverage](https://raw.githubusercontent.com/fractal-analytics-platform/fractal-server/python-coverage-comment-action-data/badge.svg)](https://htmlpreview.github.io/?https://github.com/fractal-analytics-platform/fractal-server/blob/python-coverage-comment-action-data/htmlcov/index.html)
43
- [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
48
+ [![Documentation Status](https://github.com/fractal-analytics-platform/fractal-server/actions/workflows/documentation.yaml/badge.svg)](https://fractal-analytics-platform.github.io/fractal-server)
44
49
  [![Benchmarks](https://img.shields.io/badge/Benchmarks-Done-blue)](https://htmlpreview.github.io/?https://github.com/fractal-analytics-platform/fractal-server/blob/benchmark-api/benchmarks/bench.html)
45
50
 
46
51
  [Fractal](https://fractal-analytics-platform.github.io/) is a framework developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html) to process bioimaging data at scale in the OME-Zarr format and prepare the images for interactive visualization.
47
52
 
48
- ![Fractal_overview](https://github.com/user-attachments/assets/286122d9-08cf-48e8-996d-3cf53e0a81c6)
53
+ ![Fractal_overview](https://github.com/user-attachments/assets/666c8797-2594-4b8e-b1d2-b43fca66d1df)
49
54
 
50
55
  This is the server component of the fractal analytics platform.
51
56
  Find more information about Fractal in general and the other repositories at
@@ -58,14 +63,12 @@ See https://fractal-analytics-platform.github.io/fractal-server.
58
63
 
59
64
  # Contributors and license
60
65
 
61
- Unless otherwise stated in each individual module, all Fractal components are
62
- released according to a BSD 3-Clause License, and Copyright is with Friedrich
63
- Miescher Institute for Biomedical Research and University of Zurich.
66
+ Fractal was conceived in the Liberali Lab at the Friedrich Miescher Institute for Biomedical Research and in the Pelkmans Lab at the University of Zurich by [@jluethi](https://github.com/jluethi) and [@gusqgm](https://github.com/gusqgm). The Fractal project is now developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html) at the University of Zurich and the project lead is with [@jluethi](https://github.com/jluethi). The core development is done under contract by [eXact lab S.r.l.](https://www.exact-lab.it).
67
+
68
+ Unless otherwise specified, Fractal components are released under the BSD 3-Clause License, and copyright is with the BioVisionCenter at the University of Zurich.
64
69
 
65
70
  The SLURM compatibility layer is based on
66
71
  [`clusterfutures`](https://github.com/sampsyo/clusterfutures), by
67
72
  [@sampsyo](https://github.com/sampsyo) and collaborators, and it is released
68
73
  under the terms of the MIT license.
69
74
 
70
- Fractal was conceived in the Liberali Lab at the Friedrich Miescher Institute for Biomedical Research and in the Pelkmans Lab at the University of Zurich by [@jluethi](https://github.com/jluethi) and [@gusqgm](https://github.com/gusqgm). The Fractal project is now developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html) at the University of Zurich and the project lead is with [@jluethi](https://github.com/jluethi). The core development is done under contract by [eXact lab S.r.l.](https://www.exact-lab.it/).
71
-
@@ -1,14 +1,19 @@
1
1
  # Fractal Server
2
2
 
3
+ <p align="center">
4
+ <img src="https://github.com/user-attachments/assets/16e9cf11-d47d-4db8-a9b1-f5349e4175b7" alt="Fractal server" width="400">
5
+ </p>
6
+
3
7
  [![PyPI version](https://img.shields.io/pypi/v/fractal-server?color=gree)](https://pypi.org/project/fractal-server/)
8
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
4
9
  [![CI Status](https://github.com/fractal-analytics-platform/fractal-server/actions/workflows/ci.yml/badge.svg)](https://github.com/fractal-analytics-platform/fractal-server/actions/workflows/ci.yml?query=branch%3Amain)
5
10
  [![Coverage](https://raw.githubusercontent.com/fractal-analytics-platform/fractal-server/python-coverage-comment-action-data/badge.svg)](https://htmlpreview.github.io/?https://github.com/fractal-analytics-platform/fractal-server/blob/python-coverage-comment-action-data/htmlcov/index.html)
6
- [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
11
+ [![Documentation Status](https://github.com/fractal-analytics-platform/fractal-server/actions/workflows/documentation.yaml/badge.svg)](https://fractal-analytics-platform.github.io/fractal-server)
7
12
  [![Benchmarks](https://img.shields.io/badge/Benchmarks-Done-blue)](https://htmlpreview.github.io/?https://github.com/fractal-analytics-platform/fractal-server/blob/benchmark-api/benchmarks/bench.html)
8
13
 
9
14
  [Fractal](https://fractal-analytics-platform.github.io/) is a framework developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html) to process bioimaging data at scale in the OME-Zarr format and prepare the images for interactive visualization.
10
15
 
11
- ![Fractal_overview](https://github.com/user-attachments/assets/286122d9-08cf-48e8-996d-3cf53e0a81c6)
16
+ ![Fractal_overview](https://github.com/user-attachments/assets/666c8797-2594-4b8e-b1d2-b43fca66d1df)
12
17
 
13
18
  This is the server component of the fractal analytics platform.
14
19
  Find more information about Fractal in general and the other repositories at
@@ -21,13 +26,11 @@ See https://fractal-analytics-platform.github.io/fractal-server.
21
26
 
22
27
  # Contributors and license
23
28
 
24
- Unless otherwise stated in each individual module, all Fractal components are
25
- released according to a BSD 3-Clause License, and Copyright is with Friedrich
26
- Miescher Institute for Biomedical Research and University of Zurich.
29
+ Fractal was conceived in the Liberali Lab at the Friedrich Miescher Institute for Biomedical Research and in the Pelkmans Lab at the University of Zurich by [@jluethi](https://github.com/jluethi) and [@gusqgm](https://github.com/gusqgm). The Fractal project is now developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html) at the University of Zurich and the project lead is with [@jluethi](https://github.com/jluethi). The core development is done under contract by [eXact lab S.r.l.](https://www.exact-lab.it).
30
+
31
+ Unless otherwise specified, Fractal components are released under the BSD 3-Clause License, and copyright is with the BioVisionCenter at the University of Zurich.
27
32
 
28
33
  The SLURM compatibility layer is based on
29
34
  [`clusterfutures`](https://github.com/sampsyo/clusterfutures), by
30
35
  [@sampsyo](https://github.com/sampsyo) and collaborators, and it is released
31
36
  under the terms of the MIT license.
32
-
33
- Fractal was conceived in the Liberali Lab at the Friedrich Miescher Institute for Biomedical Research and in the Pelkmans Lab at the University of Zurich by [@jluethi](https://github.com/jluethi) and [@gusqgm](https://github.com/gusqgm). The Fractal project is now developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html) at the University of Zurich and the project lead is with [@jluethi](https://github.com/jluethi). The core development is done under contract by [eXact lab S.r.l.](https://www.exact-lab.it/).
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.8.1"
@@ -36,3 +36,4 @@ class UserSettings(SQLModel, table=True):
36
36
  ssh_jobs_dir: Optional[str] = None
37
37
  slurm_user: Optional[str] = None
38
38
  cache_dir: Optional[str] = None
39
+ project_dir: Optional[str] = None
@@ -103,3 +103,18 @@ class TaskGroupV2(SQLModel, table=True):
103
103
  f"{self.pkg_name=}, {self.wheel_path=}, {self.version=}."
104
104
  )
105
105
  return f"{self.pkg_name}{extras}=={self.version}"
106
+
107
+ @property
108
+ def pinned_package_versions_string(self) -> str:
109
+ """
110
+ Prepare string to be used in `python -m pip install`.
111
+ """
112
+ if self.pinned_package_versions is None:
113
+ return ""
114
+ output = " ".join(
115
+ [
116
+ f"{key}=={value}"
117
+ for key, value in self.pinned_package_versions.items()
118
+ ]
119
+ )
120
+ return output
@@ -22,6 +22,8 @@ from ._aux_functions import _get_project_check_owner
22
22
  from ._aux_functions import _get_submitted_jobs_statement
23
23
  from fractal_server.app.models import UserOAuth
24
24
  from fractal_server.app.routes.auth import current_active_user
25
+ from fractal_server.string_tools import sanitize_string
26
+ from fractal_server.urls import normalize_url
25
27
 
26
28
  router = APIRouter()
27
29
 
@@ -40,14 +42,45 @@ async def create_dataset(
40
42
  """
41
43
  Add new dataset to current project
42
44
  """
43
- await _get_project_check_owner(
45
+ project = await _get_project_check_owner(
44
46
  project_id=project_id, user_id=user.id, db=db
45
47
  )
46
- db_dataset = DatasetV2(project_id=project_id, **dataset.dict())
47
- db.add(db_dataset)
48
- await db.commit()
49
- await db.refresh(db_dataset)
50
- await db.close()
48
+
49
+ if dataset.zarr_dir is None:
50
+
51
+ if user.settings.project_dir is None:
52
+ raise HTTPException(
53
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
54
+ detail=(
55
+ "Both 'dataset.zarr_dir' and 'user.settings.project_dir' "
56
+ "are null"
57
+ ),
58
+ )
59
+
60
+ db_dataset = DatasetV2(
61
+ project_id=project_id,
62
+ zarr_dir="__PLACEHOLDER__",
63
+ **dataset.dict(exclude={"zarr_dir"}),
64
+ )
65
+ db.add(db_dataset)
66
+ await db.commit()
67
+ await db.refresh(db_dataset)
68
+ path = (
69
+ f"{user.settings.project_dir}/fractal/"
70
+ f"{project_id}_{sanitize_string(project.name)}/"
71
+ f"{db_dataset.id}_{sanitize_string(db_dataset.name)}"
72
+ )
73
+ normalized_path = normalize_url(path)
74
+ db_dataset.zarr_dir = normalized_path
75
+
76
+ db.add(db_dataset)
77
+ await db.commit()
78
+ await db.refresh(db_dataset)
79
+ else:
80
+ db_dataset = DatasetV2(project_id=project_id, **dataset.dict())
81
+ db.add(db_dataset)
82
+ await db.commit()
83
+ await db.refresh(db_dataset)
51
84
 
52
85
  return db_dataset
53
86
 
@@ -36,8 +36,7 @@ logger = set_logger(__name__)
36
36
 
37
37
  @router.get("/", response_model=list[TaskReadV2])
38
38
  async def get_list_task(
39
- args_schema_parallel: bool = True,
40
- args_schema_non_parallel: bool = True,
39
+ args_schema: bool = True,
41
40
  category: Optional[str] = None,
42
41
  modality: Optional[str] = None,
43
42
  author: Optional[str] = None,
@@ -72,11 +71,9 @@ async def get_list_task(
72
71
  res = await db.execute(stm)
73
72
  task_list = res.scalars().all()
74
73
  await db.close()
75
- if args_schema_parallel is False:
74
+ if args_schema is False:
76
75
  for task in task_list:
77
76
  setattr(task, "args_schema_parallel", None)
78
- if args_schema_non_parallel is False:
79
- for task in task_list:
80
77
  setattr(task, "args_schema_non_parallel", None)
81
78
 
82
79
  return task_list
@@ -24,6 +24,7 @@ from ....schemas.v2 import CollectionStatusV2
24
24
  from ....schemas.v2 import TaskCollectPipV2
25
25
  from ....schemas.v2 import TaskGroupCreateV2
26
26
  from ...aux.validate_user_settings import validate_user_settings
27
+ from ._aux_functions_task_collection import get_package_version_from_pypi
27
28
  from ._aux_functions_tasks import _get_valid_user_group_id
28
29
  from ._aux_functions_tasks import _verify_non_duplication_group_constraint
29
30
  from ._aux_functions_tasks import _verify_non_duplication_user_constraint
@@ -31,16 +32,14 @@ from fractal_server.app.models import UserOAuth
31
32
  from fractal_server.app.routes.auth import current_active_user
32
33
  from fractal_server.app.routes.auth import current_active_verified_user
33
34
  from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
34
- from fractal_server.tasks.utils import _normalize_package_name
35
- from fractal_server.tasks.utils import get_collection_log_v2
36
- from fractal_server.tasks.v2.background_operations import (
37
- background_collect_pip,
35
+ from fractal_server.tasks.v2.collection_local import (
36
+ collect_package_local,
38
37
  )
39
- from fractal_server.tasks.v2.endpoint_operations import (
40
- get_package_version_from_pypi,
38
+ from fractal_server.tasks.v2.utils_package_names import _parse_wheel_filename
39
+ from fractal_server.tasks.v2.utils_package_names import normalize_package_name
40
+ from fractal_server.tasks.v2.utils_python_interpreter import (
41
+ get_python_interpreter_v2,
41
42
  )
42
- from fractal_server.tasks.v2.utils import _parse_wheel_filename
43
- from fractal_server.tasks.v2.utils import get_python_interpreter_v2
44
43
 
45
44
  router = APIRouter()
46
45
 
@@ -118,14 +117,14 @@ async def collect_tasks_pip(
118
117
  f"Original error: {str(e)}",
119
118
  ),
120
119
  )
121
- task_group_attrs["pkg_name"] = _normalize_package_name(
120
+ task_group_attrs["pkg_name"] = normalize_package_name(
122
121
  wheel_info["distribution"]
123
122
  )
124
123
  task_group_attrs["version"] = wheel_info["version"]
125
124
  task_group_attrs["origin"] = TaskGroupV2OriginEnum.WHEELFILE
126
125
  else:
127
126
  pkg_name = task_collect.package
128
- task_group_attrs["pkg_name"] = _normalize_package_name(pkg_name)
127
+ task_group_attrs["pkg_name"] = normalize_package_name(pkg_name)
129
128
  task_group_attrs["origin"] = TaskGroupV2OriginEnum.PYPI
130
129
  latest_version = await get_package_version_from_pypi(
131
130
  task_collect.package,
@@ -249,8 +248,8 @@ async def collect_tasks_pip(
249
248
  if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
250
249
  # SSH task collection
251
250
 
252
- from fractal_server.tasks.v2.background_operations_ssh import (
253
- background_collect_pip_ssh,
251
+ from fractal_server.tasks.v2.collection_ssh import (
252
+ collect_package_ssh,
254
253
  )
255
254
 
256
255
  # User appropriate FractalSSH object
@@ -263,7 +262,7 @@ async def collect_tasks_pip(
263
262
  fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
264
263
 
265
264
  background_tasks.add_task(
266
- background_collect_pip_ssh,
265
+ collect_package_ssh,
267
266
  state_id=state.id,
268
267
  task_group=task_group,
269
268
  fractal_ssh=fractal_ssh,
@@ -273,7 +272,7 @@ async def collect_tasks_pip(
273
272
  else:
274
273
  # Local task collection
275
274
  background_tasks.add_task(
276
- background_collect_pip,
275
+ collect_package_local,
277
276
  state_id=state.id,
278
277
  task_group=task_group,
279
278
  )
@@ -296,42 +295,15 @@ async def collect_tasks_pip(
296
295
  async def check_collection_status(
297
296
  state_id: int,
298
297
  user: UserOAuth = Depends(current_active_user),
299
- verbose: bool = False,
300
298
  db: AsyncSession = Depends(get_async_db),
301
299
  ) -> CollectionStateReadV2: # State[TaskCollectStatus]
302
300
  """
303
301
  Check status of background task collection
304
302
  """
305
-
306
- logger = set_logger(logger_name="check_collection_status")
307
- logger.debug(f"Querying state for state.id={state_id}")
308
303
  state = await db.get(CollectionStateV2, state_id)
309
- if not state:
310
- await db.close()
304
+ if state is None:
311
305
  raise HTTPException(
312
306
  status_code=status.HTTP_404_NOT_FOUND,
313
307
  detail=f"No task collection info with id={state_id}",
314
308
  )
315
-
316
- settings = Inject(get_settings)
317
- if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
318
- # FIXME SSH: add logic for when data.state["log"] is empty
319
- pass
320
- else:
321
- # Non-SSH mode
322
- # In some cases (i.e. a successful or ongoing task collection),
323
- # state.data["log"] is not set; if so, we collect the current logs.
324
- if verbose and not state.data.get("log"):
325
- if "path" not in state.data.keys():
326
- await db.close()
327
- raise HTTPException(
328
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
329
- detail=(
330
- f"No 'path' in CollectionStateV2[{state_id}].data"
331
- ),
332
- )
333
- state.data["log"] = get_collection_log_v2(Path(state.data["path"]))
334
-
335
- reset_logger_handlers(logger)
336
- await db.close()
337
309
  return state
@@ -27,12 +27,12 @@ from fractal_server.config import get_settings
27
27
  from fractal_server.logger import set_logger
28
28
  from fractal_server.string_tools import validate_cmd
29
29
  from fractal_server.syringe import Inject
30
- from fractal_server.tasks.v2.background_operations import (
31
- _prepare_tasks_metadata,
32
- )
33
30
  from fractal_server.tasks.v2.database_operations import (
34
31
  create_db_tasks_and_update_task_group,
35
32
  )
33
+ from fractal_server.tasks.v2.utils_background import (
34
+ _prepare_tasks_metadata,
35
+ )
36
36
 
37
37
  router = APIRouter()
38
38
 
@@ -74,7 +74,7 @@ def val_absolute_path(attribute: str, accept_none: bool = False):
74
74
  Check that a string attribute is an absolute path
75
75
  """
76
76
 
77
- def val(string: Optional[str]) -> str:
77
+ def val(string: Optional[str]) -> Optional[str]:
78
78
  if string is None:
79
79
  if accept_none:
80
80
  return string
@@ -19,6 +19,10 @@ __all__ = (
19
19
 
20
20
 
21
21
  class UserSettingsRead(BaseModel):
22
+ """
23
+ Schema reserved for superusers
24
+ """
25
+
22
26
  id: int
23
27
  ssh_host: Optional[str] = None
24
28
  ssh_username: Optional[str] = None
@@ -28,6 +32,7 @@ class UserSettingsRead(BaseModel):
28
32
  slurm_user: Optional[str] = None
29
33
  slurm_accounts: list[str]
30
34
  cache_dir: Optional[str] = None
35
+ project_dir: Optional[str] = None
31
36
 
32
37
 
33
38
  class UserSettingsReadStrict(BaseModel):
@@ -35,9 +40,14 @@ class UserSettingsReadStrict(BaseModel):
35
40
  slurm_accounts: list[str]
36
41
  cache_dir: Optional[str] = None
37
42
  ssh_username: Optional[str] = None
43
+ project_dir: Optional[str] = None
38
44
 
39
45
 
40
46
  class UserSettingsUpdate(BaseModel, extra=Extra.forbid):
47
+ """
48
+ Schema reserved for superusers
49
+ """
50
+
41
51
  ssh_host: Optional[str] = None
42
52
  ssh_username: Optional[str] = None
43
53
  ssh_private_key_path: Optional[str] = None
@@ -46,6 +56,7 @@ class UserSettingsUpdate(BaseModel, extra=Extra.forbid):
46
56
  slurm_user: Optional[str] = None
47
57
  slurm_accounts: Optional[list[StrictStr]] = None
48
58
  cache_dir: Optional[str] = None
59
+ project_dir: Optional[str] = None
49
60
 
50
61
  _ssh_host = validator("ssh_host", allow_reuse=True)(
51
62
  valstr("ssh_host", accept_none=True)
@@ -83,6 +94,13 @@ class UserSettingsUpdate(BaseModel, extra=Extra.forbid):
83
94
  validate_cmd(value)
84
95
  return val_absolute_path("cache_dir")(value)
85
96
 
97
+ @validator("project_dir")
98
+ def project_dir_validator(cls, value):
99
+ if value is None:
100
+ return None
101
+ validate_cmd(value)
102
+ return val_absolute_path("project_dir")(value)
103
+
86
104
 
87
105
  class UserSettingsUpdateStrict(BaseModel, extra=Extra.forbid):
88
106
  slurm_accounts: Optional[list[StrictStr]] = None
@@ -33,14 +33,16 @@ class DatasetCreateV2(BaseModel, extra=Extra.forbid):
33
33
 
34
34
  name: str
35
35
 
36
- zarr_dir: str
36
+ zarr_dir: Optional[str] = None
37
37
 
38
38
  filters: Filters = Field(default_factory=Filters)
39
39
 
40
40
  # Validators
41
41
  @validator("zarr_dir")
42
- def normalize_zarr_dir(cls, v: str) -> str:
43
- return normalize_url(v)
42
+ def normalize_zarr_dir(cls, v: Optional[str]) -> Optional[str]:
43
+ if v is not None:
44
+ return normalize_url(v)
45
+ return v
44
46
 
45
47
  _name = validator("name", allow_reuse=True)(valstr("name"))
46
48
 
@@ -95,7 +97,7 @@ class DatasetImportV2(BaseModel, extra=Extra.forbid):
95
97
 
96
98
  name: str
97
99
  zarr_dir: str
98
- images: list[SingleImage] = Field(default_factory=[])
100
+ images: list[SingleImage] = Field(default_factory=list)
99
101
  filters: Filters = Field(default_factory=Filters)
100
102
 
101
103
  # Validators
@@ -10,7 +10,6 @@ from pydantic import Extra
10
10
  from pydantic import root_validator
11
11
  from pydantic import validator
12
12
 
13
- from .._validators import valdictkeys
14
13
  from .._validators import valstr
15
14
  from fractal_server.app.schemas._validators import valutc
16
15
  from fractal_server.app.schemas.v2 import ManifestV2
@@ -58,19 +57,29 @@ class TaskCollectPipV2(BaseModel, extra=Extra.forbid):
58
57
  python_version: Optional[Literal["3.9", "3.10", "3.11", "3.12"]] = None
59
58
  pinned_package_versions: Optional[dict[str, str]] = None
60
59
 
61
- _package = validator("package", allow_reuse=True)(valstr("package"))
62
- _package_version = validator("package_version", allow_reuse=True)(
63
- valstr("package_version")
64
- )
65
- _pinned_package_versions = validator(
66
- "pinned_package_versions", allow_reuse=True
67
- )(valdictkeys("pinned_package_versions"))
68
- _package_extras = validator("package_extras", allow_reuse=True)(
69
- valstr("package_extras")
70
- )
60
+ @validator("pinned_package_versions")
61
+ def pinned_package_versions_validator(cls, value):
62
+ if value is None:
63
+ return value
64
+ old_keys = list(value.keys())
65
+ new_keys = [
66
+ valstr(f"pinned_package_versions[{key}]")(key) for key in old_keys
67
+ ]
68
+ if len(new_keys) != len(set(new_keys)):
69
+ raise ValueError(
70
+ f"Dictionary contains multiple identical keys: {value}."
71
+ )
72
+ for old_key, new_key in zip(old_keys, new_keys):
73
+ if new_key != old_key:
74
+ value[new_key] = value.pop(old_key)
75
+ for pkg, version in value.items():
76
+ validate_cmd(pkg)
77
+ validate_cmd(version)
78
+ return value
71
79
 
72
80
  @validator("package")
73
81
  def package_validator(cls, value):
82
+ value = valstr("package")(value)
74
83
  if "/" in value or value.endswith(".whl"):
75
84
  if not value.endswith(".whl"):
76
85
  raise ValueError(
@@ -81,17 +90,27 @@ class TaskCollectPipV2(BaseModel, extra=Extra.forbid):
81
90
  raise ValueError(
82
91
  f"Local-package path must be absolute: (given {value})."
83
92
  )
93
+ validate_cmd(value, attribute_name="package")
84
94
  return value
85
95
 
86
96
  @validator("package_version")
87
- def package_version_validator(cls, v, values):
97
+ def package_version_validator(
98
+ cls, v: Optional[str], values
99
+ ) -> Optional[str]:
88
100
  v = valstr("package_version")(v)
89
101
  if values["package"].endswith(".whl"):
90
102
  raise ValueError(
91
103
  "Cannot provide package version when package is a wheel file."
92
104
  )
105
+ validate_cmd(v, attribute_name="package_version")
93
106
  return v
94
107
 
108
+ @validator("package_extras")
109
+ def package_extras_validator(cls, value: Optional[str]) -> Optional[str]:
110
+ value = valstr("package_extras")(value)
111
+ validate_cmd(value, attribute_name="package_extras")
112
+ return value
113
+
95
114
 
96
115
  class TaskCollectCustomV2(BaseModel, extra=Extra.forbid):
97
116
  """
@@ -0,0 +1,39 @@
1
+ """user settings project dir
2
+
3
+ Revision ID: 19eca0dd47a9
4
+ Revises: 8e8f227a3e36
5
+ Create Date: 2024-10-30 14:34:28.219355
6
+
7
+ """
8
+ import sqlalchemy as sa
9
+ import sqlmodel
10
+ from alembic import op
11
+
12
+
13
+ # revision identifiers, used by Alembic.
14
+ revision = "19eca0dd47a9"
15
+ down_revision = "8e8f227a3e36"
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+
20
+ def upgrade() -> None:
21
+ # ### commands auto generated by Alembic - please adjust! ###
22
+ with op.batch_alter_table("user_settings", schema=None) as batch_op:
23
+ batch_op.add_column(
24
+ sa.Column(
25
+ "project_dir",
26
+ sqlmodel.sql.sqltypes.AutoString(),
27
+ nullable=True,
28
+ )
29
+ )
30
+
31
+ # ### end Alembic commands ###
32
+
33
+
34
+ def downgrade() -> None:
35
+ # ### commands auto generated by Alembic - please adjust! ###
36
+ with op.batch_alter_table("user_settings", schema=None) as batch_op:
37
+ batch_op.drop_column("project_dir")
38
+
39
+ # ### end Alembic commands ###
@@ -54,7 +54,12 @@ def slugify_task_name_for_source_v1(task_name: str) -> str:
54
54
  return task_name.replace(" ", "_").lower()
55
55
 
56
56
 
57
- def validate_cmd(command: str, allow_char: Optional[str] = None):
57
+ def validate_cmd(
58
+ command: str,
59
+ *,
60
+ allow_char: Optional[str] = None,
61
+ attribute_name: str = "Command",
62
+ ):
58
63
  """
59
64
  Assert that the provided `command` does not contain any of the forbidden
60
65
  characters for commands
@@ -63,6 +68,7 @@ def validate_cmd(command: str, allow_char: Optional[str] = None):
63
68
  Args:
64
69
  command: command to validate.
65
70
  allow_char: chars to accept among the forbidden ones
71
+ attribute_name: Name of the attribute, to be used in error message.
66
72
  """
67
73
  if not isinstance(command, str):
68
74
  raise ValueError(f"{command=} is not a string.")
@@ -71,6 +77,7 @@ def validate_cmd(command: str, allow_char: Optional[str] = None):
71
77
  forbidden = forbidden - set(allow_char)
72
78
  if not forbidden.isdisjoint(set(command)):
73
79
  raise ValueError(
74
- f"Command must not contain any of this characters: '{forbidden}'\n"
75
- f"Provided command: '{command}'."
80
+ f"{attribute_name} must not contain any of this characters: "
81
+ f"'{forbidden}'\n"
82
+ f"Provided {attribute_name.lower()}: '{command}'."
76
83
  )
@@ -1,4 +1,3 @@
1
- import re
2
1
  from pathlib import Path
3
2
 
4
3
  from fractal_server.config import get_settings
@@ -42,38 +41,8 @@ def get_collection_log_v1(path: Path) -> str:
42
41
  return log
43
42
 
44
43
 
45
- def get_collection_log_v2(path: Path) -> str:
46
- log_path = get_log_path(path)
47
- log = log_path.open().read()
48
- return log
49
-
50
-
51
44
  def get_collection_freeze_v1(venv_path: Path) -> str:
52
45
  package_path = get_absolute_venv_path_v1(venv_path)
53
46
  freeze_path = get_freeze_path(package_path)
54
47
  freeze = freeze_path.open().read()
55
48
  return freeze
56
-
57
-
58
- def get_collection_freeze_v2(path: Path) -> str:
59
- freeze_path = get_freeze_path(path)
60
- freeze = freeze_path.open().read()
61
- return freeze
62
-
63
-
64
- def _normalize_package_name(name: str) -> str:
65
- """
66
- Implement PyPa specifications for package-name normalization
67
-
68
- The name should be lowercased with all runs of the characters `.`, `-`,
69
- or `_` replaced with a single `-` character. This can be implemented in
70
- Python with the re module.
71
- (https://packaging.python.org/en/latest/specifications/name-normalization)
72
-
73
- Args:
74
- name: The non-normalized package name.
75
-
76
- Returns:
77
- The normalized package name.
78
- """
79
- return re.sub(r"[-_.]+", "-", name).lower()