Skip to content

Commit

Permalink
⬆️ Upgrade models-library (pydantic v2) (#6333)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrei Neagu <[email protected]>
  • Loading branch information
giancarloromeo and GitHK authored Sep 18, 2024
1 parent 6d6f5c5 commit d2d81c0
Show file tree
Hide file tree
Showing 126 changed files with 2,444 additions and 2,081 deletions.
2 changes: 2 additions & 0 deletions packages/models-library/requirements/_base.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ arrow
jsonschema
orjson
pydantic[email]
pydantic-settings
pydantic-extra-types
18 changes: 16 additions & 2 deletions packages/models-library/requirements/_base.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
annotated-types==0.7.0
# via pydantic
arrow==1.3.0
# via -r requirements/_base.in
attrs==24.2.0
Expand All @@ -18,12 +20,22 @@ orjson==3.10.7
# via
# -c requirements/../../../requirements/constraints.txt
# -r requirements/_base.in
pydantic==1.10.17
pydantic==2.9.1
# via
# -c requirements/../../../requirements/constraints.txt
# -r requirements/_base.in
# pydantic-extra-types
# pydantic-settings
pydantic-core==2.23.3
# via pydantic
pydantic-extra-types==2.9.0
# via -r requirements/_base.in
pydantic-settings==2.4.0
# via -r requirements/_base.in
python-dateutil==2.9.0.post0
# via arrow
python-dotenv==1.0.1
# via pydantic-settings
referencing==0.35.1
# via
# jsonschema
Expand All @@ -37,4 +49,6 @@ six==1.16.0
types-python-dateutil==2.9.0.20240821
# via arrow
typing-extensions==4.12.2
# via pydantic
# via
# pydantic
# pydantic-core
10 changes: 3 additions & 7 deletions packages/models-library/requirements/_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ coverage==7.6.1
# via
# -r requirements/_test.in
# pytest-cov
exceptiongroup==1.2.2
# via pytest
faker==27.0.0
# via -r requirements/_test.in
flexcache==0.3
Expand Down Expand Up @@ -68,7 +66,9 @@ python-dateutil==2.9.0.post0
# -c requirements/_base.txt
# faker
python-dotenv==1.0.1
# via -r requirements/_test.in
# via
# -c requirements/_base.txt
# -r requirements/_test.in
pyyaml==6.0.2
# via
# -c requirements/../../../requirements/constraints.txt
Expand All @@ -87,10 +87,6 @@ six==1.16.0
# python-dateutil
termcolor==2.4.0
# via pytest-sugar
tomli==2.0.1
# via
# coverage
# pytest
types-jsonschema==4.23.0.20240813
# via -r requirements/_test.in
types-pyyaml==6.0.12.20240808
Expand Down
10 changes: 0 additions & 10 deletions packages/models-library/requirements/_tools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,6 @@ setuptools==73.0.1
# via pip-tools
shellingham==1.5.4
# via typer
tomli==2.0.1
# via
# -c requirements/_test.txt
# black
# build
# mypy
# pip-tools
# pylint
tomlkit==0.13.2
# via pylint
typer==0.12.4
Expand All @@ -94,8 +86,6 @@ typing-extensions==4.12.2
# via
# -c requirements/_base.txt
# -c requirements/_test.txt
# astroid
# black
# mypy
# typer
virtualenv==20.26.3
Expand Down
12 changes: 5 additions & 7 deletions packages/models-library/scripts/validate-pg-projects.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@

import typer
from models_library.projects import ProjectAtDB
from pydantic import Json, ValidationError, validator
from pydantic.main import Extra
from pydantic import ConfigDict, Json, ValidationError, field_validator


class ProjectFromCsv(ProjectAtDB):
class Config(ProjectAtDB.Config):
extra = Extra.forbid

# TODO: missing in ProjectAtDB

access_rights: Json
Expand All @@ -22,17 +18,19 @@ class Config(ProjectAtDB.Config):

hidden: bool

model_config = ConfigDict(extra="forbid")

# NOTE: validators introduced to parse CSV

@validator("published", "hidden", pre=True, check_fields=False)
@field_validator("published", "hidden", mode="before", check_fields=False)
@classmethod
def empty_str_as_false(cls, v):
# See booleans for >v1.0 https://pydantic-docs.helpmanual.io/usage/types/#booleans
if isinstance(v, str) and v == "":
return False
return v

@validator("workbench", pre=True, check_fields=False)
@field_validator("workbench", mode="before", check_fields=False)
@classmethod
def jsonstr_to_dict(cls, v):
if isinstance(v, str):
Expand Down
5 changes: 2 additions & 3 deletions packages/models-library/src/models_library/access_rights.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from pydantic import BaseModel, Extra, Field
from pydantic import BaseModel, ConfigDict, Field


class AccessRights(BaseModel):
read: bool = Field(..., description="has read access")
write: bool = Field(..., description="has write access")
delete: bool = Field(..., description="has deletion rights")

class Config:
extra = Extra.forbid
model_config = ConfigDict(extra="forbid")
11 changes: 4 additions & 7 deletions packages/models-library/src/models_library/aiodocker_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import Field, validator
from pydantic import ConfigDict, Field, field_validator

from .generated_models.docker_rest_api import (
ContainerSpec,
Expand All @@ -16,7 +16,7 @@ class AioDockerContainerSpec(ContainerSpec):
description="aiodocker expects here a dictionary and re-convert it back internally`.\n",
)

@validator("Env", pre=True)
@field_validator("Env", mode="before")
@classmethod
def convert_list_to_dict(cls, v):
if v is not None and isinstance(v, list):
Expand All @@ -37,8 +37,7 @@ class AioDockerResources1(Resources1):
None, description="Define resources reservation.", alias="Reservations"
)

class Config(Resources1.Config): # type: ignore
allow_population_by_field_name = True
model_config = ConfigDict(populate_by_name=True)


class AioDockerTaskSpec(TaskSpec):
Expand All @@ -55,6 +54,4 @@ class AioDockerTaskSpec(TaskSpec):
class AioDockerServiceSpec(ServiceSpec):
TaskTemplate: AioDockerTaskSpec | None = None

class Config(ServiceSpec.Config): # type: ignore
alias_generator = camel_to_snake
allow_population_by_field_name = True
model_config = ConfigDict(populate_by_name=True, alias_generator=camel_to_snake)
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from typing import Any, ClassVar

from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field

from ..basic_types import VersionStr

Expand All @@ -12,11 +10,12 @@ class BaseMeta(BaseModel):
default=None, description="Maps every route's path tag with a released version"
)

class Config:
schema_extra: ClassVar[dict[str, Any]] = {
model_config = ConfigDict(
json_schema_extra={
"example": {
"name": "simcore_service_foo",
"version": "2.4.45",
"released": {"v1": "1.3.4", "v2": "2.4.45"},
}
}
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import BaseModel, Field, SecretStr
from pydantic import BaseModel, ConfigDict, Field, SecretStr


class ApiKey(BaseModel):
Expand All @@ -15,5 +15,4 @@ class ApiKeyInDB(BaseModel):
user_id: int
product_name: str

class Config:
orm_mode = True
model_config = ConfigDict(from_attributes=True)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from datetime import datetime
from typing import Any, ClassVar, TypeAlias
from typing import Any, TypeAlias

from models_library.rpc_pagination import PageRpc
from pydantic import BaseModel, Extra, Field, HttpUrl, NonNegativeInt
from pydantic import BaseModel, ConfigDict, Field, HttpUrl, NonNegativeInt

from ..boot_options import BootOptions
from ..emails import LowerCaseEmailStr
Expand All @@ -23,23 +23,23 @@


class ServiceUpdate(ServiceMetaDataEditable, ServiceAccessRights):
class Config:
schema_extra: ClassVar[dict[str, Any]] = {
model_config = ConfigDict(
json_schema_extra={
"example": {
# ServiceAccessRights
"accessRights": {
1: {
"execute_access": False,
"write_access": False,
},
}, # type: ignore[dict-item]
2: {
"execute_access": True,
"write_access": True,
},
}, # type: ignore[dict-item]
44: {
"execute_access": False,
"write_access": False,
},
}, # type: ignore[dict-item]
},
# ServiceMetaData = ServiceCommonData +
"name": "My Human Readable Service Name",
Expand Down Expand Up @@ -72,6 +72,7 @@ class Config:
},
}
}
)


_EXAMPLE_FILEPICKER: dict[str, Any] = {
Expand Down Expand Up @@ -206,12 +207,11 @@ class ServiceGet(
): # pylint: disable=too-many-ancestors
owner: LowerCaseEmailStr | None

class Config:
allow_population_by_field_name = True
extra = Extra.ignore
schema_extra: ClassVar[dict[str, Any]] = {
"examples": [_EXAMPLE_FILEPICKER, _EXAMPLE_SLEEPER]
}
model_config = ConfigDict(
extra="ignore",
populate_by_name=True,
json_schema_extra={"examples": [_EXAMPLE_FILEPICKER, _EXAMPLE_SLEEPER]},
)


class ServiceGetV2(BaseModel):
Expand All @@ -229,7 +229,7 @@ class ServiceGetV2(BaseModel):
service_type: ServiceType = Field(default=..., alias="type")

contact: LowerCaseEmailStr | None
authors: list[Author] = Field(..., min_items=1)
authors: list[Author] = Field(..., min_length=1)
owner: LowerCaseEmailStr | None

inputs: ServiceInputsDict
Expand All @@ -249,11 +249,11 @@ class ServiceGetV2(BaseModel):
" It includes current release.",
)

class Config:
extra = Extra.forbid
alias_generator = snake_to_camel
allow_population_by_field_name = True
schema_extra: ClassVar[dict[str, Any]] = {
model_config = ConfigDict(
extra="forbid",
populate_by_name=True,
alias_generator=snake_to_camel,
json_schema_extra={
"examples": [
{
**_EXAMPLE_SLEEPER, # v2.2.1 (latest)
Expand Down Expand Up @@ -304,7 +304,8 @@ class Config:
],
},
]
}
},
)


PageRpcServicesGetV2: TypeAlias = PageRpc[
Expand All @@ -330,12 +331,13 @@ class ServiceUpdateV2(BaseModel):

access_rights: dict[GroupID, ServiceGroupAccessRightsV2] | None = None

class Config:
extra = Extra.forbid
alias_generator = snake_to_camel
allow_population_by_field_name = True
model_config = ConfigDict(
extra="forbid",
populate_by_name=True,
alias_generator=snake_to_camel,
)


assert set(ServiceUpdateV2.__fields__.keys()) - set( # nosec
ServiceGetV2.__fields__.keys()
assert set(ServiceUpdateV2.model_fields.keys()) - set( # nosec
ServiceGetV2.model_fields.keys()
) == {"deprecated"}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, ClassVar, Literal
from typing import Any, Literal

from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field

from ..basic_regex import PUBLIC_VARIABLE_NAME_RE
from ..services import ServiceInput, ServiceOutput
Expand All @@ -17,7 +17,7 @@ class ServicePortGet(BaseModel):
key: str = Field(
...,
description="port identifier name",
regex=PUBLIC_VARIABLE_NAME_RE,
pattern=PUBLIC_VARIABLE_NAME_RE,
title="Key name",
)
kind: PortKindStr
Expand All @@ -26,9 +26,8 @@ class ServicePortGet(BaseModel):
None,
description="jsonschema for the port's value. SEE https://json-schema.org/understanding-json-schema/",
)

class Config:
schema_extra: ClassVar[dict[str, Any]] = {
model_config = ConfigDict(
json_schema_extra={
"example": {
"key": "input_1",
"kind": "input",
Expand All @@ -41,6 +40,7 @@ class Config:
},
}
}
)

@classmethod
def from_service_io(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ class ServiceSpecifications(BaseModel):
description="schedule-time specifications specifications for the service (follows Docker Service creation API (specifically only the Resources part), see https://docs.docker.com/engine/api/v1.41/#tag/Service/operation/ServiceCreate",
)

class Config:
pass


class ServiceSpecificationsGet(ServiceSpecifications):
...
Loading

0 comments on commit d2d81c0

Please sign in to comment.