Skip to content

Commit 5e42c7c

Browse files
bump-pydantic
1 parent 6d6f5c5 commit 5e42c7c

File tree

14 files changed

+439
-154
lines changed

14 files changed

+439
-154
lines changed

services/api-server/requirements/_base.txt

Lines changed: 311 additions & 20 deletions
Large diffs are not rendered by default.

services/api-server/requirements/_test.txt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ anyio==4.3.0
1919
# httpx
2020
asgi-lifespan==2.1.0
2121
# via -r requirements/_test.in
22-
async-timeout==4.0.3
23-
# via
24-
# -c requirements/_base.txt
25-
# aiohttp
2622
attrs==23.2.0
2723
# via
2824
# -c requirements/_base.txt
@@ -91,11 +87,6 @@ ecdsa==0.19.0
9187
# moto
9288
# python-jose
9389
# sshpubkeys
94-
exceptiongroup==1.2.0
95-
# via
96-
# -c requirements/_base.txt
97-
# anyio
98-
# pytest
9990
faker==27.0.0
10091
# via -r requirements/_test.in
10192
flask==2.1.3
@@ -318,11 +309,6 @@ sqlalchemy2-stubs==0.0.2a38
318309
# via sqlalchemy
319310
sshpubkeys==3.3.1
320311
# via moto
321-
tomli==2.0.1
322-
# via
323-
# coverage
324-
# mypy
325-
# pytest
326312
types-aiofiles==24.1.0.20240626
327313
# via -r requirements/_test.in
328314
types-awscrt==0.21.2
@@ -335,7 +321,6 @@ typing-extensions==4.10.0
335321
# via
336322
# -c requirements/_base.txt
337323
# alembic
338-
# anyio
339324
# boto3-stubs
340325
# mypy
341326
# sqlalchemy2-stubs

services/api-server/requirements/_tools.txt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,22 +91,12 @@ setuptools==69.2.0
9191
# -c requirements/_base.txt
9292
# -c requirements/_test.txt
9393
# pip-tools
94-
tomli==2.0.1
95-
# via
96-
# -c requirements/_test.txt
97-
# black
98-
# build
99-
# mypy
100-
# pip-tools
101-
# pylint
10294
tomlkit==0.13.2
10395
# via pylint
10496
typing-extensions==4.10.0
10597
# via
10698
# -c requirements/_base.txt
10799
# -c requirements/_test.txt
108-
# astroid
109-
# black
110100
# mypy
111101
virtualenv==20.26.3
112102
# via pre-commit

services/api-server/src/simcore_service_api_server/core/settings.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
from functools import cached_property
22

33
from models_library.basic_types import BootModeEnum, LogLevel
4-
from pydantic import Field, NonNegativeInt, PositiveInt, SecretStr
5-
from pydantic.class_validators import validator
4+
from pydantic import (
5+
AliasChoices,
6+
Field,
7+
NonNegativeInt,
8+
PositiveInt,
9+
SecretStr,
10+
field_validator,
11+
)
612
from settings_library.base import BaseCustomSettings
713
from settings_library.catalog import CatalogSettings
814
from settings_library.director_v2 import DirectorV2Settings
@@ -24,11 +30,14 @@ class WebServerSettings(WebServerBaseSettings, MixinSessionSettings):
2430
description="Secret key to encrypt cookies. "
2531
'TIP: python3 -c "from cryptography.fernet import *; print(Fernet.generate_key())"',
2632
min_length=44,
27-
env=["SESSION_SECRET_KEY", "WEBSERVER_SESSION_SECRET_KEY"],
33+
validation_alias=AliasChoices(
34+
"SESSION_SECRET_KEY", "WEBSERVER_SESSION_SECRET_KEY"
35+
),
2836
)
2937
WEBSERVER_SESSION_NAME: str = DEFAULT_SESSION_COOKIE_NAME
3038

31-
@validator("WEBSERVER_SESSION_SECRET_KEY")
39+
@field_validator("WEBSERVER_SESSION_SECRET_KEY")
40+
@classmethod
3241
@classmethod
3342
def check_valid_fernet_key(cls, v):
3443
return cls.do_check_valid_fernet_key(v)
@@ -41,21 +50,25 @@ class BasicSettings(BaseCustomSettings, MixinLoggingSettings):
4150
# DEVELOPMENT
4251
API_SERVER_DEV_FEATURES_ENABLED: bool = Field(
4352
default=False,
44-
env=["API_SERVER_DEV_FEATURES_ENABLED", "FAKE_API_SERVER_ENABLED"],
53+
validation_alias=AliasChoices(
54+
"API_SERVER_DEV_FEATURES_ENABLED", "FAKE_API_SERVER_ENABLED"
55+
),
4556
)
4657

4758
# LOGGING
4859
LOG_LEVEL: LogLevel = Field(
4960
default=LogLevel.INFO.value,
50-
env=["API_SERVER_LOGLEVEL", "LOG_LEVEL", "LOGLEVEL"],
61+
validation_alias=AliasChoices("API_SERVER_LOGLEVEL", "LOG_LEVEL", "LOGLEVEL"),
5162
)
5263
API_SERVER_LOG_FORMAT_LOCAL_DEV_ENABLED: bool = Field(
5364
default=False,
54-
env=["API_SERVER_LOG_FORMAT_LOCAL_DEV_ENABLED", "LOG_FORMAT_LOCAL_DEV_ENABLED"],
65+
validation_alias=AliasChoices(
66+
"API_SERVER_LOG_FORMAT_LOCAL_DEV_ENABLED", "LOG_FORMAT_LOCAL_DEV_ENABLED"
67+
),
5568
description="Enables local development log format. WARNING: make sure it is disabled if you want to have structured logs!",
5669
)
5770

58-
@validator("LOG_LEVEL", pre=True)
71+
@field_validator("LOG_LEVEL", mode="before")
5972
@classmethod
6073
def _validate_loglevel(cls, value) -> str:
6174
log_level: str = cls.validate_log_level(value)

services/api-server/src/simcore_service_api_server/models/api_resources.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import urllib.parse
33
from typing import Any
44

5-
from pydantic import BaseModel, Field
5+
from pydantic import BaseModel, ConfigDict, Field
66
from pydantic.types import ConstrainedStr
77

88
# RESOURCE NAMES https://cloud.google.com/apis/design/resource_names
@@ -32,9 +32,7 @@
3232

3333
class RelativeResourceName(ConstrainedStr):
3434
regex = re.compile(_RELATIVE_RESOURCE_NAME_RE)
35-
36-
class Config:
37-
frozen = True
35+
model_config = ConfigDict(frozen=True)
3836

3937

4038
# NOTE: we quote parts in a single resource_name and unquote when split
@@ -67,10 +65,12 @@ def split_resource_name(resource_name: RelativeResourceName) -> list[str]:
6765
# Resource IDs must be clearly documented whether they are assigned by the client, the server, or either
6866
#
6967
class BaseResource(BaseModel):
70-
name: RelativeResourceName = Field(None, example="solvers/isolve/releases/1.2.3")
71-
id: Any = Field(None, description="Resource ID", example="1.2.3") # noqa: A003
68+
name: RelativeResourceName = Field(None, examples=["solvers/isolve/releases/1.2.3"])
69+
id: Any = Field(None, description="Resource ID", examples=["1.2.3"]) # noqa: A003
7270

7371

7472
class BaseCollection(BaseModel):
75-
name: RelativeResourceName = Field(None, example="solvers/isolve/releases")
76-
id: Any = Field(None, description="Collection ID", example="releases") # noqa: A003
73+
name: RelativeResourceName = Field(None, examples=["solvers/isolve/releases"])
74+
id: Any = Field(
75+
None, description="Collection ID", examples=["releases"]
76+
) # noqa: A003

services/api-server/src/simcore_service_api_server/models/pagination.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"""
88

99
from collections.abc import Sequence
10-
from typing import Any, ClassVar, Generic, TypeAlias, TypeVar
10+
from typing import Generic, TypeAlias, TypeVar
1111

1212
from fastapi_pagination.limit_offset import LimitOffsetParams
1313
from fastapi_pagination.links.limit_offset import (
@@ -18,8 +18,7 @@
1818
MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE,
1919
)
2020
from models_library.utils.pydantic_tools_extension import FieldNotRequired
21-
from pydantic import Field, NonNegativeInt, validator
22-
from pydantic.generics import GenericModel
21+
from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt
2322

2423
T = TypeVar("T")
2524

@@ -35,7 +34,7 @@
3534
PaginationParams: TypeAlias = LimitOffsetParams
3635

3736

38-
class OnePage(GenericModel, Generic[T]):
37+
class OnePage(BaseModel, Generic[T]):
3938
"""
4039
A single page is used to envelope a small sequence that does not require
4140
pagination
@@ -47,7 +46,7 @@ class OnePage(GenericModel, Generic[T]):
4746
items: Sequence[T]
4847
total: NonNegativeInt = FieldNotRequired()
4948

50-
@validator("total", pre=True)
49+
@field_validator("total", mode="before")
5150
@classmethod
5251
def check_total(cls, v, values):
5352
items = values["items"]
@@ -60,9 +59,9 @@ def check_total(cls, v, values):
6059

6160
return v
6261

63-
class Config:
64-
frozen = True
65-
schema_extra: ClassVar[dict[str, Any]] = {
62+
model_config = ConfigDict(
63+
frozen=True,
64+
json_schema_extra={
6665
"examples": [
6766
{
6867
"total": 1,
@@ -72,7 +71,8 @@ class Config:
7271
"items": ["one"],
7372
},
7473
],
75-
}
74+
},
75+
)
7676

7777

7878
__all__: tuple[str, ...] = (
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from typing import Any, ClassVar
1+
from typing import Any
22

3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, ConfigDict
44

55

66
class ErrorGet(BaseModel):
@@ -11,12 +11,13 @@ class ErrorGet(BaseModel):
1111
# - https://github.com/ITISFoundation/osparc-simcore/issues/2446
1212
errors: list[Any]
1313

14-
class Config:
15-
schema_extra: ClassVar[dict[str, Any]] = {
14+
model_config = ConfigDict(
15+
json_schema_extra={
1616
"example": {
1717
"errors": [
1818
"some error message",
1919
"another error message",
2020
]
2121
}
2222
}
23+
)

services/api-server/src/simcore_service_api_server/models/schemas/files.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from mimetypes import guess_type
22
from pathlib import Path
3-
from typing import Any, ClassVar
3+
from typing import Annotated
44
from urllib.parse import quote as _quote
55
from urllib.parse import unquote as _unquote
66
from uuid import UUID, uuid3
@@ -14,18 +14,18 @@
1414
AnyUrl,
1515
BaseModel,
1616
ByteSize,
17-
ConstrainedStr,
17+
ConfigDict,
1818
Field,
19+
StringConstraints,
20+
field_validator,
1921
parse_obj_as,
20-
validator,
2122
)
2223
from servicelib.file_utils import create_sha256_checksum
2324

2425
_NAMESPACE_FILEID_KEY = UUID("aa154444-d22d-4290-bb15-df37dba87865")
2526

2627

27-
class FileName(ConstrainedStr):
28-
strip_whitespace = True
28+
FileName = Annotated[str, StringConstraints(strip_whitespace=True)]
2929

3030

3131
class ClientFile(BaseModel):
@@ -46,7 +46,9 @@ class File(BaseModel):
4646

4747
filename: str = Field(..., description="Name of the file with extension")
4848
content_type: str | None = Field(
49-
default=None, description="Guess of type content [EXPERIMENTAL]"
49+
default=None,
50+
description="Guess of type content [EXPERIMENTAL]",
51+
validate_default=True,
5052
)
5153
sha256_checksum: SHA256Str | None = Field(
5254
default=None,
@@ -55,9 +57,9 @@ class File(BaseModel):
5557
)
5658
e_tag: ETag | None = Field(default=None, description="S3 entity tag")
5759

58-
class Config:
59-
allow_population_by_field_name = True
60-
schema_extra: ClassVar[dict[str, Any]] = {
60+
model_config = ConfigDict(
61+
populate_by_name=True,
62+
json_schema_extra={
6163
"examples": [
6264
# complete
6365
{
@@ -72,9 +74,10 @@ class Config:
7274
"filename": "whitepaper.pdf",
7375
},
7476
]
75-
}
77+
},
78+
)
7679

77-
@validator("content_type", always=True, pre=True)
80+
@field_validator("content_type", mode="before")
7881
@classmethod
7982
def guess_content_type(cls, v, values):
8083
if v is None:

0 commit comments

Comments
 (0)