fractal-server 2.9.0a3__tar.gz → 2.9.0a5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/PKG-INFO +1 -1
- fractal_server-2.9.0a5/fractal_server/__init__.py +1 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/task_group.py +2 -2
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v1.py +13 -11
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/__init__.py +4 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/job.py +13 -5
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/task_group.py +22 -1
- fractal_server-2.9.0a5/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +269 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +40 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/submit.py +2 -5
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/task_collection.py +2 -2
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/task_group.py +3 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +7 -0
- fractal_server-2.9.0a5/fractal_server/app/routes/aux/__init__.py +20 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/ssh/executor.py +3 -30
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/__init__.py +1 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/task_group.py +28 -1
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/3082479ac4ea_taskgroup_activity_and_venv_info_to_.py +1 -1
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/ssh/_fabric.py +85 -65
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/ssh/collect.py +1 -1
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/pyproject.toml +2 -2
- fractal_server-2.9.0a3/fractal_server/__init__.py +0 -1
- fractal_server-2.9.0a3/fractal_server/app/routes/aux/_timestamp.py +0 -18
- fractal_server-2.9.0a3/fractal_server/tasks/v2/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/LICENSE +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/README.md +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/__main__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/alembic.ini +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/db/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/linkusergroup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/linkuserproject.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/security.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/user_settings.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/dataset.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/state.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v1/workflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/dataset.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/workflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/workflowtask.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/_aux_functions.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/dataset.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/task_collection.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/workflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v1/workflowtask.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/dataset.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/images.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/status.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/workflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/current_user.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/group.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/login.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/oauth.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/register.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/router.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/auth/users.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/aux/_job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/aux/_runner.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/.gitignore +0 -0
- {fractal_server-2.9.0a3/fractal_server/app/routes/aux → fractal_server-2.9.0a5/fractal_server/app/runner}/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/async_wrap.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/components.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/compress_folder.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/exceptions.py +0 -0
- {fractal_server-2.9.0a3/fractal_server/app/runner → fractal_server-2.9.0a5/fractal_server/app/runner/executors}/__init__.py +0 -0
- {fractal_server-2.9.0a3/fractal_server/app/runner/executors → fractal_server-2.9.0a5/fractal_server/app/runner/executors/slurm}/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/_batching.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/_slurm_config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/remote.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/sudo/_subprocess_run_as_user.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/extract_archive.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/filenames.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/run_subprocess.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/shutdown.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/task_files.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_common.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_local/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_local/_local_config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_local/_submit_setup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_local/executor.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_slurm/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_slurm/_submit_setup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/common.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v1/handle_failed_job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local/_local_config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local/_submit_setup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local/executor.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_local_experimental/executor.py +0 -0
- {fractal_server-2.9.0a3/fractal_server/app/runner/executors/slurm → fractal_server-2.9.0a5/fractal_server/app/runner/v2/_slurm_common}/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_slurm_ssh/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_slurm_sudo/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/handle_failed_job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/runner.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/runner_functions.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/v2/task_interface.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/runner/versions.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/_validators.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/user.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/user_group.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/user_settings.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/applyworkflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/dataset.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/dumps.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/manifest.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/state.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/task_collection.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v1/workflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/dataset.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/dumps.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/job.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/manifest.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/project.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/status.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/task.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/task_collection.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/workflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/security/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/user_settings.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/config.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/data_migrations/README.md +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/data_migrations/tools.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/gunicorn_fractal.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/images/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/images/models.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/images/tools.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/logger.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/main.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/README +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/env.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/naming_convention.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/script.py.mako +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/py.typed +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/ssh/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/string_tools.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/syringe.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/utils.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v1/_TaskCollectPip.py +0 -0
- {fractal_server-2.9.0a3/fractal_server/app/runner/v2/_slurm_common → fractal_server-2.9.0a5/fractal_server/tasks/v1}/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v1/background_operations.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v1/endpoint_operations.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v1/get_collection_data.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v1/utils.py +0 -0
- {fractal_server-2.9.0a3/fractal_server/tasks/v1 → fractal_server-2.9.0a5/fractal_server/tasks/v2}/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/local/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/local/_utils.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/local/collect.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/local/deactivate.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/local/reactivate.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/utils_background.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/utils_database.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/utils_package_names.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/tasks/v2/utils_templates.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/urls.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/utils.py +0 -0
- {fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/zip_tools.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__VERSION__ = "2.9.0a5"
|
{fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/models/v2/task_group.py
RENAMED
@@ -49,8 +49,8 @@ class TaskGroupV2(SQLModel, table=True):
|
|
49
49
|
sa_column=Column(DateTime(timezone=True), nullable=False),
|
50
50
|
)
|
51
51
|
timestamp_last_used: Optional[datetime] = Field(
|
52
|
-
|
53
|
-
sa_column=Column(DateTime(timezone=True), nullable=
|
52
|
+
default_factory=get_timestamp,
|
53
|
+
sa_column=Column(DateTime(timezone=True), nullable=False),
|
54
54
|
)
|
55
55
|
|
56
56
|
@property
|
@@ -33,7 +33,7 @@ from ..aux._job import _write_shutdown_file
|
|
33
33
|
from ..aux._runner import _check_shutdown_is_supported
|
34
34
|
from fractal_server.app.models import UserOAuth
|
35
35
|
from fractal_server.app.routes.auth import current_active_superuser
|
36
|
-
from fractal_server.app.routes.aux
|
36
|
+
from fractal_server.app.routes.aux import _raise_if_naive_datetime
|
37
37
|
|
38
38
|
router_admin_v1 = APIRouter()
|
39
39
|
|
@@ -54,6 +54,7 @@ async def view_project(
|
|
54
54
|
id: If not `None`, select a given `project.id`.
|
55
55
|
user_id: If not `None`, select a given `project.user_id`.
|
56
56
|
"""
|
57
|
+
_raise_if_naive_datetime(timestamp_created_min, timestamp_created_max)
|
57
58
|
|
58
59
|
stm = select(Project)
|
59
60
|
|
@@ -63,10 +64,8 @@ async def view_project(
|
|
63
64
|
if user_id is not None:
|
64
65
|
stm = stm.where(Project.user_list.any(UserOAuth.id == user_id))
|
65
66
|
if timestamp_created_min is not None:
|
66
|
-
timestamp_created_min = _convert_to_db_timestamp(timestamp_created_min)
|
67
67
|
stm = stm.where(Project.timestamp_created >= timestamp_created_min)
|
68
68
|
if timestamp_created_max is not None:
|
69
|
-
timestamp_created_max = _convert_to_db_timestamp(timestamp_created_max)
|
70
69
|
stm = stm.where(Project.timestamp_created <= timestamp_created_max)
|
71
70
|
|
72
71
|
res = await db.execute(stm)
|
@@ -96,6 +95,8 @@ async def view_workflow(
|
|
96
95
|
name_contains: If not `None`, select workflows such that their
|
97
96
|
`name` attribute contains `name_contains` (case-insensitive).
|
98
97
|
"""
|
98
|
+
_raise_if_naive_datetime(timestamp_created_min, timestamp_created_max)
|
99
|
+
|
99
100
|
stm = select(Workflow)
|
100
101
|
|
101
102
|
if user_id is not None:
|
@@ -112,10 +113,8 @@ async def view_workflow(
|
|
112
113
|
func.lower(Workflow.name).contains(name_contains.lower())
|
113
114
|
)
|
114
115
|
if timestamp_created_min is not None:
|
115
|
-
timestamp_created_min = _convert_to_db_timestamp(timestamp_created_min)
|
116
116
|
stm = stm.where(Workflow.timestamp_created >= timestamp_created_min)
|
117
117
|
if timestamp_created_max is not None:
|
118
|
-
timestamp_created_max = _convert_to_db_timestamp(timestamp_created_max)
|
119
118
|
stm = stm.where(Workflow.timestamp_created <= timestamp_created_max)
|
120
119
|
|
121
120
|
res = await db.execute(stm)
|
@@ -147,6 +146,8 @@ async def view_dataset(
|
|
147
146
|
`name` attribute contains `name_contains` (case-insensitive).
|
148
147
|
type: If not `None`, select a given `dataset.type`.
|
149
148
|
"""
|
149
|
+
_raise_if_naive_datetime(timestamp_created_min, timestamp_created_max)
|
150
|
+
|
150
151
|
stm = select(Dataset)
|
151
152
|
|
152
153
|
if user_id is not None:
|
@@ -165,10 +166,8 @@ async def view_dataset(
|
|
165
166
|
if type is not None:
|
166
167
|
stm = stm.where(Dataset.type == type)
|
167
168
|
if timestamp_created_min is not None:
|
168
|
-
timestamp_created_min = _convert_to_db_timestamp(timestamp_created_min)
|
169
169
|
stm = stm.where(Dataset.timestamp_created >= timestamp_created_min)
|
170
170
|
if timestamp_created_max is not None:
|
171
|
-
timestamp_created_max = _convert_to_db_timestamp(timestamp_created_max)
|
172
171
|
stm = stm.where(Dataset.timestamp_created <= timestamp_created_max)
|
173
172
|
|
174
173
|
res = await db.execute(stm)
|
@@ -218,6 +217,13 @@ async def view_job(
|
|
218
217
|
log: If `True`, include `job.log`, if `False`
|
219
218
|
`job.log` is set to `None`.
|
220
219
|
"""
|
220
|
+
_raise_if_naive_datetime(
|
221
|
+
start_timestamp_min,
|
222
|
+
start_timestamp_max,
|
223
|
+
end_timestamp_min,
|
224
|
+
end_timestamp_max,
|
225
|
+
)
|
226
|
+
|
221
227
|
stm = select(ApplyWorkflow)
|
222
228
|
|
223
229
|
if id is not None:
|
@@ -237,16 +243,12 @@ async def view_job(
|
|
237
243
|
if status is not None:
|
238
244
|
stm = stm.where(ApplyWorkflow.status == status)
|
239
245
|
if start_timestamp_min is not None:
|
240
|
-
start_timestamp_min = _convert_to_db_timestamp(start_timestamp_min)
|
241
246
|
stm = stm.where(ApplyWorkflow.start_timestamp >= start_timestamp_min)
|
242
247
|
if start_timestamp_max is not None:
|
243
|
-
start_timestamp_max = _convert_to_db_timestamp(start_timestamp_max)
|
244
248
|
stm = stm.where(ApplyWorkflow.start_timestamp <= start_timestamp_max)
|
245
249
|
if end_timestamp_min is not None:
|
246
|
-
end_timestamp_min = _convert_to_db_timestamp(end_timestamp_min)
|
247
250
|
stm = stm.where(ApplyWorkflow.end_timestamp >= end_timestamp_min)
|
248
251
|
if end_timestamp_max is not None:
|
249
|
-
end_timestamp_max = _convert_to_db_timestamp(end_timestamp_max)
|
250
252
|
stm = stm.where(ApplyWorkflow.end_timestamp <= end_timestamp_max)
|
251
253
|
|
252
254
|
res = await db.execute(stm)
|
{fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/__init__.py
RENAMED
@@ -7,6 +7,7 @@ from .job import router as job_router
|
|
7
7
|
from .project import router as project_router
|
8
8
|
from .task import router as task_router
|
9
9
|
from .task_group import router as task_group_router
|
10
|
+
from .task_group_lifecycle import router as task_group_lifecycle_router
|
10
11
|
|
11
12
|
router_admin_v2 = APIRouter()
|
12
13
|
|
@@ -14,3 +15,6 @@ router_admin_v2.include_router(job_router, prefix="/job")
|
|
14
15
|
router_admin_v2.include_router(project_router, prefix="/project")
|
15
16
|
router_admin_v2.include_router(task_router, prefix="/task")
|
16
17
|
router_admin_v2.include_router(task_group_router, prefix="/task-group")
|
18
|
+
router_admin_v2.include_router(
|
19
|
+
task_group_lifecycle_router, prefix="/task-group"
|
20
|
+
)
|
@@ -16,9 +16,9 @@ from fractal_server.app.models import UserOAuth
|
|
16
16
|
from fractal_server.app.models.v2 import JobV2
|
17
17
|
from fractal_server.app.models.v2 import ProjectV2
|
18
18
|
from fractal_server.app.routes.auth import current_active_superuser
|
19
|
+
from fractal_server.app.routes.aux import _raise_if_naive_datetime
|
19
20
|
from fractal_server.app.routes.aux._job import _write_shutdown_file
|
20
21
|
from fractal_server.app.routes.aux._runner import _check_shutdown_is_supported
|
21
|
-
from fractal_server.app.routes.aux._timestamp import _convert_to_db_timestamp
|
22
22
|
from fractal_server.app.runner.filenames import WORKFLOW_LOG_FILENAME
|
23
23
|
from fractal_server.app.schemas.v2 import JobReadV2
|
24
24
|
from fractal_server.app.schemas.v2 import JobStatusTypeV2
|
@@ -66,6 +66,14 @@ async def view_job(
|
|
66
66
|
log: If `True`, include `job.log`, if `False`
|
67
67
|
`job.log` is set to `None`.
|
68
68
|
"""
|
69
|
+
|
70
|
+
_raise_if_naive_datetime(
|
71
|
+
start_timestamp_min,
|
72
|
+
start_timestamp_max,
|
73
|
+
end_timestamp_min,
|
74
|
+
end_timestamp_max,
|
75
|
+
)
|
76
|
+
|
69
77
|
stm = select(JobV2)
|
70
78
|
|
71
79
|
if id is not None:
|
@@ -83,16 +91,16 @@ async def view_job(
|
|
83
91
|
if status is not None:
|
84
92
|
stm = stm.where(JobV2.status == status)
|
85
93
|
if start_timestamp_min is not None:
|
86
|
-
start_timestamp_min =
|
94
|
+
start_timestamp_min = start_timestamp_min
|
87
95
|
stm = stm.where(JobV2.start_timestamp >= start_timestamp_min)
|
88
96
|
if start_timestamp_max is not None:
|
89
|
-
start_timestamp_max =
|
97
|
+
start_timestamp_max = start_timestamp_max
|
90
98
|
stm = stm.where(JobV2.start_timestamp <= start_timestamp_max)
|
91
99
|
if end_timestamp_min is not None:
|
92
|
-
end_timestamp_min =
|
100
|
+
end_timestamp_min = end_timestamp_min
|
93
101
|
stm = stm.where(JobV2.end_timestamp >= end_timestamp_min)
|
94
102
|
if end_timestamp_max is not None:
|
95
|
-
end_timestamp_max =
|
103
|
+
end_timestamp_max = end_timestamp_max
|
96
104
|
stm = stm.where(JobV2.end_timestamp <= end_timestamp_max)
|
97
105
|
|
98
106
|
res = await db.execute(stm)
|
{fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/admin/v2/task_group.py
RENAMED
@@ -20,6 +20,7 @@ from fractal_server.app.routes.auth import current_active_superuser
|
|
20
20
|
from fractal_server.app.routes.auth._aux_auth import (
|
21
21
|
_verify_user_belongs_to_group,
|
22
22
|
)
|
23
|
+
from fractal_server.app.routes.aux import _raise_if_naive_datetime
|
23
24
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
24
25
|
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
25
26
|
from fractal_server.app.schemas.v2 import TaskGroupActivityV2Read
|
@@ -46,6 +47,8 @@ async def get_task_group_activity_list(
|
|
46
47
|
db: AsyncSession = Depends(get_async_db),
|
47
48
|
) -> list[TaskGroupActivityV2Read]:
|
48
49
|
|
50
|
+
_raise_if_naive_datetime(timestamp_started_min)
|
51
|
+
|
49
52
|
stm = select(TaskGroupActivityV2)
|
50
53
|
if task_group_activity_id is not None:
|
51
54
|
stm = stm.where(TaskGroupActivityV2.id == task_group_activity_id)
|
@@ -93,16 +96,26 @@ async def query_task_group_list(
|
|
93
96
|
active: Optional[bool] = None,
|
94
97
|
pkg_name: Optional[str] = None,
|
95
98
|
origin: Optional[TaskGroupV2OriginEnum] = None,
|
99
|
+
timestamp_last_used_min: Optional[datetime] = None,
|
100
|
+
timestamp_last_used_max: Optional[datetime] = None,
|
96
101
|
user: UserOAuth = Depends(current_active_superuser),
|
97
102
|
db: AsyncSession = Depends(get_async_db),
|
98
103
|
) -> list[TaskGroupReadV2]:
|
99
104
|
|
100
105
|
stm = select(TaskGroupV2)
|
101
106
|
|
107
|
+
_raise_if_naive_datetime(
|
108
|
+
timestamp_last_used_max,
|
109
|
+
timestamp_last_used_min,
|
110
|
+
)
|
111
|
+
|
102
112
|
if user_group_id is not None and private is True:
|
103
113
|
raise HTTPException(
|
104
114
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
105
|
-
detail=
|
115
|
+
detail=(
|
116
|
+
"Cannot get task groups with both "
|
117
|
+
f"{user_group_id=} and {private=}."
|
118
|
+
),
|
106
119
|
)
|
107
120
|
if user_id is not None:
|
108
121
|
stm = stm.where(TaskGroupV2.user_id == user_id)
|
@@ -122,6 +135,14 @@ async def query_task_group_list(
|
|
122
135
|
stm = stm.where(TaskGroupV2.origin == origin)
|
123
136
|
if pkg_name is not None:
|
124
137
|
stm = stm.where(TaskGroupV2.pkg_name.icontains(pkg_name))
|
138
|
+
if timestamp_last_used_min is not None:
|
139
|
+
stm = stm.where(
|
140
|
+
TaskGroupV2.timestamp_last_used >= timestamp_last_used_min
|
141
|
+
)
|
142
|
+
if timestamp_last_used_max is not None:
|
143
|
+
stm = stm.where(
|
144
|
+
TaskGroupV2.timestamp_last_used <= timestamp_last_used_max
|
145
|
+
)
|
125
146
|
|
126
147
|
res = await db.execute(stm)
|
127
148
|
task_groups_list = res.scalars().all()
|
@@ -0,0 +1,269 @@
|
|
1
|
+
from fastapi import APIRouter
|
2
|
+
from fastapi import BackgroundTasks
|
3
|
+
from fastapi import Depends
|
4
|
+
from fastapi import HTTPException
|
5
|
+
from fastapi import Request
|
6
|
+
from fastapi import Response
|
7
|
+
from fastapi import status
|
8
|
+
|
9
|
+
from fractal_server.app.db import AsyncSession
|
10
|
+
from fractal_server.app.db import get_async_db
|
11
|
+
from fractal_server.app.models import UserOAuth
|
12
|
+
from fractal_server.app.models.v2 import TaskGroupActivityV2
|
13
|
+
from fractal_server.app.routes.api.v2._aux_functions_task_lifecycle import (
|
14
|
+
check_no_ongoing_activity,
|
15
|
+
)
|
16
|
+
from fractal_server.app.routes.api.v2._aux_functions_task_lifecycle import (
|
17
|
+
check_no_submitted_job,
|
18
|
+
)
|
19
|
+
from fractal_server.app.routes.api.v2._aux_functions_tasks import (
|
20
|
+
_get_task_group_or_404,
|
21
|
+
)
|
22
|
+
from fractal_server.app.routes.auth import current_active_superuser
|
23
|
+
from fractal_server.app.routes.aux.validate_user_settings import (
|
24
|
+
validate_user_settings,
|
25
|
+
)
|
26
|
+
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
27
|
+
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
28
|
+
from fractal_server.app.schemas.v2 import TaskGroupActivityV2Read
|
29
|
+
from fractal_server.app.schemas.v2 import TaskGroupReadV2
|
30
|
+
from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
|
31
|
+
from fractal_server.config import get_settings
|
32
|
+
from fractal_server.logger import set_logger
|
33
|
+
from fractal_server.syringe import Inject
|
34
|
+
from fractal_server.tasks.v2.local import deactivate_local
|
35
|
+
from fractal_server.tasks.v2.local import reactivate_local
|
36
|
+
from fractal_server.tasks.v2.ssh import deactivate_ssh
|
37
|
+
from fractal_server.tasks.v2.ssh import reactivate_ssh
|
38
|
+
from fractal_server.utils import get_timestamp
|
39
|
+
|
40
|
+
router = APIRouter()
|
41
|
+
|
42
|
+
logger = set_logger(__name__)
|
43
|
+
|
44
|
+
|
45
|
+
@router.post(
|
46
|
+
"/{task_group_id}/deactivate/",
|
47
|
+
response_model=TaskGroupActivityV2Read,
|
48
|
+
)
|
49
|
+
async def deactivate_task_group(
|
50
|
+
task_group_id: int,
|
51
|
+
background_tasks: BackgroundTasks,
|
52
|
+
response: Response,
|
53
|
+
request: Request,
|
54
|
+
superuser: UserOAuth = Depends(current_active_superuser),
|
55
|
+
db: AsyncSession = Depends(get_async_db),
|
56
|
+
) -> TaskGroupReadV2:
|
57
|
+
"""
|
58
|
+
Deactivate task-group venv
|
59
|
+
"""
|
60
|
+
task_group = await _get_task_group_or_404(
|
61
|
+
task_group_id=task_group_id, db=db
|
62
|
+
)
|
63
|
+
|
64
|
+
# Check that task-group is active
|
65
|
+
if not task_group.active:
|
66
|
+
raise HTTPException(
|
67
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
68
|
+
detail=(
|
69
|
+
f"Cannot deactivate a task group with {task_group.active=}."
|
70
|
+
),
|
71
|
+
)
|
72
|
+
|
73
|
+
# Check no other activity is ongoing
|
74
|
+
await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
|
75
|
+
|
76
|
+
# Check no submitted jobs use tasks from this task group
|
77
|
+
await check_no_submitted_job(task_group_id=task_group.id, db=db)
|
78
|
+
|
79
|
+
# Shortcut for task-group with origin="other"
|
80
|
+
if task_group.origin == TaskGroupV2OriginEnum.OTHER:
|
81
|
+
task_group.active = False
|
82
|
+
task_group_activity = TaskGroupActivityV2(
|
83
|
+
user_id=task_group.user_id,
|
84
|
+
taskgroupv2_id=task_group.id,
|
85
|
+
status=TaskGroupActivityStatusV2.OK,
|
86
|
+
action=TaskGroupActivityActionV2.DEACTIVATE,
|
87
|
+
pkg_name=task_group.pkg_name,
|
88
|
+
version=(task_group.version or "N/A"),
|
89
|
+
log=(
|
90
|
+
f"Task group has {task_group.origin=}, set "
|
91
|
+
"task_group.active to False and exit."
|
92
|
+
),
|
93
|
+
timestamp_started=get_timestamp(),
|
94
|
+
timestamp_ended=get_timestamp(),
|
95
|
+
)
|
96
|
+
db.add(task_group)
|
97
|
+
db.add(task_group_activity)
|
98
|
+
await db.commit()
|
99
|
+
response.status_code = status.HTTP_202_ACCEPTED
|
100
|
+
return task_group_activity
|
101
|
+
|
102
|
+
task_group_activity = TaskGroupActivityV2(
|
103
|
+
user_id=task_group.user_id,
|
104
|
+
taskgroupv2_id=task_group.id,
|
105
|
+
status=TaskGroupActivityStatusV2.PENDING,
|
106
|
+
action=TaskGroupActivityActionV2.DEACTIVATE,
|
107
|
+
pkg_name=task_group.pkg_name,
|
108
|
+
version=task_group.version,
|
109
|
+
timestamp_started=get_timestamp(),
|
110
|
+
)
|
111
|
+
task_group.active = False
|
112
|
+
db.add(task_group)
|
113
|
+
db.add(task_group_activity)
|
114
|
+
await db.commit()
|
115
|
+
|
116
|
+
# Submit background task
|
117
|
+
settings = Inject(get_settings)
|
118
|
+
if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
|
119
|
+
# Validate user settings (backend-specific)
|
120
|
+
user = await db.get(UserOAuth, task_group.user_id)
|
121
|
+
user_settings = await validate_user_settings(
|
122
|
+
user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
|
123
|
+
)
|
124
|
+
# User appropriate FractalSSH object
|
125
|
+
ssh_credentials = dict(
|
126
|
+
user=user_settings.ssh_username,
|
127
|
+
host=user_settings.ssh_host,
|
128
|
+
key_path=user_settings.ssh_private_key_path,
|
129
|
+
)
|
130
|
+
fractal_ssh_list = request.app.state.fractal_ssh_list
|
131
|
+
fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
|
132
|
+
|
133
|
+
background_tasks.add_task(
|
134
|
+
deactivate_ssh,
|
135
|
+
task_group_id=task_group.id,
|
136
|
+
task_group_activity_id=task_group_activity.id,
|
137
|
+
fractal_ssh=fractal_ssh,
|
138
|
+
tasks_base_dir=user_settings.ssh_tasks_dir,
|
139
|
+
)
|
140
|
+
else:
|
141
|
+
background_tasks.add_task(
|
142
|
+
deactivate_local,
|
143
|
+
task_group_id=task_group.id,
|
144
|
+
task_group_activity_id=task_group_activity.id,
|
145
|
+
)
|
146
|
+
|
147
|
+
logger.debug(
|
148
|
+
"Admin task group deactivation endpoint: start deactivate "
|
149
|
+
"and return task_group_activity"
|
150
|
+
)
|
151
|
+
response.status_code = status.HTTP_202_ACCEPTED
|
152
|
+
return task_group_activity
|
153
|
+
|
154
|
+
|
155
|
+
@router.post(
|
156
|
+
"/{task_group_id}/reactivate/",
|
157
|
+
response_model=TaskGroupActivityV2Read,
|
158
|
+
)
|
159
|
+
async def reactivate_task_group(
|
160
|
+
task_group_id: int,
|
161
|
+
background_tasks: BackgroundTasks,
|
162
|
+
response: Response,
|
163
|
+
request: Request,
|
164
|
+
superuser: UserOAuth = Depends(current_active_superuser),
|
165
|
+
db: AsyncSession = Depends(get_async_db),
|
166
|
+
) -> TaskGroupReadV2:
|
167
|
+
"""
|
168
|
+
Deactivate task-group venv
|
169
|
+
"""
|
170
|
+
|
171
|
+
task_group = await _get_task_group_or_404(
|
172
|
+
task_group_id=task_group_id, db=db
|
173
|
+
)
|
174
|
+
|
175
|
+
# Check that task-group is not active
|
176
|
+
if task_group.active:
|
177
|
+
raise HTTPException(
|
178
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
179
|
+
detail=(
|
180
|
+
f"Cannot reactivate a task group with {task_group.active=}."
|
181
|
+
),
|
182
|
+
)
|
183
|
+
|
184
|
+
# Check no other activity is ongoing
|
185
|
+
await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
|
186
|
+
|
187
|
+
# Check no submitted jobs use tasks from this task group
|
188
|
+
await check_no_submitted_job(task_group_id=task_group.id, db=db)
|
189
|
+
|
190
|
+
# Shortcut for task-group with origin="other"
|
191
|
+
if task_group.origin == TaskGroupV2OriginEnum.OTHER:
|
192
|
+
task_group.active = True
|
193
|
+
task_group_activity = TaskGroupActivityV2(
|
194
|
+
user_id=task_group.user_id,
|
195
|
+
taskgroupv2_id=task_group.id,
|
196
|
+
status=TaskGroupActivityStatusV2.OK,
|
197
|
+
action=TaskGroupActivityActionV2.REACTIVATE,
|
198
|
+
pkg_name=task_group.pkg_name,
|
199
|
+
version=(task_group.version or "N/A"),
|
200
|
+
log=(
|
201
|
+
f"Task group has {task_group.origin=}, set "
|
202
|
+
"task_group.active to True and exit."
|
203
|
+
),
|
204
|
+
timestamp_started=get_timestamp(),
|
205
|
+
timestamp_ended=get_timestamp(),
|
206
|
+
)
|
207
|
+
db.add(task_group)
|
208
|
+
db.add(task_group_activity)
|
209
|
+
await db.commit()
|
210
|
+
response.status_code = status.HTTP_202_ACCEPTED
|
211
|
+
return task_group_activity
|
212
|
+
|
213
|
+
if task_group.pip_freeze is None:
|
214
|
+
raise HTTPException(
|
215
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
216
|
+
detail=(
|
217
|
+
"Cannot reactivate a task group with "
|
218
|
+
f"{task_group.pip_freeze=}."
|
219
|
+
),
|
220
|
+
)
|
221
|
+
|
222
|
+
task_group_activity = TaskGroupActivityV2(
|
223
|
+
user_id=task_group.user_id,
|
224
|
+
taskgroupv2_id=task_group.id,
|
225
|
+
status=TaskGroupActivityStatusV2.PENDING,
|
226
|
+
action=TaskGroupActivityActionV2.REACTIVATE,
|
227
|
+
pkg_name=task_group.pkg_name,
|
228
|
+
version=task_group.version,
|
229
|
+
timestamp_started=get_timestamp(),
|
230
|
+
)
|
231
|
+
db.add(task_group_activity)
|
232
|
+
await db.commit()
|
233
|
+
|
234
|
+
# Submit background task
|
235
|
+
settings = Inject(get_settings)
|
236
|
+
if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
|
237
|
+
# Validate user settings (backend-specific)
|
238
|
+
user = await db.get(UserOAuth, task_group.user_id)
|
239
|
+
user_settings = await validate_user_settings(
|
240
|
+
user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
|
241
|
+
)
|
242
|
+
# Use appropriate FractalSSH object
|
243
|
+
ssh_credentials = dict(
|
244
|
+
user=user_settings.ssh_username,
|
245
|
+
host=user_settings.ssh_host,
|
246
|
+
key_path=user_settings.ssh_private_key_path,
|
247
|
+
)
|
248
|
+
fractal_ssh_list = request.app.state.fractal_ssh_list
|
249
|
+
fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
|
250
|
+
|
251
|
+
background_tasks.add_task(
|
252
|
+
reactivate_ssh,
|
253
|
+
task_group_id=task_group.id,
|
254
|
+
task_group_activity_id=task_group_activity.id,
|
255
|
+
fractal_ssh=fractal_ssh,
|
256
|
+
tasks_base_dir=user_settings.ssh_tasks_dir,
|
257
|
+
)
|
258
|
+
else:
|
259
|
+
background_tasks.add_task(
|
260
|
+
reactivate_local,
|
261
|
+
task_group_id=task_group.id,
|
262
|
+
task_group_activity_id=task_group_activity.id,
|
263
|
+
)
|
264
|
+
logger.debug(
|
265
|
+
"Admin task group reactivation endpoint: start reactivate "
|
266
|
+
"and return task_group_activity"
|
267
|
+
)
|
268
|
+
response.status_code = status.HTTP_202_ACCEPTED
|
269
|
+
return task_group_activity
|
@@ -4,10 +4,16 @@ from fastapi import HTTPException
|
|
4
4
|
from fastapi import status
|
5
5
|
from httpx import AsyncClient
|
6
6
|
from httpx import TimeoutException
|
7
|
+
from sqlmodel import func
|
7
8
|
from sqlmodel import select
|
8
9
|
|
9
10
|
from fractal_server.app.db import AsyncSession
|
11
|
+
from fractal_server.app.models.v2 import JobV2
|
10
12
|
from fractal_server.app.models.v2 import TaskGroupActivityV2
|
13
|
+
from fractal_server.app.models.v2 import TaskV2
|
14
|
+
from fractal_server.app.models.v2 import WorkflowTaskV2
|
15
|
+
from fractal_server.app.models.v2 import WorkflowV2
|
16
|
+
from fractal_server.app.schemas.v2 import JobStatusTypeV2
|
11
17
|
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
12
18
|
from fractal_server.logger import set_logger
|
13
19
|
|
@@ -165,3 +171,37 @@ async def check_no_ongoing_activity(
|
|
165
171
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
166
172
|
detail=msg,
|
167
173
|
)
|
174
|
+
|
175
|
+
|
176
|
+
async def check_no_submitted_job(
|
177
|
+
*,
|
178
|
+
task_group_id: int,
|
179
|
+
db: AsyncSession,
|
180
|
+
) -> None:
|
181
|
+
"""
|
182
|
+
Find submitted jobs which include tasks from a given task group.
|
183
|
+
|
184
|
+
Arguments:
|
185
|
+
task_id_list: List of TaskV2 IDs
|
186
|
+
db: Database session
|
187
|
+
"""
|
188
|
+
stm = (
|
189
|
+
select(func.count(JobV2.id))
|
190
|
+
.join(WorkflowV2, JobV2.workflow_id == WorkflowV2.id)
|
191
|
+
.join(WorkflowTaskV2, WorkflowTaskV2.workflow_id == WorkflowV2.id)
|
192
|
+
.join(TaskV2, WorkflowTaskV2.task_id == TaskV2.id)
|
193
|
+
.where(WorkflowTaskV2.order >= JobV2.first_task_index)
|
194
|
+
.where(WorkflowTaskV2.order <= JobV2.last_task_index)
|
195
|
+
.where(JobV2.status == JobStatusTypeV2.SUBMITTED)
|
196
|
+
.where(TaskV2.taskgroupv2_id == task_group_id)
|
197
|
+
)
|
198
|
+
res = await db.execute(stm)
|
199
|
+
num_submitted_jobs = res.scalar()
|
200
|
+
if num_submitted_jobs > 0:
|
201
|
+
raise HTTPException(
|
202
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
203
|
+
detail=(
|
204
|
+
f"Cannot act on task group because {num_submitted_jobs} "
|
205
|
+
"submitted jobs use its tasks."
|
206
|
+
),
|
207
|
+
)
|
{fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/submit.py
RENAMED
@@ -15,7 +15,6 @@ from sqlmodel import select
|
|
15
15
|
from .....config import get_settings
|
16
16
|
from .....logger import set_logger
|
17
17
|
from .....syringe import Inject
|
18
|
-
from .....utils import get_timestamp
|
19
18
|
from ....db import AsyncSession
|
20
19
|
from ....db import get_async_db
|
21
20
|
from ....models.v2 import JobV2
|
@@ -62,8 +61,6 @@ async def apply_workflow(
|
|
62
61
|
db: AsyncSession = Depends(get_async_db),
|
63
62
|
) -> Optional[JobReadV2]:
|
64
63
|
|
65
|
-
now = get_timestamp()
|
66
|
-
|
67
64
|
# Remove non-submitted V2 jobs from the app state when the list grows
|
68
65
|
# beyond a threshold
|
69
66
|
settings = Inject(get_settings)
|
@@ -194,12 +191,12 @@ async def apply_workflow(
|
|
194
191
|
)
|
195
192
|
used_task_groups = res.scalars().all()
|
196
193
|
for used_task_group in used_task_groups:
|
197
|
-
used_task_group.timestamp_last_used =
|
194
|
+
used_task_group.timestamp_last_used = job.start_timestamp
|
198
195
|
db.add(used_task_group)
|
199
196
|
await db.commit()
|
200
197
|
|
201
198
|
# Define server-side job directory
|
202
|
-
timestamp_string =
|
199
|
+
timestamp_string = job.start_timestamp.strftime("%Y%m%d_%H%M%S")
|
203
200
|
WORKFLOW_DIR_LOCAL = settings.FRACTAL_RUNNER_WORKING_BASE_DIR / (
|
204
201
|
f"proj_v2_{project_id:07d}_wf_{workflow_id:07d}_job_{job.id:07d}"
|
205
202
|
f"_{timestamp_string}"
|
@@ -21,7 +21,7 @@ from ....models.v2 import TaskGroupV2
|
|
21
21
|
from ....schemas.v2 import TaskCollectPipV2
|
22
22
|
from ....schemas.v2 import TaskGroupActivityStatusV2
|
23
23
|
from ....schemas.v2 import TaskGroupActivityV2Read
|
24
|
-
from ....schemas.v2 import
|
24
|
+
from ....schemas.v2 import TaskGroupCreateV2Strict
|
25
25
|
from ...aux.validate_user_settings import validate_user_settings
|
26
26
|
from ._aux_functions_task_lifecycle import get_package_version_from_pypi
|
27
27
|
from ._aux_functions_tasks import _get_valid_user_group_id
|
@@ -164,7 +164,7 @@ async def collect_tasks_pip(
|
|
164
164
|
|
165
165
|
# Validate TaskGroupV2 attributes
|
166
166
|
try:
|
167
|
-
|
167
|
+
TaskGroupCreateV2Strict(**task_group_attrs)
|
168
168
|
except ValidationError as e:
|
169
169
|
raise HTTPException(
|
170
170
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
{fractal_server-2.9.0a3 → fractal_server-2.9.0a5}/fractal_server/app/routes/api/v2/task_group.py
RENAMED
@@ -23,6 +23,7 @@ from fractal_server.app.routes.auth import current_active_user
|
|
23
23
|
from fractal_server.app.routes.auth._aux_auth import (
|
24
24
|
_verify_user_belongs_to_group,
|
25
25
|
)
|
26
|
+
from fractal_server.app.routes.aux import _raise_if_naive_datetime
|
26
27
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
27
28
|
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
28
29
|
from fractal_server.app.schemas.v2 import TaskGroupActivityV2Read
|
@@ -47,6 +48,8 @@ async def get_task_group_activity_list(
|
|
47
48
|
db: AsyncSession = Depends(get_async_db),
|
48
49
|
) -> list[TaskGroupActivityV2Read]:
|
49
50
|
|
51
|
+
_raise_if_naive_datetime(timestamp_started_min)
|
52
|
+
|
50
53
|
stm = select(TaskGroupActivityV2).where(
|
51
54
|
TaskGroupActivityV2.user_id == user.id
|
52
55
|
)
|
@@ -8,6 +8,7 @@ from fastapi import status
|
|
8
8
|
|
9
9
|
from ...aux.validate_user_settings import validate_user_settings
|
10
10
|
from ._aux_functions_task_lifecycle import check_no_ongoing_activity
|
11
|
+
from ._aux_functions_task_lifecycle import check_no_submitted_job
|
11
12
|
from ._aux_functions_tasks import _get_task_group_full_access
|
12
13
|
from fractal_server.app.db import AsyncSession
|
13
14
|
from fractal_server.app.db import get_async_db
|
@@ -59,6 +60,9 @@ async def deactivate_task_group(
|
|
59
60
|
# Check no other activity is ongoing
|
60
61
|
await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
|
61
62
|
|
63
|
+
# Check no submitted jobs use tasks from this task group
|
64
|
+
await check_no_submitted_job(task_group_id=task_group.id, db=db)
|
65
|
+
|
62
66
|
# Check that task-group is active
|
63
67
|
if not task_group.active:
|
64
68
|
raise HTTPException(
|
@@ -181,6 +185,9 @@ async def reactivate_task_group(
|
|
181
185
|
# Check no other activity is ongoing
|
182
186
|
await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
|
183
187
|
|
188
|
+
# Check no submitted jobs use tasks from this task group
|
189
|
+
await check_no_submitted_job(task_group_id=task_group.id, db=db)
|
190
|
+
|
184
191
|
# Shortcut for task-group with origin="other"
|
185
192
|
if task_group.origin == TaskGroupV2OriginEnum.OTHER:
|
186
193
|
task_group.active = True
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Optional
|
3
|
+
|
4
|
+
from fastapi import HTTPException
|
5
|
+
from fastapi import status
|
6
|
+
|
7
|
+
|
8
|
+
def _raise_if_naive_datetime(*timestamps: tuple[Optional[datetime]]) -> None:
|
9
|
+
"""
|
10
|
+
Raise 422 if any not-null argument is a naive `datetime` object:
|
11
|
+
https://docs.python.org/3/library/datetime.html#determining-if-an-object-is-aware-or-naive
|
12
|
+
"""
|
13
|
+
for timestamp in filter(None, timestamps):
|
14
|
+
if (timestamp.tzinfo is None) or (
|
15
|
+
timestamp.tzinfo.utcoffset(timestamp) is None
|
16
|
+
):
|
17
|
+
raise HTTPException(
|
18
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
19
|
+
detail=f"{timestamp=} is naive. You must provide a timezone.",
|
20
|
+
)
|