Skip to content

Commit 9e76d4f

Browse files
authored
⬆️Pydantic V2: Diverse fixes after merges from master (#6627)
1 parent afa0b3c commit 9e76d4f

File tree

25 files changed

+126
-140
lines changed

25 files changed

+126
-140
lines changed

.env-devel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ DYNAMIC_SIDECAR_IMAGE=${DOCKER_REGISTRY:-itisfoundation}/dynamic-sidecar:${DOCKE
104104
DYNAMIC_SIDECAR_LOG_LEVEL=DEBUG
105105
DYNAMIC_SIDECAR_PROMETHEUS_MONITORING_NETWORKS=[]
106106
DYNAMIC_SIDECAR_PROMETHEUS_SERVICE_LABELS={}
107-
DYNAMIC_SIDECAR_API_SAVE_RESTORE_STATE_TIMEOUT=3600
107+
DYNAMIC_SIDECAR_API_SAVE_RESTORE_STATE_TIMEOUT=01:00:00
108108
# DIRECTOR_V2 ----
109109
DYNAMIC_SCHEDULER_LOGLEVEL=DEBUG
110110
DYNAMIC_SCHEDULER_PROFILING=1
111-
DYNAMIC_SCHEDULER_STOP_SERVICE_TIMEOUT=3600
111+
DYNAMIC_SCHEDULER_STOP_SERVICE_TIMEOUT=01:00:00
112112

113113
FUNCTION_SERVICES_AUTHORS='{"UN": {"name": "Unknown", "email": "[email protected]", "affiliation": "unknown"}}'
114114

packages/models-library/src/models_library/api_schemas__common/errors.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from pydantic import BaseModel, Field
55

66
from ..basic_types import IDStr
7-
from ..utils.pydantic_tools_extension import NOT_REQUIRED
87

98

109
class DefaultApiError(BaseModel):
@@ -13,7 +12,7 @@ class DefaultApiError(BaseModel):
1312
description="Error identifier as a code or a name. "
1413
"Mainly for machine-machine communication purposes.",
1514
)
16-
detail: Any | None = Field(NOT_REQUIRED, description="Human readable error message")
15+
detail: Any | None = Field(default=None, description="Human readable error message")
1716

1817
@classmethod
1918
def from_status_code(

packages/models-library/src/models_library/api_schemas_webserver/projects.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
from datetime import datetime
99
from typing import Any, Literal, TypeAlias
1010

11-
from models_library.folders import FolderID
12-
from models_library.workspaces import WorkspaceID
1311
from pydantic import ConfigDict, Field, HttpUrl, field_validator
1412

1513
from ..api_schemas_long_running_tasks.tasks import TaskGet
1614
from ..basic_types import LongTruncatedStr, ShortTruncatedStr
1715
from ..emails import LowerCaseEmailStr
16+
from ..folders import FolderID
1817
from ..projects import ClassifierID, DateTimeStr, NodesDict, ProjectID
1918
from ..projects_access import AccessRights, GroupIDStr
2019
from ..projects_state import ProjectState
@@ -24,7 +23,7 @@
2423
none_to_empty_str_pre_validator,
2524
null_or_none_str_to_none_validator,
2625
)
27-
from ..utils.pydantic_tools_extension import FieldNotRequired
26+
from ..workspaces import WorkspaceID
2827
from ._base import EmptyModel, InputSchema, OutputSchema
2928
from .permalinks import ProjectPermalink
3029

@@ -74,12 +73,16 @@ class ProjectGet(OutputSchema):
7473
prj_owner: LowerCaseEmailStr
7574
access_rights: dict[GroupIDStr, AccessRights]
7675
tags: list[int]
77-
classifiers: list[ClassifierID] = []
76+
classifiers: list[ClassifierID] = Field(
77+
default_factory=list, json_schema_extra={"default": []}
78+
)
7879
state: ProjectState | None = None
7980
ui: EmptyModel | StudyUI | None = None
80-
quality: dict[str, Any] = {}
81+
quality: dict[str, Any] = Field(
82+
default_factory=dict, json_schema_extra={"default": {}}
83+
)
8184
dev: dict | None
82-
permalink: ProjectPermalink = FieldNotRequired()
85+
permalink: ProjectPermalink | None = None
8386
workspace_id: WorkspaceID | None
8487
folder_id: FolderID | None
8588
trashed_at: datetime | None
@@ -107,13 +110,15 @@ class ProjectReplace(InputSchema):
107110
last_change_date: DateTimeStr
108111
workbench: NodesDict
109112
access_rights: dict[GroupIDStr, AccessRights]
110-
tags: list[int] | None = []
113+
tags: list[int] | None = Field(
114+
default_factory=list, json_schema_extra={"default": []}
115+
)
111116
classifiers: list[ClassifierID] | None = Field(
112-
default_factory=list,
117+
default_factory=list, json_schema_extra={"default": []}
113118
)
114119
ui: StudyUI | None = None
115120
quality: dict[str, Any] = Field(
116-
default_factory=dict,
121+
default_factory=dict, json_schema_extra={"default": {}}
117122
)
118123

119124
_empty_is_none = field_validator("thumbnail", mode="before")(
@@ -122,16 +127,16 @@ class ProjectReplace(InputSchema):
122127

123128

124129
class ProjectPatch(InputSchema):
125-
name: ShortTruncatedStr = FieldNotRequired()
126-
description: LongTruncatedStr = FieldNotRequired()
127-
thumbnail: HttpUrl = FieldNotRequired()
128-
access_rights: dict[GroupIDStr, AccessRights] = FieldNotRequired()
129-
classifiers: list[ClassifierID] = FieldNotRequired()
130-
dev: dict | None = FieldNotRequired()
131-
ui: StudyUI | None = FieldNotRequired()
132-
quality: dict[str, Any] = FieldNotRequired()
133-
134-
_empty_is_none = field_validator("thumbnail", allow_reuse=True, pre=True)(
130+
name: ShortTruncatedStr | None = Field(default=None)
131+
description: LongTruncatedStr | None = Field(default=None)
132+
thumbnail: HttpUrl | None = Field(default=None)
133+
access_rights: dict[GroupIDStr, AccessRights] | None = Field(default=None)
134+
classifiers: list[ClassifierID] | None = Field(default=None)
135+
dev: dict | None = Field(default=None)
136+
ui: StudyUI | None = Field(default=None)
137+
quality: dict[str, Any] | None = Field(default=None)
138+
139+
_empty_is_none = field_validator("thumbnail", mode="before")(
135140
empty_str_to_none_pre_validator
136141
)
137142

packages/models-library/src/models_library/api_schemas_webserver/projects_nodes.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from ..services import ServiceKey, ServicePortKey, ServiceVersion
1111
from ..services_enums import ServiceState
1212
from ..services_resources import ServiceResourcesDict
13-
from ..utils.pydantic_tools_extension import FieldNotRequired
1413
from ._base import InputSchemaWithoutCamelCase, OutputSchema
1514

1615
assert ServiceResourcesDict # nosec
@@ -27,19 +26,19 @@ class NodeCreate(InputSchemaWithoutCamelCase):
2726

2827

2928
class NodePatch(InputSchemaWithoutCamelCase):
30-
service_key: ServiceKey = FieldNotRequired(alias="key")
31-
service_version: ServiceVersion = FieldNotRequired(alias="version")
32-
label: str = FieldNotRequired()
33-
inputs: InputsDict = FieldNotRequired()
34-
inputs_required: list[InputID] = FieldNotRequired(alias="inputsRequired")
35-
input_nodes: list[NodeID] = FieldNotRequired(alias="inputNodes")
36-
progress: float | None = FieldNotRequired(
37-
ge=0, le=100
29+
service_key: ServiceKey | None = Field(default=None, alias="key")
30+
service_version: ServiceVersion | None = Field(default=None, alias="version")
31+
label: str | None = Field(default=None)
32+
inputs: InputsDict = Field(default=None)
33+
inputs_required: list[InputID] | None = Field(default=None, alias="inputsRequired")
34+
input_nodes: list[NodeID] | None = Field(default=None, alias="inputNodes")
35+
progress: float | None = Field(
36+
default=None, ge=0, le=100
3837
) # NOTE: it is used by frontend for File Picker progress
39-
boot_options: BootOptions = FieldNotRequired(alias="bootOptions")
40-
outputs: dict[
41-
str, Any
42-
] = FieldNotRequired() # NOTE: it is used by frontend for File Picker
38+
boot_options: BootOptions | None = Field(default=None, alias="bootOptions")
39+
outputs: dict[str, Any] | None = Field(
40+
default=None
41+
) # NOTE: it is used by frontend for File Picker
4342

4443

4544
class NodeCreated(OutputSchema):

packages/models-library/src/models_library/api_schemas_webserver/wallets.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from ..basic_types import AmountDecimal, IDStr, NonNegativeDecimal
88
from ..users import GroupID
9-
from ..utils.pydantic_tools_extension import FieldNotRequired
109
from ..wallets import WalletID, WalletStatus
1110
from ._base import InputSchema, OutputSchema
1211

@@ -21,9 +20,7 @@ class WalletGet(OutputSchema):
2120
created: datetime
2221
modified: datetime
2322

24-
model_config = ConfigDict(
25-
frozen=False
26-
)
23+
model_config = ConfigDict(frozen=False)
2724

2825

2926
class WalletGetWithAvailableCredits(WalletGet):
@@ -60,7 +57,7 @@ class PutWalletBodyParams(OutputSchema):
6057

6158
class CreateWalletPayment(InputSchema):
6259
price_dollars: AmountDecimal
63-
comment: str = FieldNotRequired(max_length=100)
60+
comment: str | None = Field(default=None, max_length=100)
6461

6562

6663
class WalletPaymentInitiated(OutputSchema):
@@ -77,15 +74,15 @@ class PaymentTransaction(OutputSchema):
7774
price_dollars: Decimal
7875
wallet_id: WalletID
7976
osparc_credits: Decimal
80-
comment: str = FieldNotRequired()
77+
comment: str | None = Field(default=None)
8178
created_at: datetime
8279
completed_at: datetime | None
8380
# SEE PaymentTransactionState enum
8481
state: Literal["PENDING", "SUCCESS", "FAILED", "CANCELED"] = Field(
8582
..., alias="completedStatus"
8683
)
87-
state_message: str = FieldNotRequired()
88-
invoice_url: HttpUrl = FieldNotRequired()
84+
state_message: str | None = Field(default=None)
85+
invoice_url: HttpUrl | None = Field(default=None)
8986

9087

9188
class PaymentMethodInitiated(OutputSchema):

packages/models-library/src/models_library/folders.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from datetime import datetime
22
from typing import TypeAlias
33

4-
from models_library.users import GroupID, UserID
5-
from models_library.workspaces import WorkspaceID
64
from pydantic import BaseModel, ConfigDict, Field, PositiveInt
75

6+
from .users import GroupID, UserID
7+
from .workspaces import WorkspaceID
8+
89
FolderID: TypeAlias = PositiveInt
910

1011

packages/models-library/src/models_library/projects.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class ProjectAtDB(BaseProjectModel):
9999
prj_owner: int | None = Field(..., description="The project owner id")
100100

101101
published: bool | None = Field(
102-
False, description="Defines if a study is available publicly"
102+
default=False, description="Defines if a study is available publicly"
103103
)
104104

105105
@field_validator("project_type", mode="before")
@@ -183,8 +183,4 @@ class Project(BaseProjectModel):
183183
alias="trashedAt",
184184
)
185185

186-
model_config = ConfigDict(
187-
description="Document that stores metadata, pipeline and UI setup of a study",
188-
title="osparc-simcore project",
189-
extra="forbid",
190-
)
186+
model_config = ConfigDict(title="osparc-simcore project", extra="forbid")

packages/models-library/src/models_library/rest_filters.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from typing import Generic, TypeVar
22

33
from pydantic import BaseModel, Field, Json
4-
from pydantic.generics import GenericModel
54

65

76
class Filters(BaseModel):
@@ -15,7 +14,7 @@ class Filters(BaseModel):
1514
FilterT = TypeVar("FilterT", bound=Filters)
1615

1716

18-
class FiltersQueryParameters(GenericModel, Generic[FilterT]):
17+
class FiltersQueryParameters(BaseModel, Generic[FilterT]):
1918
filters: Json[FilterT] | None = Field( # pylint: disable=unsubscriptable-object
2019
default=None,
2120
description="Custom filter query parameter encoded as JSON",

packages/models-library/src/models_library/utils/common_validators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class MyModel(BaseModel):
99
thumbnail: str | None
1010
11-
_empty_is_none = validator("thumbnail", allow_reuse=True, pre=True)(
11+
_empty_is_none = validator("thumbnail", mode="before")(
1212
empty_str_to_none_pre_validator
1313
)
1414
Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import functools
2-
from typing import Final, TypeVar
1+
from typing import TypeVar
32

4-
from pydantic import Field, TypeAdapter, ValidationError
3+
from pydantic import TypeAdapter, ValidationError
54

65
T = TypeVar("T")
76

@@ -11,17 +10,3 @@ def parse_obj_or_none(type_: type[T], obj) -> T | None:
1110
return TypeAdapter(type_).validate_python(obj)
1211
except ValidationError:
1312
return None
14-
15-
16-
#
17-
# NOTE: Helper to define non-nullable optional fields
18-
# SEE details in test/test_utils_pydantic_tools_extension.py
19-
#
20-
# Two usage styles:
21-
#
22-
# class Model(BaseModel):
23-
# value: FieldNotRequired(description="some optional field")
24-
# other: Field(NOT_REQUIRED, description="alternative")
25-
#
26-
NOT_REQUIRED: Final = None
27-
FieldNotRequired = functools.partial(Field, default=NOT_REQUIRED)

0 commit comments

Comments
 (0)