Skip to content
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

⬆️ pydantic migration catalog #6629

Conversation

pcrespov
Copy link
Member

@pcrespov pcrespov commented Oct 29, 2024

What do these changes do?

  • Migrates the catalog service to pydantic v2
  • Extends test coverage
  • upgrades to latest $OPENAPI_GENERATOR_NAME as in ⬆️ Upgrade openapi generator osparc-simcore-clients#202. This way we can validate the new openapi.json environs
  • regenerated openapi.json and increased api version 0.5.0 → 0.6.0

Related issue/s

How to test

cd services/catalog
make install-dev
make test-dev-unit

Dev-ops checklist

None

@pcrespov pcrespov self-assigned this Oct 29, 2024
Copy link

codecov bot commented Oct 29, 2024

Codecov Report

Attention: Patch coverage is 92.53731% with 5 lines in your changes missing coverage. Please review.

Project coverage is 71.49%. Comparing base (05cff9e) to head (be23200).
Report is 1 commits behind head on pydantic_v2_migration_do_not_squash_updates.

Additional details and impacted files
@@                               Coverage Diff                               @@
##           pydantic_v2_migration_do_not_squash_updates    #6629      +/-   ##
===============================================================================
- Coverage                                        71.53%   71.49%   -0.05%     
===============================================================================
  Files                                             1094      992     -102     
  Lines                                            48641    44968    -3673     
  Branches                                          1243      496     -747     
===============================================================================
- Hits                                             34795    32148    -2647     
+ Misses                                           13625    12730     -895     
+ Partials                                           221       90     -131     
Flag Coverage Δ *Carryforward flag
integrationtests 64.79% <ø> (ø) Carriedforward from afd3bbe
unittests 84.52% <92.53%> (+2.49%) ⬆️

*This pull request uses carry forward flags. Click here to find out more.

Components Coverage Δ
api ∅ <ø> (∅)
pkg_aws_library ∅ <ø> (∅)
pkg_dask_task_models_library ∅ <ø> (∅)
pkg_models_library ∅ <ø> (∅)
pkg_notifications_library ∅ <ø> (∅)
pkg_postgres_database ∅ <ø> (∅)
pkg_service_integration 70.00% <ø> (ø)
pkg_service_library ∅ <ø> (∅)
pkg_settings_library 90.74% <100.00%> (+0.01%) ⬆️
pkg_simcore_sdk 77.44% <ø> (ø)
agent 97.21% <ø> (ø)
api_server ∅ <ø> (∅)
autoscaling 95.25% <ø> (ø)
catalog 90.59% <92.30%> (∅)
clusters_keeper 98.85% <ø> (ø)
dask_sidecar 90.84% <ø> (ø)
datcore_adapter 93.14% <ø> (ø)
director 58.38% <ø> (ø)
director_v2 76.22% <ø> (ø)
dynamic_scheduler ∅ <ø> (∅)
dynamic_sidecar 59.66% <ø> (ø)
efs_guardian 87.12% <ø> (ø)
invitations 93.44% <ø> (ø)
osparc_gateway_server 85.15% <ø> (ø)
payments 92.98% <ø> (ø)
resource_usage_tracker ∅ <ø> (∅)
storage 89.63% <ø> (ø)
webclient ∅ <ø> (∅)
webserver 59.70% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 05cff9e...be23200. Read the comment docs.

@pcrespov pcrespov force-pushed the is4481/pydantic-migration-catalog branch from 6728e00 to b051792 Compare October 29, 2024 10:21
@pcrespov pcrespov added this to the Caveman milestone Oct 29, 2024
@pcrespov pcrespov force-pushed the is4481/pydantic-migration-catalog branch from 1fad4bb to e1d9437 Compare October 31, 2024 11:21
@pcrespov pcrespov changed the title ⬆️ Is4481/pydantic migration catalog ⬆️ pydantic migration catalog Oct 31, 2024
@pcrespov pcrespov marked this pull request as ready for review October 31, 2024 15:20
@pcrespov pcrespov added the t:maintenance Some planned maintenance work label Oct 31, 2024
Copy link
Contributor

@giancarloromeo giancarloromeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@pcrespov pcrespov merged commit 34c9f3e into ITISFoundation:pydantic_v2_migration_do_not_squash_updates Oct 31, 2024
9 of 10 checks passed
@pcrespov pcrespov deleted the is4481/pydantic-migration-catalog branch October 31, 2024 16:19
Copy link

sonarcloud bot commented Oct 31, 2024

@@ -33,7 +33,9 @@ class ServiceMetaDataEditable(ServiceBaseDisplay):
"If now>=deprecated, the service is retired",
)
classifiers: list[str] | None
quality: dict[str, Any] = {}
quality: dict[str, Any] = Field(
default_factory=dict, json_schema_extra={"default": {}}
Copy link
Member

@sanderegg sanderegg Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pcrespov question, is this necessary? is this used in a json schema? well I guess it does not hurt

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. It is only necessary for the models in the OAS. I was writing those systematically and missed this.

limit: StrictInt | StrictFloat | str
reservation: StrictInt | StrictFloat | str

@model_validator(mode="before")
@classmethod
def _ensure_limits_are_equal_or_above_reservations(cls, values):
# WARNING: this does not validate ON-ASSIGNMENT!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so how does it work now? what does validate_assignment=True do? nothing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So on assignment it does not work. What I did is recreating everytime the model. It has only two values so it is not that heavy

assert res.reservation == 10

# https://docs.pydantic.dev/latest/api/config/#pydantic.config.ConfigDict.validate_assignment
# before-validators DO NOT work on Assignment!!!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then why we don't change to an AFTER validator?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have tried that... yes. I will do that

"reservation": parse_obj_as(ByteSize, "2Gib"),
},
},
_in_bytes = TypeAdapter(ByteSize).validate_python
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I get that one.
but anyway you forgot the typing

@@ -29,4 +30,4 @@ async def _http_error_handler(_: Request, exc: type[BaseException]) -> JSONRespo
content=jsonable_encoder({"errors": [str(exc)]}), status_code=status_code
)

return _http_error_handler
return _http_error_handler # type: ignore[return-value]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this one needed? that looks weird.

# for a partial update all members must be Optional
classifiers: list[str] | None = Field(default_factory=list)
owner: PositiveInt | None
# for a partial update all Editable members must be Optional
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# for a partial update all Editable members must be Optional
# for a partial update all editable members must be Optional

if service_db.thumbnail
else None
),
thumbnail=HttpUrl(service_db.thumbnail) if service_db.thumbnail else None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that does not validate does it?

res_value * _DOCKER_TO_OSPARC_RESOURCE_CONVERTER[res_name],
)

scale = _DOCKER_TO_OSPARC_RESOURCE_CONVERTER[res_name]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not a necessaryily a scaling. it is a conversion between 2 types.

return f"{randint(0,100)}.{randint(0,100)}.{randint(0,100)}"
def service_version(faker: Faker) -> str:
return (
f"{faker.random_int(0,100)}.{faker.random_int(0,100)}.{faker.random_int(0,100)}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the difference with using faker.pyint(min_value=0, max_value=100)?

mocked_director_service_labels.respond(json={"data": params.simcore_service_label})
url = URL(f"/v0/services/{service_key}/{service_version}/resources")
response = client.get(f"{url}")
assert response.status_code == 200, f"{response.text}"
data = response.json()
received_resources: ServiceResourcesDict = parse_obj_as(ServiceResourcesDict, data)
received_resources: ServiceResourcesDict = ServiceResourcesDict(**data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this now validate? before it would not

Comment on lines +134 to 140
service_key = (
f"simcore/services/{faker.random_element(['comp', 'dynamic'])}/jupyter-math"
)
service_version = (
f"{faker.random_int(0,100)}.{faker.random_int(0,100)}.{faker.random_int(0,100)}"
)
url = URL(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not re-use the fixture in the other file?

Comment on lines +156 to 159
service_key = f"simcore/services/{faker.random_element(['comp', 'dynamic'])}/{faker.pystr().lower()}"
service_version = (
f"{faker.random_int(0,100)}.{faker.random_int(0,100)}.{faker.random_int(0,100)}"
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

url = URL(
f"/v0/services/{service_key}/{service_version}/specifications"
).with_query(user_id=user_id)
response = client.get(f"{url}")
assert response.status_code == status.HTTP_200_OK
service_specs = ServiceSpecificationsGet.parse_obj(response.json())
service_specs = ServiceSpecifications.model_validate(response.json())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

went from ServiceSpecificationsget to ServiceSpecifications. is that a typo?

@@ -161,7 +161,7 @@ async def test_rpc_catalog_client(
"description": "bar",
"version_display": "this is a nice version",
"description_ui": True, # owner activates wiki view
},
}, # type: ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
t:maintenance Some planned maintenance work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants