Skip to content

Commit c94ea58

Browse files
authored
♻️Maintenance: remove circular dependency (#8245)
1 parent 81315d3 commit c94ea58

File tree

27 files changed

+337
-308
lines changed

27 files changed

+337
-308
lines changed
Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from pydantic import BaseModel, ConfigDict, ValidationInfo, field_validator
2+
from pydantic.config import JsonDict
23
from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict
34
TypedDict,
45
)
@@ -26,42 +27,46 @@ def ensure_default_included(cls, v, info: ValidationInfo):
2627
raise ValueError(msg)
2728
return v
2829

29-
model_config = ConfigDict(
30-
json_schema_extra={
31-
"examples": [
32-
{
33-
"label": "Boot mode",
34-
"description": "Start it in web page mode",
35-
"default": "0",
36-
"items": {
37-
"0": {
38-
"label": "Non Voila",
39-
"description": "Tooltip for non Voila boot mode",
40-
},
41-
"1": {
42-
"label": "Voila",
43-
"description": "Tooltip for Voila boot mode",
30+
@staticmethod
31+
def _update_json_schema_extra(schema: JsonDict) -> None:
32+
schema.update(
33+
{
34+
"examples": [
35+
{
36+
"label": "Boot mode",
37+
"description": "Start it in web page mode",
38+
"default": "0",
39+
"items": {
40+
"0": {
41+
"label": "Non Voila",
42+
"description": "Tooltip for non Voila boot mode",
43+
},
44+
"1": {
45+
"label": "Voila",
46+
"description": "Tooltip for Voila boot mode",
47+
},
4448
},
4549
},
46-
},
47-
{
48-
"label": "Application theme",
49-
"description": "Select a theme for the application",
50-
"default": "b",
51-
"items": {
52-
"a": {
53-
"label": "Clear",
54-
"description": "Using white background",
55-
},
56-
"b": {
57-
"label": "Dark",
58-
"description": "Using black and gray tones",
50+
{
51+
"label": "Application theme",
52+
"description": "Select a theme for the application",
53+
"default": "b",
54+
"items": {
55+
"a": {
56+
"label": "Clear",
57+
"description": "Using white background",
58+
},
59+
"b": {
60+
"label": "Dark",
61+
"description": "Using black and gray tones",
62+
},
5963
},
6064
},
61-
},
62-
]
63-
}
64-
)
65+
]
66+
}
67+
)
68+
69+
model_config = ConfigDict(json_schema_extra=_update_json_schema_extra)
6570

6671

6772
BootOptions = dict[EnvVarKey, BootOption]

packages/models-library/src/models_library/docker.py

Lines changed: 1 addition & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
1-
import contextlib
21
import re
3-
from typing import Annotated, Any, Final, TypeAlias
2+
from typing import Annotated, TypeAlias
43

54
from pydantic import (
6-
BaseModel,
7-
ByteSize,
8-
ConfigDict,
9-
Field,
105
StringConstraints,
11-
TypeAdapter,
12-
ValidationError,
13-
model_validator,
146
)
157

168
from .basic_regex import DOCKER_GENERIC_TAG_KEY_RE, DOCKER_LABEL_KEY_REGEX
179
from .basic_types import ConstrainedStr
18-
from .generated_models.docker_rest_api import Task
19-
from .products import ProductName
20-
from .projects import ProjectID
21-
from .projects_nodes_io import NodeID
22-
from .users import UserID
2310

2411

2512
class DockerLabelKey(ConstrainedStr):
@@ -47,192 +34,6 @@ def from_key(cls, key: str) -> "DockerLabelKey":
4734
),
4835
]
4936

50-
_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX: Final[str] = "io.simcore.runtime."
51-
_BACKWARDS_COMPATIBILITY_SIMCORE_RUNTIME_DOCKER_LABELS_MAP: Final[dict[str, str]] = {
52-
"node_id": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}node-id",
53-
"product_name": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}product-name",
54-
"project_id": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}project-id",
55-
"simcore_user_agent": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}simcore-user-agent",
56-
"study_id": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}project-id",
57-
"user_id": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}user-id",
58-
"uuid": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}node-id",
59-
"mem_limit": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}memory-limit",
60-
"swarm_stack_name": f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}swarm-stack-name",
61-
}
62-
_UNDEFINED_LABEL_VALUE_STR: Final[str] = "undefined"
63-
_UNDEFINED_LABEL_VALUE_INT: Final[str] = "0"
64-
65-
66-
DOCKER_TASK_EC2_INSTANCE_TYPE_PLACEMENT_CONSTRAINT_KEY: Final[DockerLabelKey] = (
67-
TypeAdapter(DockerLabelKey).validate_python("ec2-instance-type")
68-
)
69-
70-
71-
def to_simcore_runtime_docker_label_key(key: str) -> DockerLabelKey:
72-
return DockerLabelKey(
73-
f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}{key.replace('_', '-').lower()}"
74-
)
75-
76-
77-
class StandardSimcoreDockerLabels(BaseModel):
78-
"""
79-
Represents the standard label on oSparc created containers (not yet services)
80-
In order to create this object in code, please use model_construct() method!
81-
"""
82-
83-
user_id: UserID = Field(..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}user-id") # type: ignore[literal-required]
84-
project_id: ProjectID = Field( # type: ignore[literal-required]
85-
..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}project-id"
86-
)
87-
node_id: NodeID = Field(..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}node-id") # type: ignore[literal-required]
88-
89-
product_name: ProductName = Field( # type: ignore[literal-required]
90-
..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}product-name"
91-
)
92-
simcore_user_agent: str = Field( # type: ignore[literal-required]
93-
..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}simcore-user-agent"
94-
)
95-
96-
swarm_stack_name: str = Field( # type: ignore[literal-required]
97-
..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}swarm-stack-name"
98-
)
99-
100-
memory_limit: ByteSize = Field( # type: ignore[literal-required]
101-
..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}memory-limit"
102-
)
103-
cpu_limit: float = Field( # type: ignore[literal-required]
104-
..., alias=f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}cpu-limit"
105-
)
106-
107-
@model_validator(mode="before")
108-
@classmethod
109-
def _backwards_compatibility(cls, values: dict[str, Any]) -> dict[str, Any]:
110-
# NOTE: this is necessary for dy-sidecar and legacy service until they are adjusted
111-
if mapped_values := {
112-
_BACKWARDS_COMPATIBILITY_SIMCORE_RUNTIME_DOCKER_LABELS_MAP[k]: v
113-
for k, v in values.items()
114-
if k in _BACKWARDS_COMPATIBILITY_SIMCORE_RUNTIME_DOCKER_LABELS_MAP
115-
}:
116-
# these values were sometimes omitted, so let's provide some defaults
117-
for key in ["product-name", "simcore-user-agent", "swarm-stack-name"]:
118-
mapped_values.setdefault(
119-
f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}{key}",
120-
_UNDEFINED_LABEL_VALUE_STR,
121-
)
122-
123-
mapped_values.setdefault(
124-
f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}memory-limit",
125-
values.get("memory_limit", _UNDEFINED_LABEL_VALUE_INT),
126-
)
127-
128-
def _convert_nano_cpus_to_cpus(nano_cpu: str) -> str:
129-
with contextlib.suppress(ValidationError):
130-
return f"{TypeAdapter(float).validate_python(nano_cpu) / (1.0 * 10**9):.2f}"
131-
return _UNDEFINED_LABEL_VALUE_INT
132-
133-
mapped_values.setdefault(
134-
f"{_SIMCORE_RUNTIME_DOCKER_LABEL_PREFIX}cpu-limit",
135-
values.get(
136-
"cpu_limit",
137-
_convert_nano_cpus_to_cpus(
138-
values.get(
139-
"nano_cpus_limit",
140-
_UNDEFINED_LABEL_VALUE_INT,
141-
)
142-
),
143-
),
144-
)
145-
return mapped_values
146-
return values
147-
148-
def to_simcore_runtime_docker_labels(self) -> dict[DockerLabelKey, str]:
149-
"""returns a dictionary of strings as required by docker"""
150-
return {
151-
to_simcore_runtime_docker_label_key(k): f"{v}"
152-
for k, v in sorted(self.model_dump().items())
153-
}
154-
155-
@classmethod
156-
def from_docker_task(cls, docker_task: Task) -> "StandardSimcoreDockerLabels":
157-
assert docker_task.spec # nosec
158-
assert docker_task.spec.container_spec # nosec
159-
task_labels = docker_task.spec.container_spec.labels or {}
160-
return cls.model_validate(task_labels)
161-
162-
model_config = ConfigDict(
163-
populate_by_name=True,
164-
json_schema_extra={
165-
"examples": [
166-
# legacy service labels
167-
{
168-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
169-
"swarm_stack_name": "devel-simcore",
170-
"user_id": "5",
171-
"uuid": "1f963626-66e1-43f1-a777-33955c08b909",
172-
},
173-
# legacy container labels
174-
{
175-
"mem_limit": "1073741824",
176-
"nano_cpus_limit": "4000000000",
177-
"node_id": "1f963626-66e1-43f1-a777-33955c08b909",
178-
"simcore_user_agent": "puppeteer",
179-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
180-
"swarm_stack_name": "devel-simcore",
181-
"user_id": "5",
182-
},
183-
# dy-sidecar service labels
184-
{
185-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
186-
"swarm_stack_name": "devel-simcore",
187-
"user_id": "5",
188-
"uuid": "1f963626-66e1-43f1-a777-33955c08b909",
189-
},
190-
# dy-sidecar container labels
191-
{
192-
"mem_limit": "1073741824",
193-
"nano_cpus_limit": "4000000000",
194-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
195-
"user_id": "5",
196-
"uuid": "1f963626-66e1-43f1-a777-33955c08b909",
197-
},
198-
# dy-proxy service labels
199-
{
200-
"dynamic-type": "dynamic-sidecar",
201-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
202-
"swarm_stack_name": "devel-simcore",
203-
"type": "dependency-v2",
204-
"user_id": "5",
205-
"uuid": "1f963626-66e1-43f1-a777-33955c08b909",
206-
},
207-
# dy-proxy container labels
208-
{
209-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
210-
"user_id": "5",
211-
"uuid": "1f963626-66e1-43f1-a777-33955c08b909",
212-
},
213-
# dy-sidecar user-services labels
214-
{
215-
"product_name": "osparc",
216-
"simcore_user_agent": "puppeteer",
217-
"study_id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
218-
"user_id": "5",
219-
"uuid": "1f963626-66e1-43f1-a777-33955c08b909",
220-
},
221-
# modern both dynamic-sidecar services and computational services
222-
{
223-
"io.simcore.runtime.cpu-limit": "2.4",
224-
"io.simcore.runtime.memory-limit": "1073741824",
225-
"io.simcore.runtime.node-id": "1f963626-66e1-43f1-a777-33955c08b909",
226-
"io.simcore.runtime.product-name": "osparc",
227-
"io.simcore.runtime.project-id": "29f393fc-1410-47b3-b4b9-61dfce21a2a6",
228-
"io.simcore.runtime.simcore-user-agent": "puppeteer",
229-
"io.simcore.runtime.swarm-stack-name": "devel-osparc",
230-
"io.simcore.runtime.user-id": "5",
231-
},
232-
]
233-
},
234-
)
235-
23637

23738
DockerNodeID: TypeAlias = Annotated[
23839
str, StringConstraints(strip_whitespace=True, pattern=re.compile(r"[a-zA-Z0-9]"))

packages/models-library/src/models_library/services_metadata_published.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@
7676
}
7777
},
7878
"boot-options": {
79-
"example_service_defined_boot_mode": BootOption.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
80-
"example_service_defined_theme_selection": BootOption.model_config["json_schema_extra"]["examples"][1], # type: ignore [index]
79+
"example_service_defined_boot_mode": BootOption.model_json_schema()["examples"][
80+
0
81+
],
82+
"example_service_defined_theme_selection": BootOption.model_json_schema()[
83+
"examples"
84+
][1],
8185
},
8286
"min-visible-inputs": 2,
8387
}

0 commit comments

Comments
 (0)