-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
⬆️ Upgrade models-library (pydantic v2) #6333
⬆️ Upgrade models-library (pydantic v2) #6333
Conversation
packages/models-library/src/models_library/api_schemas_directorv2/dynamic_services_service.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/rabbitmq_messages.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot, looks good! 💯 I have added few questions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is still in progress.
There are missing model examples and a =None that might have been added by the migration tool?
Happy to review again once these are in. thanks a lot for the good work!!!
packages/models-library/src/models_library/api_schemas_clusters_keeper/clusters.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/clusters.py
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/clusters.py
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/clusters.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/clusters.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/dynamic_services.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/dynamic_services.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/health.py
Outdated
Show resolved
Hide resolved
Thanks a lot for your feedback, the PR is still in progress :) All your precious observations are already under control. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is my initial round. I'd like to talk about this PR in person if possible. there are some things that I would like to understand .
Also it's extreenmly hard to review
packages/models-library/src/models_library/api_schemas_catalog/services.py
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_catalog/services.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_clusters_keeper/clusters.py
Outdated
Show resolved
Hide resolved
packages/models-library/src/models_library/api_schemas_directorv2/clusters.py
Outdated
Show resolved
Hide resolved
|
||
|
||
class ProjectFromCsv(ProjectAtDB): | ||
class Config(ProjectAtDB.Config): | ||
extra = Extra.forbid | ||
|
||
# TODO: missing in ProjectAtDB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you please check if this comment has any relevance and just drop it if not?
with pytest.raises(KeyError, match="missing"): | ||
str(MyErrorBefore(value=42)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about this example? why was it removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MyErrorBefore
inherited from PydanticErrorMixin
that in Pydantic v2 changed completely.
@@ -14,15 +14,20 @@ class MyModel(BaseModel): | |||
|
|||
|
|||
def test_schema(): | |||
assert MyModel.schema() == { | |||
assert MyModel.model_json_schema() == { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like your changes broke the test. Are you sure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this tests is showing that now pydantic NICELY distinguishes nullable fields. NOTE
class MyModel(BaseModel):
a: int
b: int | None = Field(...)
c: int = 42
d: int | None = None
e: int = FieldNotRequired(description="optional non-nullable")
And we should get an schema that defines:
a
is a requiredint
b
is a required eitherint
orNullable
c
is an optionalint
that defaults to42
d
is an optional eitherint
orNullable
that defaults toNone
e
is an optionalint
(if not set, it just gives youNone
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GitHK: change is correct.
The method "schema" in class "BaseModel" is deprecated
Theschema
method is deprecated; usemodel_json_schema
instead.
…/services.py Co-authored-by: Andrei Neagu <5694077+GitHK@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bravo! I left some comments and questions. Also
On my side this is good enough for a first merge. We can further refine.
packages/models-library/src/models_library/api_schemas_catalog/services_specifications.py
Outdated
Show resolved
Hide resolved
if v is None: | ||
cluster_type = values["type"] | ||
default_thumbnails = { | ||
ClusterTypeInModel.AWS.value: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/250px-Amazon_Web_Services_Logo.svg.png", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
THOUGHT: wouldn't it make more sense to have links here to assets that we control? they could indeed be a copy of these (if allowed). At least we make sure nobody changes the source
e.g. we have https://github.com/ITISFoundation/osparc-assets repo where we could add default
assets link these
@@ -25,7 +22,7 @@ class TaskProgress(BaseModel): | |||
message: ProgressMessage = Field(default="") | |||
percent: ProgressPercent = Field(default=0.0) | |||
|
|||
@validate_arguments | |||
@validate_call | |||
def update( | |||
self, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the impression that here self
is also validated. Do we want this? I think there is a way to skip some of the parameters if so.
packages/models-library/src/models_library/api_schemas_long_running_tasks/base.py
Outdated
Show resolved
Hide resolved
class FileMetaDataArray(BaseModel): | ||
__root__: list[FileMetaDataGet] = [] | ||
class FileMetaDataArray(RootModel[list[FileMetaDataGet]]): | ||
root: list[FileMetaDataGet] = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
THOUGHT: IMO we should get rid of all these root models. They are very confusing. In this case, I would rather annotated list[FileMetaDataGet]
than FileMetaDataArray
AnyUrl = Annotated[str, pydantic.AnyUrl] | ||
|
||
AnyHttpUrl = Annotated[str, pydantic.AnyHttpUrl] | ||
|
||
HttpUrl = Annotated[str, pydantic.HttpUrl] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overriding names this way is misleading ...
Either you use different names or force users to use explicit Annotated
(my preferred option)
Imaging this scenario:
from models_library.basic_types import AnyUrl
from pydantic import *
class MyModel(BaseModel):
url : Annotated[str, AnyUrl]
|
||
DictKey = TypeVar("DictKey") | ||
DictValue = TypeVar("DictValue") | ||
|
||
|
||
class DictModel(GenericModel, Generic[DictKey, DictValue]): | ||
__root__: dict[DictKey, DictValue] | ||
class DictModel(RootModel[dict[DictKey, DictValue]], Generic[DictKey, DictValue]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ListModel and DictModel are not used anywhere in the codebase, I suggest to drop them and rather use explicit list[MyModel]
and dict[str, MyModel]
CC @sanderegg , @GitHK @matusdrobuliak66
@@ -14,15 +14,20 @@ class MyModel(BaseModel): | |||
|
|||
|
|||
def test_schema(): | |||
assert MyModel.schema() == { | |||
assert MyModel.model_json_schema() == { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this tests is showing that now pydantic NICELY distinguishes nullable fields. NOTE
class MyModel(BaseModel):
a: int
b: int | None = Field(...)
c: int = 42
d: int | None = None
e: int = FieldNotRequired(description="optional non-nullable")
And we should get an schema that defines:
a
is a requiredint
b
is a required eitherint
orNullable
c
is an optionalint
that defaults to42
d
is an optional eitherint
orNullable
that defaults toNone
e
is an optionalint
(if not set, it just gives youNone
)
"e": { | ||
"default": None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wonder whether we could change FieldNotRequired
to returns some NotSet
-like value
From Pydantic v1 official documentation:
from pydantic import BaseModel, Field, ValidationError
class Model(BaseModel):
a: int | None
b: int | None = ...
c: int | None = Field(...)
print(Model(b=1, c=2))
#> a=None b=1 c=2
try:
Model(a=1, b=2)
except ValidationError as e:
print(e)
"""
1 validation error for Model
c
field required (type=value_error.missing)
"""
Details: https://docs.pydantic.dev/1.10/usage/models/#required-optional-fields |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥇
state: ProjectState | None | ||
ui: EmptyModel | StudyUI | None | ||
state: ProjectState | None = None | ||
ui: EmptyModel | StudyUI | None = None | ||
quality: dict[str, Any] = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pcrespov If I revert the = None
for the fields in this model, the create-project-schemas test fails because the mocked response payload doesn't contain them. Are these fields intended as optional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@giancarloromeo IMO this case a default =None
makes sense
These mocks were generated using real payload from the front-end so it is important that they pass since there is no guarantee that the front-end always follows the openapi specs in the web-api.
Also, as you can see in services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml
that these fields are not required:
BTW, once all the tests in the models_library
pass, you might want to try to re-generate services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml
and see if the changes make sense. In principle only the new nullable fields should be update and the rest should be the same. Pay special attention to required
fields for instance ...
For that you can use
cd web/server
make openapi-specs
Quality Gate passedIssues Measures |
d2d81c0
into
ITISFoundation:pydantic_v2_migration
What do these changes do?
Related issue/s
How to test
Dev-ops checklist