Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/common-library/tests/test_pydantic_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pytest
from common_library.pydantic_validators import (
validate_legacy_timedelta_str,
_validate_legacy_timedelta_str,
validate_numeric_string_as_timedelta,
)
from faker import Faker
Expand All @@ -16,7 +16,7 @@ def test_validate_legacy_timedelta(monkeypatch: pytest.MonkeyPatch, faker: Faker
class Settings(BaseSettings):
APP_NAME: str
REQUEST_TIMEOUT: Annotated[
timedelta, BeforeValidator(validate_legacy_timedelta_str)
timedelta, BeforeValidator(_validate_legacy_timedelta_str)
] = Field(default=timedelta(hours=1))

model_config = SettingsConfigDict()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class ClusterDetailsGet(ClusterDetails):


class ClusterCreate(BaseCluster):
owner: GroupID | None
owner: GroupID | None = None # type: ignore[assignment]
authentication: ExternalClusterAuthentication
access_rights: dict[GroupID, ClusterAccessRights] = Field(
alias="accessRights", default_factory=dict
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Any, TypeAlias

from models_library.basic_types import IDStr
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, field_validator
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, ConfigDict, Field, field_validator

from ..clusters import ClusterID
from ..projects import ProjectID
Expand All @@ -18,6 +18,7 @@ class ComputationGet(ComputationTask):
stop_url: AnyHttpUrl | None = Field(
None, description="the link where to stop the task"
)
model_config = ConfigDict(json_schema_extra={"examples": []})


class ComputationCreate(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
Field,
NonNegativeFloat,
NonNegativeInt,
root_validator,
validator,
model_validator,
)

from ..projects_nodes_io import NodeID
Expand Down Expand Up @@ -56,29 +55,13 @@ class DiskUsage(BaseModel):
free: ByteSize = Field(description="remaining space")

total: ByteSize = Field(description="total space = free + used")
used_percent: NonNegativeFloat = Field(
used_percent: float = Field(
ge=0.00,
le=100.00,
description="Percent of used space relative to the total space",
)

@validator("free")
@classmethod
def _free_positive(cls, v: float) -> float:
if v < 0:
msg = f"free={v} cannot be a negative value"
raise ValueError(msg)
return v

@validator("used")
@classmethod
def _used_positive(cls, v: float) -> float:
if v < 0:
msg = f"used={v} cannot be a negative value"
raise ValueError(msg)
return v

@root_validator(pre=True)
@model_validator(mode="before")
@classmethod
def _check_total(cls, values: dict[str, Any]) -> dict[str, Any]:
total = values["total"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,12 @@ class FileUploadCompleteFutureResponse(BaseModel):


class FoldersBody(BaseModel):
source: dict[str, Any] = Field(default_factory=dict)
destination: dict[str, Any] = Field(default_factory=dict)
nodes_map: dict[NodeID, NodeID] = Field(default_factory=dict)
source: Annotated[dict[str, Any], Field(default_factory=dict)]
destination: Annotated[dict[str, Any], Field(default_factory=dict)]
nodes_map: Annotated[dict[NodeID, NodeID], Field(default_factory=dict)]

@model_validator(mode="after")
def ensure_consistent_entries(self) -> Self:
def ensure_consistent_entries(self: Self) -> Self:
source_node_keys = (NodeID(n) for n in self.source.get("workbench", {}))
if set(source_node_keys) != set(self.nodes_map.keys()):
msg = "source project nodes do not fit with nodes_map entries"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ class ProjectReplace(InputSchema):
uuid: ProjectID
name: ShortTruncatedStr
description: LongTruncatedStr
thumbnail: Annotated[HttpUrl | None, BeforeValidator(empty_str_to_none_pre_validator)] = Field(default=None)
thumbnail: Annotated[
HttpUrl | None, BeforeValidator(empty_str_to_none_pre_validator)
] = Field(default=None)
creation_date: DateTimeStr
last_change_date: DateTimeStr
workbench: NodesDict
Expand All @@ -127,13 +129,15 @@ class ProjectReplace(InputSchema):
class ProjectPatch(InputSchema):
name: ShortTruncatedStr | None = Field(default=None)
description: LongTruncatedStr | None = Field(default=None)
thumbnail: Annotated[HttpUrl | None, BeforeValidator(empty_str_to_none_pre_validator)] = Field(default=None)
thumbnail: Annotated[
HttpUrl | None, BeforeValidator(empty_str_to_none_pre_validator)
] = Field(default=None)
access_rights: dict[GroupIDStr, AccessRights] | None = Field(default=None)
classifiers: list[ClassifierID] | None = Field(default=None)
dev: dict | None = Field(default=None)
ui: StudyUI | None = Field(default=None)
quality: dict[str, Any] | None = Field(default=None)


__all__: tuple[str, ...] = (
"EmptyModel",
Expand Down
4 changes: 2 additions & 2 deletions packages/models-library/src/models_library/progress_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class ProgressStructuredMessage(BaseModel):
description: IDStr
current: float
total: int
unit: str | None
sub: "ProgressStructuredMessage | None"
unit: str | None = None
sub: "ProgressStructuredMessage | None" = None

model_config = ConfigDict(
json_schema_extra={
Expand Down
32 changes: 1 addition & 31 deletions packages/models-library/src/models_library/rest_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,34 +136,4 @@ def _check_data_compatible_with_meta(cls, v, info: ValidationInfo):
raise ValueError(msg)
return v

model_config = ConfigDict(
extra="forbid",
json_schema_extra={
"examples": [
# first page Page[str]
{
"_meta": {"total": 7, "count": 4, "limit": 4, "offset": 0},
"_links": {
"self": "https://osparc.io/v2/listing?offset=0&limit=4",
"first": "https://osparc.io/v2/listing?offset=0&limit=4",
"prev": None,
"next": "https://osparc.io/v2/listing?offset=1&limit=4",
"last": "https://osparc.io/v2/listing?offset=1&limit=4",
},
"data": ["data 1", "data 2", "data 3", "data 4"],
},
# second and last page
{
"_meta": {"total": 7, "count": 3, "limit": 4, "offset": 1},
"_links": {
"self": "https://osparc.io/v2/listing?offset=1&limit=4",
"first": "https://osparc.io/v2/listing?offset=0&limit=4",
"prev": "https://osparc.io/v2/listing?offset=0&limit=4",
"next": None,
"last": "https://osparc.io/v2/listing?offset=1&limit=4",
},
"data": ["data 5", "data 6", "data 7"],
},
]
},
)
model_config = ConfigDict(extra="forbid")
32 changes: 1 addition & 31 deletions packages/models-library/src/models_library/rpc_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,34 +74,4 @@ def create(
data=chunk,
)

model_config = ConfigDict(
extra="forbid",
json_schema_extra={
"examples": [
# first page Page[str]
{
"_meta": {"total": 7, "count": 4, "limit": 4, "offset": 0},
"_links": {
"self": {"offset": 0, "limit": 4},
"first": {"offset": 0, "limit": 4},
"prev": None,
"next": {"offset": 1, "limit": 4},
"last": {"offset": 1, "limit": 4},
},
"data": ["data 1", "data 2", "data 3", "data 4"],
},
# second and last page
{
"_meta": {"total": 7, "count": 3, "limit": 4, "offset": 1},
"_links": {
"self": {"offset": 1, "limit": 4},
"first": {"offset": 0, "limit": 4},
"prev": {"offset": 0, "limit": 4},
"next": None,
"last": {"offset": 1, "limit": 4},
},
"data": ["data 5", "data 6", "data 7"],
},
]
},
)
model_config = ConfigDict(extra="forbid")
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from enum import Enum
from functools import cached_property
from pathlib import Path
from typing import Any, Literal, TypeAlias
from typing import Annotated, Any, Literal, TypeAlias

from common_library.json_serialization import json_dumps
from pydantic import (
Expand Down Expand Up @@ -317,13 +317,14 @@ class DynamicSidecarServiceLabels(BaseModel):
),
)

containers_allowed_outgoing_permit_list: None | (
Json[dict[str, list[NATRule]]]
) = Field(
None,
alias="simcore.service.containers-allowed-outgoing-permit-list",
description="allow internet access to certain domain names and ports per container",
)
containers_allowed_outgoing_permit_list: Annotated[
None | (Json[dict[str, list[NATRule]]]),
Field(
None,
alias="simcore.service.containers-allowed-outgoing-permit-list",
description="allow internet access to certain domain names and ports per container",
),
]

containers_allowed_outgoing_internet: Json[set[str]] | None = Field(
None,
Expand Down
4 changes: 3 additions & 1 deletion packages/models-library/src/models_library/services_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ def create(cls) -> "RunID":

@classmethod
def __get_pydantic_core_schema__(
cls, source_type: Any, handler: GetCoreSchemaHandler
cls,
source_type: Any, # pylint:disable=unused-argument
handler: GetCoreSchemaHandler,
) -> CoreSchema:
return core_schema.no_info_after_validator_function(cls, handler(str))

Expand Down
55 changes: 55 additions & 0 deletions packages/models-library/tests/shared_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import Final

PAGE_EXAMPLES: Final[list[dict]] = [
# first page Page[str]
{
"_meta": {"total": 7, "count": 4, "limit": 4, "offset": 0},
"_links": {
"self": "https://osparc.io/v2/listing?offset=0&limit=4",
"first": "https://osparc.io/v2/listing?offset=0&limit=4",
"prev": None,
"next": "https://osparc.io/v2/listing?offset=1&limit=4",
"last": "https://osparc.io/v2/listing?offset=1&limit=4",
},
"data": ["data 1", "data 2", "data 3", "data 4"],
},
# second and last page
{
"_meta": {"total": 7, "count": 3, "limit": 4, "offset": 1},
"_links": {
"self": "https://osparc.io/v2/listing?offset=1&limit=4",
"first": "https://osparc.io/v2/listing?offset=0&limit=4",
"prev": "https://osparc.io/v2/listing?offset=0&limit=4",
"next": None,
"last": "https://osparc.io/v2/listing?offset=1&limit=4",
},
"data": ["data 5", "data 6", "data 7"],
},
]

RPC_PAGE_EXAMPLES: Final[list[dict]] = [
# first page Page[str]
{
"_meta": {"total": 7, "count": 4, "limit": 4, "offset": 0},
"_links": {
"self": {"offset": 0, "limit": 4},
"first": {"offset": 0, "limit": 4},
"prev": None,
"next": {"offset": 1, "limit": 4},
"last": {"offset": 1, "limit": 4},
},
"data": ["data 1", "data 2", "data 3", "data 4"],
},
# second and last page
{
"_meta": {"total": 7, "count": 3, "limit": 4, "offset": 1},
"_links": {
"self": {"offset": 1, "limit": 4},
"first": {"offset": 0, "limit": 4},
"prev": {"offset": 0, "limit": 4},
"next": None,
"last": {"offset": 1, "limit": 4},
},
"data": ["data 5", "data 6", "data 7"],
},
]
17 changes: 15 additions & 2 deletions packages/models-library/tests/test__models_examples.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import json
from itertools import chain
from typing import Any

import models_library
import pytest
from models_library.rest_pagination import Page
from models_library.rpc_pagination import PageRpc
from pydantic import BaseModel
from pytest_simcore.pydantic_models import walk_model_examples_in_package
from pytest_simcore.pydantic_models import (
ModelExample,
iter_examples,
walk_model_examples_in_package,
)
from shared_examples import PAGE_EXAMPLES, RPC_PAGE_EXAMPLES

GENERIC_EXAMPLES: list[ModelExample] = [
*iter_examples(model_cls=Page[str], examples=PAGE_EXAMPLES),
*iter_examples(model_cls=PageRpc[str], examples=RPC_PAGE_EXAMPLES),
]


@pytest.mark.parametrize(
"model_cls, example_name, example_data",
walk_model_examples_in_package(models_library),
chain(GENERIC_EXAMPLES, walk_model_examples_in_package(models_library)),
)
def test_all_models_library_models_config_examples(
model_cls: type[BaseModel], example_name: int, example_data: Any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ def test_failing_validation():
with pytest.raises(ValidationError) as exc:
assert DiskUsage.from_efs_guardian(100, 10)

assert "free=" in f"{exc.value}"
assert "negative value" in f"{exc.value}"
assert "free" in f"{exc.value}"
assert "input_value=-90" in f"{exc.value}"

with pytest.raises(ValidationError) as exc:
assert DiskUsage(
Expand All @@ -52,8 +52,8 @@ def test_failing_validation():
total=ByteSize(0),
used_percent=-10,
)
assert "used=" in f"{exc.value}"
assert "negative value" in f"{exc.value}"
assert "used" in f"{exc.value}"
assert "input_value=-10" in f"{exc.value}"

with pytest.raises(ValidationError) as exc:
DiskUsage(
Expand Down
5 changes: 3 additions & 2 deletions packages/models-library/tests/test_project_nodes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# pylint:disable=unused-variable
# pylint:disable=unused-argument
# pylint:disable=no-member
# pylint:disable=redefined-outer-name
# pylint:disable=unused-argument
# pylint:disable=unused-variable

from typing import Any

Expand Down
Loading
Loading