fractal-server 2.12.1__py3-none-any.whl → 2.13.0__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 (73) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/models/security.py +9 -12
  3. fractal_server/app/models/v2/dataset.py +2 -2
  4. fractal_server/app/models/v2/job.py +11 -9
  5. fractal_server/app/models/v2/task.py +2 -3
  6. fractal_server/app/models/v2/task_group.py +6 -2
  7. fractal_server/app/models/v2/workflowtask.py +15 -8
  8. fractal_server/app/routes/admin/v2/task.py +1 -1
  9. fractal_server/app/routes/admin/v2/task_group.py +1 -1
  10. fractal_server/app/routes/api/v2/dataset.py +4 -4
  11. fractal_server/app/routes/api/v2/images.py +11 -11
  12. fractal_server/app/routes/api/v2/project.py +2 -2
  13. fractal_server/app/routes/api/v2/status.py +1 -1
  14. fractal_server/app/routes/api/v2/submit.py +8 -6
  15. fractal_server/app/routes/api/v2/task.py +4 -2
  16. fractal_server/app/routes/api/v2/task_collection.py +3 -2
  17. fractal_server/app/routes/api/v2/task_group.py +2 -2
  18. fractal_server/app/routes/api/v2/workflow.py +3 -3
  19. fractal_server/app/routes/api/v2/workflow_import.py +3 -3
  20. fractal_server/app/routes/api/v2/workflowtask.py +3 -1
  21. fractal_server/app/routes/auth/_aux_auth.py +4 -1
  22. fractal_server/app/routes/auth/current_user.py +3 -5
  23. fractal_server/app/routes/auth/group.py +1 -1
  24. fractal_server/app/routes/auth/users.py +2 -4
  25. fractal_server/app/routes/aux/_runner.py +1 -1
  26. fractal_server/app/routes/aux/validate_user_settings.py +1 -2
  27. fractal_server/app/runner/executors/_job_states.py +13 -0
  28. fractal_server/app/runner/executors/slurm/_slurm_config.py +26 -18
  29. fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -3
  30. fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +31 -22
  31. fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +2 -5
  32. fractal_server/app/runner/executors/slurm/ssh/executor.py +21 -27
  33. fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -3
  34. fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +1 -2
  35. fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +37 -47
  36. fractal_server/app/runner/executors/slurm/sudo/executor.py +25 -24
  37. fractal_server/app/runner/v2/__init__.py +0 -9
  38. fractal_server/app/runner/v2/_local/_local_config.py +5 -4
  39. fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +4 -4
  40. fractal_server/app/runner/v2/_slurm_sudo/__init__.py +2 -2
  41. fractal_server/app/runner/v2/deduplicate_list.py +1 -1
  42. fractal_server/app/runner/v2/runner.py +9 -4
  43. fractal_server/app/runner/v2/task_interface.py +15 -7
  44. fractal_server/app/schemas/_filter_validators.py +6 -3
  45. fractal_server/app/schemas/_validators.py +7 -5
  46. fractal_server/app/schemas/user.py +23 -18
  47. fractal_server/app/schemas/user_group.py +25 -11
  48. fractal_server/app/schemas/user_settings.py +31 -24
  49. fractal_server/app/schemas/v2/dataset.py +48 -35
  50. fractal_server/app/schemas/v2/dumps.py +16 -14
  51. fractal_server/app/schemas/v2/job.py +49 -29
  52. fractal_server/app/schemas/v2/manifest.py +32 -28
  53. fractal_server/app/schemas/v2/project.py +18 -8
  54. fractal_server/app/schemas/v2/task.py +86 -75
  55. fractal_server/app/schemas/v2/task_collection.py +41 -30
  56. fractal_server/app/schemas/v2/task_group.py +39 -20
  57. fractal_server/app/schemas/v2/workflow.py +24 -12
  58. fractal_server/app/schemas/v2/workflowtask.py +63 -61
  59. fractal_server/app/security/__init__.py +1 -1
  60. fractal_server/config.py +32 -25
  61. fractal_server/images/models.py +18 -12
  62. fractal_server/main.py +1 -1
  63. fractal_server/tasks/v2/utils_background.py +1 -1
  64. fractal_server/tasks/v2/utils_database.py +1 -1
  65. {fractal_server-2.12.1.dist-info → fractal_server-2.13.0.dist-info}/METADATA +9 -10
  66. {fractal_server-2.12.1.dist-info → fractal_server-2.13.0.dist-info}/RECORD +69 -72
  67. fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -121
  68. fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -108
  69. fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -42
  70. fractal_server/app/runner/v2/_local_experimental/executor.py +0 -157
  71. {fractal_server-2.12.1.dist-info → fractal_server-2.13.0.dist-info}/LICENSE +0 -0
  72. {fractal_server-2.12.1.dist-info → fractal_server-2.13.0.dist-info}/WHEEL +0 -0
  73. {fractal_server-2.12.1.dist-info → fractal_server-2.13.0.dist-info}/entry_points.txt +0 -0
@@ -3,9 +3,9 @@ from typing import Literal
3
3
  from typing import Optional
4
4
 
5
5
  from pydantic import BaseModel
6
- from pydantic import Extra
7
- from pydantic import root_validator
8
- from pydantic import validator
6
+ from pydantic import ConfigDict
7
+ from pydantic import field_validator
8
+ from pydantic import model_validator
9
9
 
10
10
  from .._validators import valstr
11
11
  from fractal_server.app.schemas.v2 import ManifestV2
@@ -21,7 +21,7 @@ class WheelFile(BaseModel):
21
21
  contents: bytes
22
22
 
23
23
 
24
- class TaskCollectPipV2(BaseModel, extra=Extra.forbid):
24
+ class TaskCollectPipV2(BaseModel):
25
25
  """
26
26
  TaskCollectPipV2 class
27
27
 
@@ -45,35 +45,40 @@ class TaskCollectPipV2(BaseModel, extra=Extra.forbid):
45
45
 
46
46
  """
47
47
 
48
+ model_config = ConfigDict(extra="forbid")
48
49
  package: Optional[str] = None
49
50
  package_version: Optional[str] = None
50
51
  package_extras: Optional[str] = None
51
52
  python_version: Optional[Literal["3.9", "3.10", "3.11", "3.12"]] = None
52
53
  pinned_package_versions: Optional[dict[str, str]] = None
53
54
 
54
- @validator("package")
55
+ @field_validator("package")
56
+ @classmethod
55
57
  def package_validator(cls, value: Optional[str]) -> Optional[str]:
56
58
  if value is None:
57
59
  return value
58
- value = valstr("package")(value)
60
+ value = valstr("package")(cls, value)
59
61
  validate_cmd(value, attribute_name="package")
60
62
  return value
61
63
 
62
- @validator("package_version")
64
+ @field_validator("package_version")
65
+ @classmethod
63
66
  def package_version_validator(cls, value: Optional[str]) -> Optional[str]:
64
67
  if value is None:
65
68
  return value
66
- value = valstr("package_version")(value)
69
+ value = valstr("package_version")(cls, value)
67
70
  validate_cmd(value, attribute_name="package_version")
68
71
  return value
69
72
 
70
- @validator("pinned_package_versions")
73
+ @field_validator("pinned_package_versions")
74
+ @classmethod
71
75
  def pinned_package_versions_validator(cls, value):
72
76
  if value is None:
73
77
  return value
74
78
  old_keys = list(value.keys())
75
79
  new_keys = [
76
- valstr(f"pinned_package_versions[{key}]")(key) for key in old_keys
80
+ valstr(f"pinned_package_versions[{key}]")(cls, key)
81
+ for key in old_keys
77
82
  ]
78
83
  if len(new_keys) != len(set(new_keys)):
79
84
  raise ValueError(
@@ -87,16 +92,17 @@ class TaskCollectPipV2(BaseModel, extra=Extra.forbid):
87
92
  validate_cmd(version)
88
93
  return value
89
94
 
90
- @validator("package_extras")
95
+ @field_validator("package_extras")
96
+ @classmethod
91
97
  def package_extras_validator(cls, value: Optional[str]) -> Optional[str]:
92
98
  if value is None:
93
99
  return value
94
- value = valstr("package_extras")(value)
100
+ value = valstr("package_extras")(cls, value)
95
101
  validate_cmd(value, attribute_name="package_extras")
96
102
  return value
97
103
 
98
104
 
99
- class TaskCollectCustomV2(BaseModel, extra=Extra.forbid):
105
+ class TaskCollectCustomV2(BaseModel):
100
106
  """
101
107
  Attributes:
102
108
  manifest: Manifest of a Fractal task package (this is typically the
@@ -114,29 +120,31 @@ class TaskCollectCustomV2(BaseModel, extra=Extra.forbid):
114
120
  version: Optional version of tasks to be collected.
115
121
  """
116
122
 
123
+ model_config = ConfigDict(extra="forbid")
117
124
  manifest: ManifestV2
118
125
  python_interpreter: str
119
126
  label: str
120
- package_root: Optional[str]
121
- package_name: Optional[str]
122
- version: Optional[str]
127
+ package_root: Optional[str] = None
128
+ package_name: Optional[str] = None
129
+ version: Optional[str] = None
123
130
 
124
131
  # Valstr
125
- _python_interpreter = validator("python_interpreter", allow_reuse=True)(
126
- valstr("python_interpreter")
132
+ _python_interpreter = field_validator("python_interpreter")(
133
+ classmethod(valstr("python_interpreter"))
127
134
  )
128
- _label = validator("label", allow_reuse=True)(valstr("label"))
129
- _package_root = validator("package_root", allow_reuse=True)(
130
- valstr("package_root", accept_none=True)
135
+ _label = field_validator("label")(classmethod(valstr("label")))
136
+ _package_root = field_validator("package_root")(
137
+ classmethod(valstr("package_root", accept_none=True))
131
138
  )
132
- _package_name = validator("package_name", allow_reuse=True)(
133
- valstr("package_name", accept_none=True)
139
+ _package_name = field_validator("package_name")(
140
+ classmethod(valstr("package_name", accept_none=True))
134
141
  )
135
- _version = validator("version", allow_reuse=True)(
136
- valstr("version", accept_none=True)
142
+ _version = field_validator("version")(
143
+ classmethod(valstr("version", accept_none=True))
137
144
  )
138
145
 
139
- @root_validator(pre=True)
146
+ @model_validator(mode="before")
147
+ @classmethod
140
148
  def one_of_package_root_or_name(cls, values):
141
149
  package_root = values.get("package_root")
142
150
  package_name = values.get("package_name")
@@ -149,18 +157,20 @@ class TaskCollectCustomV2(BaseModel, extra=Extra.forbid):
149
157
  )
150
158
  return values
151
159
 
152
- @validator("package_name")
160
+ @field_validator("package_name")
161
+ @classmethod
153
162
  def package_name_validator(cls, value: str):
154
163
  """
155
164
  Remove all whitespace characters, then check for invalid code.
156
165
  """
157
166
  if value is not None:
158
167
  validate_cmd(value)
159
- value = valstr("package_name")(value)
168
+ value = valstr("package_name")(cls, value)
160
169
  value = value.replace(" ", "")
161
170
  return value
162
171
 
163
- @validator("package_root")
172
+ @field_validator("package_root")
173
+ @classmethod
164
174
  def package_root_validator(cls, value):
165
175
  if (value is not None) and (not Path(value).is_absolute()):
166
176
  raise ValueError(
@@ -168,7 +178,8 @@ class TaskCollectCustomV2(BaseModel, extra=Extra.forbid):
168
178
  )
169
179
  return value
170
180
 
171
- @validator("python_interpreter")
181
+ @field_validator("python_interpreter")
182
+ @classmethod
172
183
  def python_interpreter_validator(cls, value):
173
184
  if not Path(value).is_absolute():
174
185
  raise ValueError(
@@ -3,9 +3,11 @@ from enum import Enum
3
3
  from typing import Optional
4
4
 
5
5
  from pydantic import BaseModel
6
- from pydantic import Extra
6
+ from pydantic import ConfigDict
7
7
  from pydantic import Field
8
- from pydantic import validator
8
+ from pydantic import field_serializer
9
+ from pydantic import field_validator
10
+ from pydantic.types import AwareDatetime
9
11
 
10
12
  from .._validators import val_absolute_path
11
13
  from .._validators import valdict_keys
@@ -32,7 +34,8 @@ class TaskGroupActivityActionV2(str, Enum):
32
34
  REACTIVATE = "reactivate"
33
35
 
34
36
 
35
- class TaskGroupCreateV2(BaseModel, extra=Extra.forbid):
37
+ class TaskGroupCreateV2(BaseModel):
38
+ model_config = ConfigDict(extra="forbid")
36
39
  user_id: int
37
40
  user_group_id: Optional[int] = None
38
41
  active: bool = True
@@ -48,21 +51,21 @@ class TaskGroupCreateV2(BaseModel, extra=Extra.forbid):
48
51
  pinned_package_versions: dict[str, str] = Field(default_factory=dict)
49
52
 
50
53
  # Validators
51
- _path = validator("path", allow_reuse=True)(val_absolute_path("path"))
52
- _venv_path = validator("venv_path", allow_reuse=True)(
53
- val_absolute_path("venv_path")
54
+ _path = field_validator("path")(classmethod(val_absolute_path("path")))
55
+ _venv_path = field_validator("venv_path")(
56
+ classmethod(val_absolute_path("venv_path"))
54
57
  )
55
- _wheel_path = validator("wheel_path", allow_reuse=True)(
56
- val_absolute_path("wheel_path")
58
+ _wheel_path = field_validator("wheel_path")(
59
+ classmethod(val_absolute_path("wheel_path"))
57
60
  )
58
- _pinned_package_versions = validator(
59
- "pinned_package_versions", allow_reuse=True
60
- )(valdict_keys("pinned_package_versions"))
61
- _pip_extras = validator("pip_extras", allow_reuse=True)(
62
- valstr("pip_extras")
61
+ _pinned_package_versions = field_validator("pinned_package_versions")(
62
+ valdict_keys("pinned_package_versions")
63
63
  )
64
- _python_version = validator("python_version", allow_reuse=True)(
65
- valstr("python_version")
64
+ _pip_extras = field_validator("pip_extras")(
65
+ classmethod(valstr("pip_extras"))
66
+ )
67
+ _python_version = field_validator("python_version")(
68
+ classmethod(valstr("python_version"))
66
69
  )
67
70
 
68
71
 
@@ -99,11 +102,16 @@ class TaskGroupReadV2(BaseModel):
99
102
  venv_file_number: Optional[int] = None
100
103
 
101
104
  active: bool
102
- timestamp_created: datetime
103
- timestamp_last_used: datetime
105
+ timestamp_created: AwareDatetime
106
+ timestamp_last_used: AwareDatetime
107
+
108
+ @field_serializer("timestamp_created", "timestamp_last_used")
109
+ def serialize_datetime(v: datetime) -> str:
110
+ return v.isoformat()
104
111
 
105
112
 
106
- class TaskGroupUpdateV2(BaseModel, extra=Extra.forbid):
113
+ class TaskGroupUpdateV2(BaseModel):
114
+ model_config = ConfigDict(extra="forbid")
107
115
  user_group_id: Optional[int] = None
108
116
 
109
117
 
@@ -111,10 +119,21 @@ class TaskGroupActivityV2Read(BaseModel):
111
119
  id: int
112
120
  user_id: int
113
121
  taskgroupv2_id: Optional[int] = None
114
- timestamp_started: datetime
115
- timestamp_ended: Optional[datetime] = None
122
+ timestamp_started: AwareDatetime
123
+ timestamp_ended: Optional[AwareDatetime] = None
116
124
  pkg_name: str
117
125
  version: str
118
126
  status: TaskGroupActivityStatusV2
119
127
  action: TaskGroupActivityActionV2
120
128
  log: Optional[str] = None
129
+
130
+ @field_serializer("timestamp_started")
131
+ def serialize_datetime_start(v: datetime) -> str:
132
+ return v.isoformat()
133
+
134
+ @field_serializer("timestamp_ended")
135
+ def serialize_datetime_end(v: Optional[datetime]) -> Optional[str]:
136
+ if v is None:
137
+ return None
138
+ else:
139
+ return v.isoformat()
@@ -2,8 +2,10 @@ from datetime import datetime
2
2
  from typing import Optional
3
3
 
4
4
  from pydantic import BaseModel
5
- from pydantic import Extra
6
- from pydantic import validator
5
+ from pydantic import ConfigDict
6
+ from pydantic import field_serializer
7
+ from pydantic import field_validator
8
+ from pydantic.types import AwareDatetime
7
9
 
8
10
  from .._validators import valstr
9
11
  from .project import ProjectReadV2
@@ -13,12 +15,14 @@ from .workflowtask import WorkflowTaskReadV2
13
15
  from .workflowtask import WorkflowTaskReadV2WithWarning
14
16
 
15
17
 
16
- class WorkflowCreateV2(BaseModel, extra=Extra.forbid):
18
+ class WorkflowCreateV2(BaseModel):
19
+
20
+ model_config = ConfigDict(extra="forbid")
17
21
 
18
22
  name: str
19
23
 
20
24
  # Validators
21
- _name = validator("name", allow_reuse=True)(valstr("name"))
25
+ _name = field_validator("name")(classmethod(valstr("name")))
22
26
 
23
27
 
24
28
  class WorkflowReadV2(BaseModel):
@@ -28,22 +32,29 @@ class WorkflowReadV2(BaseModel):
28
32
  project_id: int
29
33
  task_list: list[WorkflowTaskReadV2]
30
34
  project: ProjectReadV2
31
- timestamp_created: datetime
35
+ timestamp_created: AwareDatetime
36
+
37
+ @field_serializer("timestamp_created")
38
+ def serialize_datetime(v: datetime) -> str:
39
+ return v.isoformat()
32
40
 
33
41
 
34
42
  class WorkflowReadV2WithWarnings(WorkflowReadV2):
35
43
  task_list: list[WorkflowTaskReadV2WithWarning]
36
44
 
37
45
 
38
- class WorkflowUpdateV2(BaseModel, extra=Extra.forbid):
46
+ class WorkflowUpdateV2(BaseModel):
47
+
48
+ model_config = ConfigDict(extra="forbid")
39
49
 
40
- name: Optional[str]
41
- reordered_workflowtask_ids: Optional[list[int]]
50
+ name: Optional[str] = None
51
+ reordered_workflowtask_ids: Optional[list[int]] = None
42
52
 
43
53
  # Validators
44
- _name = validator("name", allow_reuse=True)(valstr("name"))
54
+ _name = field_validator("name")(classmethod(valstr("name")))
45
55
 
46
- @validator("reordered_workflowtask_ids")
56
+ @field_validator("reordered_workflowtask_ids")
57
+ @classmethod
47
58
  def check_positive_and_unique(cls, value):
48
59
  if any(i < 0 for i in value):
49
60
  raise ValueError("Negative `id` in `reordered_workflowtask_ids`")
@@ -52,7 +63,7 @@ class WorkflowUpdateV2(BaseModel, extra=Extra.forbid):
52
63
  return value
53
64
 
54
65
 
55
- class WorkflowImportV2(BaseModel, extra=Extra.forbid):
66
+ class WorkflowImportV2(BaseModel):
56
67
  """
57
68
  Class for `Workflow` import.
58
69
 
@@ -60,11 +71,12 @@ class WorkflowImportV2(BaseModel, extra=Extra.forbid):
60
71
  task_list:
61
72
  """
62
73
 
74
+ model_config = ConfigDict(extra="forbid")
63
75
  name: str
64
76
  task_list: list[WorkflowTaskImportV2]
65
77
 
66
78
  # Validators
67
- _name = validator("name", allow_reuse=True)(valstr("name"))
79
+ _name = field_validator("name")(classmethod(valstr("name")))
68
80
 
69
81
 
70
82
  class WorkflowExportV2(BaseModel):
@@ -4,10 +4,10 @@ from typing import Optional
4
4
  from typing import Union
5
5
 
6
6
  from pydantic import BaseModel
7
- from pydantic import Extra
7
+ from pydantic import ConfigDict
8
8
  from pydantic import Field
9
- from pydantic import root_validator
10
- from pydantic import validator
9
+ from pydantic import field_validator
10
+ from pydantic import model_validator
11
11
 
12
12
  from .._filter_validators import validate_type_filters
13
13
  from .._validators import root_validate_dict_keys
@@ -39,34 +39,35 @@ class WorkflowTaskStatusTypeV2(str, Enum):
39
39
  FAILED = "failed"
40
40
 
41
41
 
42
- class WorkflowTaskCreateV2(BaseModel, extra=Extra.forbid):
42
+ class WorkflowTaskCreateV2(BaseModel):
43
+ model_config = ConfigDict(extra="forbid")
43
44
 
44
- meta_non_parallel: Optional[dict[str, Any]]
45
- meta_parallel: Optional[dict[str, Any]]
46
- args_non_parallel: Optional[dict[str, Any]]
47
- args_parallel: Optional[dict[str, Any]]
45
+ meta_non_parallel: Optional[dict[str, Any]] = None
46
+ meta_parallel: Optional[dict[str, Any]] = None
47
+ args_non_parallel: Optional[dict[str, Any]] = None
48
+ args_parallel: Optional[dict[str, Any]] = None
48
49
  type_filters: dict[str, bool] = Field(default_factory=dict)
49
50
 
50
51
  # Validators
51
- _dict_keys = root_validator(pre=True, allow_reuse=True)(
52
- root_validate_dict_keys
52
+ _dict_keys = model_validator(mode="before")(
53
+ classmethod(root_validate_dict_keys)
53
54
  )
54
- _type_filters = validator("type_filters", allow_reuse=True)(
55
- validate_type_filters
55
+ _type_filters = field_validator("type_filters")(
56
+ classmethod(validate_type_filters)
56
57
  )
57
-
58
- _meta_non_parallel = validator("meta_non_parallel", allow_reuse=True)(
59
- valdict_keys("meta_non_parallel")
58
+ _meta_non_parallel = field_validator("meta_non_parallel")(
59
+ classmethod(valdict_keys("meta_non_parallel"))
60
60
  )
61
- _meta_parallel = validator("meta_parallel", allow_reuse=True)(
62
- valdict_keys("meta_parallel")
61
+ _meta_parallel = field_validator("meta_parallel")(
62
+ classmethod(valdict_keys("meta_parallel"))
63
63
  )
64
64
 
65
- @validator("args_non_parallel")
65
+ @field_validator("args_non_parallel")
66
+ @classmethod
66
67
  def validate_args_non_parallel(cls, value):
67
68
  if value is None:
68
69
  return
69
- valdict_keys("args_non_parallel")(value)
70
+ valdict_keys("args_non_parallel")(cls, value)
70
71
  args_keys = set(value.keys())
71
72
  intersect_keys = RESERVED_ARGUMENTS.intersection(args_keys)
72
73
  if intersect_keys:
@@ -76,11 +77,12 @@ class WorkflowTaskCreateV2(BaseModel, extra=Extra.forbid):
76
77
  )
77
78
  return value
78
79
 
79
- @validator("args_parallel")
80
+ @field_validator("args_parallel")
81
+ @classmethod
80
82
  def validate_args_parallel(cls, value):
81
83
  if value is None:
82
84
  return
83
- valdict_keys("args_parallel")(value)
85
+ valdict_keys("args_parallel")(cls, value)
84
86
  args_keys = set(value.keys())
85
87
  intersect_keys = RESERVED_ARGUMENTS.intersection(args_keys)
86
88
  if intersect_keys:
@@ -99,16 +101,15 @@ class WorkflowTaskReplaceV2(BaseModel):
99
101
 
100
102
 
101
103
  class WorkflowTaskReadV2(BaseModel):
102
-
103
104
  id: int
104
105
 
105
106
  workflow_id: int
106
- order: Optional[int]
107
- meta_non_parallel: Optional[dict[str, Any]]
108
- meta_parallel: Optional[dict[str, Any]]
107
+ order: Optional[int] = None
108
+ meta_non_parallel: Optional[dict[str, Any]] = None
109
+ meta_parallel: Optional[dict[str, Any]] = None
109
110
 
110
- args_non_parallel: Optional[dict[str, Any]]
111
- args_parallel: Optional[dict[str, Any]]
111
+ args_non_parallel: Optional[dict[str, Any]] = None
112
+ args_parallel: Optional[dict[str, Any]] = None
112
113
 
113
114
  type_filters: dict[str, bool]
114
115
 
@@ -121,34 +122,35 @@ class WorkflowTaskReadV2WithWarning(WorkflowTaskReadV2):
121
122
  warning: Optional[str] = None
122
123
 
123
124
 
124
- class WorkflowTaskUpdateV2(BaseModel, extra=Extra.forbid):
125
+ class WorkflowTaskUpdateV2(BaseModel):
126
+ model_config = ConfigDict(extra="forbid")
125
127
 
126
- meta_non_parallel: Optional[dict[str, Any]]
127
- meta_parallel: Optional[dict[str, Any]]
128
- args_non_parallel: Optional[dict[str, Any]]
129
- args_parallel: Optional[dict[str, Any]]
130
- type_filters: Optional[dict[str, bool]]
128
+ meta_non_parallel: Optional[dict[str, Any]] = None
129
+ meta_parallel: Optional[dict[str, Any]] = None
130
+ args_non_parallel: Optional[dict[str, Any]] = None
131
+ args_parallel: Optional[dict[str, Any]] = None
132
+ type_filters: Optional[dict[str, bool]] = None
131
133
 
132
134
  # Validators
133
- _dict_keys = root_validator(pre=True, allow_reuse=True)(
134
- root_validate_dict_keys
135
+ _dict_keys = model_validator(mode="before")(
136
+ classmethod(root_validate_dict_keys)
135
137
  )
136
- _type_filters = validator("type_filters", allow_reuse=True)(
137
- validate_type_filters
138
+ _type_filters = field_validator("type_filters")(
139
+ classmethod(validate_type_filters)
138
140
  )
139
-
140
- _meta_non_parallel = validator("meta_non_parallel", allow_reuse=True)(
141
- valdict_keys("meta_non_parallel")
141
+ _meta_non_parallel = field_validator("meta_non_parallel")(
142
+ classmethod(valdict_keys("meta_non_parallel"))
142
143
  )
143
- _meta_parallel = validator("meta_parallel", allow_reuse=True)(
144
- valdict_keys("meta_parallel")
144
+ _meta_parallel = field_validator("meta_parallel")(
145
+ classmethod(valdict_keys("meta_parallel"))
145
146
  )
146
147
 
147
- @validator("args_non_parallel")
148
+ @field_validator("args_non_parallel")
149
+ @classmethod
148
150
  def validate_args_non_parallel(cls, value):
149
151
  if value is None:
150
152
  return
151
- valdict_keys("args_non_parallel")(value)
153
+ valdict_keys("args_non_parallel")(cls, value)
152
154
  args_keys = set(value.keys())
153
155
  intersect_keys = RESERVED_ARGUMENTS.intersection(args_keys)
154
156
  if intersect_keys:
@@ -158,11 +160,12 @@ class WorkflowTaskUpdateV2(BaseModel, extra=Extra.forbid):
158
160
  )
159
161
  return value
160
162
 
161
- @validator("args_parallel")
163
+ @field_validator("args_parallel")
164
+ @classmethod
162
165
  def validate_args_parallel(cls, value):
163
166
  if value is None:
164
167
  return
165
- valdict_keys("args_parallel")(value)
168
+ valdict_keys("args_parallel")(cls, value)
166
169
  args_keys = set(value.keys())
167
170
  intersect_keys = RESERVED_ARGUMENTS.intersection(args_keys)
168
171
  if intersect_keys:
@@ -173,7 +176,8 @@ class WorkflowTaskUpdateV2(BaseModel, extra=Extra.forbid):
173
176
  return value
174
177
 
175
178
 
176
- class WorkflowTaskImportV2(BaseModel, extra=Extra.forbid):
179
+ class WorkflowTaskImportV2(BaseModel):
180
+ model_config = ConfigDict(extra="forbid")
177
181
 
178
182
  meta_non_parallel: Optional[dict[str, Any]] = None
179
183
  meta_parallel: Optional[dict[str, Any]] = None
@@ -185,7 +189,8 @@ class WorkflowTaskImportV2(BaseModel, extra=Extra.forbid):
185
189
  task: Union[TaskImportV2, TaskImportV2Legacy]
186
190
 
187
191
  # Validators
188
- @root_validator(pre=True)
192
+ @model_validator(mode="before")
193
+ @classmethod
189
194
  def update_legacy_filters(cls, values: dict):
190
195
  """
191
196
  Transform legacy filters (created with fractal-server<2.11.0)
@@ -197,7 +202,6 @@ class WorkflowTaskImportV2(BaseModel, extra=Extra.forbid):
197
202
  "Cannot set filters both through the legacy field "
198
203
  "('filters') and the new one ('type_filters')."
199
204
  )
200
-
201
205
  else:
202
206
  # As of 2.11.0, WorkflowTask do not have attribute filters
203
207
  # any more.
@@ -213,26 +217,24 @@ class WorkflowTaskImportV2(BaseModel, extra=Extra.forbid):
213
217
 
214
218
  return values
215
219
 
216
- _type_filters = validator("type_filters", allow_reuse=True)(
217
- validate_type_filters
220
+ _type_filters = field_validator("type_filters")(
221
+ classmethod(validate_type_filters)
218
222
  )
219
-
220
- _meta_non_parallel = validator("meta_non_parallel", allow_reuse=True)(
221
- valdict_keys("meta_non_parallel")
223
+ _meta_non_parallel = field_validator("meta_non_parallel")(
224
+ classmethod(valdict_keys("meta_non_parallel"))
222
225
  )
223
- _meta_parallel = validator("meta_parallel", allow_reuse=True)(
224
- valdict_keys("meta_parallel")
226
+ _meta_parallel = field_validator("meta_parallel")(
227
+ classmethod(valdict_keys("meta_parallel"))
225
228
  )
226
- _args_non_parallel = validator("args_non_parallel", allow_reuse=True)(
227
- valdict_keys("args_non_parallel")
229
+ _args_non_parallel = field_validator("args_non_parallel")(
230
+ classmethod(valdict_keys("args_non_parallel"))
228
231
  )
229
- _args_parallel = validator("args_parallel", allow_reuse=True)(
230
- valdict_keys("args_parallel")
232
+ _args_parallel = field_validator("args_parallel")(
233
+ classmethod(valdict_keys("args_parallel"))
231
234
  )
232
235
 
233
236
 
234
237
  class WorkflowTaskExportV2(BaseModel):
235
-
236
238
  meta_non_parallel: Optional[dict[str, Any]] = None
237
239
  meta_parallel: Optional[dict[str, Any]] = None
238
240
  args_non_parallel: Optional[dict[str, Any]] = None
@@ -83,7 +83,7 @@ class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
83
83
 
84
84
  session: AsyncSession
85
85
  user_model: Type[UP]
86
- oauth_account_model: Optional[Type[OAuthAccount]]
86
+ oauth_account_model: Optional[Type[OAuthAccount]] = None
87
87
 
88
88
  def __init__(
89
89
  self,