fractal-server 2.16.3__tar.gz → 2.16.4a0__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 (243) hide show
  1. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/PKG-INFO +5 -5
  2. fractal_server-2.16.4a0/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/job.py +3 -3
  4. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/task.py +1 -1
  5. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/task_group.py +1 -1
  6. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +3 -3
  7. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/_aux_functions.py +7 -7
  8. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/_aux_functions_history.py +2 -2
  9. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +37 -13
  10. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +8 -8
  11. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/dataset.py +4 -4
  12. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/history.py +2 -2
  13. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/images.py +3 -3
  14. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/job.py +1 -1
  15. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/project.py +1 -1
  16. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/status_legacy.py +1 -1
  17. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/submit.py +9 -9
  18. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task.py +4 -4
  19. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task_collection.py +5 -5
  20. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task_collection_custom.py +6 -6
  21. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task_collection_pixi.py +5 -5
  22. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +3 -3
  23. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task_version_update.py +3 -3
  24. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/workflow.py +4 -4
  25. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/workflow_import.py +1 -1
  26. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/workflowtask.py +6 -6
  27. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/group.py +2 -2
  28. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/users.py +1 -1
  29. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/aux/_job.py +1 -1
  30. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/aux/_runner.py +2 -2
  31. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/aux/validate_user_settings.py +2 -2
  32. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/config.py +2 -2
  33. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/main.py +1 -1
  34. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/base_runner.py +1 -1
  35. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/call_command_wrapper.py +1 -1
  36. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/local/runner.py +9 -9
  37. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/_slurm_config.py +1 -1
  38. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/base_slurm_runner.py +13 -13
  39. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/slurm_job_task_models.py +1 -1
  40. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_sudo/runner.py +1 -1
  41. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/task_files.py +1 -1
  42. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/_local.py +2 -2
  43. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/_slurm_ssh.py +3 -3
  44. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/_slurm_sudo.py +2 -2
  45. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/deduplicate_list.py +2 -2
  46. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/merge_outputs.py +2 -2
  47. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/runner.py +3 -3
  48. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/runner_functions.py +12 -12
  49. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/submit_workflow.py +13 -13
  50. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/task_interface.py +2 -2
  51. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/ssh/_fabric.py +61 -18
  52. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/pyproject.toml +6 -6
  53. fractal_server-2.16.3/fractal_server/__init__.py +0 -1
  54. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/LICENSE +0 -0
  55. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/README.md +0 -0
  56. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/__main__.py +0 -0
  57. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/alembic.ini +0 -0
  58. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/__init__.py +0 -0
  59. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/db/__init__.py +0 -0
  60. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/__init__.py +0 -0
  61. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/linkusergroup.py +0 -0
  62. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/linkuserproject.py +0 -0
  63. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/security.py +0 -0
  64. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/user_settings.py +0 -0
  65. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/__init__.py +0 -0
  66. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/accounting.py +0 -0
  67. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/dataset.py +0 -0
  68. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/history.py +0 -0
  69. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/job.py +0 -0
  70. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/project.py +0 -0
  71. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/task.py +0 -0
  72. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/task_group.py +0 -0
  73. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/workflow.py +0 -0
  74. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/models/v2/workflowtask.py +0 -0
  75. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/__init__.py +0 -0
  76. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/__init__.py +0 -0
  77. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  78. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  79. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  80. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/admin/v2/project.py +0 -0
  81. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/__init__.py +0 -0
  82. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  83. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
  84. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
  85. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  86. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  87. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/__init__.py +0 -0
  88. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  89. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/current_user.py +0 -0
  90. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/login.py +0 -0
  91. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/oauth.py +0 -0
  92. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/register.py +0 -0
  93. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/auth/router.py +0 -0
  94. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/aux/__init__.py +0 -0
  95. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/routes/pagination.py +0 -0
  96. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/__init__.py +0 -0
  97. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/user.py +0 -0
  98. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/user_group.py +0 -0
  99. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/user_settings.py +0 -0
  100. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/__init__.py +0 -0
  101. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/accounting.py +0 -0
  102. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/dataset.py +0 -0
  103. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/dumps.py +0 -0
  104. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/history.py +0 -0
  105. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/job.py +0 -0
  106. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/manifest.py +0 -0
  107. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/project.py +0 -0
  108. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  109. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/task.py +0 -0
  110. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  111. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/task_group.py +0 -0
  112. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/workflow.py +0 -0
  113. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  114. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/security/__init__.py +0 -0
  115. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/security/signup_email.py +0 -0
  116. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/app/user_settings.py +0 -0
  117. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/data_migrations/2_14_10.py +0 -0
  118. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/data_migrations/README.md +0 -0
  119. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/data_migrations/tools.py +0 -0
  120. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/exceptions.py +0 -0
  121. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/gunicorn_fractal.py +0 -0
  122. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/images/__init__.py +0 -0
  123. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/images/models.py +0 -0
  124. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/images/status_tools.py +0 -0
  125. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/images/tools.py +0 -0
  126. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/logger.py +0 -0
  127. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/env.py +0 -0
  128. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/naming_convention.py +0 -0
  129. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  130. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  131. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
  132. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  133. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
  134. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  135. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  136. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  137. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  138. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  139. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  140. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  141. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  142. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  143. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  144. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
  145. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  146. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  147. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  148. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  149. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
  150. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  151. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
  152. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  153. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  154. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  155. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  156. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  157. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  158. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  159. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
  160. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
  161. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  162. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  163. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  164. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  165. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  166. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  167. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  168. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  169. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  170. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  171. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  172. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/py.typed +0 -0
  173. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/__init__.py +0 -0
  174. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/components.py +0 -0
  175. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/exceptions.py +0 -0
  176. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/__init__.py +0 -0
  177. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/local/__init__.py +0 -0
  178. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/local/get_local_config.py +0 -0
  179. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/__init__.py +0 -0
  180. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/_batching.py +0 -0
  181. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/_job_states.py +0 -0
  182. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/get_slurm_config.py +0 -0
  183. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_common/remote.py +0 -0
  184. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_ssh/__init__.py +0 -0
  185. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  186. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_ssh/runner.py +0 -0
  187. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_ssh/tar_commands.py +0 -0
  188. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_sudo/__init__.py +0 -0
  189. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  190. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/filenames.py +0 -0
  191. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/set_start_and_last_task_index.py +0 -0
  192. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/shutdown.py +0 -0
  193. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/__init__.py +0 -0
  194. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/v2/db_tools.py +0 -0
  195. {fractal_server-2.16.3/fractal_server/app → fractal_server-2.16.4a0/fractal_server}/runner/versions.py +0 -0
  196. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/ssh/__init__.py +0 -0
  197. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/string_tools.py +0 -0
  198. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/syringe.py +0 -0
  199. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/__init__.py +0 -0
  200. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/utils.py +0 -0
  201. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/__init__.py +0 -0
  202. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/__init__.py +0 -0
  203. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/_utils.py +0 -0
  204. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/collect.py +0 -0
  205. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
  206. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  207. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
  208. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/delete.py +0 -0
  209. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  210. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
  211. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  212. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +0 -0
  213. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  214. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  215. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
  216. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  217. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
  218. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/delete.py +0 -0
  219. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  220. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
  221. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  222. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  223. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  224. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  225. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  226. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  227. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
  228. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
  229. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
  230. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/utils_background.py +0 -0
  231. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/utils_database.py +0 -0
  232. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  233. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/utils_pixi.py +0 -0
  234. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  235. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/tasks/v2/utils_templates.py +0 -0
  236. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/types/__init__.py +0 -0
  237. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/types/validators/__init__.py +0 -0
  238. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/types/validators/_common_validators.py +0 -0
  239. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/types/validators/_filter_validators.py +0 -0
  240. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  241. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/urls.py +0 -0
  242. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/utils.py +0 -0
  243. {fractal_server-2.16.3 → fractal_server-2.16.4a0}/fractal_server/zip_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fractal-server
3
- Version: 2.16.3
3
+ Version: 2.16.4a0
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License: BSD-3-Clause
6
6
  Author: Tommaso Comparin
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Dist: alembic (>=1.13.1,<2.0.0)
15
15
  Requires-Dist: cryptography (>=46.0.0,<47.0.0)
16
16
  Requires-Dist: fabric (>=3.2.2,<3.3.0)
17
- Requires-Dist: fastapi (>=0.116.0,<0.117.0)
17
+ Requires-Dist: fastapi (>=0.117.0,<0.118.0)
18
18
  Requires-Dist: fastapi-users[oauth] (>=14,<15)
19
19
  Requires-Dist: gunicorn (>=23.0,<24.0)
20
20
  Requires-Dist: packaging (>=25.0.0,<26.0.0)
@@ -23,10 +23,10 @@ Requires-Dist: pydantic (>=2.11.0,<2.12.0)
23
23
  Requires-Dist: pydantic-settings (>=2.7.0)
24
24
  Requires-Dist: python-dotenv (>=1.1.0,<1.2.0)
25
25
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
26
- Requires-Dist: sqlmodel (==0.0.24)
26
+ Requires-Dist: sqlmodel (==0.0.25)
27
27
  Requires-Dist: tomli_w (>=1.2.0,<1.3.0)
28
- Requires-Dist: uvicorn (>=0.29.0,<0.35.0)
29
- Requires-Dist: uvicorn-worker (==0.3.0)
28
+ Requires-Dist: uvicorn (>=0.29.0,<=0.36.0)
29
+ Requires-Dist: uvicorn-worker (==0.4.0)
30
30
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
31
31
  Project-URL: Homepage, https://github.com/fractal-analytics-platform/fractal-server
32
32
  Project-URL: Repository, https://github.com/fractal-analytics-platform/fractal-server
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.16.4a0"
@@ -19,11 +19,11 @@ from fractal_server.app.models.v2 import ProjectV2
19
19
  from fractal_server.app.routes.auth import current_active_superuser
20
20
  from fractal_server.app.routes.aux._job import _write_shutdown_file
21
21
  from fractal_server.app.routes.aux._runner import _check_shutdown_is_supported
22
- from fractal_server.app.runner.filenames import WORKFLOW_LOG_FILENAME
23
22
  from fractal_server.app.schemas.v2 import HistoryUnitStatus
24
23
  from fractal_server.app.schemas.v2 import JobReadV2
25
24
  from fractal_server.app.schemas.v2 import JobStatusTypeV2
26
25
  from fractal_server.app.schemas.v2 import JobUpdateV2
26
+ from fractal_server.runner.filenames import WORKFLOW_LOG_FILENAME
27
27
  from fractal_server.utils import get_timestamp
28
28
  from fractal_server.zip_tools import _zip_folder_to_byte_stream_iterator
29
29
 
@@ -153,13 +153,13 @@ async def update_job(
153
153
  )
154
154
  if job.status != JobStatusTypeV2.SUBMITTED:
155
155
  raise HTTPException(
156
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
156
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
157
157
  detail=f"Job {job_id} has status {job.status=} != 'submitted'.",
158
158
  )
159
159
 
160
160
  if job_update.status != JobStatusTypeV2.FAILED:
161
161
  raise HTTPException(
162
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
162
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
163
163
  detail=f"Cannot set job status to {job_update.status}",
164
164
  )
165
165
 
@@ -99,7 +99,7 @@ async def query_tasks(
99
99
  if len(task_list) > max_number_of_results:
100
100
  await db.close()
101
101
  raise HTTPException(
102
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
102
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
103
103
  detail=(
104
104
  f"Too many Tasks ({len(task_list)} > {max_number_of_results})."
105
105
  " Please add more query filters."
@@ -96,7 +96,7 @@ async def query_task_group_list(
96
96
 
97
97
  if user_group_id is not None and private is True:
98
98
  raise HTTPException(
99
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
99
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
100
100
  detail=(
101
101
  "Cannot get task groups with both "
102
102
  f"{user_group_id=} and {private=}."
@@ -67,7 +67,7 @@ async def deactivate_task_group(
67
67
  # Check that task-group is active
68
68
  if not task_group.active:
69
69
  raise HTTPException(
70
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
70
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
71
71
  detail=(
72
72
  f"Cannot deactivate a task group with {task_group.active=}."
73
73
  ),
@@ -173,7 +173,7 @@ async def reactivate_task_group(
173
173
  # Check that task-group is not active
174
174
  if task_group.active:
175
175
  raise HTTPException(
176
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
176
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
177
177
  detail=(
178
178
  f"Cannot reactivate a task group with {task_group.active=}."
179
179
  ),
@@ -210,7 +210,7 @@ async def reactivate_task_group(
210
210
 
211
211
  if task_group.env_info is None:
212
212
  raise HTTPException(
213
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
213
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
214
214
  detail=(
215
215
  "Cannot reactivate a task group with "
216
216
  f"{task_group.env_info=}."
@@ -105,7 +105,7 @@ async def _get_workflow_check_owner(
105
105
  )
106
106
  if workflow.project_id != project.id:
107
107
  raise HTTPException(
108
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
108
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
109
109
  detail=(f"Invalid {project_id=} for {workflow_id=}."),
110
110
  )
111
111
 
@@ -159,7 +159,7 @@ async def _get_workflow_task_check_owner(
159
159
  # If WorkflowTask is not part of the expected Workflow, exit
160
160
  if workflow_id != workflow_task.workflow_id:
161
161
  raise HTTPException(
162
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
162
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
163
163
  detail=f"Invalid {workflow_id=} for {workflow_task_id=}",
164
164
  )
165
165
 
@@ -192,7 +192,7 @@ async def _check_workflow_exists(
192
192
  res = await db.execute(stm)
193
193
  if res.scalars().all():
194
194
  raise HTTPException(
195
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
195
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
196
196
  detail=f"Workflow with {name=} and {project_id=} already exists.",
197
197
  )
198
198
 
@@ -224,7 +224,7 @@ async def _check_project_exists(
224
224
  res = await db.execute(stm)
225
225
  if res.scalars().all():
226
226
  raise HTTPException(
227
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
227
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
228
228
  detail=f"Project name ({project_name}) already in use",
229
229
  )
230
230
 
@@ -268,7 +268,7 @@ async def _get_dataset_check_owner(
268
268
  )
269
269
  if dataset.project_id != project_id:
270
270
  raise HTTPException(
271
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
271
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
272
272
  detail=f"Invalid {project_id=} for {dataset_id=}",
273
273
  )
274
274
 
@@ -313,7 +313,7 @@ async def _get_job_check_owner(
313
313
  )
314
314
  if job.project_id != project_id:
315
315
  raise HTTPException(
316
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
316
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
317
317
  detail=f"Invalid {project_id=} for {job_id=}",
318
318
  )
319
319
  return dict(job=job, project=project)
@@ -535,6 +535,6 @@ async def _get_submitted_job_or_none(
535
535
  )
536
536
  logger.error(f"{error_msg} Original error: {str(e)}.")
537
537
  raise HTTPException(
538
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
538
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
539
539
  detail=error_msg,
540
540
  )
@@ -119,7 +119,7 @@ async def _verify_workflow_and_dataset_access(
119
119
  )
120
120
  if workflow.project_id != project_id:
121
121
  raise HTTPException(
122
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
122
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
123
123
  detail="Workflow does not belong to expected project.",
124
124
  )
125
125
  dataset = await _get_dataset_or_404(
@@ -128,7 +128,7 @@ async def _verify_workflow_and_dataset_access(
128
128
  )
129
129
  if dataset.project_id != project_id:
130
130
  raise HTTPException(
131
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
131
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
132
132
  detail="Dataset does not belong to expected project.",
133
133
  )
134
134
 
@@ -2,6 +2,8 @@ from fastapi import HTTPException
2
2
  from fastapi import status
3
3
  from httpx import AsyncClient
4
4
  from httpx import TimeoutException
5
+ from packaging.version import InvalidVersion
6
+ from packaging.version import Version
5
7
  from sqlmodel import func
6
8
  from sqlmodel import select
7
9
 
@@ -15,11 +17,33 @@ from fractal_server.app.models.v2 import WorkflowV2
15
17
  from fractal_server.app.schemas.v2 import JobStatusTypeV2
16
18
  from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
17
19
  from fractal_server.logger import set_logger
20
+ from fractal_server.tasks.v2.utils_package_names import normalize_package_name
21
+
22
+ # See https://packaging.python.org/en/latest/specifications/simple-repository-api/#content-types # noqa
23
+ PYPI_JSON_HEADERS = {"Accept": "application/vnd.pypi.simple.v1+json"}
18
24
 
19
25
 
20
26
  logger = set_logger(__name__)
21
27
 
22
28
 
29
+ def _find_latest_version_or_422(versions: list[str]) -> str:
30
+ """
31
+ > For PEP 440 versions, this is easy enough for the client to do (using
32
+ > the `packaging` library [...]. For non-standard versions, there is no
33
+ > well-defined ordering, and clients will need to decide on what rule is
34
+ > appropriate for their needs.
35
+ (https://peps.python.org/pep-0700/#why-not-provide-a-latest-version-value)
36
+ """
37
+ try:
38
+ latest = max(versions, key=lambda v_str: Version(v_str))
39
+ return latest
40
+ except InvalidVersion as e:
41
+ raise HTTPException(
42
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
43
+ detail=f"Cannot find latest version (original error: {str(e)}).",
44
+ )
45
+
46
+
23
47
  async def get_package_version_from_pypi(
24
48
  name: str,
25
49
  version: str | None = None,
@@ -41,14 +65,14 @@ async def get_package_version_from_pypi(
41
65
  Could be a correct version (`1.3.0`), an incomplete one
42
66
  (`1.3`) or `None`.
43
67
  """
44
-
45
- url = f"https://pypi.org/pypi/{name}/json"
68
+ normalized_name = normalize_package_name(name)
69
+ url = f"https://pypi.org/simple/{normalized_name}/"
46
70
  hint = f"Hint: specify the required version for '{name}'."
47
71
 
48
72
  # Make request to PyPI
49
73
  try:
50
74
  async with AsyncClient(timeout=5.0) as client:
51
- res = await client.get(url)
75
+ res = await client.get(url, headers=PYPI_JSON_HEADERS)
52
76
  except TimeoutException as e:
53
77
  error_msg = (
54
78
  f"A TimeoutException occurred while getting {url}.\n"
@@ -56,7 +80,7 @@ async def get_package_version_from_pypi(
56
80
  )
57
81
  logger.warning(error_msg)
58
82
  raise HTTPException(
59
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
83
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
60
84
  detail=error_msg,
61
85
  )
62
86
  except BaseException as e:
@@ -66,14 +90,14 @@ async def get_package_version_from_pypi(
66
90
  )
67
91
  logger.warning(error_msg)
68
92
  raise HTTPException(
69
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
93
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
70
94
  detail=error_msg,
71
95
  )
72
96
 
73
97
  # Parse response
74
98
  if res.status_code != 200:
75
99
  raise HTTPException(
76
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
100
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
77
101
  detail=(
78
102
  f"Could not get {url} (status_code {res.status_code})."
79
103
  f"\n{hint}"
@@ -81,15 +105,15 @@ async def get_package_version_from_pypi(
81
105
  )
82
106
  try:
83
107
  response_data = res.json()
84
- latest_version = response_data["info"]["version"]
85
- available_releases = response_data["releases"].keys()
108
+ available_releases = response_data["versions"]
109
+ latest_version = _find_latest_version_or_422(available_releases)
86
110
  except KeyError as e:
87
111
  logger.warning(
88
112
  f"A KeyError occurred while getting {url}. "
89
113
  f"Original error: {str(e)}."
90
114
  )
91
115
  raise HTTPException(
92
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
116
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
93
117
  detail=f"A KeyError error occurred while getting {url}.\n{hint}",
94
118
  )
95
119
 
@@ -118,7 +142,7 @@ async def get_package_version_from_pypi(
118
142
  if len(matching_versions) == 0:
119
143
  logger.info(f"No version starting with {version} found.")
120
144
  raise HTTPException(
121
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
145
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
122
146
  detail=(
123
147
  f"No version starting with {version} found.\n"
124
148
  f"{hint}"
@@ -167,7 +191,7 @@ async def check_no_ongoing_activity(
167
191
  f"timestamp_started={activity.timestamp_started}."
168
192
  )
169
193
  raise HTTPException(
170
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
194
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
171
195
  detail=msg,
172
196
  )
173
197
 
@@ -198,7 +222,7 @@ async def check_no_submitted_job(
198
222
  num_submitted_jobs = res.scalar()
199
223
  if num_submitted_jobs > 0:
200
224
  raise HTTPException(
201
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
225
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
202
226
  detail=(
203
227
  f"Cannot act on task group because {num_submitted_jobs} "
204
228
  "submitted jobs use its tasks."
@@ -222,6 +246,6 @@ async def check_no_related_workflowtask(
222
246
  bad_wftask = res.scalars().first()
223
247
  if bad_wftask is not None:
224
248
  raise HTTPException(
225
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
249
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
226
250
  detail=f"TaskV2 {bad_wftask.task_id} is still in use",
227
251
  )
@@ -182,7 +182,7 @@ async def _get_task_read_access(
182
182
  if require_active:
183
183
  if not task_group.active:
184
184
  raise HTTPException(
185
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
185
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
186
186
  detail=f"Error: task {task_id} ({task.name}) is not active.",
187
187
  )
188
188
  return task
@@ -206,7 +206,7 @@ async def _get_valid_user_group_id(
206
206
  """
207
207
  if (user_group_id is not None) and (private is True):
208
208
  raise HTTPException(
209
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
209
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
210
210
  detail=f"Cannot set both {user_group_id=} and {private=}",
211
211
  )
212
212
  elif private is True:
@@ -278,7 +278,7 @@ async def _verify_non_duplication_user_constraint(
278
278
  )
279
279
  logger.error(f"UnreachableBranchError: {error_msg}")
280
280
  raise HTTPException(
281
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
281
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
282
282
  detail=(
283
283
  f"Invalid state: {error_msg}\n"
284
284
  "This should have not happened: please contact an admin."
@@ -288,7 +288,7 @@ async def _verify_non_duplication_user_constraint(
288
288
  duplicate[0].id, db
289
289
  )
290
290
  raise HTTPException(
291
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
291
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
292
292
  detail=(
293
293
  f"User '{user.email}' already owns a task group "
294
294
  f"with name='{pkg_name}' and {version=}.{state_msg}"
@@ -323,7 +323,7 @@ async def _verify_non_duplication_group_constraint(
323
323
  )
324
324
  logger.error(error_msg)
325
325
  raise HTTPException(
326
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
326
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
327
327
  detail=(
328
328
  f"Invalid state:\n{error_msg}"
329
329
  "This should have not happened: please contact an admin."
@@ -333,7 +333,7 @@ async def _verify_non_duplication_group_constraint(
333
333
  duplicate[0].id, db
334
334
  )
335
335
  raise HTTPException(
336
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
336
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
337
337
  detail=(
338
338
  f"UserGroup {user_group.name} already owns a task group "
339
339
  f"with {pkg_name=} and {version=}.{state_msg}"
@@ -355,7 +355,7 @@ async def _verify_non_duplication_group_path(
355
355
  duplicate_ids = res.scalars().all()
356
356
  if duplicate_ids:
357
357
  raise HTTPException(
358
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
358
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
359
359
  detail=(
360
360
  f"Other TaskGroups already have {path=}: "
361
361
  f"{sorted(duplicate_ids)}."
@@ -398,6 +398,6 @@ def _check_type_filters_compatibility(
398
398
  )
399
399
  except ValueError as e:
400
400
  raise HTTPException(
401
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
401
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
402
402
  detail=f"Incompatible type filters.\nOriginal error: {str(e)}",
403
403
  )
@@ -47,7 +47,7 @@ async def create_dataset(
47
47
  if dataset.zarr_dir is None:
48
48
  if user.settings.project_dir is None:
49
49
  raise HTTPException(
50
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
50
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
51
51
  detail=(
52
52
  "Both 'dataset.zarr_dir' and 'user.settings.project_dir' "
53
53
  "are null"
@@ -158,7 +158,7 @@ async def update_dataset(
158
158
 
159
159
  if (dataset_update.zarr_dir is not None) and (len(db_dataset.images) != 0):
160
160
  raise HTTPException(
161
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
161
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
162
162
  detail=(
163
163
  "Cannot modify `zarr_dir` because the dataset has a non-empty "
164
164
  "image list."
@@ -203,7 +203,7 @@ async def delete_dataset(
203
203
  if jobs:
204
204
  string_ids = str([job.id for job in jobs])[1:-1]
205
205
  raise HTTPException(
206
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
206
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
207
207
  detail=(
208
208
  f"Cannot delete dataset {dataset.id} because it "
209
209
  f"is linked to active job(s) {string_ids}."
@@ -287,7 +287,7 @@ async def import_dataset(
287
287
  for image in dataset.images:
288
288
  if not image.zarr_url.startswith(dataset.zarr_dir):
289
289
  raise HTTPException(
290
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
290
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
291
291
  detail=(
292
292
  f"Cannot import dataset: zarr_url {image.zarr_url} is not "
293
293
  f"relative to zarr_dir={dataset.zarr_dir}."
@@ -51,7 +51,7 @@ def check_historyrun_related_to_dataset_and_wftask(
51
51
  or history_run.workflowtask_id != workflowtask_id
52
52
  ):
53
53
  raise HTTPException(
54
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
54
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
55
55
  detail=(
56
56
  f"Invalid query parameters: HistoryRun[{history_run.id}] is "
57
57
  f"not related to {dataset_id=} and {workflowtask_id=}."
@@ -480,7 +480,7 @@ async def get_history_unit_log(
480
480
 
481
481
  if history_unit.history_run_id != history_run_id:
482
482
  raise HTTPException(
483
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
483
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
484
484
  detail=(
485
485
  f"Invalid query parameters: HistoryUnit[{history_unit_id}] "
486
486
  f"is not related to HistoryRun[{history_run_id}]"
@@ -70,7 +70,7 @@ async def post_new_image(
70
70
 
71
71
  if not new_image.zarr_url.startswith(dataset.zarr_dir):
72
72
  raise HTTPException(
73
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
73
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
74
74
  detail=(
75
75
  "Cannot create image with zarr_url which is not relative to "
76
76
  f"{dataset.zarr_dir}."
@@ -78,7 +78,7 @@ async def post_new_image(
78
78
  )
79
79
  elif new_image.zarr_url == dataset.zarr_dir:
80
80
  raise HTTPException(
81
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
81
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
82
82
  detail=(
83
83
  "`SingleImage.zarr_url` cannot be equal to `Dataset.zarr_dir`:"
84
84
  f" {dataset.zarr_dir}"
@@ -87,7 +87,7 @@ async def post_new_image(
87
87
 
88
88
  if new_image.zarr_url in dataset.image_zarr_urls:
89
89
  raise HTTPException(
90
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
90
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
91
91
  detail=(
92
92
  f"Image with zarr_url '{new_image.zarr_url}' "
93
93
  f"already in DatasetV2 {dataset_id}",
@@ -15,7 +15,6 @@ from ....db import AsyncSession
15
15
  from ....db import get_async_db
16
16
  from ....models.v2 import JobV2
17
17
  from ....models.v2 import ProjectV2
18
- from ....runner.filenames import WORKFLOW_LOG_FILENAME
19
18
  from ....schemas.v2 import JobReadV2
20
19
  from ....schemas.v2 import JobStatusTypeV2
21
20
  from ...aux._job import _write_shutdown_file
@@ -25,6 +24,7 @@ from ._aux_functions import _get_project_check_owner
25
24
  from ._aux_functions import _get_workflow_check_owner
26
25
  from fractal_server.app.models import UserOAuth
27
26
  from fractal_server.app.routes.auth import current_active_user
27
+ from fractal_server.runner.filenames import WORKFLOW_LOG_FILENAME
28
28
 
29
29
 
30
30
  # https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
@@ -134,7 +134,7 @@ async def delete_project(
134
134
  if jobs:
135
135
  string_ids = str([job.id for job in jobs])[1:-1]
136
136
  raise HTTPException(
137
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
137
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
138
138
  detail=(
139
139
  f"Cannot delete project {project.id} because it "
140
140
  f"is linked to active job(s) {string_ids}."
@@ -72,7 +72,7 @@ async def get_workflowtask_status(
72
72
  else:
73
73
  string_ids = str([job.id for job in running_jobs])[1:-1]
74
74
  raise HTTPException(
75
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
75
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
76
76
  detail=(
77
77
  f"Cannot get WorkflowTaskV2 statuses as DatasetV2 {dataset.id}"
78
78
  f" is linked to multiple active jobs: {string_ids}."
@@ -26,15 +26,15 @@ from fractal_server.app.routes.auth import current_active_verified_user
26
26
  from fractal_server.app.routes.aux.validate_user_settings import (
27
27
  validate_user_settings,
28
28
  )
29
- from fractal_server.app.runner.set_start_and_last_task_index import (
30
- set_start_and_last_task_index,
31
- )
32
- from fractal_server.app.runner.v2.submit_workflow import submit_workflow
33
29
  from fractal_server.app.schemas.v2 import JobCreateV2
34
30
  from fractal_server.app.schemas.v2 import JobReadV2
35
31
  from fractal_server.app.schemas.v2 import JobStatusTypeV2
36
32
  from fractal_server.config import get_settings
37
33
  from fractal_server.logger import set_logger
34
+ from fractal_server.runner.set_start_and_last_task_index import (
35
+ set_start_and_last_task_index,
36
+ )
37
+ from fractal_server.runner.v2.submit_workflow import submit_workflow
38
38
  from fractal_server.syringe import Inject
39
39
 
40
40
 
@@ -84,7 +84,7 @@ async def apply_workflow(
84
84
  num_tasks = len(workflow.task_list)
85
85
  if num_tasks == 0:
86
86
  raise HTTPException(
87
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
87
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
88
88
  detail=f"Workflow {workflow_id} has empty task list",
89
89
  )
90
90
 
@@ -99,7 +99,7 @@ async def apply_workflow(
99
99
  job_create.last_task_index = last_task_index
100
100
  except ValueError as e:
101
101
  raise HTTPException(
102
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
102
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
103
103
  detail=(
104
104
  "Invalid values for first_task_index or last_task_index "
105
105
  f"(with {num_tasks=}).\n"
@@ -136,7 +136,7 @@ async def apply_workflow(
136
136
  res = await db.execute(stm)
137
137
  if res.scalars().all():
138
138
  raise HTTPException(
139
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
139
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
140
140
  detail=(
141
141
  f"Dataset {dataset_id} is already in use "
142
142
  "in submitted job(s)."
@@ -146,7 +146,7 @@ async def apply_workflow(
146
146
  if job_create.slurm_account is not None:
147
147
  if job_create.slurm_account not in user_settings.slurm_accounts:
148
148
  raise HTTPException(
149
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
149
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
150
150
  detail=(
151
151
  f"SLURM account '{job_create.slurm_account}' is not "
152
152
  "among those available to the current user"
@@ -172,7 +172,7 @@ async def apply_workflow(
172
172
  f"Original error: '{str(e)}'."
173
173
  )
174
174
  raise HTTPException(
175
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
175
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
176
176
  detail="Error in setting up the SSH connection.",
177
177
  )
178
178
  else:
@@ -112,12 +112,12 @@ async def patch_task(
112
112
  # Forbid changes that set a previously unset command
113
113
  if db_task.type == TaskType.NON_PARALLEL and "command_parallel" in update:
114
114
  raise HTTPException(
115
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
115
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
116
116
  detail="Cannot set an unset `command_parallel`.",
117
117
  )
118
118
  if db_task.type == TaskType.PARALLEL and "command_non_parallel" in update:
119
119
  raise HTTPException(
120
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
120
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
121
121
  detail="Cannot set an unset `command_non_parallel`.",
122
122
  )
123
123
 
@@ -157,7 +157,7 @@ async def create_task(
157
157
  or task.meta_non_parallel is not None
158
158
  ):
159
159
  raise HTTPException(
160
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
160
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
161
161
  detail=(
162
162
  "Cannot set `TaskV2.args_schema_non_parallel` or "
163
163
  "`TaskV2.args_schema_non_parallel` if TaskV2 is parallel"
@@ -167,7 +167,7 @@ async def create_task(
167
167
  task.args_schema_parallel is not None or task.meta_parallel is not None
168
168
  ):
169
169
  raise HTTPException(
170
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
170
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
171
171
  detail=(
172
172
  "Cannot set `TaskV2.args_schema_parallel` or "
173
173
  "`TaskV2.args_schema_parallel` if TaskV2 is non_parallel"
@@ -145,7 +145,7 @@ def parse_request_data(
145
145
 
146
146
  except (ValidationError, json.JSONDecodeError) as e:
147
147
  raise HTTPException(
148
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
148
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
149
149
  detail=f"Invalid request-body\n{str(e)}",
150
150
  )
151
151
 
@@ -193,7 +193,7 @@ async def collect_tasks_pip(
193
193
  )
194
194
  except ValueError:
195
195
  raise HTTPException(
196
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
196
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
197
197
  detail=(
198
198
  f"Python version {task_group_attrs['python_version']} is "
199
199
  "not available for Fractal task collection."
@@ -229,7 +229,7 @@ async def collect_tasks_pip(
229
229
  )
230
230
  except ValueError as e:
231
231
  raise HTTPException(
232
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
232
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
233
233
  detail=(
234
234
  f"Invalid wheel-file name {wheel_filename}. "
235
235
  f"Original error: {str(e)}",
@@ -283,7 +283,7 @@ async def collect_tasks_pip(
283
283
  TaskGroupCreateV2Strict(**task_group_attrs)
284
284
  except ValidationError as e:
285
285
  raise HTTPException(
286
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
286
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
287
287
  detail=f"Invalid task-group object. Original error: {e}",
288
288
  )
289
289
 
@@ -313,7 +313,7 @@ async def collect_tasks_pip(
313
313
  # Verify that folder does not exist (for local collection)
314
314
  if Path(task_group_path).exists():
315
315
  raise HTTPException(
316
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
316
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
317
317
  detail=f"{task_group_path} already exists.",
318
318
  )
319
319