fractal-server 2.14.0a9__tar.gz → 2.14.0a11__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.14.0a9 → fractal_server-2.14.0a11}/PKG-INFO +1 -1
- fractal_server-2.14.0a11/fractal_server/__init__.py +1 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/dataset.py +0 -10
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/job.py +3 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/__init__.py +2 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/history.py +14 -9
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/images.py +5 -2
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/submit.py +16 -14
- fractal_server-2.14.0a11/fractal_server/app/routes/api/v2/verify_image_types.py +64 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/workflow.py +11 -7
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/components.py +0 -3
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/exceptions.py +4 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/base_runner.py +16 -17
- fractal_server-2.14.0a9/fractal_server/app/runner/executors/local/_local_config.py → fractal_server-2.14.0a11/fractal_server/app/runner/executors/local/get_local_config.py +0 -7
- fractal_server-2.14.0a11/fractal_server/app/runner/executors/local/runner.py +215 -0
- {fractal_server-2.14.0a9/fractal_server/app/runner/executors/slurm_sudo → fractal_server-2.14.0a11/fractal_server/app/runner/executors/slurm_common}/_check_jobs_status.py +4 -0
- fractal_server-2.14.0a11/fractal_server/app/runner/executors/slurm_ssh/_check_job_status_ssh.py +67 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_ssh/executor.py +7 -5
- {fractal_server-2.14.0a9/fractal_server/app/runner/executors/slurm_sudo → fractal_server-2.14.0a11/fractal_server/app/runner/executors/slurm_ssh}/runner.py +191 -124
- fractal_server-2.14.0a11/fractal_server/app/runner/executors/slurm_sudo/runner.py +791 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/task_files.py +8 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/_local.py +4 -2
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/_slurm_ssh.py +4 -2
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/_slurm_sudo.py +4 -2
- fractal_server-2.14.0a11/fractal_server/app/runner/v2/db_tools.py +87 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/runner.py +83 -89
- fractal_server-2.14.0a11/fractal_server/app/runner/v2/runner_functions.py +546 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/runner_functions_low_level.py +37 -39
- fractal_server-2.14.0a9/fractal_server/app/runner/v2/__init__.py → fractal_server-2.14.0a11/fractal_server/app/runner/v2/submit_workflow.py +1 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/task_interface.py +31 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/dataset.py +4 -71
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/dumps.py +6 -5
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/job.py +6 -3
- fractal_server-2.14.0a11/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +50 -0
- fractal_server-2.14.0a11/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +36 -0
- fractal_server-2.14.0a11/fractal_server/tasks/v2/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/pyproject.toml +2 -2
- fractal_server-2.14.0a9/fractal_server/__init__.py +0 -1
- fractal_server-2.14.0a9/fractal_server/app/runner/executors/local/_submit_setup.py +0 -46
- fractal_server-2.14.0a9/fractal_server/app/runner/executors/local/runner.py +0 -156
- fractal_server-2.14.0a9/fractal_server/app/runner/executors/slurm_common/_submit_setup.py +0 -84
- fractal_server-2.14.0a9/fractal_server/app/runner/v2/_db_tools.py +0 -48
- fractal_server-2.14.0a9/fractal_server/app/runner/v2/runner_functions.py +0 -703
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/LICENSE +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/README.md +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/__main__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/alembic.ini +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/db/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/history/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/linkusergroup.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/linkuserproject.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/security.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/user_settings.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/accounting.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/history.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/project.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/task.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/task_group.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/workflow.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/workflowtask.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/job.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/project.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/task.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/dataset.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/job.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/project.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/task.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/task_group.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/current_user.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/group.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/login.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/oauth.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/register.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/router.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/auth/users.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/aux/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/aux/_job.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/aux/_runner.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/pagination.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/compress_folder.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/local/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/remote.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_common/utils_executors.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_ssh/_executor_wait_thread.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_ssh/_slurm_job.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/extract_archive.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/filenames.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/run_subprocess.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/shutdown.py +0 -0
- {fractal_server-2.14.0a9/fractal_server/tasks → fractal_server-2.14.0a11/fractal_server/app/runner}/v2/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/versions.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/_filter_validators.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/_validators.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/user.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/user_group.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/user_settings.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/accounting.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/history.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/manifest.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/project.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/task.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/task_collection.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/task_group.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/workflow.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/security/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/security/signup_email.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/user_settings.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/config.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/data_migrations/README.md +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/data_migrations/tools.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/gunicorn_fractal.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/images/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/images/models.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/images/tools.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/logger.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/main.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/env.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/naming_convention.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/py.typed +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/ssh/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/ssh/_fabric.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/string_tools.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/syringe.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/utils.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/local/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/local/_utils.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/local/collect.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/local/deactivate.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/local/reactivate.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/ssh/collect.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/utils_background.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/utils_database.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/utils_package_names.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/tasks/v2/utils_templates.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/urls.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/utils.py +0 -0
- {fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/zip_tools.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__VERSION__ = "2.14.0a11"
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/models/v2/dataset.py
RENAMED
@@ -11,7 +11,6 @@ from sqlmodel import Relationship
|
|
11
11
|
from sqlmodel import SQLModel
|
12
12
|
|
13
13
|
from ....utils import get_timestamp
|
14
|
-
from fractal_server.images.models import AttributeFiltersType
|
15
14
|
|
16
15
|
|
17
16
|
class DatasetV2(SQLModel, table=True):
|
@@ -34,20 +33,11 @@ class DatasetV2(SQLModel, table=True):
|
|
34
33
|
sa_column=Column(DateTime(timezone=True), nullable=False),
|
35
34
|
)
|
36
35
|
|
37
|
-
# New in V2
|
38
|
-
|
39
36
|
zarr_dir: str
|
40
37
|
images: list[dict[str, Any]] = Field(
|
41
38
|
sa_column=Column(JSON, server_default="[]", nullable=False)
|
42
39
|
)
|
43
40
|
|
44
|
-
type_filters: dict[str, bool] = Field(
|
45
|
-
sa_column=Column(JSON, nullable=False, server_default="{}")
|
46
|
-
)
|
47
|
-
attribute_filters: AttributeFiltersType = Field(
|
48
|
-
sa_column=Column(JSON, nullable=False, server_default="{}")
|
49
|
-
)
|
50
|
-
|
51
41
|
@property
|
52
42
|
def image_zarr_urls(self) -> list[str]:
|
53
43
|
return [image["zarr_url"] for image in self.images]
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/__init__.py
RENAMED
@@ -15,6 +15,7 @@ from .task_collection import router as task_collection_router_v2
|
|
15
15
|
from .task_collection_custom import router as task_collection_router_v2_custom
|
16
16
|
from .task_group import router as task_group_router_v2
|
17
17
|
from .task_group_lifecycle import router as task_group_lifecycle_router_v2
|
18
|
+
from .verify_image_types import router as verify_image_types_router
|
18
19
|
from .workflow import router as workflow_router_v2
|
19
20
|
from .workflow_import import router as workflow_import_router_v2
|
20
21
|
from .workflowtask import router as workflowtask_router_v2
|
@@ -25,6 +26,7 @@ from fractal_server.syringe import Inject
|
|
25
26
|
router_api_v2 = APIRouter()
|
26
27
|
|
27
28
|
router_api_v2.include_router(dataset_router_v2, tags=["V2 Dataset"])
|
29
|
+
router_api_v2.include_router(verify_image_types_router, tags=["V2 Job"])
|
28
30
|
router_api_v2.include_router(job_router_v2, tags=["V2 Job"])
|
29
31
|
router_api_v2.include_router(images_routes_v2, tags=["V2 Images"])
|
30
32
|
router_api_v2.include_router(project_router_v2, tags=["V2 Project"])
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/history.py
RENAMED
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
1
3
|
from fastapi import APIRouter
|
2
4
|
from fastapi import Depends
|
3
5
|
from fastapi import HTTPException
|
@@ -165,6 +167,7 @@ async def get_history_run_units(
|
|
165
167
|
dataset_id: int,
|
166
168
|
workflowtask_id: int,
|
167
169
|
history_run_id: int,
|
170
|
+
unit_status: Optional[HistoryUnitStatus] = None,
|
168
171
|
user: UserOAuth = Depends(current_active_user),
|
169
172
|
db: AsyncSession = Depends(get_async_db),
|
170
173
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
@@ -183,21 +186,23 @@ async def get_history_run_units(
|
|
183
186
|
await get_history_run_or_404(history_run_id=history_run_id, db=db)
|
184
187
|
|
185
188
|
# Count `HistoryUnit`s
|
186
|
-
|
187
|
-
|
188
|
-
HistoryUnit.history_run_id == history_run_id
|
189
|
-
)
|
189
|
+
stmt = select(func.count(HistoryUnit.id)).where(
|
190
|
+
HistoryUnit.history_run_id == history_run_id
|
190
191
|
)
|
192
|
+
if unit_status:
|
193
|
+
stmt = stmt.where(HistoryUnit.status == unit_status)
|
194
|
+
res = await db.execute(stmt)
|
191
195
|
total_count = res.scalar()
|
192
196
|
page_size = pagination.page_size or total_count
|
193
197
|
|
194
198
|
# Query `HistoryUnit`s
|
195
|
-
|
196
|
-
|
197
|
-
.where(HistoryUnit.history_run_id == history_run_id)
|
198
|
-
.offset((pagination.page - 1) * page_size)
|
199
|
-
.limit(page_size)
|
199
|
+
stmt = select(HistoryUnit).where(
|
200
|
+
HistoryUnit.history_run_id == history_run_id
|
200
201
|
)
|
202
|
+
if unit_status:
|
203
|
+
stmt = stmt.where(HistoryUnit.status == unit_status)
|
204
|
+
stmt = stmt.offset((pagination.page - 1) * page_size).limit(page_size)
|
205
|
+
res = await db.execute(stmt)
|
201
206
|
units = res.scalars().all()
|
202
207
|
|
203
208
|
return dict(
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/images.py
RENAMED
@@ -41,7 +41,6 @@ class ImagePage(PaginationResponse[SingleImage]):
|
|
41
41
|
|
42
42
|
|
43
43
|
class ImageQuery(BaseModel):
|
44
|
-
zarr_url: Optional[str] = None
|
45
44
|
type_filters: dict[str, bool] = Field(default_factory=dict)
|
46
45
|
attribute_filters: AttributeFiltersType = Field(default_factory=dict)
|
47
46
|
|
@@ -56,6 +55,10 @@ class ImageQuery(BaseModel):
|
|
56
55
|
)
|
57
56
|
|
58
57
|
|
58
|
+
class ImageQueryWithZarrUrl(ImageQuery):
|
59
|
+
zarr_url: Optional[str] = None
|
60
|
+
|
61
|
+
|
59
62
|
@router.post(
|
60
63
|
"/project/{project_id}/dataset/{dataset_id}/images/",
|
61
64
|
status_code=status.HTTP_201_CREATED,
|
@@ -115,7 +118,7 @@ async def post_new_image(
|
|
115
118
|
async def query_dataset_images(
|
116
119
|
project_id: int,
|
117
120
|
dataset_id: int,
|
118
|
-
query: Optional[
|
121
|
+
query: Optional[ImageQueryWithZarrUrl] = None,
|
119
122
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
120
123
|
user: UserOAuth = Depends(current_active_user),
|
121
124
|
db: AsyncSession = Depends(get_async_db),
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/submit.py
RENAMED
@@ -11,30 +11,32 @@ from fastapi import Request
|
|
11
11
|
from fastapi import status
|
12
12
|
from sqlmodel import select
|
13
13
|
|
14
|
-
from .....config import get_settings
|
15
|
-
from .....logger import set_logger
|
16
|
-
from .....syringe import Inject
|
17
|
-
from ....db import AsyncSession
|
18
|
-
from ....db import get_async_db
|
19
|
-
from ....models.v2 import JobV2
|
20
|
-
from ....runner.set_start_and_last_task_index import (
|
21
|
-
set_start_and_last_task_index,
|
22
|
-
)
|
23
|
-
from ....runner.v2 import submit_workflow
|
24
|
-
from ....schemas.v2 import JobCreateV2
|
25
|
-
from ....schemas.v2 import JobReadV2
|
26
|
-
from ....schemas.v2 import JobStatusTypeV2
|
27
|
-
from ...aux.validate_user_settings import validate_user_settings
|
28
14
|
from ._aux_functions import _get_dataset_check_owner
|
29
15
|
from ._aux_functions import _get_workflow_check_owner
|
30
16
|
from ._aux_functions import clean_app_job_list_v2
|
31
17
|
from ._aux_functions_tasks import _check_type_filters_compatibility
|
18
|
+
from fractal_server.app.db import AsyncSession
|
19
|
+
from fractal_server.app.db import get_async_db
|
32
20
|
from fractal_server.app.models import TaskGroupV2
|
33
21
|
from fractal_server.app.models import UserOAuth
|
22
|
+
from fractal_server.app.models.v2 import JobV2
|
34
23
|
from fractal_server.app.routes.api.v2._aux_functions_tasks import (
|
35
24
|
_get_task_read_access,
|
36
25
|
)
|
37
26
|
from fractal_server.app.routes.auth import current_active_verified_user
|
27
|
+
from fractal_server.app.routes.aux.validate_user_settings import (
|
28
|
+
validate_user_settings,
|
29
|
+
)
|
30
|
+
from fractal_server.app.runner.set_start_and_last_task_index import (
|
31
|
+
set_start_and_last_task_index,
|
32
|
+
)
|
33
|
+
from fractal_server.app.runner.v2.submit_workflow import submit_workflow
|
34
|
+
from fractal_server.app.schemas.v2 import JobCreateV2
|
35
|
+
from fractal_server.app.schemas.v2 import JobReadV2
|
36
|
+
from fractal_server.app.schemas.v2 import JobStatusTypeV2
|
37
|
+
from fractal_server.config import get_settings
|
38
|
+
from fractal_server.logger import set_logger
|
39
|
+
from fractal_server.syringe import Inject
|
38
40
|
|
39
41
|
|
40
42
|
router = APIRouter()
|
@@ -0,0 +1,64 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from fastapi import APIRouter
|
4
|
+
from fastapi import Depends
|
5
|
+
from fastapi import status
|
6
|
+
|
7
|
+
from ._aux_functions import _get_dataset_check_owner
|
8
|
+
from .images import ImageQuery
|
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.routes.auth import current_active_user
|
13
|
+
from fractal_server.images.tools import filter_image_list
|
14
|
+
|
15
|
+
router = APIRouter()
|
16
|
+
|
17
|
+
|
18
|
+
@router.post(
|
19
|
+
"/project/{project_id}/dataset/{dataset_id}/images/verify-unique-types/",
|
20
|
+
status_code=status.HTTP_200_OK,
|
21
|
+
)
|
22
|
+
async def verify_unique_types(
|
23
|
+
project_id: int,
|
24
|
+
dataset_id: int,
|
25
|
+
query: Optional[ImageQuery] = None,
|
26
|
+
user: UserOAuth = Depends(current_active_user),
|
27
|
+
db: AsyncSession = Depends(get_async_db),
|
28
|
+
) -> list[str]:
|
29
|
+
# Get dataset
|
30
|
+
output = await _get_dataset_check_owner(
|
31
|
+
project_id=project_id, dataset_id=dataset_id, user_id=user.id, db=db
|
32
|
+
)
|
33
|
+
dataset = output["dataset"]
|
34
|
+
|
35
|
+
# Filter images
|
36
|
+
if query is None:
|
37
|
+
filtered_images = dataset.images
|
38
|
+
else:
|
39
|
+
filtered_images = filter_image_list(
|
40
|
+
images=dataset.images,
|
41
|
+
attribute_filters=query.attribute_filters,
|
42
|
+
type_filters=query.type_filters,
|
43
|
+
)
|
44
|
+
|
45
|
+
# Get all available types (#FIXME use aux function)
|
46
|
+
available_types = set(
|
47
|
+
_type for _img in filtered_images for _type in _img["types"].keys()
|
48
|
+
)
|
49
|
+
|
50
|
+
# Get actual values for each available type
|
51
|
+
values_per_type: dict[str, set] = {
|
52
|
+
_type: set() for _type in available_types
|
53
|
+
}
|
54
|
+
for _img in filtered_images:
|
55
|
+
for _type in available_types:
|
56
|
+
values_per_type[_type].add(_img["types"].get(_type, False))
|
57
|
+
|
58
|
+
# Find types with non-unique value
|
59
|
+
non_unique_types = [
|
60
|
+
key for key, value in values_per_type.items() if len(value) > 1
|
61
|
+
]
|
62
|
+
non_unique_types = sorted(non_unique_types)
|
63
|
+
|
64
|
+
return non_unique_types
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/routes/api/v2/workflow.py
RENAMED
@@ -290,6 +290,7 @@ async def get_user_workflows(
|
|
290
290
|
|
291
291
|
|
292
292
|
class WorkflowTaskTypeFiltersInfo(BaseModel):
|
293
|
+
workflowtask_id: int
|
293
294
|
current_type_filters: dict[str, bool]
|
294
295
|
input_type_filters: dict[str, bool]
|
295
296
|
output_type_filters: dict[str, bool]
|
@@ -301,7 +302,7 @@ async def get_workflow_type_filters(
|
|
301
302
|
workflow_id: int,
|
302
303
|
user: UserOAuth = Depends(current_active_user),
|
303
304
|
db: AsyncSession = Depends(get_async_db),
|
304
|
-
) ->
|
305
|
+
) -> list[WorkflowTaskTypeFiltersInfo]:
|
305
306
|
"""
|
306
307
|
Get info on type/type-filters flow for a workflow.
|
307
308
|
"""
|
@@ -322,7 +323,7 @@ async def get_workflow_type_filters(
|
|
322
323
|
|
323
324
|
current_type_filters = {}
|
324
325
|
|
325
|
-
|
326
|
+
response_items = []
|
326
327
|
for wftask in workflow.task_list:
|
327
328
|
|
328
329
|
# Compute input_type_filters, based on wftask and task manifest
|
@@ -332,13 +333,16 @@ async def get_workflow_type_filters(
|
|
332
333
|
)
|
333
334
|
|
334
335
|
# Append current item to response list
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
336
|
+
response_items.append(
|
337
|
+
dict(
|
338
|
+
workflowtask_id=wftask.id,
|
339
|
+
current_type_filters=copy(current_type_filters),
|
340
|
+
input_type_filters=copy(input_type_filters),
|
341
|
+
output_type_filters=copy(wftask.task.output_types),
|
342
|
+
)
|
339
343
|
)
|
340
344
|
|
341
345
|
# Update `current_type_filters`
|
342
346
|
current_type_filters.update(wftask.task.output_types)
|
343
347
|
|
344
|
-
return
|
348
|
+
return response_items
|
{fractal_server-2.14.0a9 → fractal_server-2.14.0a11}/fractal_server/app/runner/exceptions.py
RENAMED
@@ -37,6 +37,10 @@ class TaskExecutionError(RuntimeError):
|
|
37
37
|
self.task_name = task_name
|
38
38
|
|
39
39
|
|
40
|
+
class TaskOutputValidationError(ValueError):
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
40
44
|
class JobExecutionError(RuntimeError):
|
41
45
|
"""
|
42
46
|
Forwards errors in the execution of a task that are due to external factors
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
|
-
from fractal_server.app.runner.
|
3
|
+
from fractal_server.app.runner.task_files import TaskFiles
|
4
4
|
from fractal_server.app.schemas.v2.task import TaskTypeType
|
5
5
|
|
6
6
|
|
@@ -29,9 +29,10 @@ class BaseRunner(object):
|
|
29
29
|
self,
|
30
30
|
func: callable,
|
31
31
|
parameters: dict[str, Any],
|
32
|
-
|
32
|
+
history_unit_id: int,
|
33
|
+
task_files: TaskFiles,
|
33
34
|
task_type: TaskTypeType,
|
34
|
-
|
35
|
+
config: Any,
|
35
36
|
) -> tuple[Any, BaseException]:
|
36
37
|
"""
|
37
38
|
Run a single fractal task.
|
@@ -45,7 +46,7 @@ class BaseRunner(object):
|
|
45
46
|
history_item_id:
|
46
47
|
Database ID of the corresponding `HistoryItemV2` entry.
|
47
48
|
task_type: Task type.
|
48
|
-
|
49
|
+
config: Runner-specific parameters.
|
49
50
|
"""
|
50
51
|
raise NotImplementedError()
|
51
52
|
|
@@ -53,9 +54,10 @@ class BaseRunner(object):
|
|
53
54
|
self,
|
54
55
|
func: callable,
|
55
56
|
list_parameters: list[dict[str, Any]],
|
56
|
-
|
57
|
+
history_unit_ids: list[int],
|
58
|
+
list_task_files: list[TaskFiles],
|
57
59
|
task_type: TaskTypeType,
|
58
|
-
|
60
|
+
config: Any,
|
59
61
|
) -> tuple[dict[int, Any], dict[int, BaseException]]:
|
60
62
|
"""
|
61
63
|
Run a parallel fractal task.
|
@@ -70,7 +72,7 @@ class BaseRunner(object):
|
|
70
72
|
history_item_id:
|
71
73
|
Database ID of the corresponding `HistoryItemV2` entry.
|
72
74
|
task_type: Task type.
|
73
|
-
|
75
|
+
config: Runner-specific parameters.
|
74
76
|
"""
|
75
77
|
raise NotImplementedError()
|
76
78
|
|
@@ -101,15 +103,11 @@ class BaseRunner(object):
|
|
101
103
|
f"Forbidden 'zarr_urls' key in {list(parameters.keys())}"
|
102
104
|
)
|
103
105
|
|
104
|
-
if _COMPONENT_KEY_ not in parameters.keys():
|
105
|
-
raise ValueError(
|
106
|
-
f"No '{_COMPONENT_KEY_}' key in in {list(parameters.keys())}"
|
107
|
-
)
|
108
|
-
|
109
106
|
def validate_multisubmit_parameters(
|
110
107
|
self,
|
111
108
|
list_parameters: list[dict[str, Any]],
|
112
109
|
task_type: TaskTypeType,
|
110
|
+
list_task_files: list[TaskFiles],
|
113
111
|
) -> None:
|
114
112
|
"""
|
115
113
|
Validate parameters for `multi_submit` method
|
@@ -121,6 +119,12 @@ class BaseRunner(object):
|
|
121
119
|
if task_type not in TASK_TYPES_MULTISUBMIT:
|
122
120
|
raise ValueError(f"Invalid {task_type=} for `multisubmit`.")
|
123
121
|
|
122
|
+
subfolders = set(
|
123
|
+
task_file.wftask_subfolder_local for task_file in list_task_files
|
124
|
+
)
|
125
|
+
if len(subfolders) != 1:
|
126
|
+
raise ValueError(f"More than one subfolders: {subfolders}.")
|
127
|
+
|
124
128
|
if not isinstance(list_parameters, list):
|
125
129
|
raise ValueError("`parameters` must be a list.")
|
126
130
|
|
@@ -131,11 +135,6 @@ class BaseRunner(object):
|
|
131
135
|
raise ValueError(
|
132
136
|
f"No 'zarr_url' key in in {list(single_kwargs.keys())}"
|
133
137
|
)
|
134
|
-
if _COMPONENT_KEY_ not in single_kwargs.keys():
|
135
|
-
raise ValueError(
|
136
|
-
f"No '{_COMPONENT_KEY_}' key "
|
137
|
-
f"in {list(single_kwargs.keys())}"
|
138
|
-
)
|
139
138
|
if task_type == "parallel":
|
140
139
|
zarr_urls = [kwargs["zarr_url"] for kwargs in list_parameters]
|
141
140
|
if len(zarr_urls) != len(set(zarr_urls)):
|
@@ -48,13 +48,6 @@ class LocalBackendConfig(BaseModel):
|
|
48
48
|
parallel_tasks_per_job: Optional[int] = None
|
49
49
|
|
50
50
|
|
51
|
-
def get_default_local_backend_config():
|
52
|
-
"""
|
53
|
-
Return a default `LocalBackendConfig` configuration object
|
54
|
-
"""
|
55
|
-
return LocalBackendConfig(parallel_tasks_per_job=None)
|
56
|
-
|
57
|
-
|
58
51
|
def get_local_backend_config(
|
59
52
|
wftask: WorkflowTaskV2,
|
60
53
|
which_type: Literal["non_parallel", "parallel"],
|
@@ -0,0 +1,215 @@
|
|
1
|
+
from concurrent.futures import Future
|
2
|
+
from concurrent.futures import ThreadPoolExecutor
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Any
|
5
|
+
from typing import Literal
|
6
|
+
|
7
|
+
from .get_local_config import LocalBackendConfig
|
8
|
+
from fractal_server.app.db import get_sync_db
|
9
|
+
from fractal_server.app.runner.executors.base_runner import BaseRunner
|
10
|
+
from fractal_server.app.runner.task_files import TaskFiles
|
11
|
+
from fractal_server.app.runner.v2.db_tools import update_status_of_history_unit
|
12
|
+
from fractal_server.app.schemas.v2 import HistoryUnitStatus
|
13
|
+
from fractal_server.logger import set_logger
|
14
|
+
|
15
|
+
logger = set_logger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
class LocalRunner(BaseRunner):
|
19
|
+
executor: ThreadPoolExecutor
|
20
|
+
root_dir_local: Path
|
21
|
+
|
22
|
+
def __init__(
|
23
|
+
self,
|
24
|
+
root_dir_local: Path,
|
25
|
+
):
|
26
|
+
|
27
|
+
self.root_dir_local = root_dir_local
|
28
|
+
self.root_dir_local.mkdir(parents=True, exist_ok=True)
|
29
|
+
self.executor = ThreadPoolExecutor()
|
30
|
+
logger.debug("Create LocalRunner")
|
31
|
+
|
32
|
+
def __enter__(self):
|
33
|
+
logger.debug("Enter LocalRunner")
|
34
|
+
return self
|
35
|
+
|
36
|
+
def shutdown(self):
|
37
|
+
logger.debug("Now shut LocalRunner.executor down")
|
38
|
+
self.executor.shutdown(
|
39
|
+
wait=False,
|
40
|
+
cancel_futures=True,
|
41
|
+
)
|
42
|
+
|
43
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
44
|
+
logger.debug("Exit LocalRunner")
|
45
|
+
self.shutdown()
|
46
|
+
return self.executor.__exit__(exc_type, exc_val, exc_tb)
|
47
|
+
|
48
|
+
def submit(
|
49
|
+
self,
|
50
|
+
func: callable,
|
51
|
+
parameters: dict[str, Any],
|
52
|
+
history_unit_id: int,
|
53
|
+
task_files: TaskFiles,
|
54
|
+
task_type: Literal[
|
55
|
+
"non_parallel",
|
56
|
+
"converter_non_parallel",
|
57
|
+
"compound",
|
58
|
+
"converter_compound",
|
59
|
+
],
|
60
|
+
config: LocalBackendConfig,
|
61
|
+
) -> tuple[Any, Exception]:
|
62
|
+
logger.debug("[submit] START")
|
63
|
+
|
64
|
+
self.validate_submit_parameters(parameters, task_type=task_type)
|
65
|
+
workdir_local = task_files.wftask_subfolder_local
|
66
|
+
workdir_local.mkdir()
|
67
|
+
|
68
|
+
# SUBMISSION PHASE
|
69
|
+
future = self.executor.submit(
|
70
|
+
func,
|
71
|
+
parameters=parameters,
|
72
|
+
remote_files=task_files.remote_files_dict,
|
73
|
+
)
|
74
|
+
|
75
|
+
# RETRIEVAL PHASE
|
76
|
+
with next(get_sync_db()) as db:
|
77
|
+
try:
|
78
|
+
result = future.result()
|
79
|
+
logger.debug("[submit] END with result")
|
80
|
+
if task_type not in ["compound", "converter_compound"]:
|
81
|
+
update_status_of_history_unit(
|
82
|
+
history_unit_id=history_unit_id,
|
83
|
+
status=HistoryUnitStatus.DONE,
|
84
|
+
db_sync=db,
|
85
|
+
)
|
86
|
+
return result, None
|
87
|
+
except Exception as e:
|
88
|
+
exception = e
|
89
|
+
logger.debug("[submit] END with exception")
|
90
|
+
update_status_of_history_unit(
|
91
|
+
history_unit_id=history_unit_id,
|
92
|
+
status=HistoryUnitStatus.FAILED,
|
93
|
+
db_sync=db,
|
94
|
+
)
|
95
|
+
|
96
|
+
return None, exception
|
97
|
+
|
98
|
+
def multisubmit(
|
99
|
+
self,
|
100
|
+
func: callable,
|
101
|
+
list_parameters: list[dict],
|
102
|
+
history_unit_ids: list[int],
|
103
|
+
list_task_files: list[TaskFiles],
|
104
|
+
task_type: Literal["parallel", "compound", "converter_compound"],
|
105
|
+
config: LocalBackendConfig,
|
106
|
+
):
|
107
|
+
"""
|
108
|
+
Note:
|
109
|
+
|
110
|
+
1. The number of sruns and futures is equal to `len(list_parameters)`.
|
111
|
+
2. The number of `HistoryUnit`s is equal to `len(history_unit_ids)`.
|
112
|
+
3. For compound tasks, these two numbers are not the same.
|
113
|
+
|
114
|
+
For this reason, we defer database updates to the caller function,
|
115
|
+
when we are in one of the "compound" cases
|
116
|
+
|
117
|
+
"""
|
118
|
+
# FIXME: De-duplicate this check
|
119
|
+
if task_type in ["compound", "converter_compound"]:
|
120
|
+
if len(history_unit_ids) != 1:
|
121
|
+
raise NotImplementedError(
|
122
|
+
"We are breaking the assumption that compound/multisubmit "
|
123
|
+
"is associated to a single HistoryUnit. This is not "
|
124
|
+
"supported."
|
125
|
+
)
|
126
|
+
elif task_type == "parallel" and len(history_unit_ids) != len(
|
127
|
+
list_parameters
|
128
|
+
):
|
129
|
+
raise ValueError(
|
130
|
+
f"{len(history_unit_ids)=} differs from "
|
131
|
+
f"{len(list_parameters)=}."
|
132
|
+
)
|
133
|
+
|
134
|
+
logger.debug(f"[multisubmit] START, {len(list_parameters)=}")
|
135
|
+
|
136
|
+
self.validate_multisubmit_parameters(
|
137
|
+
list_parameters=list_parameters,
|
138
|
+
task_type=task_type,
|
139
|
+
list_task_files=list_task_files,
|
140
|
+
)
|
141
|
+
|
142
|
+
workdir_local = list_task_files[0].wftask_subfolder_local
|
143
|
+
if task_type == "parallel":
|
144
|
+
workdir_local.mkdir()
|
145
|
+
|
146
|
+
# Set `n_elements` and `parallel_tasks_per_job`
|
147
|
+
n_elements = len(list_parameters)
|
148
|
+
parallel_tasks_per_job = config.parallel_tasks_per_job
|
149
|
+
if parallel_tasks_per_job is None:
|
150
|
+
parallel_tasks_per_job = n_elements
|
151
|
+
|
152
|
+
# Execute tasks, in chunks of size `parallel_tasks_per_job`
|
153
|
+
results: dict[int, Any] = {}
|
154
|
+
exceptions: dict[int, BaseException] = {}
|
155
|
+
for ind_chunk in range(0, n_elements, parallel_tasks_per_job):
|
156
|
+
list_parameters_chunk = list_parameters[
|
157
|
+
ind_chunk : ind_chunk + parallel_tasks_per_job
|
158
|
+
]
|
159
|
+
|
160
|
+
active_futures: dict[int, Future] = {}
|
161
|
+
for ind_within_chunk, kwargs in enumerate(list_parameters_chunk):
|
162
|
+
positional_index = ind_chunk + ind_within_chunk
|
163
|
+
future = self.executor.submit(
|
164
|
+
func,
|
165
|
+
parameters=kwargs,
|
166
|
+
remote_files=list_task_files[
|
167
|
+
positional_index
|
168
|
+
].remote_files_dict,
|
169
|
+
)
|
170
|
+
active_futures[positional_index] = future
|
171
|
+
|
172
|
+
while active_futures:
|
173
|
+
# FIXME: add shutdown detection
|
174
|
+
# if file exists: cancel all futures, and raise
|
175
|
+
finished_futures = [
|
176
|
+
index_and_future
|
177
|
+
for index_and_future in active_futures.items()
|
178
|
+
if not index_and_future[1].running()
|
179
|
+
]
|
180
|
+
if len(finished_futures) == 0:
|
181
|
+
continue
|
182
|
+
|
183
|
+
with next(get_sync_db()) as db:
|
184
|
+
for positional_index, fut in finished_futures:
|
185
|
+
active_futures.pop(positional_index)
|
186
|
+
if task_type == "parallel":
|
187
|
+
current_history_unit_id = history_unit_ids[
|
188
|
+
positional_index
|
189
|
+
]
|
190
|
+
|
191
|
+
try:
|
192
|
+
results[positional_index] = fut.result()
|
193
|
+
if task_type == "parallel":
|
194
|
+
update_status_of_history_unit(
|
195
|
+
history_unit_id=current_history_unit_id,
|
196
|
+
status=HistoryUnitStatus.DONE,
|
197
|
+
db_sync=db,
|
198
|
+
)
|
199
|
+
|
200
|
+
except Exception as e:
|
201
|
+
exceptions[positional_index] = e
|
202
|
+
if task_type == "parallel":
|
203
|
+
update_status_of_history_unit(
|
204
|
+
history_unit_id=current_history_unit_id,
|
205
|
+
status=HistoryUnitStatus.FAILED,
|
206
|
+
db_sync=db,
|
207
|
+
)
|
208
|
+
|
209
|
+
# FIXME: what should happen here? Option 1: stop
|
210
|
+
# all existing tasks and shutdown runner (for the
|
211
|
+
# compound-task case)
|
212
|
+
|
213
|
+
logger.debug(f"[multisubmit] END, {results=}, {exceptions=}")
|
214
|
+
|
215
|
+
return results, exceptions
|
@@ -32,6 +32,10 @@ def run_squeue(job_ids: list[str]) -> subprocess.CompletedProcess:
|
|
32
32
|
return res
|
33
33
|
|
34
34
|
|
35
|
+
def are_all_jobs_on_squeue(job_ids: list[str]) -> bool:
|
36
|
+
pass
|
37
|
+
|
38
|
+
|
35
39
|
def get_finished_jobs(job_ids: list[str]) -> set[str]:
|
36
40
|
"""
|
37
41
|
Check which ones of the given Slurm jobs already finished
|