fractal-server 2.14.0a13__py3-none-any.whl → 2.14.0a14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/models/linkusergroup.py +6 -2
  3. fractal_server/app/models/v2/dataset.py +1 -1
  4. fractal_server/app/models/v2/job.py +7 -3
  5. fractal_server/app/models/v2/task_group.py +2 -2
  6. fractal_server/app/models/v2/workflow.py +1 -1
  7. fractal_server/app/models/v2/workflowtask.py +1 -1
  8. fractal_server/app/routes/admin/v2/task_group.py +0 -17
  9. fractal_server/app/routes/api/v2/dataset.py +0 -8
  10. fractal_server/app/routes/api/v2/history.py +112 -27
  11. fractal_server/app/routes/api/v2/images.py +16 -14
  12. fractal_server/app/routes/api/v2/project.py +0 -52
  13. fractal_server/app/routes/api/v2/task_group.py +0 -17
  14. fractal_server/app/routes/api/v2/workflow.py +0 -8
  15. fractal_server/app/routes/auth/group.py +0 -16
  16. fractal_server/app/runner/executors/base_runner.py +5 -0
  17. fractal_server/app/runner/executors/local/runner.py +15 -7
  18. fractal_server/app/runner/executors/slurm_common/_handle_exception_proxy.py +17 -0
  19. fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +676 -0
  20. fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +102 -0
  21. fractal_server/app/runner/executors/slurm_ssh/runner.py +110 -648
  22. fractal_server/app/runner/executors/slurm_sudo/runner.py +32 -661
  23. fractal_server/app/runner/task_files.py +20 -6
  24. fractal_server/app/runner/v2/_slurm_ssh.py +6 -6
  25. fractal_server/app/runner/v2/_slurm_sudo.py +4 -4
  26. fractal_server/app/runner/v2/runner.py +4 -0
  27. fractal_server/app/runner/v2/runner_functions.py +2 -2
  28. fractal_server/app/runner/v2/submit_workflow.py +7 -16
  29. fractal_server/app/schemas/v2/__init__.py +3 -1
  30. fractal_server/app/schemas/v2/history.py +27 -2
  31. fractal_server/config.py +6 -2
  32. fractal_server/images/tools.py +23 -0
  33. fractal_server/migrations/versions/5b6007027595_on_cascade.py +250 -0
  34. fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +2 -2
  35. fractal_server/tasks/v2/utils_background.py +0 -19
  36. {fractal_server-2.14.0a13.dist-info → fractal_server-2.14.0a14.dist-info}/METADATA +1 -1
  37. {fractal_server-2.14.0a13.dist-info → fractal_server-2.14.0a14.dist-info}/RECORD +40 -41
  38. fractal_server/app/runner/executors/slurm_common/_check_jobs_status.py +0 -77
  39. fractal_server/app/runner/executors/slurm_ssh/_check_job_status_ssh.py +0 -67
  40. fractal_server/app/runner/executors/slurm_ssh/_executor_wait_thread.py +0 -126
  41. fractal_server/app/runner/executors/slurm_ssh/_slurm_job.py +0 -116
  42. fractal_server/app/runner/executors/slurm_ssh/executor.py +0 -1386
  43. {fractal_server-2.14.0a13.dist-info → fractal_server-2.14.0a14.dist-info}/LICENSE +0 -0
  44. {fractal_server-2.14.0a13.dist-info → fractal_server-2.14.0a14.dist-info}/WHEEL +0 -0
  45. {fractal_server-2.14.0a13.dist-info → fractal_server-2.14.0a14.dist-info}/entry_points.txt +0 -0
@@ -34,6 +34,7 @@ class TaskFiles(BaseModel):
34
34
 
35
35
  # Per-single-component
36
36
  component: Optional[str] = None
37
+ prefix: Optional[str] = None
37
38
 
38
39
  def _check_component(self):
39
40
  if self.component is None:
@@ -55,46 +56,55 @@ class TaskFiles(BaseModel):
55
56
  def wftask_subfolder_local(self) -> Path:
56
57
  return self.root_dir_local / self.subfolder_name
57
58
 
59
+ @property
60
+ def prefix_component(self):
61
+ if self.prefix is None:
62
+ return self.component
63
+ else:
64
+ return f"{self.prefix}-{self.component}"
65
+
58
66
  @property
59
67
  def log_file_local(self) -> str:
60
68
  self._check_component()
61
69
  return (
62
- self.wftask_subfolder_local / f"{self.component}-log.txt"
70
+ self.wftask_subfolder_local / f"{self.prefix_component}-log.txt"
63
71
  ).as_posix()
64
72
 
65
73
  @property
66
74
  def log_file_remote(self) -> str:
67
75
  self._check_component()
68
76
  return (
69
- self.wftask_subfolder_remote / f"{self.component}-log.txt"
77
+ self.wftask_subfolder_remote / f"{self.prefix_component}-log.txt"
70
78
  ).as_posix()
71
79
 
72
80
  @property
73
81
  def args_file_local(self) -> str:
74
82
  self._check_component()
75
83
  return (
76
- self.wftask_subfolder_local / f"{self.component}-args.json"
84
+ self.wftask_subfolder_local / f"{self.prefix_component}-args.json"
77
85
  ).as_posix()
78
86
 
79
87
  @property
80
88
  def args_file_remote(self) -> str:
81
89
  self._check_component()
82
90
  return (
83
- self.wftask_subfolder_remote / f"{self.component}-args.json"
91
+ self.wftask_subfolder_remote / f"{self.prefix_component}-args.json"
84
92
  ).as_posix()
85
93
 
86
94
  @property
87
95
  def metadiff_file_local(self) -> str:
88
96
  self._check_component()
89
97
  return (
90
- self.wftask_subfolder_local / f"{self.component}-metadiff.json"
98
+ self.wftask_subfolder_local
99
+ / f"{self.prefix_component}-metadiff.json"
91
100
  ).as_posix()
92
101
 
93
102
  @property
94
103
  def metadiff_file_remote(self) -> str:
95
104
  self._check_component()
96
105
  return (
97
- self.wftask_subfolder_remote / f"{self.component}-metadiff.json"
106
+ self.wftask_subfolder_remote
107
+ / f"{self.prefix_component}-metadiff.json"
98
108
  ).as_posix()
99
109
 
100
110
  @property
@@ -104,3 +114,7 @@ class TaskFiles(BaseModel):
104
114
  metadiff_file_remote=self.metadiff_file_remote,
105
115
  log_file_remote=self.log_file_remote,
106
116
  )
117
+
118
+
119
+ SUBMIT_PREFIX = "non_par"
120
+ MULTISUBMIT_PREFIX = "par"
@@ -24,7 +24,7 @@ from ...models.v2 import DatasetV2
24
24
  from ...models.v2 import WorkflowV2
25
25
  from ..exceptions import JobExecutionError
26
26
  from ..executors.slurm_common.get_slurm_config import get_slurm_config
27
- from ..executors.slurm_ssh.executor import FractalSlurmSSHExecutor
27
+ from ..executors.slurm_ssh.runner import SlurmSSHRunner
28
28
  from ..set_start_and_last_task_index import set_start_and_last_task_index
29
29
  from .runner import execute_tasks_v2
30
30
  from fractal_server.images.models import AttributeFiltersType
@@ -76,18 +76,18 @@ def process_workflow(
76
76
  logger.error(error_msg)
77
77
  raise JobExecutionError(info=error_msg)
78
78
 
79
- with FractalSlurmSSHExecutor(
79
+ with SlurmSSHRunner(
80
80
  fractal_ssh=fractal_ssh,
81
- workflow_dir_local=workflow_dir_local,
82
- workflow_dir_remote=workflow_dir_remote,
81
+ root_dir_local=workflow_dir_local,
82
+ root_dir_remote=workflow_dir_remote,
83
83
  common_script_lines=worker_init,
84
- ) as executor:
84
+ ) as runner:
85
85
  execute_tasks_v2(
86
86
  wf_task_list=workflow.task_list[
87
87
  first_task_index : (last_task_index + 1)
88
88
  ],
89
89
  dataset=dataset,
90
- runner=executor,
90
+ runner=runner,
91
91
  workflow_dir_local=workflow_dir_local,
92
92
  workflow_dir_remote=workflow_dir_remote,
93
93
  logger_name=logger_name,
@@ -22,7 +22,7 @@ from typing import Optional
22
22
  from ...models.v2 import DatasetV2
23
23
  from ...models.v2 import WorkflowV2
24
24
  from ..executors.slurm_common.get_slurm_config import get_slurm_config
25
- from ..executors.slurm_sudo.runner import RunnerSlurmSudo
25
+ from ..executors.slurm_sudo.runner import SudoSlurmRunner
26
26
  from ..set_start_and_last_task_index import set_start_and_last_task_index
27
27
  from .runner import execute_tasks_v2
28
28
  from fractal_server.images.models import AttributeFiltersType
@@ -66,20 +66,20 @@ def process_workflow(
66
66
  if isinstance(worker_init, str):
67
67
  worker_init = worker_init.split("\n")
68
68
 
69
- with RunnerSlurmSudo(
69
+ with SudoSlurmRunner(
70
70
  slurm_user=slurm_user,
71
71
  user_cache_dir=user_cache_dir,
72
72
  root_dir_local=workflow_dir_local,
73
73
  root_dir_remote=workflow_dir_remote,
74
74
  common_script_lines=worker_init,
75
75
  slurm_account=slurm_account,
76
- ) as executor:
76
+ ) as runner:
77
77
  execute_tasks_v2(
78
78
  wf_task_list=workflow.task_list[
79
79
  first_task_index : (last_task_index + 1)
80
80
  ],
81
81
  dataset=dataset,
82
- runner=executor,
82
+ runner=runner,
83
83
  workflow_dir_local=workflow_dir_local,
84
84
  workflow_dir_remote=workflow_dir_remote,
85
85
  logger_name=logger_name,
@@ -126,6 +126,10 @@ def execute_tasks_v2(
126
126
  db.commit()
127
127
  db.refresh(history_run)
128
128
  history_run_id = history_run.id
129
+ logger.debug(
130
+ f"Created {history_run_id=}, for "
131
+ f"{wftask.id=} and {dataset.id=}"
132
+ )
129
133
 
130
134
  # TASK EXECUTION (V2)
131
135
  if task.type in ["non_parallel", "converter_non_parallel"]:
@@ -372,7 +372,7 @@ def run_v2_task_compound(
372
372
  root_dir_remote=workflow_dir_remote,
373
373
  task_order=wftask.order,
374
374
  task_name=wftask.task.name,
375
- component=f"init_{_index_to_component(0)}",
375
+ component=_index_to_component(0),
376
376
  )
377
377
 
378
378
  runner_config_init = get_runner_config(
@@ -483,7 +483,7 @@ def run_v2_task_compound(
483
483
  root_dir_remote=workflow_dir_remote,
484
484
  task_order=wftask.order,
485
485
  task_name=wftask.task.name,
486
- component=f"compute_{_index_to_component(ind)}",
486
+ component=_index_to_component(ind),
487
487
  )
488
488
  for ind in range(len(parallelization_list))
489
489
  ]
@@ -27,7 +27,6 @@ from ...models.v2 import WorkflowV2
27
27
  from ...schemas.v2 import JobStatusTypeV2
28
28
  from ..exceptions import JobExecutionError
29
29
  from ..exceptions import TaskExecutionError
30
- from ..executors.slurm_sudo._subprocess_run_as_user import _mkdir_as_user
31
30
  from ..filenames import WORKFLOW_LOG_FILENAME
32
31
  from ._local import process_workflow as local_process_workflow
33
32
  from ._slurm_ssh import process_workflow as slurm_ssh_process_workflow
@@ -170,35 +169,27 @@ def submit_workflow(
170
169
  return
171
170
 
172
171
  try:
173
- # Create WORKFLOW_DIR_LOCAL
174
- if FRACTAL_RUNNER_BACKEND == "slurm":
175
- original_umask = os.umask(0)
176
- WORKFLOW_DIR_LOCAL.mkdir(parents=True, mode=0o755)
177
- os.umask(original_umask)
178
- else:
179
- WORKFLOW_DIR_LOCAL.mkdir(parents=True)
180
-
181
- # Define and create WORKFLOW_DIR_REMOTE
172
+ # Create WORKFLOW_DIR_LOCAL and define WORKFLOW_DIR_REMOTE
182
173
  if FRACTAL_RUNNER_BACKEND == "local":
174
+ WORKFLOW_DIR_LOCAL.mkdir(parents=True)
183
175
  WORKFLOW_DIR_REMOTE = WORKFLOW_DIR_LOCAL
184
176
  elif FRACTAL_RUNNER_BACKEND == "slurm":
177
+ original_umask = os.umask(0)
178
+ WORKFLOW_DIR_LOCAL.mkdir(parents=True, mode=0o755)
179
+ os.umask(original_umask)
185
180
  WORKFLOW_DIR_REMOTE = (
186
181
  Path(user_cache_dir) / WORKFLOW_DIR_LOCAL.name
187
182
  )
188
- _mkdir_as_user(
189
- folder=str(WORKFLOW_DIR_REMOTE), user=slurm_user
190
- )
191
183
  elif FRACTAL_RUNNER_BACKEND == "slurm_ssh":
192
- # Folder creation is deferred to _process_workflow
184
+ WORKFLOW_DIR_LOCAL.mkdir(parents=True)
193
185
  WORKFLOW_DIR_REMOTE = (
194
186
  Path(user_settings.ssh_jobs_dir) / WORKFLOW_DIR_LOCAL.name
195
187
  )
196
188
  else:
197
- logger.error(
189
+ raise ValueError(
198
190
  "Invalid FRACTAL_RUNNER_BACKEND="
199
191
  f"{settings.FRACTAL_RUNNER_BACKEND}."
200
192
  )
201
-
202
193
  except Exception as e:
203
194
  error_type = type(e).__name__
204
195
  fail_job(
@@ -10,11 +10,13 @@ from .dumps import TaskDumpV2 # noqa F401
10
10
  from .dumps import TaskGroupDumpV2 # noqa F401
11
11
  from .dumps import WorkflowDumpV2 # noqa F401
12
12
  from .dumps import WorkflowTaskDumpV2 # noqa F401
13
+ from .history import HistoryRunRead # noqa F401
13
14
  from .history import HistoryRunReadAggregated # noqa F401
14
15
  from .history import HistoryUnitRead # noqa F401
15
16
  from .history import HistoryUnitStatus # noqa F401
17
+ from .history import HistoryUnitStatusQuery # noqa F401
16
18
  from .history import ImageLogsRequest # noqa F401
17
- from .history import ZarrUrlAndStatus # noqa F401
19
+ from .history import SingleImageWithStatus # noqa F401
18
20
  from .job import JobCreateV2 # noqa F401
19
21
  from .job import JobReadV2 # noqa F401
20
22
  from .job import JobStatusTypeV2 # noqa F401
@@ -7,6 +7,8 @@ from pydantic import AwareDatetime
7
7
  from pydantic import BaseModel
8
8
  from pydantic import field_serializer
9
9
 
10
+ from ....images import SingleImage
11
+
10
12
 
11
13
  class HistoryUnitStatus(str, Enum):
12
14
  """
@@ -23,6 +25,15 @@ class HistoryUnitStatus(str, Enum):
23
25
  FAILED = "failed"
24
26
 
25
27
 
28
+ class HistoryUnitStatusQuery(str, Enum):
29
+
30
+ SUBMITTED = "submitted"
31
+ DONE = "done"
32
+ FAILED = "failed"
33
+
34
+ UNSET = "unset"
35
+
36
+
26
37
  class HistoryUnitRead(BaseModel):
27
38
  id: int
28
39
  logfile: Optional[str] = None
@@ -30,6 +41,21 @@ class HistoryUnitRead(BaseModel):
30
41
  zarr_urls: list[str]
31
42
 
32
43
 
44
+ class HistoryRunRead(BaseModel):
45
+ id: int
46
+ dataset_id: int
47
+ workflowtask_id: Optional[int] = None
48
+ workflowtask_dump: dict[str, Any]
49
+ task_group_dump: dict[str, Any]
50
+ timestamp_started: AwareDatetime
51
+ status: HistoryUnitStatus
52
+ num_available_images: int
53
+
54
+ @field_serializer("timestamp_started")
55
+ def serialize_datetime(v: datetime) -> str:
56
+ return v.isoformat()
57
+
58
+
33
59
  class HistoryRunReadAggregated(BaseModel):
34
60
  id: int
35
61
  timestamp_started: AwareDatetime
@@ -49,6 +75,5 @@ class ImageLogsRequest(BaseModel):
49
75
  zarr_url: str
50
76
 
51
77
 
52
- class ZarrUrlAndStatus(BaseModel):
53
- zarr_url: str
78
+ class SingleImageWithStatus(SingleImage):
54
79
  status: Optional[HistoryUnitStatus] = None
fractal_server/config.py CHANGED
@@ -489,8 +489,12 @@ class Settings(BaseSettings):
489
489
  FRACTAL_SLURM_POLL_INTERVAL: int = 5
490
490
  """
491
491
  Interval to wait (in seconds) before checking whether unfinished job are
492
- still running on SLURM (see `SlurmWaitThread` in
493
- [`clusterfutures`](https://github.com/sampsyo/clusterfutures/blob/master/cfut/__init__.py)).
492
+ still running on SLURM.
493
+ """
494
+
495
+ FRACTAL_SLURM_INTERVAL_BEFORE_RETRIEVAL: int = 2
496
+ """
497
+ FIXME: this is a workaround, we are still investigating.
494
498
  """
495
499
 
496
500
  FRACTAL_SLURM_SBATCH_SLEEP: float = 0
@@ -121,3 +121,26 @@ def merge_type_filters(
121
121
  merged_dict = task_input_types
122
122
  merged_dict.update(wftask_type_filters)
123
123
  return merged_dict
124
+
125
+
126
+ def aggregate_attributes(images: list[dict[str, Any]]) -> dict[str, list[Any]]:
127
+ """
128
+ Given a list of images, this function returns a dictionary of all image
129
+ attributes, each mapped to a list of present values.
130
+ """
131
+ attributes = {}
132
+ for image in images:
133
+ for k, v in image["attributes"].items():
134
+ attributes.setdefault(k, []).append(v)
135
+ for k, v in attributes.items():
136
+ attributes[k] = list(set(v))
137
+ return attributes
138
+
139
+
140
+ def aggregate_types(images: list[dict[str, Any]]) -> list[str]:
141
+ """
142
+ Given a list of images, this function returns a list of all image types.
143
+ """
144
+ return list(
145
+ set(type for image in images for type in image["types"].keys())
146
+ )
@@ -0,0 +1,250 @@
1
+ """on cascade
2
+
3
+ Revision ID: 5b6007027595
4
+ Revises: af1ef1c83c9b
5
+ Create Date: 2025-04-02 17:03:59.542921
6
+
7
+ """
8
+ from alembic import op
9
+
10
+
11
+ # revision identifiers, used by Alembic.
12
+ revision = "5b6007027595"
13
+ down_revision = "af1ef1c83c9b"
14
+ branch_labels = None
15
+ depends_on = None
16
+
17
+
18
+ def upgrade() -> None:
19
+ # ### commands auto generated by Alembic - please adjust! ###
20
+ with op.batch_alter_table("datasetv2", schema=None) as batch_op:
21
+ batch_op.drop_constraint(
22
+ "fk_datasetv2_project_id_projectv2", type_="foreignkey"
23
+ )
24
+ batch_op.create_foreign_key(
25
+ batch_op.f("fk_datasetv2_project_id_projectv2"),
26
+ "projectv2",
27
+ ["project_id"],
28
+ ["id"],
29
+ ondelete="CASCADE",
30
+ )
31
+
32
+ with op.batch_alter_table("jobv2", schema=None) as batch_op:
33
+ batch_op.drop_constraint(
34
+ "fk_jobv2_dataset_id_datasetv2", type_="foreignkey"
35
+ )
36
+ batch_op.drop_constraint(
37
+ "fk_jobv2_workflow_id_workflowv2", type_="foreignkey"
38
+ )
39
+ batch_op.drop_constraint(
40
+ "fk_jobv2_project_id_projectv2", type_="foreignkey"
41
+ )
42
+ batch_op.create_foreign_key(
43
+ batch_op.f("fk_jobv2_project_id_projectv2"),
44
+ "projectv2",
45
+ ["project_id"],
46
+ ["id"],
47
+ ondelete="SET NULL",
48
+ )
49
+ batch_op.create_foreign_key(
50
+ batch_op.f("fk_jobv2_dataset_id_datasetv2"),
51
+ "datasetv2",
52
+ ["dataset_id"],
53
+ ["id"],
54
+ ondelete="SET NULL",
55
+ )
56
+ batch_op.create_foreign_key(
57
+ batch_op.f("fk_jobv2_workflow_id_workflowv2"),
58
+ "workflowv2",
59
+ ["workflow_id"],
60
+ ["id"],
61
+ ondelete="SET NULL",
62
+ )
63
+
64
+ with op.batch_alter_table("linkusergroup", schema=None) as batch_op:
65
+ batch_op.drop_constraint(
66
+ "fk_linkusergroup_group_id_usergroup", type_="foreignkey"
67
+ )
68
+ batch_op.drop_constraint(
69
+ "fk_linkusergroup_user_id_user_oauth", type_="foreignkey"
70
+ )
71
+ batch_op.create_foreign_key(
72
+ batch_op.f("fk_linkusergroup_group_id_usergroup"),
73
+ "usergroup",
74
+ ["group_id"],
75
+ ["id"],
76
+ ondelete="CASCADE",
77
+ )
78
+ batch_op.create_foreign_key(
79
+ batch_op.f("fk_linkusergroup_user_id_user_oauth"),
80
+ "user_oauth",
81
+ ["user_id"],
82
+ ["id"],
83
+ ondelete="CASCADE",
84
+ )
85
+
86
+ with op.batch_alter_table("taskgroupactivityv2", schema=None) as batch_op:
87
+ batch_op.drop_constraint(
88
+ "fk_taskgroupactivityv2_taskgroupv2_id_taskgroupv2",
89
+ type_="foreignkey",
90
+ )
91
+ batch_op.create_foreign_key(
92
+ batch_op.f("fk_taskgroupactivityv2_taskgroupv2_id_taskgroupv2"),
93
+ "taskgroupv2",
94
+ ["taskgroupv2_id"],
95
+ ["id"],
96
+ ondelete="SET NULL",
97
+ )
98
+
99
+ with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
100
+ batch_op.drop_constraint(
101
+ "fk_taskgroupv2_user_group_id_usergroup", type_="foreignkey"
102
+ )
103
+ batch_op.create_foreign_key(
104
+ batch_op.f("fk_taskgroupv2_user_group_id_usergroup"),
105
+ "usergroup",
106
+ ["user_group_id"],
107
+ ["id"],
108
+ ondelete="SET NULL",
109
+ )
110
+
111
+ with op.batch_alter_table("workflowtaskv2", schema=None) as batch_op:
112
+ batch_op.drop_constraint(
113
+ "fk_workflowtaskv2_workflow_id_workflowv2", type_="foreignkey"
114
+ )
115
+ batch_op.create_foreign_key(
116
+ batch_op.f("fk_workflowtaskv2_workflow_id_workflowv2"),
117
+ "workflowv2",
118
+ ["workflow_id"],
119
+ ["id"],
120
+ ondelete="CASCADE",
121
+ )
122
+
123
+ with op.batch_alter_table("workflowv2", schema=None) as batch_op:
124
+ batch_op.drop_constraint(
125
+ "fk_workflowv2_project_id_projectv2", type_="foreignkey"
126
+ )
127
+ batch_op.create_foreign_key(
128
+ batch_op.f("fk_workflowv2_project_id_projectv2"),
129
+ "projectv2",
130
+ ["project_id"],
131
+ ["id"],
132
+ ondelete="CASCADE",
133
+ )
134
+
135
+ # ### end Alembic commands ###
136
+
137
+
138
+ def downgrade() -> None:
139
+ # ### commands auto generated by Alembic - please adjust! ###
140
+ with op.batch_alter_table("workflowv2", schema=None) as batch_op:
141
+ batch_op.drop_constraint(
142
+ batch_op.f("fk_workflowv2_project_id_projectv2"),
143
+ type_="foreignkey",
144
+ )
145
+ batch_op.create_foreign_key(
146
+ "fk_workflowv2_project_id_projectv2",
147
+ "projectv2",
148
+ ["project_id"],
149
+ ["id"],
150
+ )
151
+
152
+ with op.batch_alter_table("workflowtaskv2", schema=None) as batch_op:
153
+ batch_op.drop_constraint(
154
+ batch_op.f("fk_workflowtaskv2_workflow_id_workflowv2"),
155
+ type_="foreignkey",
156
+ )
157
+ batch_op.create_foreign_key(
158
+ "fk_workflowtaskv2_workflow_id_workflowv2",
159
+ "workflowv2",
160
+ ["workflow_id"],
161
+ ["id"],
162
+ )
163
+
164
+ with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
165
+ batch_op.drop_constraint(
166
+ batch_op.f("fk_taskgroupv2_user_group_id_usergroup"),
167
+ type_="foreignkey",
168
+ )
169
+ batch_op.create_foreign_key(
170
+ "fk_taskgroupv2_user_group_id_usergroup",
171
+ "usergroup",
172
+ ["user_group_id"],
173
+ ["id"],
174
+ )
175
+
176
+ with op.batch_alter_table("taskgroupactivityv2", schema=None) as batch_op:
177
+ batch_op.drop_constraint(
178
+ batch_op.f("fk_taskgroupactivityv2_taskgroupv2_id_taskgroupv2"),
179
+ type_="foreignkey",
180
+ )
181
+ batch_op.create_foreign_key(
182
+ "fk_taskgroupactivityv2_taskgroupv2_id_taskgroupv2",
183
+ "taskgroupv2",
184
+ ["taskgroupv2_id"],
185
+ ["id"],
186
+ )
187
+
188
+ with op.batch_alter_table("linkusergroup", schema=None) as batch_op:
189
+ batch_op.drop_constraint(
190
+ batch_op.f("fk_linkusergroup_user_id_user_oauth"),
191
+ type_="foreignkey",
192
+ )
193
+ batch_op.drop_constraint(
194
+ batch_op.f("fk_linkusergroup_group_id_usergroup"),
195
+ type_="foreignkey",
196
+ )
197
+ batch_op.create_foreign_key(
198
+ "fk_linkusergroup_user_id_user_oauth",
199
+ "user_oauth",
200
+ ["user_id"],
201
+ ["id"],
202
+ )
203
+ batch_op.create_foreign_key(
204
+ "fk_linkusergroup_group_id_usergroup",
205
+ "usergroup",
206
+ ["group_id"],
207
+ ["id"],
208
+ )
209
+
210
+ with op.batch_alter_table("jobv2", schema=None) as batch_op:
211
+ batch_op.drop_constraint(
212
+ batch_op.f("fk_jobv2_workflow_id_workflowv2"), type_="foreignkey"
213
+ )
214
+ batch_op.drop_constraint(
215
+ batch_op.f("fk_jobv2_dataset_id_datasetv2"), type_="foreignkey"
216
+ )
217
+ batch_op.drop_constraint(
218
+ batch_op.f("fk_jobv2_project_id_projectv2"), type_="foreignkey"
219
+ )
220
+ batch_op.create_foreign_key(
221
+ "fk_jobv2_project_id_projectv2",
222
+ "projectv2",
223
+ ["project_id"],
224
+ ["id"],
225
+ )
226
+ batch_op.create_foreign_key(
227
+ "fk_jobv2_workflow_id_workflowv2",
228
+ "workflowv2",
229
+ ["workflow_id"],
230
+ ["id"],
231
+ )
232
+ batch_op.create_foreign_key(
233
+ "fk_jobv2_dataset_id_datasetv2",
234
+ "datasetv2",
235
+ ["dataset_id"],
236
+ ["id"],
237
+ )
238
+
239
+ with op.batch_alter_table("datasetv2", schema=None) as batch_op:
240
+ batch_op.drop_constraint(
241
+ batch_op.f("fk_datasetv2_project_id_projectv2"), type_="foreignkey"
242
+ )
243
+ batch_op.create_foreign_key(
244
+ "fk_datasetv2_project_id_projectv2",
245
+ "projectv2",
246
+ ["project_id"],
247
+ ["id"],
248
+ )
249
+
250
+ # ### end Alembic commands ###
@@ -1,7 +1,7 @@
1
1
  """new history items
2
2
 
3
3
  Revision ID: fbce16ff4e47
4
- Revises: af1ef1c83c9b
4
+ Revises: 5b6007027595
5
5
  Create Date: 2025-03-14 15:25:01.083619
6
6
 
7
7
  """
@@ -12,7 +12,7 @@ from sqlalchemy.dialects import postgresql
12
12
 
13
13
  # revision identifiers, used by Alembic.
14
14
  revision = "fbce16ff4e47"
15
- down_revision = "af1ef1c83c9b"
15
+ down_revision = "5b6007027595"
16
16
  branch_labels = None
17
17
  depends_on = None
18
18
 
@@ -3,7 +3,6 @@ from typing import Optional
3
3
  from typing import TypeVar
4
4
 
5
5
  from sqlalchemy.orm import Session as DBSyncSession
6
- from sqlmodel import select
7
6
 
8
7
  from fractal_server.app.models.v2 import TaskGroupActivityV2
9
8
  from fractal_server.app.models.v2 import TaskGroupV2
@@ -44,24 +43,6 @@ def fail_and_cleanup(
44
43
  task_group_activity.log = get_current_log(log_file_path)
45
44
  task_group_activity = add_commit_refresh(obj=task_group_activity, db=db)
46
45
  if task_group_activity.action == TaskGroupActivityActionV2.COLLECT:
47
- logger.info(f"Now delete TaskGroupV2 with {task_group.id=}")
48
-
49
- logger.info("Start of TaskGroupActivityV2 cascade operations.")
50
- stm = select(TaskGroupActivityV2).where(
51
- TaskGroupActivityV2.taskgroupv2_id == task_group.id
52
- )
53
- res = db.execute(stm)
54
- task_group_activity_list = res.scalars().all()
55
- for task_group_activity in task_group_activity_list:
56
- logger.info(
57
- f"Setting TaskGroupActivityV2[{task_group_activity.id}]"
58
- ".taskgroupv2_id to None."
59
- )
60
- task_group_activity.taskgroupv2_id = None
61
- db.add(task_group_activity)
62
- logger.info("End of TaskGroupActivityV2 cascade operations.")
63
- logger.info(f"TaskGroupV2 with {task_group.id=} deleted")
64
-
65
46
  db.delete(task_group)
66
47
  db.commit()
67
48
  reset_logger_handlers(logger)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fractal-server
3
- Version: 2.14.0a13
3
+ Version: 2.14.0a14
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License: BSD-3-Clause
6
6
  Author: Tommaso Comparin