Skip to content

Commit

Permalink
Merge branch 'pydantic_v2_migration_do_not_squash_updates' into is448…
Browse files Browse the repository at this point in the history
…1/cleanup-network-legacy
  • Loading branch information
giancarloromeo authored Nov 20, 2024
2 parents ae63578 + 0aea337 commit 3af1779
Show file tree
Hide file tree
Showing 45 changed files with 250 additions and 272 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Makefile @pcrespov @sanderegg
/ci/ @sanderegg @pcrespov
/docs/ @pcrespov
/packages/common-library/ @giancarloromeo
/packages/models-library/ @sanderegg @pcrespov @matusdrobuliak66
/packages/models-library/ @sanderegg @pcrespov @matusdrobuliak66 @giancarloromeo
/packages/postgres-database/ @matusdrobuliak66
/packages/pytest-simcore/ @pcrespov @sanderegg
/packages/service-integration/ @pcrespov @sanderegg @GitHK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _get_full_class_name(cls) -> str:
]
return ".".join(reversed(relevant_classes))

def error_context(self):
def error_context(self) -> dict[str, Any]:
"""Returns context in which error occurred and stored within the exception"""
return dict(**self.__dict__)

Expand Down
4 changes: 3 additions & 1 deletion packages/models-library/src/models_library/boot_options.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from pydantic import BaseModel, ConfigDict, ValidationInfo, field_validator
from typing_extensions import TypedDict
from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)

from .basic_types import EnvVarKey

Expand Down
4 changes: 3 additions & 1 deletion packages/models-library/src/models_library/projects_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic_extra_types.color import Color
from typing_extensions import TypedDict
from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)

from .projects_nodes_io import NodeID, NodeIDStr
from .projects_nodes_ui import Marker, Position
Expand Down
2 changes: 1 addition & 1 deletion packages/models-library/src/models_library/rest_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class RequestParameters(BaseModel):
"""

def as_params(self, **export_options) -> dict[str, str]:
data = self.dict(**export_options)
data = self.model_dump(**export_options)
return {k: f"{v}" for k, v in data.items()}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
from typing import Any, Protocol, runtime_checkable

from pydantic import AnyHttpUrl, TypeAdapter
from typing_extensions import TypedDict
from pydantic import TypeAdapter
from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)

from .rest_pagination import PageLinks, PageMetaInfoLimitOffset

Expand Down
6 changes: 5 additions & 1 deletion packages/models-library/src/models_library/socketio.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from typing import Any, TypedDict
from typing import Any

from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)


class SocketMessageDict(TypedDict):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def parse_json_pre_validator(value: Any):
return json_loads(value)
except JSONDecodeError as err:
msg = f"Invalid JSON {value=}: {err}"
raise TypeError(msg) from err
raise ValueError(msg) from err
return value


Expand Down
28 changes: 24 additions & 4 deletions packages/models-library/tests/test_rest_ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,11 @@ def test_ordering_query_model_class__defaults():

# checks all defaults
model = OrderQueryParamsModel()
assert model.order_by
assert isinstance(model.order_by, OrderBy) # nosec
assert model.order_by.field == "modified_at" # NOTE that this was mapped!
assert model.order_by.direction == OrderDirection.DESC
assert model.order_by is not None
assert (
model.order_by.field == "modified_at" # pylint: disable=no-member
) # NOTE that this was mapped!
assert model.order_by.direction is OrderDirection.DESC # pylint: disable=no-member

# partial defaults
model = OrderQueryParamsModel.model_validate({"order_by": {"field": "name"}})
Expand All @@ -150,3 +151,22 @@ def test_ordering_query_model_with_map():
model = OrderQueryParamsModel.model_validate({"order_by": {"field": "modified"}})
assert model.order_by
assert model.order_by.field == "some_db_column_name"


def test_ordering_query_parse_json_pre_validator():

OrderQueryParamsModel = create_ordering_query_model_classes(
ordering_fields={"modified", "name"},
default=OrderBy(field=IDStr("modified"), direction=OrderDirection.DESC),
)

bad_json_value = ",invalid json"
with pytest.raises(ValidationError) as err_info:
OrderQueryParamsModel.model_validate({"order_by": bad_json_value})

exc = err_info.value
assert exc.error_count() == 1
error = exc.errors()[0]
assert error["loc"] == ("order_by",)
assert error["type"] == "value_error"
assert error["input"] == bad_json_value
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.sql import func
from typing_extensions import TypedDict
from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)

from .base import metadata
from .groups import groups
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
from collections.abc import Callable
from copy import deepcopy
from enum import Enum
from typing import Any, Protocol, TypedDict
from typing import Any, Protocol

import arrow
from aiohttp import web
from pydantic import TypeAdapter
from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)

from .application_keys import APP_CONFIG_KEY, APP_SETTINGS_KEY

Expand Down
6 changes: 5 additions & 1 deletion packages/service-library/src/servicelib/rest_constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# SEE https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict

from typing import Final, TypedDict
from typing import Final

from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
TypedDict,
)


class PydanticExportParametersDict(TypedDict):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,9 @@ def test_parse_request_query_parameters_as_with_order_by_query_models():

expected = OrderBy(field="name", direction=OrderDirection.ASC)

url = URL("/test").with_query(order_by=expected.json())
url = URL("/test").with_query(order_by=expected.model_dump_json())

request = make_mocked_request("GET", path=f"{url}")

query_params = parse_request_query_parameters_as(OrderQueryModel, request)
assert query_params.order_by == expected
assert query_params.order_by.model_dump() == expected.model_dump()
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@
ClusterNotFoundError,
ClustersKeeperNotAvailableError,
ComputationalRunNotFoundError,
ComputationalSchedulerError,
ConfigurationError,
PricingPlanUnitNotFoundError,
ProjectNotFoundError,
SchedulerError,
WalletNotEnoughCreditsError,
)
from ...models.comp_pipelines import CompPipelineAtDB
Expand Down Expand Up @@ -204,7 +204,9 @@ async def _get_project_node_names(
except DBProjectNotFoundError:
_logger.exception("Could not find project: %s", f"{project_id=}")
except ProjectNotFoundError as exc:
_logger.exception("Could not find parent project: %s", f"{exc.project_id=}")
_logger.exception(
"Could not find parent project: %s", exc.error_context().get("project_id")
)

return {}

Expand Down Expand Up @@ -510,7 +512,9 @@ async def get_computation(
pipeline_details=pipeline_details,
url=TypeAdapter(AnyHttpUrl).validate_python(f"{request.url}"),
stop_url=(
TypeAdapter(AnyHttpUrl).validate_python(f"{self_url}:stop?user_id={user_id}")
TypeAdapter(AnyHttpUrl).validate_python(
f"{self_url}:stop?user_id={user_id}"
)
if pipeline_state.is_running()
else None
),
Expand Down Expand Up @@ -598,7 +602,7 @@ async def stop_computation(

except ProjectNotFoundError as e:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"{e}") from e
except SchedulerError as e:
except ComputationalSchedulerError as e:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"{e}") from e


Expand Down Expand Up @@ -639,7 +643,7 @@ async def delete_computation(
# abort the pipeline first
try:
await scheduler.stop_pipeline(computation_stop.user_id, project_id)
except SchedulerError as e:
except ComputationalSchedulerError as e:
_logger.warning(
"Project %s could not be stopped properly.\n reason: %s",
project_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def create_base_app(settings: AppSettings | None = None) -> FastAPI:
for name in _NOISY_LOGGERS:
logging.getLogger(name).setLevel(quiet_level)

assert settings.SC_BOOT_MODE # nosec
app = FastAPI(
debug=settings.SC_BOOT_MODE.is_devel_mode(),
title=PROJECT_NAME,
Expand Down
Loading

0 comments on commit 3af1779

Please sign in to comment.