fractal-server 2.7.0a4__tar.gz → 2.7.0a5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/PKG-INFO +1 -1
  2. fractal_server-2.7.0a5/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/v2/task.py +0 -5
  4. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/task_collection.py +2 -2
  5. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/_aux_functions.py +1 -7
  6. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/task_collection.py +49 -39
  7. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/task_group.py +10 -6
  8. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/workflowtask.py +0 -1
  9. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/dumps.py +0 -1
  10. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/task.py +1 -6
  11. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/workflowtask.py +0 -3
  12. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/utils.py +19 -5
  13. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v1/background_operations.py +3 -3
  14. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v1/get_collection_data.py +2 -2
  15. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/background_operations.py +4 -4
  16. fractal_server-2.7.0a5/fractal_server/tasks/v2/endpoint_operations.py +124 -0
  17. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/pyproject.toml +2 -2
  18. fractal_server-2.7.0a4/fractal_server/__init__.py +0 -1
  19. fractal_server-2.7.0a4/fractal_server/tasks/v2/endpoint_operations.py +0 -44
  20. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/LICENSE +0 -0
  21. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/README.md +0 -0
  22. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/__main__.py +0 -0
  23. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/alembic.ini +0 -0
  24. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/__init__.py +0 -0
  25. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/db/__init__.py +0 -0
  26. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/__init__.py +0 -0
  27. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/linkusergroup.py +0 -0
  28. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/linkuserproject.py +0 -0
  29. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/security.py +0 -0
  30. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/user_settings.py +0 -0
  31. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/__init__.py +0 -0
  32. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/dataset.py +0 -0
  33. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/job.py +0 -0
  34. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/project.py +0 -0
  35. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/state.py +0 -0
  36. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/task.py +0 -0
  37. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v1/workflow.py +0 -0
  38. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/__init__.py +0 -0
  39. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/collection_state.py +0 -0
  40. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/dataset.py +0 -0
  41. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/job.py +0 -0
  42. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/project.py +0 -0
  43. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/task.py +0 -0
  44. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/workflow.py +0 -0
  45. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/models/v2/workflowtask.py +0 -0
  46. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/__init__.py +0 -0
  47. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/__init__.py +0 -0
  48. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/v1.py +0 -0
  49. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  50. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/v2/job.py +0 -0
  51. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/v2/project.py +0 -0
  52. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  53. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/__init__.py +0 -0
  54. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/__init__.py +0 -0
  55. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/_aux_functions.py +0 -0
  56. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/dataset.py +0 -0
  57. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/job.py +0 -0
  58. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/project.py +0 -0
  59. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/task.py +0 -0
  60. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/workflow.py +0 -0
  61. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v1/workflowtask.py +0 -0
  62. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  63. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  64. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  65. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/images.py +0 -0
  66. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/job.py +0 -0
  67. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/project.py +0 -0
  68. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/status.py +0 -0
  69. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/submit.py +0 -0
  70. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/task.py +0 -0
  71. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  72. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  73. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/__init__.py +0 -0
  74. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  75. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/current_user.py +0 -0
  76. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/group.py +0 -0
  77. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/login.py +0 -0
  78. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/oauth.py +0 -0
  79. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/register.py +0 -0
  80. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/router.py +0 -0
  81. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/auth/users.py +0 -0
  82. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/aux/__init__.py +0 -0
  83. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/aux/_job.py +0 -0
  84. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/aux/_runner.py +0 -0
  85. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  86. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/.gitignore +0 -0
  87. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/__init__.py +0 -0
  88. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/async_wrap.py +0 -0
  89. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/components.py +0 -0
  90. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/compress_folder.py +0 -0
  91. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/exceptions.py +0 -0
  92. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/__init__.py +0 -0
  93. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/__init__.py +0 -0
  94. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/_batching.py +0 -0
  95. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/_slurm_config.py +0 -0
  96. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/remote.py +0 -0
  97. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -0
  98. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -0
  99. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -0
  100. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/ssh/executor.py +0 -0
  101. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -0
  102. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -0
  103. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -0
  104. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/sudo/_subprocess_run_as_user.py +0 -0
  105. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -0
  106. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/extract_archive.py +0 -0
  107. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/filenames.py +0 -0
  108. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/run_subprocess.py +0 -0
  109. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  110. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/shutdown.py +0 -0
  111. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/task_files.py +0 -0
  112. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/__init__.py +0 -0
  113. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_common.py +0 -0
  114. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_local/__init__.py +0 -0
  115. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_local/_local_config.py +0 -0
  116. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_local/_submit_setup.py +0 -0
  117. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_local/executor.py +0 -0
  118. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_slurm/__init__.py +0 -0
  119. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_slurm/_submit_setup.py +0 -0
  120. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -0
  121. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/common.py +0 -0
  122. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v1/handle_failed_job.py +0 -0
  123. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/__init__.py +0 -0
  124. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local/__init__.py +0 -0
  125. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local/_local_config.py +0 -0
  126. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local/_submit_setup.py +0 -0
  127. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local/executor.py +0 -0
  128. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -0
  129. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -0
  130. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -0
  131. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_local_experimental/executor.py +0 -0
  132. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_slurm_common/__init__.py +0 -0
  133. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +0 -0
  134. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_slurm_ssh/__init__.py +0 -0
  135. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -0
  136. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_slurm_sudo/__init__.py +0 -0
  137. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -0
  138. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  139. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/handle_failed_job.py +0 -0
  140. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  141. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/runner.py +0 -0
  142. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  143. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
  144. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/v2/task_interface.py +0 -0
  145. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/runner/versions.py +0 -0
  146. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/__init__.py +0 -0
  147. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/_validators.py +0 -0
  148. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/user.py +0 -0
  149. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/user_group.py +0 -0
  150. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/user_settings.py +0 -0
  151. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/__init__.py +0 -0
  152. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/applyworkflow.py +0 -0
  153. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/dataset.py +0 -0
  154. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/dumps.py +0 -0
  155. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/manifest.py +0 -0
  156. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/project.py +0 -0
  157. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/state.py +0 -0
  158. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/task.py +0 -0
  159. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/task_collection.py +0 -0
  160. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v1/workflow.py +0 -0
  161. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/__init__.py +0 -0
  162. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/dataset.py +0 -0
  163. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/job.py +0 -0
  164. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/manifest.py +0 -0
  165. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/project.py +0 -0
  166. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/status.py +0 -0
  167. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  168. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/task_group.py +0 -0
  169. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/schemas/v2/workflow.py +0 -0
  170. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/security/__init__.py +0 -0
  171. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/app/user_settings.py +0 -0
  172. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/config.py +0 -0
  173. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/data_migrations/2_7_0.py +0 -0
  174. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/data_migrations/README.md +0 -0
  175. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/data_migrations/tools.py +0 -0
  176. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/gunicorn_fractal.py +0 -0
  177. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/images/__init__.py +0 -0
  178. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/images/models.py +0 -0
  179. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/images/tools.py +0 -0
  180. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/logger.py +0 -0
  181. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/main.py +0 -0
  182. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/README +0 -0
  183. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/env.py +0 -0
  184. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/naming_convention.py +0 -0
  185. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/script.py.mako +0 -0
  186. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  187. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  188. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  189. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  190. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  191. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  192. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  193. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  194. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  195. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  196. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  197. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  198. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  199. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  200. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  201. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  202. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  203. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  204. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  205. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  206. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  207. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  208. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/py.typed +0 -0
  209. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/ssh/__init__.py +0 -0
  210. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/ssh/_fabric.py +0 -0
  211. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/string_tools.py +0 -0
  212. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/syringe.py +0 -0
  213. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/__init__.py +0 -0
  214. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v1/_TaskCollectPip.py +0 -0
  215. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v1/__init__.py +0 -0
  216. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v1/endpoint_operations.py +0 -0
  217. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v1/utils.py +0 -0
  218. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/__init__.py +0 -0
  219. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/_venv_pip.py +0 -0
  220. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/background_operations_ssh.py +0 -0
  221. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/database_operations.py +0 -0
  222. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/templates/_1_create_venv.sh +0 -0
  223. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/templates/_2_upgrade_pip.sh +0 -0
  224. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/templates/_3_pip_install.sh +0 -0
  225. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/templates/_4_pip_freeze.sh +0 -0
  226. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/templates/_5_pip_show.sh +0 -0
  227. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/tasks/v2/utils.py +0 -0
  228. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/urls.py +0 -0
  229. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/fractal_server/utils.py +0 -0
  230. {fractal_server-2.7.0a4 → fractal_server-2.7.0a5}/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.0a4
3
+ Version: 2.7.0a5
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.7.0a5"
@@ -29,7 +29,6 @@ class TaskV2Minimal(BaseModel):
29
29
  command_non_parallel: Optional[str] = None
30
30
  command_parallel: Optional[str]
31
31
  source: Optional[str] = None
32
- owner: Optional[str] = None
33
32
  version: Optional[str] = None
34
33
 
35
34
 
@@ -60,7 +59,6 @@ async def query_tasks(
60
59
  source: Optional[str] = None,
61
60
  version: Optional[str] = None,
62
61
  name: Optional[str] = None,
63
- owner: Optional[str] = None,
64
62
  max_number_of_results: int = 25,
65
63
  user: UserOAuth = Depends(current_active_superuser),
66
64
  db: AsyncSession = Depends(get_async_db),
@@ -75,7 +73,6 @@ async def query_tasks(
75
73
  `task.source`.
76
74
  version: If not `None`, query for matching `task.version`.
77
75
  name: If not `None`, query for contained case insensitive `task.name`.
78
- owner: If not `None`, query for matching `task.owner`.
79
76
  max_number_of_results: The maximum length of the response.
80
77
  """
81
78
 
@@ -89,8 +86,6 @@ async def query_tasks(
89
86
  stm = stm.where(TaskV2.version == version)
90
87
  if name is not None:
91
88
  stm = stm.where(TaskV2.name.icontains(name))
92
- if owner is not None:
93
- stm = stm.where(TaskV2.owner == owner)
94
89
 
95
90
  res = await db.execute(stm)
96
91
  task_list = res.scalars().all()
@@ -27,7 +27,7 @@ from fractal_server.app.models import UserOAuth
27
27
  from fractal_server.app.routes.auth import current_active_user
28
28
  from fractal_server.app.routes.auth import current_active_verified_user
29
29
  from fractal_server.string_tools import slugify_task_name_for_source_v1
30
- from fractal_server.tasks.utils import get_collection_log
30
+ from fractal_server.tasks.utils import get_collection_log_v1
31
31
  from fractal_server.tasks.v1._TaskCollectPip import _TaskCollectPip
32
32
  from fractal_server.tasks.v1.background_operations import (
33
33
  background_collect_pip,
@@ -232,7 +232,7 @@ async def check_collection_status(
232
232
  # In some cases (i.e. a successful or ongoing task collection), data.log is
233
233
  # not set; if so, we collect the current logs
234
234
  if verbose and not data.log:
235
- data.log = get_collection_log(data.venv_path)
235
+ data.log = get_collection_log_v1(data.venv_path)
236
236
  state.data = data.sanitised_dict()
237
237
  close_logger(logger)
238
238
  await db.close()
@@ -332,7 +332,6 @@ async def _workflow_insert_task(
332
332
  *,
333
333
  workflow_id: int,
334
334
  task_id: int,
335
- order: Optional[int] = None,
336
335
  meta_parallel: Optional[dict[str, Any]] = None,
337
336
  meta_non_parallel: Optional[dict[str, Any]] = None,
338
337
  args_non_parallel: Optional[dict[str, Any]] = None,
@@ -347,7 +346,6 @@ async def _workflow_insert_task(
347
346
  workflow_id:
348
347
  task_id:
349
348
 
350
- order:
351
349
  meta_parallel:
352
350
  meta_non_parallel:
353
351
  args_non_parallel:
@@ -359,9 +357,6 @@ async def _workflow_insert_task(
359
357
  if db_workflow is None:
360
358
  raise ValueError(f"Workflow {workflow_id} does not exist")
361
359
 
362
- if order is None:
363
- order = len(db_workflow.task_list)
364
-
365
360
  # Get task from db
366
361
  db_task = await db.get(TaskV2, task_id)
367
362
  if db_task is None:
@@ -397,8 +392,7 @@ async def _workflow_insert_task(
397
392
  meta_non_parallel=final_meta_non_parallel,
398
393
  **input_filters_kwarg,
399
394
  )
400
- db_workflow.task_list.insert(order, wf_task)
401
- db_workflow.task_list.reorder() # type: ignore
395
+ db_workflow.task_list.append(wf_task)
402
396
  flag_modified(db_workflow, "task_list")
403
397
  await db.commit()
404
398
 
@@ -31,7 +31,7 @@ from fractal_server.app.models import UserOAuth
31
31
  from fractal_server.app.routes.auth import current_active_user
32
32
  from fractal_server.app.routes.auth import current_active_verified_user
33
33
  from fractal_server.tasks.utils import _normalize_package_name
34
- from fractal_server.tasks.utils import get_collection_log
34
+ from fractal_server.tasks.utils import get_collection_log_v2
35
35
  from fractal_server.tasks.v2.background_operations import (
36
36
  background_collect_pip,
37
37
  )
@@ -70,33 +70,40 @@ async def collect_tasks_pip(
70
70
  # Get settings
71
71
  settings = Inject(get_settings)
72
72
 
73
+ # Initialize task-group attributes
74
+ task_group_attrs = dict(user_id=user.id)
75
+
73
76
  # Set/check python version
74
77
  if task_collect.python_version is None:
75
- task_collect.python_version = (
76
- settings.FRACTAL_TASKS_PYTHON_DEFAULT_VERSION
77
- )
78
+ task_group_attrs[
79
+ "python_version"
80
+ ] = settings.FRACTAL_TASKS_PYTHON_DEFAULT_VERSION
81
+ else:
82
+ task_group_attrs["python_version"] = task_collect.python_version
78
83
  try:
79
- get_python_interpreter_v2(python_version=task_collect.python_version)
84
+ get_python_interpreter_v2(
85
+ python_version=task_group_attrs["python_version"]
86
+ )
80
87
  except ValueError:
81
88
  raise HTTPException(
82
89
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
83
90
  detail=(
84
- f"Python version {task_collect.python_version} is "
91
+ f"Python version {task_group_attrs['python_version']} is "
85
92
  "not available for Fractal task collection."
86
93
  ),
87
94
  )
88
95
 
89
- # Populate task-group attributes
90
- task_group_attrs = dict(
91
- user_id=user.id,
92
- python_version=task_collect.python_version,
93
- )
96
+ # Set pip_extras
94
97
  if task_collect.package_extras is not None:
95
98
  task_group_attrs["pip_extras"] = task_collect.package_extras
99
+
100
+ # Set pinned_package_versions
96
101
  if task_collect.pinned_package_versions is not None:
97
102
  task_group_attrs[
98
103
  "pinned_package_versions"
99
104
  ] = task_collect.pinned_package_versions
105
+
106
+ # Set pkg_name, version, origin and wheel_path
100
107
  if task_collect.package.endswith(".whl"):
101
108
  try:
102
109
  task_group_attrs["wheel_path"] = task_collect.package
@@ -119,19 +126,11 @@ async def collect_tasks_pip(
119
126
  pkg_name = task_collect.package
120
127
  task_group_attrs["pkg_name"] = _normalize_package_name(pkg_name)
121
128
  task_group_attrs["origin"] = "pypi"
122
- if task_collect.package_version is None:
123
- latest_version = await get_package_version_from_pypi(
124
- task_collect.package
125
- )
126
- task_group_attrs["version"] = latest_version
127
- task_collect.package_version = latest_version
128
- else:
129
- task_group_attrs["version"] = task_collect.package_version
130
-
131
- # Validate user settings (backend-specific)
132
- user_settings = await validate_user_settings(
133
- user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
134
- )
129
+ latest_version = await get_package_version_from_pypi(
130
+ task_collect.package,
131
+ task_collect.package_version,
132
+ )
133
+ task_group_attrs["version"] = latest_version
135
134
 
136
135
  # Validate query parameters related to user-group ownership
137
136
  user_group_id = await _get_valid_user_group_id(
@@ -140,9 +139,16 @@ async def collect_tasks_pip(
140
139
  user_id=user.id,
141
140
  db=db,
142
141
  )
142
+
143
+ # Set user_group_id
143
144
  task_group_attrs["user_group_id"] = user_group_id
144
145
 
145
- # Construct task_group.path
146
+ # Validate user settings (backend-specific)
147
+ user_settings = await validate_user_settings(
148
+ user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
149
+ )
150
+
151
+ # Set path and venv_path
146
152
  if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
147
153
  base_tasks_path = user_settings.ssh_tasks_dir
148
154
  else:
@@ -165,6 +171,8 @@ async def collect_tasks_pip(
165
171
  detail=f"Invalid task-group object. Original error: {e}",
166
172
  )
167
173
 
174
+ # Database checks
175
+
168
176
  # Verify non-duplication constraints
169
177
  await _verify_non_duplication_user_constraint(
170
178
  user_id=user.id,
@@ -191,15 +199,18 @@ async def collect_tasks_pip(
191
199
  ),
192
200
  )
193
201
 
194
- # Verify that folder does not exist (for local collection)
202
+ # On-disk checks
203
+
195
204
  if settings.FRACTAL_RUNNER_BACKEND != "slurm_ssh":
205
+
206
+ # Verify that folder does not exist (for local collection)
196
207
  if Path(task_group_path).exists():
197
208
  raise HTTPException(
198
209
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
199
210
  detail=f"{task_group_path} already exists.",
200
211
  )
201
212
 
202
- if settings.FRACTAL_RUNNER_BACKEND != "slurm_ssh":
213
+ # Verify that wheel file exists
203
214
  wheel_path = task_group_attrs.get("wheel_path", None)
204
215
  if wheel_path is not None:
205
216
  if not Path(wheel_path).exists():
@@ -216,13 +227,15 @@ async def collect_tasks_pip(
216
227
  db.expunge(task_group)
217
228
 
218
229
  # All checks are OK, proceed with task collection
219
- collection_status = dict(
230
+ collection_state_data = dict(
220
231
  status=CollectionStatusV2.PENDING,
221
- venv_path=task_group_attrs["venv_path"],
222
- package=task_collect.package,
232
+ package=task_group.pkg_name,
233
+ version=task_group.version,
234
+ path=task_group.path,
235
+ venv_path=task_group.venv_path,
223
236
  )
224
237
  state = CollectionStateV2(
225
- data=collection_status, taskgroupv2_id=task_group.id
238
+ data=collection_state_data, taskgroupv2_id=task_group.id
226
239
  )
227
240
  db.add(state)
228
241
  await db.commit()
@@ -270,7 +283,7 @@ async def collect_tasks_pip(
270
283
  reset_logger_handlers(logger)
271
284
  info = (
272
285
  "Collecting tasks in the background. "
273
- f"GET /task/collect/{state.id} to query collection status"
286
+ f"GET /task/collect/{state.id}/ to query collection status"
274
287
  )
275
288
  state.data["info"] = info
276
289
  response.status_code = status.HTTP_201_CREATED
@@ -306,20 +319,17 @@ async def check_collection_status(
306
319
  else:
307
320
  # Non-SSH mode
308
321
  # In some cases (i.e. a successful or ongoing task collection),
309
- # state.data.log is not set; if so, we collect the current logs.
322
+ # state.data["log"] is not set; if so, we collect the current logs.
310
323
  if verbose and not state.data.get("log"):
311
- if "venv_path" not in state.data.keys():
324
+ if "path" not in state.data.keys():
312
325
  await db.close()
313
326
  raise HTTPException(
314
327
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
315
328
  detail=(
316
- f"No 'venv_path' in CollectionStateV2[{state_id}].data"
329
+ f"No 'path' in CollectionStateV2[{state_id}].data"
317
330
  ),
318
331
  )
319
- state.data["log"] = get_collection_log(
320
- Path(state.data["venv_path"])
321
- )
322
- state.data["venv_path"] = str(state.data["venv_path"])
332
+ state.data["log"] = get_collection_log_v2(Path(state.data["path"]))
323
333
 
324
334
  reset_logger_handlers(logger)
325
335
  await db.close()
@@ -143,12 +143,16 @@ async def patch_task_group(
143
143
  user_id=user.id,
144
144
  db=db,
145
145
  )
146
- await _verify_non_duplication_group_constraint(
147
- db=db,
148
- pkg_name=task_group.pkg_name,
149
- version=task_group.version,
150
- user_group_id=task_group_update.user_group_id,
151
- )
146
+ if (
147
+ "user_group_id" in task_group_update.dict(exclude_unset=True)
148
+ and task_group_update.user_group_id != task_group.user_group_id
149
+ ):
150
+ await _verify_non_duplication_group_constraint(
151
+ db=db,
152
+ pkg_name=task_group.pkg_name,
153
+ version=task_group.version,
154
+ user_group_id=task_group_update.user_group_id,
155
+ )
152
156
  for key, value in task_group_update.dict(exclude_unset=True).items():
153
157
  if (key == "user_group_id") and (value is not None):
154
158
  await _verify_user_belongs_to_group(
@@ -77,7 +77,6 @@ async def create_workflowtask(
77
77
  workflow_task = await _workflow_insert_task(
78
78
  workflow_id=workflow.id,
79
79
  task_id=task_id,
80
- order=new_task.order,
81
80
  meta_non_parallel=new_task.meta_non_parallel,
82
81
  meta_parallel=new_task.meta_parallel,
83
82
  args_non_parallel=new_task.args_non_parallel,
@@ -31,7 +31,6 @@ class TaskDumpV2(BaseModel):
31
31
  command_non_parallel: Optional[str]
32
32
  command_parallel: Optional[str]
33
33
  source: Optional[str] = None
34
- owner: Optional[str]
35
34
  version: Optional[str]
36
35
 
37
36
  input_types: dict[str, bool]
@@ -21,7 +21,6 @@ class TaskCreateV2(BaseModel, extra=Extra.forbid):
21
21
 
22
22
  command_non_parallel: Optional[str] = None
23
23
  command_parallel: Optional[str] = None
24
- source: Optional[str] = None
25
24
 
26
25
  meta_non_parallel: Optional[dict[str, Any]] = None
27
26
  meta_parallel: Optional[dict[str, Any]] = None
@@ -64,7 +63,6 @@ class TaskCreateV2(BaseModel, extra=Extra.forbid):
64
63
  _command_parallel = validator("command_parallel", allow_reuse=True)(
65
64
  valstr("command_parallel")
66
65
  )
67
- _source = validator("source", allow_reuse=True)(valstr("source"))
68
66
  _version = validator("version", allow_reuse=True)(valstr("version"))
69
67
 
70
68
  _meta_non_parallel = validator("meta_non_parallel", allow_reuse=True)(
@@ -137,7 +135,6 @@ class TaskReadV2(BaseModel):
137
135
  class TaskUpdateV2(BaseModel, extra=Extra.forbid):
138
136
 
139
137
  name: Optional[str] = None
140
- version: Optional[str] = None
141
138
  command_parallel: Optional[str] = None
142
139
  command_non_parallel: Optional[str] = None
143
140
  input_types: Optional[dict[str, bool]] = None
@@ -156,9 +153,7 @@ class TaskUpdateV2(BaseModel, extra=Extra.forbid):
156
153
  return v
157
154
 
158
155
  _name = validator("name", allow_reuse=True)(valstr("name"))
159
- _version = validator("version", allow_reuse=True)(
160
- valstr("version", accept_none=True)
161
- )
156
+
162
157
  _command_parallel = validator("command_parallel", allow_reuse=True)(
163
158
  valstr("command_parallel")
164
159
  )
@@ -8,7 +8,6 @@ from pydantic import Field
8
8
  from pydantic import validator
9
9
 
10
10
  from .._validators import valdictkeys
11
- from .._validators import valint
12
11
  from .task import TaskExportV2
13
12
  from .task import TaskImportV2
14
13
  from .task import TaskReadV2
@@ -42,7 +41,6 @@ class WorkflowTaskCreateV2(BaseModel, extra=Extra.forbid):
42
41
  meta_parallel: Optional[dict[str, Any]]
43
42
  args_non_parallel: Optional[dict[str, Any]]
44
43
  args_parallel: Optional[dict[str, Any]]
45
- order: Optional[int]
46
44
  input_filters: Filters = Field(default_factory=Filters)
47
45
 
48
46
  # Validators
@@ -52,7 +50,6 @@ class WorkflowTaskCreateV2(BaseModel, extra=Extra.forbid):
52
50
  _meta_parallel = validator("meta_parallel", allow_reuse=True)(
53
51
  valdictkeys("meta_parallel")
54
52
  )
55
- _order = validator("order", allow_reuse=True)(valint("order", min_val=0))
56
53
 
57
54
  @validator("args_non_parallel")
58
55
  def validate_args_non_parallel(cls, value):
@@ -9,9 +9,11 @@ COLLECTION_LOG_FILENAME = "collection.log"
9
9
  COLLECTION_FREEZE_FILENAME = "collection_freeze.txt"
10
10
 
11
11
 
12
- def get_absolute_venv_path(venv_path: Path) -> Path:
12
+ def get_absolute_venv_path_v1(venv_path: Path) -> Path:
13
13
  """
14
14
  If a path is not absolute, make it a relative path of FRACTAL_TASKS_DIR.
15
+
16
+ As of v2.7.0, we rename this to v1 since it is only to be used in v1.
15
17
  """
16
18
  if venv_path.is_absolute():
17
19
  package_path = venv_path
@@ -33,20 +35,32 @@ def get_freeze_path(base: Path) -> Path:
33
35
  return base / COLLECTION_FREEZE_FILENAME
34
36
 
35
37
 
36
- def get_collection_log(venv_path: Path) -> str:
37
- package_path = get_absolute_venv_path(venv_path)
38
+ def get_collection_log_v1(path: Path) -> str:
39
+ package_path = get_absolute_venv_path_v1(path)
38
40
  log_path = get_log_path(package_path)
39
41
  log = log_path.open().read()
40
42
  return log
41
43
 
42
44
 
43
- def get_collection_freeze(venv_path: Path) -> str:
44
- package_path = get_absolute_venv_path(venv_path)
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
+ def get_collection_freeze_v1(venv_path: Path) -> str:
52
+ package_path = get_absolute_venv_path_v1(venv_path)
45
53
  freeze_path = get_freeze_path(package_path)
46
54
  freeze = freeze_path.open().read()
47
55
  return freeze
48
56
 
49
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
+
50
64
  def _normalize_package_name(name: str) -> str:
51
65
  """
52
66
  Implement PyPa specifications for package-name normalization
@@ -8,7 +8,7 @@ from shutil import rmtree as shell_rmtree
8
8
 
9
9
  from ...string_tools import slugify_task_name_for_source_v1
10
10
  from ..utils import _normalize_package_name
11
- from ..utils import get_collection_log
11
+ from ..utils import get_collection_log_v1
12
12
  from ..utils import get_collection_path
13
13
  from ..utils import get_log_path
14
14
  from ._TaskCollectPip import _TaskCollectPip
@@ -321,7 +321,7 @@ async def background_collect_pip(
321
321
 
322
322
  # Update DB
323
323
  data.status = "OK"
324
- data.log = get_collection_log(venv_path)
324
+ data.log = get_collection_log_v1(venv_path)
325
325
  state.data = data.sanitised_dict()
326
326
  db.add(state)
327
327
  db.merge(state)
@@ -342,7 +342,7 @@ async def background_collect_pip(
342
342
  # Update db
343
343
  data.status = "fail"
344
344
  data.info = f"Original error: {e}"
345
- data.log = get_collection_log(venv_path)
345
+ data.log = get_collection_log_v1(venv_path)
346
346
  state.data = data.sanitised_dict()
347
347
  db.merge(state)
348
348
  db.commit()
@@ -2,12 +2,12 @@ import json
2
2
  from pathlib import Path
3
3
 
4
4
  from fractal_server.app.schemas.v1 import TaskCollectStatusV1
5
- from fractal_server.tasks.utils import get_absolute_venv_path
5
+ from fractal_server.tasks.utils import get_absolute_venv_path_v1
6
6
  from fractal_server.tasks.utils import get_collection_path
7
7
 
8
8
 
9
9
  def get_collection_data(venv_path: Path) -> TaskCollectStatusV1:
10
- package_path = get_absolute_venv_path(venv_path)
10
+ package_path = get_absolute_venv_path_v1(venv_path)
11
11
  collection_path = get_collection_path(package_path)
12
12
  with collection_path.open() as f:
13
13
  data = json.load(f)
@@ -14,8 +14,8 @@ from sqlalchemy.orm import Session as DBSyncSession
14
14
  from sqlalchemy.orm.attributes import flag_modified
15
15
  from sqlmodel import select
16
16
 
17
- from ..utils import get_collection_freeze
18
- from ..utils import get_collection_log
17
+ from ..utils import get_collection_freeze_v2
18
+ from ..utils import get_collection_log_v2
19
19
  from ..utils import get_collection_path
20
20
  from ..utils import get_log_path
21
21
  from .database_operations import create_db_tasks_and_update_task_group
@@ -419,10 +419,10 @@ async def background_collect_pip(
419
419
  for task in task_group.task_list
420
420
  ]
421
421
  collection_state.data["task_list"] = task_read_list
422
- collection_state.data["log"] = get_collection_log(
422
+ collection_state.data["log"] = get_collection_log_v2(
423
423
  Path(task_group.path)
424
424
  )
425
- collection_state.data["freeze"] = get_collection_freeze(
425
+ collection_state.data["freeze"] = get_collection_freeze_v2(
426
426
  Path(task_group.path)
427
427
  )
428
428
  with collection_path.open("w") as f:
@@ -0,0 +1,124 @@
1
+ from typing import Optional
2
+
3
+ from fastapi import HTTPException
4
+ from fastapi import status
5
+ from httpx import AsyncClient
6
+ from httpx import TimeoutException
7
+
8
+ from fractal_server.logger import set_logger
9
+
10
+
11
+ logger = set_logger(__name__)
12
+
13
+
14
+ async def get_package_version_from_pypi(
15
+ name: str,
16
+ version: Optional[str] = None,
17
+ ) -> str:
18
+ """
19
+ Make a GET call to PyPI JSON API and get latest *compatible* version.
20
+
21
+ There are three cases:
22
+
23
+ 1. `version` is set and it is found on PyPI as-is.
24
+ 2. `version` is set but it is not found on PyPI as-is.
25
+ 3. `version` is unset, and we query `PyPI` for latest.
26
+
27
+ Ref https://warehouse.pypa.io/api-reference/json.html.
28
+
29
+ Arguments:
30
+ name: Package name.
31
+ version:
32
+ Could be a correct version (`1.3.0`), an incomplete one
33
+ (`1.3`) or `None`.
34
+ """
35
+
36
+ url = f"https://pypi.org/pypi/{name}/json"
37
+ hint = f"Hint: specify the required version for '{name}'."
38
+
39
+ # Make request to PyPI
40
+ try:
41
+ async with AsyncClient(timeout=5.0) as client:
42
+ res = await client.get(url)
43
+ except TimeoutException as e:
44
+ error_msg = (
45
+ f"A TimeoutException occurred while getting {url}.\n"
46
+ f"Original error: {str(e)}."
47
+ )
48
+ logger.error(error_msg)
49
+ raise HTTPException(
50
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
51
+ detail=error_msg,
52
+ )
53
+ except BaseException as e:
54
+ error_msg = (
55
+ f"An unknown error occurred while getting {url}. "
56
+ f"Original error: {str(e)}."
57
+ )
58
+ logger.error(error_msg)
59
+ raise HTTPException(
60
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
61
+ detail=error_msg,
62
+ )
63
+
64
+ # Parse response
65
+ if res.status_code != 200:
66
+ raise HTTPException(
67
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
68
+ detail=(
69
+ f"Could not get {url} (status_code {res.status_code})."
70
+ f"\n{hint}"
71
+ ),
72
+ )
73
+ try:
74
+ response_data = res.json()
75
+ latest_version = response_data["info"]["version"]
76
+ available_releases = response_data["releases"].keys()
77
+ except KeyError as e:
78
+ logger.error(
79
+ f"A KeyError occurred while getting {url}. "
80
+ f"Original error: {str(e)}."
81
+ )
82
+ raise HTTPException(
83
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
84
+ detail=f"A KeyError error occurred while getting {url}.\n{hint}",
85
+ )
86
+
87
+ logger.info(
88
+ f"Obtained data from {url}: "
89
+ f"{len(available_releases)} releases, "
90
+ f"latest={latest_version}."
91
+ )
92
+
93
+ if version is not None:
94
+ if version in available_releases:
95
+ logger.info(f"Requested {version=} available on PyPI.")
96
+ # Case 1: `version` is set and it is found on PyPI as-is
97
+ return version
98
+ else:
99
+ # Case 2: `version` is set but it is not found on PyPI as-is
100
+ # Filter using `version` as prefix, and sort
101
+ matching_versions = [
102
+ v for v in available_releases if v.startswith(version)
103
+ ]
104
+ logger.info(
105
+ f"Requested {version=} not available on PyPI, "
106
+ f"found {len(matching_versions)} versions matching "
107
+ f"`{version}*`."
108
+ )
109
+ if len(matching_versions) == 0:
110
+ logger.info(f"No version starting with {version} found.")
111
+ raise HTTPException(
112
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
113
+ detail=(
114
+ f"No version starting with {version} found.\n"
115
+ f"{hint}"
116
+ ),
117
+ )
118
+ else:
119
+ latest_matching_version = sorted(matching_versions)[-1]
120
+ return latest_matching_version
121
+ else:
122
+ # Case 3: `version` is unset and we use latest
123
+ logger.info(f"No version requested, returning {latest_version=}.")
124
+ return latest_version
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "fractal-server"
3
- version = "2.7.0a4"
3
+ version = "2.7.0a5"
4
4
  description = "Server component of the Fractal analytics platform"
5
5
  authors = [
6
6
  "Tommaso Comparin <tommaso.comparin@exact-lab.it>",
@@ -92,7 +92,7 @@ filterwarnings = [
92
92
  ]
93
93
 
94
94
  [tool.bumpver]
95
- current_version = "2.7.0a4"
95
+ current_version = "2.7.0a5"
96
96
  version_pattern = "MAJOR.MINOR.PATCH[PYTAGNUM]"
97
97
  commit_message = "bump version {old_version} -> {new_version}"
98
98
  commit = true
@@ -1 +0,0 @@
1
- __VERSION__ = "2.7.0a4"