fractal-server 2.15.0a5__tar.gz → 2.15.2__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.15.0a5 → fractal_server-2.15.2}/PKG-INFO +1 -1
- fractal_server-2.15.2/fractal_server/__init__.py +1 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/db/__init__.py +2 -6
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/security.py +2 -2
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/user_settings.py +2 -2
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/dataset.py +3 -3
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/job.py +6 -6
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/task.py +5 -4
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/task_group.py +2 -2
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/workflowtask.py +5 -4
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/job.py +8 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_functions.py +18 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/workflow.py +13 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/workflowtask.py +10 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +10 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +85 -18
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +8 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/remote.py +9 -9
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/_slurm_ssh.py +0 -13
- fractal_server-2.15.2/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +264 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/ssh/_fabric.py +6 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/collect_pixi.py +1 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/reactivate_pixi.py +1 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/collect_pixi.py +6 -3
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +7 -4
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +1 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/pixi_2_install.sh +2 -2
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +1 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/pyproject.toml +3 -3
- fractal_server-2.15.0a5/fractal_server/__init__.py +0 -1
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/LICENSE +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/README.md +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/__main__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/alembic.ini +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/linkusergroup.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/linkuserproject.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/accounting.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/history.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/project.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/workflow.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/project.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/task.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/dataset.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/history.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/images.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/job.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/project.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/submit.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task_collection_pixi.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task_group.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/current_user.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/group.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/login.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/oauth.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/register.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/router.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/auth/users.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/aux/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/aux/_job.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/aux/_runner.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/pagination.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/components.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/exceptions.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/base_runner.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/call_command_wrapper.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/local/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/local/get_local_config.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/local/runner.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_ssh/run_subprocess.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_ssh/runner.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_ssh/tar_commands.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/executors/slurm_sudo/runner.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/filenames.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/shutdown.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/task_files.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/_local.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/_slurm_sudo.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/db_tools.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/runner.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/runner_functions.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/submit_workflow.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/task_interface.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/versions.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/user.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/user_group.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/user_settings.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/accounting.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/dataset.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/dumps.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/history.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/job.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/manifest.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/project.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/task.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/task_collection.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/task_group.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/workflow.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/security/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/security/signup_email.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/user_settings.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/config.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/data_migrations/2_14_10.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/data_migrations/README.md +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/data_migrations/tools.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/exceptions.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/gunicorn_fractal.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/images/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/images/models.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/images/status_tools.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/images/tools.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/logger.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/main.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/env.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/naming_convention.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/py.typed +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/ssh/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/string_tools.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/syringe.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/utils.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/_utils.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/collect.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/deactivate.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/local/reactivate.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/collect.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/utils_background.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/utils_database.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/utils_package_names.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/utils_pixi.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/tasks/v2/utils_templates.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/types/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/types/validators/__init__.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/types/validators/_common_validators.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/types/validators/_filter_validators.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/urls.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/utils.py +0 -0
- {fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/zip_tools.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__VERSION__ = "2.15.2"
|
|
@@ -45,13 +45,11 @@ class DB:
|
|
|
45
45
|
settings = Inject(get_settings)
|
|
46
46
|
settings.check_db()
|
|
47
47
|
|
|
48
|
-
engine_kwargs_async = {"pool_pre_ping": True}
|
|
49
|
-
|
|
50
48
|
cls._engine_async = create_async_engine(
|
|
51
49
|
settings.DATABASE_ASYNC_URL,
|
|
52
50
|
echo=settings.DB_ECHO,
|
|
53
51
|
future=True,
|
|
54
|
-
|
|
52
|
+
pool_pre_ping=True,
|
|
55
53
|
)
|
|
56
54
|
cls._async_session_maker = sessionmaker(
|
|
57
55
|
cls._engine_async,
|
|
@@ -65,13 +63,11 @@ class DB:
|
|
|
65
63
|
settings = Inject(get_settings)
|
|
66
64
|
settings.check_db()
|
|
67
65
|
|
|
68
|
-
engine_kwargs_sync = {}
|
|
69
|
-
|
|
70
66
|
cls._engine_sync = create_engine(
|
|
71
67
|
settings.DATABASE_SYNC_URL,
|
|
72
68
|
echo=settings.DB_ECHO,
|
|
73
69
|
future=True,
|
|
74
|
-
|
|
70
|
+
pool_pre_ping=True,
|
|
75
71
|
)
|
|
76
72
|
|
|
77
73
|
cls._sync_session_maker = sessionmaker(
|
|
@@ -15,8 +15,8 @@ from typing import Optional
|
|
|
15
15
|
from pydantic import ConfigDict
|
|
16
16
|
from pydantic import EmailStr
|
|
17
17
|
from sqlalchemy import Column
|
|
18
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
18
19
|
from sqlalchemy.types import DateTime
|
|
19
|
-
from sqlalchemy.types import JSON
|
|
20
20
|
from sqlmodel import Field
|
|
21
21
|
from sqlmodel import Relationship
|
|
22
22
|
from sqlmodel import SQLModel
|
|
@@ -124,5 +124,5 @@ class UserGroup(SQLModel, table=True):
|
|
|
124
124
|
sa_column=Column(DateTime(timezone=True), nullable=False),
|
|
125
125
|
)
|
|
126
126
|
viewer_paths: list[str] = Field(
|
|
127
|
-
sa_column=Column(
|
|
127
|
+
sa_column=Column(JSONB, server_default="[]", nullable=False)
|
|
128
128
|
)
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/user_settings.py
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from sqlalchemy import Column
|
|
2
|
-
from sqlalchemy.
|
|
2
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
3
3
|
from sqlmodel import Field
|
|
4
4
|
from sqlmodel import SQLModel
|
|
5
5
|
|
|
@@ -25,7 +25,7 @@ class UserSettings(SQLModel, table=True):
|
|
|
25
25
|
|
|
26
26
|
id: int | None = Field(default=None, primary_key=True)
|
|
27
27
|
slurm_accounts: list[str] = Field(
|
|
28
|
-
sa_column=Column(
|
|
28
|
+
sa_column=Column(JSONB, server_default="[]", nullable=False)
|
|
29
29
|
)
|
|
30
30
|
ssh_host: str | None = None
|
|
31
31
|
ssh_username: str | None = None
|
|
@@ -3,8 +3,8 @@ from typing import Any
|
|
|
3
3
|
|
|
4
4
|
from pydantic import ConfigDict
|
|
5
5
|
from sqlalchemy import Column
|
|
6
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
6
7
|
from sqlalchemy.types import DateTime
|
|
7
|
-
from sqlalchemy.types import JSON
|
|
8
8
|
from sqlmodel import Field
|
|
9
9
|
from sqlmodel import Relationship
|
|
10
10
|
from sqlmodel import SQLModel
|
|
@@ -24,7 +24,7 @@ class DatasetV2(SQLModel, table=True):
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
history: list[dict[str, Any]] = Field(
|
|
27
|
-
sa_column=Column(
|
|
27
|
+
sa_column=Column(JSONB, server_default="[]", nullable=False)
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
timestamp_created: datetime = Field(
|
|
@@ -34,7 +34,7 @@ class DatasetV2(SQLModel, table=True):
|
|
|
34
34
|
|
|
35
35
|
zarr_dir: str
|
|
36
36
|
images: list[dict[str, Any]] = Field(
|
|
37
|
-
sa_column=Column(
|
|
37
|
+
sa_column=Column(JSONB, server_default="[]", nullable=False)
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
@property
|
|
@@ -3,8 +3,8 @@ from typing import Any
|
|
|
3
3
|
|
|
4
4
|
from pydantic import ConfigDict
|
|
5
5
|
from sqlalchemy import Column
|
|
6
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
6
7
|
from sqlalchemy.types import DateTime
|
|
7
|
-
from sqlalchemy.types import JSON
|
|
8
8
|
from sqlmodel import Field
|
|
9
9
|
from sqlmodel import SQLModel
|
|
10
10
|
|
|
@@ -31,13 +31,13 @@ class JobV2(SQLModel, table=True):
|
|
|
31
31
|
slurm_account: str | None = None
|
|
32
32
|
|
|
33
33
|
dataset_dump: dict[str, Any] = Field(
|
|
34
|
-
sa_column=Column(
|
|
34
|
+
sa_column=Column(JSONB, nullable=False)
|
|
35
35
|
)
|
|
36
36
|
workflow_dump: dict[str, Any] = Field(
|
|
37
|
-
sa_column=Column(
|
|
37
|
+
sa_column=Column(JSONB, nullable=False)
|
|
38
38
|
)
|
|
39
39
|
project_dump: dict[str, Any] = Field(
|
|
40
|
-
sa_column=Column(
|
|
40
|
+
sa_column=Column(JSONB, nullable=False)
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
worker_init: str | None = None
|
|
@@ -57,8 +57,8 @@ class JobV2(SQLModel, table=True):
|
|
|
57
57
|
log: str | None = None
|
|
58
58
|
|
|
59
59
|
attribute_filters: AttributeFilters = Field(
|
|
60
|
-
sa_column=Column(
|
|
60
|
+
sa_column=Column(JSONB, nullable=False, server_default="{}")
|
|
61
61
|
)
|
|
62
62
|
type_filters: dict[str, bool] = Field(
|
|
63
|
-
sa_column=Column(
|
|
63
|
+
sa_column=Column(JSONB, nullable=False, server_default="{}")
|
|
64
64
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
3
|
from sqlalchemy import Column
|
|
4
|
-
from sqlalchemy.
|
|
4
|
+
from sqlalchemy.dialects.postgresql import JSON
|
|
5
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
5
6
|
from sqlmodel import Field
|
|
6
7
|
from sqlmodel import SQLModel
|
|
7
8
|
|
|
@@ -33,8 +34,8 @@ class TaskV2(SQLModel, table=True):
|
|
|
33
34
|
docs_info: str | None = None
|
|
34
35
|
docs_link: str | None = None
|
|
35
36
|
|
|
36
|
-
input_types: dict[str, bool] = Field(sa_column=Column(
|
|
37
|
-
output_types: dict[str, bool] = Field(sa_column=Column(
|
|
37
|
+
input_types: dict[str, bool] = Field(sa_column=Column(JSONB), default={})
|
|
38
|
+
output_types: dict[str, bool] = Field(sa_column=Column(JSONB), default={})
|
|
38
39
|
|
|
39
40
|
taskgroupv2_id: int = Field(foreign_key="taskgroupv2.id")
|
|
40
41
|
|
|
@@ -42,5 +43,5 @@ class TaskV2(SQLModel, table=True):
|
|
|
42
43
|
modality: str | None = None
|
|
43
44
|
authors: str | None = None
|
|
44
45
|
tags: list[str] = Field(
|
|
45
|
-
sa_column=Column(
|
|
46
|
+
sa_column=Column(JSONB, server_default="[]", nullable=False)
|
|
46
47
|
)
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/task_group.py
RENAMED
|
@@ -2,8 +2,8 @@ from datetime import datetime
|
|
|
2
2
|
from datetime import timezone
|
|
3
3
|
|
|
4
4
|
from sqlalchemy import Column
|
|
5
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
5
6
|
from sqlalchemy.types import DateTime
|
|
6
|
-
from sqlalchemy.types import JSON
|
|
7
7
|
from sqlmodel import Field
|
|
8
8
|
from sqlmodel import Relationship
|
|
9
9
|
from sqlmodel import SQLModel
|
|
@@ -35,7 +35,7 @@ class TaskGroupV2(SQLModel, table=True):
|
|
|
35
35
|
pip_extras: str | None = None
|
|
36
36
|
pinned_package_versions: dict[str, str] = Field(
|
|
37
37
|
sa_column=Column(
|
|
38
|
-
|
|
38
|
+
JSONB,
|
|
39
39
|
server_default="{}",
|
|
40
40
|
default={},
|
|
41
41
|
nullable=True,
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/models/v2/workflowtask.py
RENAMED
|
@@ -2,7 +2,8 @@ from typing import Any
|
|
|
2
2
|
|
|
3
3
|
from pydantic import ConfigDict
|
|
4
4
|
from sqlalchemy import Column
|
|
5
|
-
from sqlalchemy.
|
|
5
|
+
from sqlalchemy.dialects.postgresql import JSON
|
|
6
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
6
7
|
from sqlmodel import Field
|
|
7
8
|
from sqlmodel import Relationship
|
|
8
9
|
from sqlmodel import SQLModel
|
|
@@ -24,14 +25,14 @@ class WorkflowTaskV2(SQLModel, table=True):
|
|
|
24
25
|
sa_column=Column(JSON), default=None
|
|
25
26
|
)
|
|
26
27
|
args_parallel: dict[str, Any] | None = Field(
|
|
27
|
-
sa_column=Column(
|
|
28
|
+
sa_column=Column(JSONB), default=None
|
|
28
29
|
)
|
|
29
30
|
args_non_parallel: dict[str, Any] | None = Field(
|
|
30
|
-
sa_column=Column(
|
|
31
|
+
sa_column=Column(JSONB), default=None
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
type_filters: dict[str, bool] = Field(
|
|
34
|
-
sa_column=Column(
|
|
35
|
+
sa_column=Column(JSONB, nullable=False, server_default="{}")
|
|
35
36
|
)
|
|
36
37
|
|
|
37
38
|
# Task
|
|
@@ -156,8 +156,15 @@ async def update_job(
|
|
|
156
156
|
detail=f"Cannot set job status to {job_update.status}",
|
|
157
157
|
)
|
|
158
158
|
|
|
159
|
+
timestamp = get_timestamp()
|
|
159
160
|
setattr(job, "status", job_update.status)
|
|
160
|
-
setattr(job, "end_timestamp",
|
|
161
|
+
setattr(job, "end_timestamp", timestamp)
|
|
162
|
+
setattr(
|
|
163
|
+
job,
|
|
164
|
+
"log",
|
|
165
|
+
f"{job.log or ''}\nThis job was manually marked as "
|
|
166
|
+
f"'{JobStatusTypeV2.FAILED}' by an admin ({timestamp.isoformat()}).",
|
|
167
|
+
)
|
|
161
168
|
await db.commit()
|
|
162
169
|
await db.refresh(job)
|
|
163
170
|
await db.close()
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/_aux_functions.py
RENAMED
|
@@ -325,6 +325,24 @@ def _get_submitted_jobs_statement() -> SelectOfScalar:
|
|
|
325
325
|
return stm
|
|
326
326
|
|
|
327
327
|
|
|
328
|
+
async def _workflow_has_submitted_job(
|
|
329
|
+
workflow_id: int,
|
|
330
|
+
db: AsyncSession,
|
|
331
|
+
) -> bool:
|
|
332
|
+
|
|
333
|
+
res = await db.execute(
|
|
334
|
+
select(JobV2.id)
|
|
335
|
+
.where(JobV2.status == JobStatusTypeV2.SUBMITTED)
|
|
336
|
+
.where(JobV2.workflow_id == workflow_id)
|
|
337
|
+
.limit(1)
|
|
338
|
+
)
|
|
339
|
+
submitted_jobs = res.scalar_one_or_none()
|
|
340
|
+
if submitted_jobs is not None:
|
|
341
|
+
return True
|
|
342
|
+
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
|
|
328
346
|
async def _workflow_insert_task(
|
|
329
347
|
*,
|
|
330
348
|
workflow_id: int,
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/workflow.py
RENAMED
|
@@ -22,6 +22,7 @@ from ._aux_functions import _check_workflow_exists
|
|
|
22
22
|
from ._aux_functions import _get_project_check_owner
|
|
23
23
|
from ._aux_functions import _get_submitted_jobs_statement
|
|
24
24
|
from ._aux_functions import _get_workflow_check_owner
|
|
25
|
+
from ._aux_functions import _workflow_has_submitted_job
|
|
25
26
|
from ._aux_functions_tasks import _add_warnings_to_workflow_tasks
|
|
26
27
|
from fractal_server.app.models import UserOAuth
|
|
27
28
|
from fractal_server.app.models.v2 import TaskGroupV2
|
|
@@ -146,6 +147,18 @@ async def update_workflow(
|
|
|
146
147
|
|
|
147
148
|
for key, value in patch.model_dump(exclude_unset=True).items():
|
|
148
149
|
if key == "reordered_workflowtask_ids":
|
|
150
|
+
|
|
151
|
+
if await _workflow_has_submitted_job(
|
|
152
|
+
workflow_id=workflow_id, db=db
|
|
153
|
+
):
|
|
154
|
+
raise HTTPException(
|
|
155
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
156
|
+
detail=(
|
|
157
|
+
"Cannot re-order WorkflowTasks while a Job is running "
|
|
158
|
+
"for this Workflow."
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
|
|
149
162
|
current_workflowtask_ids = [
|
|
150
163
|
wftask.id for wftask in workflow.task_list
|
|
151
164
|
]
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/routes/api/v2/workflowtask.py
RENAMED
|
@@ -10,6 +10,7 @@ from ....db import AsyncSession
|
|
|
10
10
|
from ....db import get_async_db
|
|
11
11
|
from ._aux_functions import _get_workflow_check_owner
|
|
12
12
|
from ._aux_functions import _get_workflow_task_check_owner
|
|
13
|
+
from ._aux_functions import _workflow_has_submitted_job
|
|
13
14
|
from ._aux_functions import _workflow_insert_task
|
|
14
15
|
from ._aux_functions_tasks import _check_type_filters_compatibility
|
|
15
16
|
from ._aux_functions_tasks import _get_task_read_access
|
|
@@ -224,6 +225,15 @@ async def delete_workflowtask(
|
|
|
224
225
|
db=db,
|
|
225
226
|
)
|
|
226
227
|
|
|
228
|
+
if await _workflow_has_submitted_job(workflow_id=workflow_id, db=db):
|
|
229
|
+
raise HTTPException(
|
|
230
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
231
|
+
detail=(
|
|
232
|
+
"Cannot delete a WorkflowTask while a Job is running for this "
|
|
233
|
+
"Workflow."
|
|
234
|
+
),
|
|
235
|
+
)
|
|
236
|
+
|
|
227
237
|
# Delete WorkflowTask
|
|
228
238
|
await db.delete(db_workflow_task)
|
|
229
239
|
await db.commit()
|
|
@@ -48,6 +48,8 @@ class _SlurmConfigSet(BaseModel):
|
|
|
48
48
|
constraint:
|
|
49
49
|
gres:
|
|
50
50
|
time:
|
|
51
|
+
exclude:
|
|
52
|
+
nodelist:
|
|
51
53
|
account:
|
|
52
54
|
extra_lines:
|
|
53
55
|
"""
|
|
@@ -59,6 +61,8 @@ class _SlurmConfigSet(BaseModel):
|
|
|
59
61
|
mem: int | str | None = None
|
|
60
62
|
constraint: str | None = None
|
|
61
63
|
gres: str | None = None
|
|
64
|
+
exclude: str | None = None
|
|
65
|
+
nodelist: str | None = None
|
|
62
66
|
time: str | None = None
|
|
63
67
|
account: str | None = None
|
|
64
68
|
extra_lines: list[str] | None = None
|
|
@@ -227,6 +231,8 @@ class SlurmConfig(BaseModel):
|
|
|
227
231
|
account: Corresponds to SLURM option.
|
|
228
232
|
gpus: Corresponds to SLURM option.
|
|
229
233
|
time: Corresponds to SLURM option (WARNING: not fully supported).
|
|
234
|
+
nodelist: Corresponds to SLURM option.
|
|
235
|
+
exclude: Corresponds to SLURM option.
|
|
230
236
|
prefix: Prefix of configuration lines in SLURM submission scripts.
|
|
231
237
|
shebang_line: Shebang line for SLURM submission scripts.
|
|
232
238
|
extra_lines: Additional lines to include in SLURM submission scripts.
|
|
@@ -268,6 +274,8 @@ class SlurmConfig(BaseModel):
|
|
|
268
274
|
gpus: str | None = None
|
|
269
275
|
time: str | None = None
|
|
270
276
|
account: str | None = None
|
|
277
|
+
nodelist: str | None = None
|
|
278
|
+
exclude: str | None = None
|
|
271
279
|
|
|
272
280
|
# Free-field attribute for extra lines to be added to the SLURM job
|
|
273
281
|
# preamble
|
|
@@ -361,6 +369,8 @@ class SlurmConfig(BaseModel):
|
|
|
361
369
|
"gpus",
|
|
362
370
|
"time",
|
|
363
371
|
"account",
|
|
372
|
+
"exclude",
|
|
373
|
+
"nodelist",
|
|
364
374
|
]:
|
|
365
375
|
value = getattr(self, key)
|
|
366
376
|
if value is not None:
|
|
@@ -137,6 +137,34 @@ class BaseSlurmRunner(BaseRunner):
|
|
|
137
137
|
def run_squeue(self, *, job_ids: list[str], **kwargs) -> str:
|
|
138
138
|
raise NotImplementedError("Implement in child class.")
|
|
139
139
|
|
|
140
|
+
def _is_squeue_error_recoverable(self, exception: BaseException) -> True:
|
|
141
|
+
"""
|
|
142
|
+
Determine whether a `squeue` error is considered recoverable.
|
|
143
|
+
|
|
144
|
+
A _recoverable_ error is one which will disappear after some time,
|
|
145
|
+
without any specific action from the `fractal-server` side.
|
|
146
|
+
|
|
147
|
+
Note: if this function returns `True` for an error that does not
|
|
148
|
+
actually recover, this leads to an infinite loop where
|
|
149
|
+
`fractal-server` keeps polling `squeue` information forever.
|
|
150
|
+
|
|
151
|
+
More info at
|
|
152
|
+
https://github.com/fractal-analytics-platform/fractal-server/issues/2682
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
exception: The exception raised by `self.run_squeue`.
|
|
156
|
+
Returns:
|
|
157
|
+
Whether the error is considered recoverable.
|
|
158
|
+
"""
|
|
159
|
+
str_exception = str(exception)
|
|
160
|
+
if (
|
|
161
|
+
"slurm_load_jobs" in str_exception
|
|
162
|
+
and "Socket timed out on send/recv operation" in str_exception
|
|
163
|
+
):
|
|
164
|
+
return True
|
|
165
|
+
else:
|
|
166
|
+
return False
|
|
167
|
+
|
|
140
168
|
def _get_finished_jobs(self, job_ids: list[str]) -> set[str]:
|
|
141
169
|
# If there is no Slurm job to check, return right away
|
|
142
170
|
if not job_ids:
|
|
@@ -161,12 +189,26 @@ class BaseSlurmRunner(BaseRunner):
|
|
|
161
189
|
{stdout.split()[0]: stdout.split()[1]}
|
|
162
190
|
)
|
|
163
191
|
except Exception as e:
|
|
164
|
-
|
|
165
|
-
"[_get_finished_jobs] `squeue` failed for "
|
|
166
|
-
f"{job_id=}, mark job as completed. "
|
|
192
|
+
msg = (
|
|
193
|
+
f"[_get_finished_jobs] `squeue` failed for {job_id=}. "
|
|
167
194
|
f"Original error: {str(e)}."
|
|
168
195
|
)
|
|
169
|
-
|
|
196
|
+
logger.warning(msg)
|
|
197
|
+
if self._is_squeue_error_recoverable(e):
|
|
198
|
+
logger.warning(
|
|
199
|
+
"[_get_finished_jobs] Recoverable `squeue` "
|
|
200
|
+
f"error - mark {job_id=} as FRACTAL_UNDEFINED and"
|
|
201
|
+
" retry later."
|
|
202
|
+
)
|
|
203
|
+
slurm_statuses.update(
|
|
204
|
+
{str(job_id): "FRACTAL_UNDEFINED"}
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
logger.warning(
|
|
208
|
+
"[_get_finished_jobs] Non-recoverable `squeue`"
|
|
209
|
+
f"error - mark {job_id=} as completed."
|
|
210
|
+
)
|
|
211
|
+
slurm_statuses.update({str(job_id): "COMPLETED"})
|
|
170
212
|
|
|
171
213
|
# If a job is not in `squeue` output, mark it as completed.
|
|
172
214
|
finished_jobs = {
|
|
@@ -182,33 +224,53 @@ class BaseSlurmRunner(BaseRunner):
|
|
|
182
224
|
def _mkdir_remote_folder(self, folder: str) -> None:
|
|
183
225
|
raise NotImplementedError("Implement in child class.")
|
|
184
226
|
|
|
185
|
-
def
|
|
227
|
+
def _enrich_slurm_config(
|
|
186
228
|
self,
|
|
187
|
-
*,
|
|
188
|
-
base_command: str,
|
|
189
|
-
slurm_job: SlurmJob,
|
|
190
229
|
slurm_config: SlurmConfig,
|
|
191
|
-
) ->
|
|
192
|
-
|
|
230
|
+
) -> SlurmConfig:
|
|
231
|
+
"""
|
|
232
|
+
Return an enriched `SlurmConfig` object
|
|
193
233
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
234
|
+
Include `self.account` and `self.common_script_lines` into a
|
|
235
|
+
`SlurmConfig` object. Extracting this logic into an independent
|
|
236
|
+
class method is useful to fix issue #2659 (which was due to
|
|
237
|
+
performing this same operation multiple times rather than once).
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
slurm_config: The original `SlurmConfig` object.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
A new, up-to-date, `SlurmConfig` object.
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
new_slurm_config = slurm_config.model_copy()
|
|
247
|
+
|
|
248
|
+
# Include SLURM account in `slurm_config`.
|
|
198
249
|
if self.slurm_account is not None:
|
|
199
|
-
|
|
250
|
+
new_slurm_config.account = self.slurm_account
|
|
200
251
|
|
|
201
252
|
# Include common_script_lines in extra_lines
|
|
202
253
|
if len(self.common_script_lines) > 0:
|
|
203
254
|
logger.debug(
|
|
204
255
|
f"Add {self.common_script_lines} to "
|
|
205
|
-
f"{
|
|
256
|
+
f"{new_slurm_config.extra_lines=}."
|
|
206
257
|
)
|
|
207
|
-
current_extra_lines =
|
|
208
|
-
|
|
258
|
+
current_extra_lines = new_slurm_config.extra_lines or []
|
|
259
|
+
new_slurm_config.extra_lines = (
|
|
209
260
|
current_extra_lines + self.common_script_lines
|
|
210
261
|
)
|
|
211
262
|
|
|
263
|
+
return new_slurm_config
|
|
264
|
+
|
|
265
|
+
def _submit_single_sbatch(
|
|
266
|
+
self,
|
|
267
|
+
*,
|
|
268
|
+
base_command: str,
|
|
269
|
+
slurm_job: SlurmJob,
|
|
270
|
+
slurm_config: SlurmConfig,
|
|
271
|
+
) -> str:
|
|
272
|
+
logger.debug("[_submit_single_sbatch] START")
|
|
273
|
+
|
|
212
274
|
for task in slurm_job.tasks:
|
|
213
275
|
# Write input file
|
|
214
276
|
if self.slurm_runner_type == "ssh":
|
|
@@ -508,6 +570,9 @@ class BaseSlurmRunner(BaseRunner):
|
|
|
508
570
|
user_id: int,
|
|
509
571
|
) -> tuple[Any, Exception]:
|
|
510
572
|
logger.debug("[submit] START")
|
|
573
|
+
|
|
574
|
+
config = self._enrich_slurm_config(config)
|
|
575
|
+
|
|
511
576
|
try:
|
|
512
577
|
workdir_local = task_files.wftask_subfolder_local
|
|
513
578
|
workdir_remote = task_files.wftask_subfolder_remote
|
|
@@ -649,6 +714,8 @@ class BaseSlurmRunner(BaseRunner):
|
|
|
649
714
|
input images, while for compound tasks these can differ.
|
|
650
715
|
"""
|
|
651
716
|
|
|
717
|
+
config = self._enrich_slurm_config(config)
|
|
718
|
+
|
|
652
719
|
logger.debug(f"[multisubmit] START, {len(list_parameters)=}")
|
|
653
720
|
try:
|
|
654
721
|
if self.is_shutdown():
|
|
@@ -125,7 +125,14 @@ def get_slurm_config_internal(
|
|
|
125
125
|
)
|
|
126
126
|
logger.error(error_msg)
|
|
127
127
|
raise SlurmConfigError(error_msg)
|
|
128
|
-
for key in [
|
|
128
|
+
for key in [
|
|
129
|
+
"time",
|
|
130
|
+
"gres",
|
|
131
|
+
"gpus",
|
|
132
|
+
"constraint",
|
|
133
|
+
"nodelist",
|
|
134
|
+
"exclude",
|
|
135
|
+
]:
|
|
129
136
|
value = wftask_meta.get(key, None)
|
|
130
137
|
if value is not None:
|
|
131
138
|
slurm_dict[key] = value
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import json
|
|
3
|
-
import logging
|
|
4
3
|
import os
|
|
5
4
|
import sys
|
|
6
5
|
|
|
@@ -32,7 +31,6 @@ def worker(
|
|
|
32
31
|
# Create output folder, if missing
|
|
33
32
|
out_dir = os.path.dirname(out_fname)
|
|
34
33
|
if not os.path.exists(out_dir):
|
|
35
|
-
logging.debug(f"_slurm.remote.worker: create {out_dir=}")
|
|
36
34
|
os.mkdir(out_dir)
|
|
37
35
|
|
|
38
36
|
# Execute the job and capture exceptions
|
|
@@ -40,10 +38,8 @@ def worker(
|
|
|
40
38
|
with open(in_fname) as f:
|
|
41
39
|
input_data = json.load(f)
|
|
42
40
|
|
|
43
|
-
server_python_version = input_data["python_version"]
|
|
44
|
-
server_fractal_server_version = input_data["fractal_server_version"]
|
|
45
|
-
|
|
46
41
|
# Fractal-server version must be identical
|
|
42
|
+
server_fractal_server_version = input_data["fractal_server_version"]
|
|
47
43
|
worker_fractal_server_version = __VERSION__
|
|
48
44
|
if worker_fractal_server_version != server_fractal_server_version:
|
|
49
45
|
raise FractalVersionMismatch(
|
|
@@ -51,11 +47,16 @@ def worker(
|
|
|
51
47
|
f"{worker_fractal_server_version=}"
|
|
52
48
|
)
|
|
53
49
|
|
|
54
|
-
#
|
|
55
|
-
|
|
50
|
+
# Get `worker_python_version` as a `list` since this is the type of
|
|
51
|
+
# `server_python_version` after a JSON dump/load round trip.
|
|
52
|
+
worker_python_version = list(sys.version_info[:3])
|
|
53
|
+
|
|
54
|
+
# Print a warning for Python version mismatch
|
|
55
|
+
server_python_version = input_data["python_version"]
|
|
56
56
|
if worker_python_version != server_python_version:
|
|
57
57
|
if worker_python_version[:2] != server_python_version[:2]:
|
|
58
|
-
|
|
58
|
+
print(
|
|
59
|
+
"WARNING: "
|
|
59
60
|
f"{server_python_version=} but {worker_python_version=}."
|
|
60
61
|
)
|
|
61
62
|
|
|
@@ -116,7 +117,6 @@ if __name__ == "__main__":
|
|
|
116
117
|
required=True,
|
|
117
118
|
)
|
|
118
119
|
parsed_args = parser.parse_args()
|
|
119
|
-
logging.debug(f"{parsed_args=}")
|
|
120
120
|
|
|
121
121
|
kwargs = dict(
|
|
122
122
|
in_fname=parsed_args.input_file,
|
{fractal_server-2.15.0a5 → fractal_server-2.15.2}/fractal_server/app/runner/v2/_slurm_ssh.py
RENAMED
|
@@ -20,7 +20,6 @@ from pathlib import Path
|
|
|
20
20
|
from ....ssh._fabric import FractalSSH
|
|
21
21
|
from ...models.v2 import DatasetV2
|
|
22
22
|
from ...models.v2 import WorkflowV2
|
|
23
|
-
from ..exceptions import JobExecutionError
|
|
24
23
|
from ..executors.slurm_common.get_slurm_config import get_slurm_config
|
|
25
24
|
from ..executors.slurm_ssh.runner import SlurmSSHRunner
|
|
26
25
|
from ..set_start_and_last_task_index import set_start_and_last_task_index
|
|
@@ -64,18 +63,6 @@ def process_workflow(
|
|
|
64
63
|
if isinstance(worker_init, str):
|
|
65
64
|
worker_init = worker_init.split("\n")
|
|
66
65
|
|
|
67
|
-
# Create main remote folder
|
|
68
|
-
try:
|
|
69
|
-
fractal_ssh.mkdir(folder=str(workflow_dir_remote))
|
|
70
|
-
logger.info(f"Created {str(workflow_dir_remote)} via SSH.")
|
|
71
|
-
except Exception as e:
|
|
72
|
-
error_msg = (
|
|
73
|
-
f"Could not create {str(workflow_dir_remote)} via SSH.\n"
|
|
74
|
-
f"Original error: {str(e)}."
|
|
75
|
-
)
|
|
76
|
-
logger.error(error_msg)
|
|
77
|
-
raise JobExecutionError(info=error_msg)
|
|
78
|
-
|
|
79
66
|
with SlurmSSHRunner(
|
|
80
67
|
fractal_ssh=fractal_ssh,
|
|
81
68
|
root_dir_local=workflow_dir_local,
|