fractal-server 2.3.7__tar.gz → 2.3.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. {fractal_server-2.3.7 → fractal_server-2.3.8}/PKG-INFO +5 -5
  2. {fractal_server-2.3.7 → fractal_server-2.3.8}/README.md +2 -3
  3. fractal_server-2.3.8/fractal_server/__init__.py +1 -0
  4. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/admin/v1.py +2 -3
  5. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/admin/v2.py +2 -3
  6. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/_aux_functions.py +11 -0
  7. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/dataset.py +7 -2
  8. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/job.py +2 -3
  9. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/project.py +5 -10
  10. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/task.py +4 -2
  11. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/task_collection.py +2 -1
  12. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/workflow.py +5 -2
  13. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/workflowtask.py +4 -3
  14. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/job.py +5 -9
  15. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/aux/_job.py +0 -23
  16. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/__init__.py +32 -21
  17. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/config.py +1 -1
  18. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/gunicorn_fractal.py +1 -1
  19. fractal_server-2.3.8/fractal_server/zip_tools.py +110 -0
  20. {fractal_server-2.3.7 → fractal_server-2.3.8}/pyproject.toml +5 -4
  21. fractal_server-2.3.7/fractal_server/__init__.py +0 -1
  22. {fractal_server-2.3.7 → fractal_server-2.3.8}/LICENSE +0 -0
  23. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/__main__.py +0 -0
  24. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/alembic.ini +0 -0
  25. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/__init__.py +0 -0
  26. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/db/__init__.py +0 -0
  27. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/__init__.py +0 -0
  28. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/linkuserproject.py +0 -0
  29. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/security.py +0 -0
  30. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/__init__.py +0 -0
  31. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/dataset.py +0 -0
  32. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/job.py +0 -0
  33. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/project.py +0 -0
  34. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/state.py +0 -0
  35. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/task.py +0 -0
  36. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v1/workflow.py +0 -0
  37. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/__init__.py +0 -0
  38. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/collection_state.py +0 -0
  39. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/dataset.py +0 -0
  40. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/job.py +0 -0
  41. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/project.py +0 -0
  42. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/task.py +0 -0
  43. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/workflow.py +0 -0
  44. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/models/v2/workflowtask.py +0 -0
  45. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/__init__.py +0 -0
  46. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/admin/__init__.py +0 -0
  47. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/__init__.py +0 -0
  48. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v1/__init__.py +0 -0
  49. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  50. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  51. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  52. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/images.py +0 -0
  53. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/project.py +0 -0
  54. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/status.py +0 -0
  55. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/submit.py +0 -0
  56. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/task.py +0 -0
  57. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
  58. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  59. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/task_legacy.py +0 -0
  60. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  61. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  62. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/auth.py +0 -0
  63. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/aux/__init__.py +0 -0
  64. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/routes/aux/_runner.py +0 -0
  65. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/.gitignore +0 -0
  66. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/__init__.py +0 -0
  67. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/async_wrap.py +0 -0
  68. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/components.py +0 -0
  69. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/compress_folder.py +0 -0
  70. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/exceptions.py +0 -0
  71. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/__init__.py +0 -0
  72. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/__init__.py +0 -0
  73. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/_batching.py +0 -0
  74. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/_slurm_config.py +0 -0
  75. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/remote.py +0 -0
  76. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -0
  77. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -0
  78. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -0
  79. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/ssh/executor.py +0 -0
  80. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -0
  81. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -0
  82. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -0
  83. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/sudo/_subprocess_run_as_user.py +0 -0
  84. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -0
  85. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/extract_archive.py +0 -0
  86. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/filenames.py +0 -0
  87. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/run_subprocess.py +0 -0
  88. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  89. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/shutdown.py +0 -0
  90. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/task_files.py +0 -0
  91. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/__init__.py +0 -0
  92. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_common.py +0 -0
  93. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_local/__init__.py +0 -0
  94. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_local/_local_config.py +0 -0
  95. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_local/_submit_setup.py +0 -0
  96. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_local/executor.py +0 -0
  97. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_slurm/__init__.py +0 -0
  98. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_slurm/_submit_setup.py +0 -0
  99. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -0
  100. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/common.py +0 -0
  101. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v1/handle_failed_job.py +0 -0
  102. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local/__init__.py +0 -0
  103. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local/_local_config.py +0 -0
  104. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local/_submit_setup.py +0 -0
  105. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local/executor.py +0 -0
  106. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -0
  107. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -0
  108. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -0
  109. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_local_experimental/executor.py +0 -0
  110. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_slurm_common/__init__.py +0 -0
  111. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +0 -0
  112. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_slurm_ssh/__init__.py +0 -0
  113. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -0
  114. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_slurm_sudo/__init__.py +0 -0
  115. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -0
  116. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  117. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/handle_failed_job.py +0 -0
  118. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  119. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/runner.py +0 -0
  120. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  121. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
  122. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/task_interface.py +0 -0
  123. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/v2/v1_compat.py +0 -0
  124. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/runner/versions.py +0 -0
  125. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/__init__.py +0 -0
  126. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/_validators.py +0 -0
  127. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/user.py +0 -0
  128. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/__init__.py +0 -0
  129. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/applyworkflow.py +0 -0
  130. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/dataset.py +0 -0
  131. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/dumps.py +0 -0
  132. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/manifest.py +0 -0
  133. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/project.py +0 -0
  134. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/state.py +0 -0
  135. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/task.py +0 -0
  136. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/task_collection.py +0 -0
  137. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v1/workflow.py +0 -0
  138. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/__init__.py +0 -0
  139. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/dataset.py +0 -0
  140. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/dumps.py +0 -0
  141. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/job.py +0 -0
  142. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/manifest.py +0 -0
  143. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/project.py +0 -0
  144. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/status.py +0 -0
  145. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/task.py +0 -0
  146. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  147. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/workflow.py +0 -0
  148. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  149. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/app/security/__init__.py +0 -0
  150. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/data_migrations/README.md +0 -0
  151. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/images/__init__.py +0 -0
  152. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/images/models.py +0 -0
  153. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/images/tools.py +0 -0
  154. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/logger.py +0 -0
  155. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/main.py +0 -0
  156. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/README +0 -0
  157. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/env.py +0 -0
  158. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/script.py.mako +0 -0
  159. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  160. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  161. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  162. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  163. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  164. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  165. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  166. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  167. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  168. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  169. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  170. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  171. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  172. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  173. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  174. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  175. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/py.typed +0 -0
  176. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/ssh/__init__.py +0 -0
  177. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/ssh/_fabric.py +0 -0
  178. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/string_tools.py +0 -0
  179. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/syringe.py +0 -0
  180. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/__init__.py +0 -0
  181. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/utils.py +0 -0
  182. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v1/_TaskCollectPip.py +0 -0
  183. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v1/__init__.py +0 -0
  184. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v1/background_operations.py +0 -0
  185. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v1/endpoint_operations.py +0 -0
  186. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v1/get_collection_data.py +0 -0
  187. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v1/utils.py +0 -0
  188. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/_TaskCollectPip.py +0 -0
  189. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/__init__.py +0 -0
  190. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/_venv_pip.py +0 -0
  191. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/background_operations.py +0 -0
  192. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/background_operations_ssh.py +0 -0
  193. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/endpoint_operations.py +0 -0
  194. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/templates/_1_create_venv.sh +0 -0
  195. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/templates/_2_upgrade_pip.sh +0 -0
  196. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/templates/_3_pip_install.sh +0 -0
  197. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/templates/_4_pip_freeze.sh +0 -0
  198. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/templates/_5_pip_show.sh +0 -0
  199. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/tasks/v2/utils.py +0 -0
  200. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/urls.py +0 -0
  201. {fractal_server-2.3.7 → fractal_server-2.3.8}/fractal_server/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.3.7
3
+ Version: 2.3.8
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
@@ -23,7 +23,7 @@ Requires-Dist: bcrypt (==4.0.1)
23
23
  Requires-Dist: cloudpickle (>=3.0.0,<3.1.0)
24
24
  Requires-Dist: clusterfutures (>=0.5,<0.6)
25
25
  Requires-Dist: fabric (>=3.2.2,<4.0.0)
26
- Requires-Dist: fastapi (>=0.110.0,<0.111.0)
26
+ Requires-Dist: fastapi (>=0.112.0,<0.113.0)
27
27
  Requires-Dist: fastapi-users[oauth] (>=12.1.0,<13.0.0)
28
28
  Requires-Dist: gunicorn (>=21.2,<23.0) ; extra == "gunicorn"
29
29
  Requires-Dist: packaging (>=23.2,<24.0)
@@ -35,6 +35,7 @@ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
35
35
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
36
36
  Requires-Dist: sqlmodel (>=0.0.21,<0.0.22)
37
37
  Requires-Dist: uvicorn (>=0.29.0,<0.30.0)
38
+ Requires-Dist: uvicorn-worker (>=0.2.0,<0.3.0)
38
39
  Project-URL: Changelog, https://github.com/fractal-analytics-platform/fractal-server/blob/main/CHANGELOG.md
39
40
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
40
41
  Project-URL: Repository, https://github.com/fractal-analytics-platform/fractal-server
@@ -48,10 +49,9 @@ Description-Content-Type: text/markdown
48
49
  [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
49
50
  [![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)
50
51
 
51
- Fractal is a framework to process high content imaging data at scale and
52
- prepare it for interactive visualization.
52
+ [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.
53
53
 
54
- ![Fractal_Overview](https://fractal-analytics-platform.github.io/assets/fractal_overview.jpg)
54
+ ![Fractal_overview](https://github.com/user-attachments/assets/286122d9-08cf-48e8-996d-3cf53e0a81c6)
55
55
 
56
56
  This is the server component of the fractal analytics platform.
57
57
  Find more information about Fractal in general and the other repositories at
@@ -6,10 +6,9 @@
6
6
  [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
7
7
  [![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
8
 
9
- Fractal is a framework to process high content imaging data at scale and
10
- prepare it for interactive visualization.
9
+ [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.
11
10
 
12
- ![Fractal_Overview](https://fractal-analytics-platform.github.io/assets/fractal_overview.jpg)
11
+ ![Fractal_overview](https://github.com/user-attachments/assets/286122d9-08cf-48e8-996d-3cf53e0a81c6)
13
12
 
14
13
  This is the server component of the fractal analytics platform.
15
14
  Find more information about Fractal in general and the other repositories at
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.3.8"
@@ -18,6 +18,7 @@ from sqlmodel import select
18
18
  from ....config import get_settings
19
19
  from ....syringe import Inject
20
20
  from ....utils import get_timestamp
21
+ from ....zip_tools import _zip_folder_to_byte_stream_iterator
21
22
  from ...db import AsyncSession
22
23
  from ...db import get_async_db
23
24
  from ...models.security import UserOAuth as User
@@ -34,7 +35,6 @@ from ...schemas.v1 import ProjectReadV1
34
35
  from ...schemas.v1 import WorkflowReadV1
35
36
  from ...security import current_active_superuser
36
37
  from ..aux._job import _write_shutdown_file
37
- from ..aux._job import _zip_folder_to_byte_stream
38
38
  from ..aux._runner import _check_shutdown_is_supported
39
39
 
40
40
  router_admin_v1 = APIRouter()
@@ -387,9 +387,8 @@ async def download_job_logs(
387
387
  # Create and return byte stream for zipped log folder
388
388
  PREFIX_ZIP = Path(job.working_dir).name
389
389
  zip_filename = f"{PREFIX_ZIP}_archive.zip"
390
- byte_stream = _zip_folder_to_byte_stream(folder=job.working_dir)
391
390
  return StreamingResponse(
392
- iter([byte_stream.getvalue()]),
391
+ _zip_folder_to_byte_stream_iterator(folder=job.working_dir),
393
392
  media_type="application/x-zip-compressed",
394
393
  headers={"Content-Disposition": f"attachment;filename={zip_filename}"},
395
394
  )
@@ -21,6 +21,7 @@ from sqlmodel import select
21
21
  from ....config import get_settings
22
22
  from ....syringe import Inject
23
23
  from ....utils import get_timestamp
24
+ from ....zip_tools import _zip_folder_to_byte_stream_iterator
24
25
  from ...db import AsyncSession
25
26
  from ...db import get_async_db
26
27
  from ...models.security import UserOAuth as User
@@ -37,7 +38,6 @@ from ...schemas.v2 import JobUpdateV2
37
38
  from ...schemas.v2 import ProjectReadV2
38
39
  from ...security import current_active_superuser
39
40
  from ..aux._job import _write_shutdown_file
40
- from ..aux._job import _zip_folder_to_byte_stream
41
41
  from ..aux._runner import _check_shutdown_is_supported
42
42
 
43
43
  router_admin_v2 = APIRouter()
@@ -274,9 +274,8 @@ async def download_job_logs(
274
274
  # Create and return byte stream for zipped log folder
275
275
  PREFIX_ZIP = Path(job.working_dir).name
276
276
  zip_filename = f"{PREFIX_ZIP}_archive.zip"
277
- byte_stream = _zip_folder_to_byte_stream(folder=job.working_dir)
278
277
  return StreamingResponse(
279
- iter([byte_stream.getvalue()]),
278
+ _zip_folder_to_byte_stream_iterator(folder=job.working_dir),
280
279
  media_type="application/x-zip-compressed",
281
280
  headers={"Content-Disposition": f"attachment;filename={zip_filename}"},
282
281
  )
@@ -11,6 +11,8 @@ from fastapi import status
11
11
  from sqlmodel import select
12
12
  from sqlmodel.sql.expression import SelectOfScalar
13
13
 
14
+ from .....config import get_settings
15
+ from .....syringe import Inject
14
16
  from ....db import AsyncSession
15
17
  from ....models.v1 import ApplyWorkflow
16
18
  from ....models.v1 import Dataset
@@ -23,6 +25,15 @@ from ....schemas.v1 import JobStatusTypeV1
23
25
  from ....security import User
24
26
 
25
27
 
28
+ def _raise_if_v1_is_read_only() -> None:
29
+ settings = Inject(get_settings)
30
+ if settings.FRACTAL_API_V1_MODE == "include_read_only":
31
+ raise HTTPException(
32
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
33
+ detail="Legacy API is in read-only mode.",
34
+ )
35
+
36
+
26
37
  async def _get_project_check_owner(
27
38
  *,
28
39
  project_id: int,
@@ -33,7 +33,7 @@ from ._aux_functions import _get_dataset_check_owner
33
33
  from ._aux_functions import _get_project_check_owner
34
34
  from ._aux_functions import _get_submitted_jobs_statement
35
35
  from ._aux_functions import _get_workflow_check_owner
36
-
36
+ from ._aux_functions import _raise_if_v1_is_read_only
37
37
 
38
38
  router = APIRouter()
39
39
 
@@ -52,6 +52,7 @@ async def create_dataset(
52
52
  """
53
53
  Add new dataset to current project
54
54
  """
55
+ _raise_if_v1_is_read_only()
55
56
  await _get_project_check_owner(
56
57
  project_id=project_id, user_id=user.id, db=db
57
58
  )
@@ -133,7 +134,7 @@ async def update_dataset(
133
134
  """
134
135
  Edit a dataset associated to the current project
135
136
  """
136
-
137
+ _raise_if_v1_is_read_only()
137
138
  if dataset_update.history is not None:
138
139
  raise HTTPException(
139
140
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
@@ -170,6 +171,7 @@ async def delete_dataset(
170
171
  """
171
172
  Delete a dataset associated to the current project
172
173
  """
174
+ _raise_if_v1_is_read_only()
173
175
  output = await _get_dataset_check_owner(
174
176
  project_id=project_id,
175
177
  dataset_id=dataset_id,
@@ -243,6 +245,7 @@ async def create_resource(
243
245
  """
244
246
  Add resource to an existing dataset
245
247
  """
248
+ _raise_if_v1_is_read_only()
246
249
  output = await _get_dataset_check_owner(
247
250
  project_id=project_id,
248
251
  dataset_id=dataset_id,
@@ -299,6 +302,7 @@ async def update_resource(
299
302
  """
300
303
  Edit a resource of a dataset
301
304
  """
305
+ _raise_if_v1_is_read_only()
302
306
  output = await _get_dataset_check_owner(
303
307
  project_id=project_id,
304
308
  dataset_id=dataset_id,
@@ -339,6 +343,7 @@ async def delete_resource(
339
343
  """
340
344
  Delete a resource of a dataset
341
345
  """
346
+ _raise_if_v1_is_read_only()
342
347
  # Get the dataset DB entry
343
348
  output = await _get_dataset_check_owner(
344
349
  project_id=project_id,
@@ -8,6 +8,7 @@ from fastapi import status
8
8
  from fastapi.responses import StreamingResponse
9
9
  from sqlmodel import select
10
10
 
11
+ from .....zip_tools import _zip_folder_to_byte_stream_iterator
11
12
  from ....db import AsyncSession
12
13
  from ....db import get_async_db
13
14
  from ....models.v1 import ApplyWorkflow
@@ -18,7 +19,6 @@ from ....schemas.v1 import ApplyWorkflowReadV1
18
19
  from ....security import current_active_user
19
20
  from ....security import User
20
21
  from ...aux._job import _write_shutdown_file
21
- from ...aux._job import _zip_folder_to_byte_stream
22
22
  from ...aux._runner import _check_shutdown_is_supported
23
23
  from ._aux_functions import _get_job_check_owner
24
24
  from ._aux_functions import _get_project_check_owner
@@ -128,9 +128,8 @@ async def download_job_logs(
128
128
  # Create and return byte stream for zipped log folder
129
129
  PREFIX_ZIP = Path(job.working_dir).name
130
130
  zip_filename = f"{PREFIX_ZIP}_archive.zip"
131
- byte_stream = _zip_folder_to_byte_stream(folder=job.working_dir)
132
131
  return StreamingResponse(
133
- iter([byte_stream.getvalue()]),
132
+ _zip_folder_to_byte_stream_iterator(folder=job.working_dir),
134
133
  media_type="application/x-zip-compressed",
135
134
  headers={"Content-Disposition": f"attachment;filename={zip_filename}"},
136
135
  )
@@ -42,6 +42,7 @@ from ._aux_functions import _get_dataset_check_owner
42
42
  from ._aux_functions import _get_project_check_owner
43
43
  from ._aux_functions import _get_submitted_jobs_statement
44
44
  from ._aux_functions import _get_workflow_check_owner
45
+ from ._aux_functions import _raise_if_v1_is_read_only
45
46
  from ._aux_functions import clean_app_job_list_v1
46
47
 
47
48
  router = APIRouter()
@@ -80,7 +81,7 @@ async def create_project(
80
81
  """
81
82
  Create new poject
82
83
  """
83
-
84
+ _raise_if_v1_is_read_only()
84
85
  # Check that there is no project with the same user and name
85
86
  await _check_project_exists(
86
87
  project_name=project.name, user_id=user.id, db=db
@@ -120,6 +121,7 @@ async def update_project(
120
121
  user: User = Depends(current_active_user),
121
122
  db: AsyncSession = Depends(get_async_db),
122
123
  ):
124
+ _raise_if_v1_is_read_only()
123
125
  project = await _get_project_check_owner(
124
126
  project_id=project_id, user_id=user.id, db=db
125
127
  )
@@ -148,6 +150,7 @@ async def delete_project(
148
150
  """
149
151
  Delete project
150
152
  """
153
+ _raise_if_v1_is_read_only()
151
154
  project = await _get_project_check_owner(
152
155
  project_id=project_id, user_id=user.id, db=db
153
156
  )
@@ -249,16 +252,8 @@ async def apply_workflow(
249
252
  user: User = Depends(current_active_verified_user),
250
253
  db: AsyncSession = Depends(get_async_db),
251
254
  ) -> Optional[ApplyWorkflowReadV1]:
252
-
255
+ _raise_if_v1_is_read_only()
253
256
  settings = Inject(get_settings)
254
- if settings.FRACTAL_API_V1_MODE == "include_without_submission":
255
- raise HTTPException(
256
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
257
- detail=(
258
- "Legacy API is still accessible, "
259
- "but the submission of legacy jobs is not available."
260
- ),
261
- )
262
257
 
263
258
  # Remove non-submitted V1 jobs from the app state when the list grows
264
259
  # beyond a threshold
@@ -21,6 +21,7 @@ from ....security import current_active_user
21
21
  from ....security import current_active_verified_user
22
22
  from ....security import User
23
23
  from ._aux_functions import _get_task_check_owner
24
+ from ._aux_functions import _raise_if_v1_is_read_only
24
25
 
25
26
  router = APIRouter()
26
27
 
@@ -75,7 +76,7 @@ async def patch_task(
75
76
  """
76
77
  Edit a specific task (restricted to superusers and task owner)
77
78
  """
78
-
79
+ _raise_if_v1_is_read_only()
79
80
  if task_update.source:
80
81
  raise HTTPException(
81
82
  status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
@@ -121,6 +122,7 @@ async def create_task(
121
122
  """
122
123
  Create a new task
123
124
  """
125
+ _raise_if_v1_is_read_only()
124
126
  # Set task.owner attribute
125
127
  if user.username:
126
128
  owner = user.username
@@ -174,7 +176,7 @@ async def delete_task(
174
176
  """
175
177
  Delete a task
176
178
  """
177
-
179
+ _raise_if_v1_is_read_only()
178
180
  db_task = await _get_task_check_owner(task_id=task_id, user=user, db=db)
179
181
 
180
182
  # Check that the Task is not in relationship with some WorkflowTask
@@ -25,6 +25,7 @@ from ....schemas.v1 import TaskCollectStatusV1
25
25
  from ....security import current_active_user
26
26
  from ....security import current_active_verified_user
27
27
  from ....security import User
28
+ from ._aux_functions import _raise_if_v1_is_read_only
28
29
  from fractal_server.string_tools import slugify_task_name_for_source
29
30
  from fractal_server.tasks.utils import get_collection_log
30
31
  from fractal_server.tasks.v1._TaskCollectPip import _TaskCollectPip
@@ -71,7 +72,7 @@ async def collect_tasks_pip(
71
72
  Trigger the creation of a dedicated virtual environment, the installation
72
73
  of a package and the collection of tasks as advertised in the manifest.
73
74
  """
74
-
75
+ _raise_if_v1_is_read_only()
75
76
  logger = set_logger(logger_name="collect_tasks_pip")
76
77
 
77
78
  # Validate payload as _TaskCollectPip, which has more strict checks than
@@ -39,6 +39,7 @@ from ._aux_functions import _check_workflow_exists
39
39
  from ._aux_functions import _get_project_check_owner
40
40
  from ._aux_functions import _get_submitted_jobs_statement
41
41
  from ._aux_functions import _get_workflow_check_owner
42
+ from ._aux_functions import _raise_if_v1_is_read_only
42
43
  from ._aux_functions import _workflow_insert_task
43
44
 
44
45
 
@@ -84,6 +85,7 @@ async def create_workflow(
84
85
  """
85
86
  Create a workflow, associate to a project
86
87
  """
88
+ _raise_if_v1_is_read_only()
87
89
  await _get_project_check_owner(
88
90
  project_id=project_id,
89
91
  user_id=user.id,
@@ -136,6 +138,7 @@ async def update_workflow(
136
138
  """
137
139
  Edit a workflow
138
140
  """
141
+ _raise_if_v1_is_read_only()
139
142
  workflow = await _get_workflow_check_owner(
140
143
  project_id=project_id, workflow_id=workflow_id, user_id=user.id, db=db
141
144
  )
@@ -187,7 +190,7 @@ async def delete_workflow(
187
190
  """
188
191
  Delete a workflow
189
192
  """
190
-
193
+ _raise_if_v1_is_read_only()
191
194
  workflow = await _get_workflow_check_owner(
192
195
  project_id=project_id, workflow_id=workflow_id, user_id=user.id, db=db
193
196
  )
@@ -275,7 +278,7 @@ async def import_workflow(
275
278
  Also create all required objects (i.e. Workflow and WorkflowTask's) along
276
279
  the way.
277
280
  """
278
-
281
+ _raise_if_v1_is_read_only()
279
282
  # Preliminary checks
280
283
  await _get_project_check_owner(
281
284
  project_id=project_id,
@@ -30,6 +30,7 @@ from ....security import current_active_user
30
30
  from ....security import User
31
31
  from ._aux_functions import _get_workflow_check_owner
32
32
  from ._aux_functions import _get_workflow_task_check_owner
33
+ from ._aux_functions import _raise_if_v1_is_read_only
33
34
  from ._aux_functions import _workflow_insert_task
34
35
 
35
36
  router = APIRouter()
@@ -51,7 +52,7 @@ async def create_workflowtask(
51
52
  """
52
53
  Add a WorkflowTask to a Workflow
53
54
  """
54
-
55
+ _raise_if_v1_is_read_only()
55
56
  workflow = await _get_workflow_check_owner(
56
57
  project_id=project_id, workflow_id=workflow_id, user_id=user.id, db=db
57
58
  )
@@ -112,7 +113,7 @@ async def update_workflowtask(
112
113
  """
113
114
  Edit a WorkflowTask of a Workflow
114
115
  """
115
-
116
+ _raise_if_v1_is_read_only()
116
117
  db_workflow_task, db_workflow = await _get_workflow_task_check_owner(
117
118
  project_id=project_id,
118
119
  workflow_task_id=workflow_task_id,
@@ -167,7 +168,7 @@ async def delete_workflowtask(
167
168
  """
168
169
  Delete a WorkflowTask of a Workflow
169
170
  """
170
-
171
+ _raise_if_v1_is_read_only()
171
172
  db_workflow_task, db_workflow = await _get_workflow_task_check_owner(
172
173
  project_id=project_id,
173
174
  workflow_task_id=workflow_task_id,
@@ -8,6 +8,7 @@ from fastapi import status
8
8
  from fastapi.responses import StreamingResponse
9
9
  from sqlmodel import select
10
10
 
11
+ from .....zip_tools import _zip_folder_to_byte_stream_iterator
11
12
  from ....db import AsyncSession
12
13
  from ....db import get_async_db
13
14
  from ....models.v2 import JobV2
@@ -18,7 +19,6 @@ from ....schemas.v2 import JobStatusTypeV2
18
19
  from ....security import current_active_user
19
20
  from ....security import User
20
21
  from ...aux._job import _write_shutdown_file
21
- from ...aux._job import _zip_folder_to_byte_stream
22
22
  from ...aux._runner import _check_shutdown_is_supported
23
23
  from ._aux_functions import _get_job_check_owner
24
24
  from ._aux_functions import _get_project_check_owner
@@ -118,7 +118,7 @@ async def download_job_logs(
118
118
  db: AsyncSession = Depends(get_async_db),
119
119
  ) -> StreamingResponse:
120
120
  """
121
- Download job folder
121
+ Download zipped job folder
122
122
  """
123
123
  output = await _get_job_check_owner(
124
124
  project_id=project_id,
@@ -127,15 +127,11 @@ async def download_job_logs(
127
127
  db=db,
128
128
  )
129
129
  job = output["job"]
130
-
131
- # Create and return byte stream for zipped log folder
132
- PREFIX_ZIP = Path(job.working_dir).name
133
- zip_filename = f"{PREFIX_ZIP}_archive.zip"
134
- byte_stream = _zip_folder_to_byte_stream(folder=job.working_dir)
130
+ zip_name = f"{Path(job.working_dir).name}_archive.zip"
135
131
  return StreamingResponse(
136
- iter([byte_stream.getvalue()]),
132
+ _zip_folder_to_byte_stream_iterator(folder=job.working_dir),
137
133
  media_type="application/x-zip-compressed",
138
- headers={"Content-Disposition": f"attachment;filename={zip_filename}"},
134
+ headers={"Content-Disposition": f"attachment;filename={zip_name}"},
139
135
  )
140
136
 
141
137
 
@@ -1,9 +1,5 @@
1
- import os
2
- from io import BytesIO
3
1
  from pathlib import Path
4
2
  from typing import Union
5
- from zipfile import ZIP_DEFLATED
6
- from zipfile import ZipFile
7
3
 
8
4
  from ...models.v1 import ApplyWorkflow
9
5
  from ...models.v2 import JobV2
@@ -24,22 +20,3 @@ def _write_shutdown_file(*, job: Union[ApplyWorkflow, JobV2]):
24
20
  shutdown_file = Path(job.working_dir) / SHUTDOWN_FILENAME
25
21
  with shutdown_file.open("w") as f:
26
22
  f.write(f"Trigger executor shutdown for {job.id=}.")
27
-
28
-
29
- def _zip_folder_to_byte_stream(*, folder: str) -> BytesIO:
30
- """
31
- Get byte stream with the zipped log folder of a job.
32
-
33
- Args:
34
- folder: the folder to zip
35
- """
36
-
37
- byte_stream = BytesIO()
38
- with ZipFile(byte_stream, mode="w", compression=ZIP_DEFLATED) as zipfile:
39
- for root, dirs, files in os.walk(folder):
40
- for file in files:
41
- file_path = os.path.join(root, file)
42
- archive_path = os.path.relpath(file_path, folder)
43
- zipfile.write(file_path, archive_path)
44
-
45
- return byte_stream
@@ -5,7 +5,6 @@ This module is the single entry point to the runner backend subsystem V2.
5
5
  Other subystems should only import this module and not its submodules or
6
6
  the individual backends.
7
7
  """
8
- import logging
9
8
  import os
10
9
  import traceback
11
10
  from pathlib import Path
@@ -21,6 +20,7 @@ from ....logger import set_logger
21
20
  from ....ssh._fabric import FractalSSH
22
21
  from ....syringe import Inject
23
22
  from ....utils import get_timestamp
23
+ from ....zip_tools import _zip_folder_to_file_and_remove
24
24
  from ...db import DB
25
25
  from ...models.v2 import DatasetV2
26
26
  from ...models.v2 import JobV2
@@ -114,9 +114,34 @@ async def submit_workflow(
114
114
 
115
115
  with next(DB.get_sync_db()) as db_sync:
116
116
 
117
- job: JobV2 = db_sync.get(JobV2, job_id)
118
- if not job:
117
+ try:
118
+ job: Optional[JobV2] = db_sync.get(JobV2, job_id)
119
+ dataset: Optional[DatasetV2] = db_sync.get(DatasetV2, dataset_id)
120
+ workflow: Optional[WorkflowV2] = db_sync.get(
121
+ WorkflowV2, workflow_id
122
+ )
123
+ except Exception as e:
124
+ logger.error(
125
+ f"Error conneting to the database. Original error: {str(e)}"
126
+ )
127
+ reset_logger_handlers(logger)
128
+ return
129
+
130
+ if job is None:
119
131
  logger.error(f"JobV2 {job_id} does not exist")
132
+ reset_logger_handlers(logger)
133
+ return
134
+ if dataset is None or workflow is None:
135
+ log_msg = ""
136
+ if not dataset:
137
+ log_msg += f"Cannot fetch dataset {dataset_id} from database\n"
138
+ if not workflow:
139
+ log_msg += (
140
+ f"Cannot fetch workflow {workflow_id} from database\n"
141
+ )
142
+ fail_job(
143
+ db=db_sync, job=job, log_msg=log_msg, logger_name=logger_name
144
+ )
120
145
  return
121
146
 
122
147
  # Declare runner backend and set `process_workflow` function
@@ -137,21 +162,6 @@ async def submit_workflow(
137
162
  )
138
163
  return
139
164
 
140
- dataset: DatasetV2 = db_sync.get(DatasetV2, dataset_id)
141
- workflow: WorkflowV2 = db_sync.get(WorkflowV2, workflow_id)
142
- if not (dataset and workflow):
143
- log_msg = ""
144
- if not dataset:
145
- log_msg += f"Cannot fetch dataset {dataset_id} from database\n"
146
- if not workflow:
147
- log_msg += (
148
- f"Cannot fetch workflow {workflow_id} from database\n"
149
- )
150
- fail_job(
151
- db=db_sync, job=job, log_msg=log_msg, logger_name=logger_name
152
- )
153
- return
154
-
155
165
  # Define and create server-side working folder
156
166
  WORKFLOW_DIR_LOCAL = Path(job.working_dir)
157
167
  if WORKFLOW_DIR_LOCAL.exists():
@@ -192,9 +202,9 @@ async def submit_workflow(
192
202
  fractal_ssh.mkdir(
193
203
  folder=str(WORKFLOW_DIR_REMOTE),
194
204
  )
195
- logging.info(f"Created {str(WORKFLOW_DIR_REMOTE)} via SSH.")
205
+ logger.info(f"Created {str(WORKFLOW_DIR_REMOTE)} via SSH.")
196
206
  else:
197
- logging.error(
207
+ logger.error(
198
208
  "Invalid FRACTAL_RUNNER_BACKEND="
199
209
  f"{settings.FRACTAL_RUNNER_BACKEND}."
200
210
  )
@@ -219,7 +229,7 @@ async def submit_workflow(
219
229
  user=slurm_user,
220
230
  )
221
231
  else:
222
- logging.info("Skip remote-subfolder creation")
232
+ logger.info("Skip remote-subfolder creation")
223
233
  except Exception as e:
224
234
  error_type = type(e).__name__
225
235
  fail_job(
@@ -448,3 +458,4 @@ async def submit_workflow(
448
458
  finally:
449
459
  reset_logger_handlers(logger)
450
460
  db_sync.close()
461
+ _zip_folder_to_file_and_remove(folder=job.working_dir)
@@ -547,7 +547,7 @@ class Settings(BaseSettings):
547
547
  """
548
548
 
549
549
  FRACTAL_API_V1_MODE: Literal[
550
- "include", "include_without_submission", "exclude"
550
+ "include", "include_read_only", "exclude"
551
551
  ] = "include"
552
552
  """
553
553
  Whether to include the v1 API.
@@ -3,7 +3,7 @@ import os
3
3
  import signal
4
4
 
5
5
  from gunicorn.glogging import Logger as GunicornLogger
6
- from uvicorn.workers import UvicornWorker
6
+ from uvicorn_worker import UvicornWorker
7
7
 
8
8
  logger = logging.getLogger("uvicorn.error")
9
9