Skip to content

Commit dc35757

Browse files
authored
♻️Pydantic V2 and SQLAlchemy warning fixes (#6877)
1 parent 931595e commit dc35757

File tree

9 files changed

+43
-55
lines changed

9 files changed

+43
-55
lines changed

services/clusters-keeper/src/simcore_service_clusters_keeper/core/settings.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -381,15 +381,6 @@ def LOG_LEVEL(self) -> LogLevel: # noqa: N802
381381
def _valid_log_level(cls, value: str) -> str:
382382
return cls.validate_log_level(value)
383383

384-
@field_validator("SERVICE_TRACKING_HEARTBEAT", mode="before")
385-
@classmethod
386-
def _validate_interval(
387-
cls, value: str | datetime.timedelta
388-
) -> int | datetime.timedelta:
389-
if isinstance(value, str):
390-
return int(value)
391-
return value
392-
393384

394385
def get_application_settings(app: FastAPI) -> ApplicationSettings:
395386
return cast(ApplicationSettings, app.state.settings)

services/clusters-keeper/tests/unit/test_modules_clusters_management_core.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import asyncio
66
import dataclasses
7+
import datetime
78
from collections.abc import Awaitable, Callable
89
from typing import Final
910
from unittest.mock import MagicMock
@@ -36,7 +37,9 @@ def wallet_id(faker: Faker, request: pytest.FixtureRequest) -> WalletID | None:
3637
return faker.pyint(min_value=1) if request.param == "with_wallet" else None
3738

3839

39-
_FAST_TIME_BEFORE_TERMINATION_SECONDS: Final[int] = 10
40+
_FAST_TIME_BEFORE_TERMINATION_SECONDS: Final[datetime.timedelta] = datetime.timedelta(
41+
seconds=10
42+
)
4043

4144

4245
@pytest.fixture
@@ -149,7 +152,7 @@ async def test_cluster_management_core_properly_removes_unused_instances(
149152
mocked_dask_ping_scheduler.is_scheduler_busy.reset_mock()
150153

151154
# running the cluster management task after the heartbeat came in shall not remove anything
152-
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS + 1)
155+
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS.total_seconds() + 1)
153156
await cluster_heartbeat(initialized_app, user_id=user_id, wallet_id=wallet_id)
154157
await check_clusters(initialized_app)
155158
await _assert_cluster_exist_and_state(
@@ -161,7 +164,7 @@ async def test_cluster_management_core_properly_removes_unused_instances(
161164
mocked_dask_ping_scheduler.is_scheduler_busy.reset_mock()
162165

163166
# after waiting the termination time, running the task shall remove the cluster
164-
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS + 1)
167+
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS.total_seconds() + 1)
165168
await check_clusters(initialized_app)
166169
await _assert_cluster_exist_and_state(
167170
ec2_client, instances=created_clusters, state="terminated"
@@ -201,7 +204,7 @@ async def test_cluster_management_core_properly_removes_workers_on_shutdown(
201204
ec2_client, instance_ids=worker_instance_ids, state="running"
202205
)
203206
# after waiting the termination time, running the task shall remove the cluster
204-
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS + 1)
207+
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS.total_seconds() + 1)
205208
await check_clusters(initialized_app)
206209
await _assert_cluster_exist_and_state(
207210
ec2_client, instances=created_clusters, state="terminated"
@@ -314,7 +317,7 @@ async def test_cluster_management_core_removes_broken_clusters_after_some_delay(
314317
mocked_dask_ping_scheduler.is_scheduler_busy.reset_mock()
315318

316319
# waiting for the termination time will now terminate the cluster
317-
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS + 1)
320+
await asyncio.sleep(_FAST_TIME_BEFORE_TERMINATION_SECONDS.total_seconds() + 1)
318321
await check_clusters(initialized_app)
319322
await _assert_cluster_exist_and_state(
320323
ec2_client, instances=created_clusters, state="terminated"

services/director-v2/src/simcore_service_director_v2/modules/comp_scheduler/_scheduler_base.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -540,11 +540,7 @@ async def apply(
540540
project_id: ProjectID,
541541
iteration: Iteration,
542542
) -> None:
543-
"""schedules a pipeline for a given user, project and iteration.
544-
545-
Arguments:
546-
wake_up_callback -- a callback function that is called in a separate thread everytime a pipeline node is completed
547-
"""
543+
"""apply the scheduling of a pipeline for a given user, project and iteration."""
548544
with log_context(
549545
_logger,
550546
level=logging.INFO,

services/director-v2/src/simcore_service_director_v2/modules/db/repositories/comp_runs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ async def list(
143143
return [
144144
CompRunsAtDB.model_validate(row)
145145
async for row in conn.execute(
146-
sa.select(comp_runs).where(sa.and_(*conditions))
146+
sa.select(comp_runs).where(
147+
sa.and_(True, *conditions) # noqa: FBT003
148+
)
147149
)
148150
]
149151

services/director-v2/src/simcore_service_director_v2/modules/db/repositories/comp_tasks/_utils.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,7 @@ async def _get_service_details(
8989
node.version,
9090
product_name,
9191
)
92-
obj: ServiceMetaDataPublished = ServiceMetaDataPublished.model_construct(
93-
**service_details
94-
)
92+
obj: ServiceMetaDataPublished = ServiceMetaDataPublished(**service_details)
9593
return obj
9694

9795

@@ -105,7 +103,7 @@ def _compute_node_requirements(
105103
node_defined_resources[resource_name] = node_defined_resources.get(
106104
resource_name, 0
107105
) + min(resource_value.limit, resource_value.reservation)
108-
return NodeRequirements.model_validate(node_defined_resources)
106+
return NodeRequirements(**node_defined_resources)
109107

110108

111109
def _compute_node_boot_mode(node_resources: ServiceResourcesDict) -> BootMode:
@@ -146,12 +144,12 @@ async def _get_node_infos(
146144
None,
147145
)
148146

149-
result: tuple[ServiceMetaDataPublished, ServiceExtras, SimcoreServiceLabels] = (
150-
await asyncio.gather(
151-
_get_service_details(catalog_client, user_id, product_name, node),
152-
director_client.get_service_extras(node.key, node.version),
153-
director_client.get_service_labels(node),
154-
)
147+
result: tuple[
148+
ServiceMetaDataPublished, ServiceExtras, SimcoreServiceLabels
149+
] = await asyncio.gather(
150+
_get_service_details(catalog_client, user_id, product_name, node),
151+
director_client.get_service_extras(node.key, node.version),
152+
director_client.get_service_labels(node),
155153
)
156154
return result
157155

@@ -189,7 +187,7 @@ async def _generate_task_image(
189187
data.update(envs=_compute_node_envs(node_labels))
190188
if node_extras and node_extras.container_spec:
191189
data.update(command=node_extras.container_spec.command)
192-
return Image.model_validate(data)
190+
return Image(**data)
193191

194192

195193
async def _get_pricing_and_hardware_infos(
@@ -247,9 +245,9 @@ async def _get_pricing_and_hardware_infos(
247245
return pricing_info, hardware_info
248246

249247

250-
_RAM_SAFE_MARGIN_RATIO: Final[float] = (
251-
0.1 # NOTE: machines always have less available RAM than advertised
252-
)
248+
_RAM_SAFE_MARGIN_RATIO: Final[
249+
float
250+
] = 0.1 # NOTE: machines always have less available RAM than advertised
253251
_CPUS_SAFE_MARGIN: Final[float] = 0.1
254252

255253

@@ -267,11 +265,11 @@ async def _update_project_node_resources_from_hardware_info(
267265
if not hardware_info.aws_ec2_instances:
268266
return
269267
try:
270-
unordered_list_ec2_instance_types: list[EC2InstanceTypeGet] = (
271-
await get_instance_type_details(
272-
rabbitmq_rpc_client,
273-
instance_type_names=set(hardware_info.aws_ec2_instances),
274-
)
268+
unordered_list_ec2_instance_types: list[
269+
EC2InstanceTypeGet
270+
] = await get_instance_type_details(
271+
rabbitmq_rpc_client,
272+
instance_type_names=set(hardware_info.aws_ec2_instances),
275273
)
276274

277275
assert unordered_list_ec2_instance_types # nosec
@@ -347,7 +345,7 @@ async def generate_tasks_list_from_project(
347345
list_comp_tasks = []
348346

349347
unique_service_key_versions: set[ServiceKeyVersion] = {
350-
ServiceKeyVersion.model_construct(
348+
ServiceKeyVersion(
351349
key=node.key, version=node.version
352350
) # the service key version is frozen
353351
for node in project.workbench.values()
@@ -366,9 +364,7 @@ async def generate_tasks_list_from_project(
366364

367365
for internal_id, node_id in enumerate(project.workbench, 1):
368366
node: Node = project.workbench[node_id]
369-
node_key_version = ServiceKeyVersion.model_construct(
370-
key=node.key, version=node.version
371-
)
367+
node_key_version = ServiceKeyVersion(key=node.key, version=node.version)
372368
node_details, node_extras, node_labels = key_version_to_node_infos.get(
373369
node_key_version,
374370
(None, None, None),
@@ -434,8 +430,8 @@ async def generate_tasks_list_from_project(
434430
task_db = CompTaskAtDB(
435431
project_id=project.uuid,
436432
node_id=NodeID(node_id),
437-
schema=NodeSchema.model_validate(
438-
node_details.model_dump(
433+
schema=NodeSchema(
434+
**node_details.model_dump(
439435
exclude_unset=True, by_alias=True, include={"inputs", "outputs"}
440436
)
441437
),

services/director-v2/tests/unit/with_dbs/test_api_route_computations.py renamed to services/director-v2/tests/unit/with_dbs/comp_scheduler/test_api_route_computations.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ def minimal_configuration(
8888
redis_service: RedisSettings,
8989
monkeypatch: pytest.MonkeyPatch,
9090
faker: Faker,
91+
with_disabled_auto_scheduling: mock.Mock,
92+
with_disabled_scheduler_publisher: mock.Mock,
9193
):
9294
monkeypatch.setenv("DIRECTOR_V2_DYNAMIC_SIDECAR_ENABLED", "false")
9395
monkeypatch.setenv("COMPUTATIONAL_BACKEND_DASK_CLIENT_ENABLED", "1")
@@ -588,11 +590,7 @@ async def test_create_computation_with_wallet(
588590

589591
@pytest.mark.parametrize(
590592
"default_pricing_plan",
591-
[
592-
PricingPlanGet.model_construct(
593-
**PricingPlanGet.model_config["json_schema_extra"]["examples"][0]
594-
)
595-
],
593+
[PricingPlanGet(**PricingPlanGet.model_config["json_schema_extra"]["examples"][0])],
596594
)
597595
async def test_create_computation_with_wallet_with_invalid_pricing_unit_name_raises_422(
598596
minimal_configuration: None,
@@ -631,7 +629,7 @@ async def test_create_computation_with_wallet_with_invalid_pricing_unit_name_rai
631629
@pytest.mark.parametrize(
632630
"default_pricing_plan",
633631
[
634-
PricingPlanGet.model_construct(
632+
PricingPlanGet(
635633
**PricingPlanGet.model_config["json_schema_extra"]["examples"][0] # type: ignore
636634
)
637635
],

services/director-v2/tests/unit/with_dbs/comp_scheduler/test_scheduler_dask.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1606,7 +1606,9 @@ async def _return_random_task_result(job_id) -> TaskOutputData:
16061606
@pytest.fixture
16071607
def with_fast_service_heartbeat_s(monkeypatch: pytest.MonkeyPatch) -> int:
16081608
seconds = 1
1609-
monkeypatch.setenv("SERVICE_TRACKING_HEARTBEAT", f"{seconds}")
1609+
monkeypatch.setenv(
1610+
"SERVICE_TRACKING_HEARTBEAT", f"{datetime.timedelta(seconds=seconds)}"
1611+
)
16101612
return seconds
16111613

16121614

services/director-v2/tests/unit/with_dbs/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,9 @@ async def _(user: dict[str, Any], **cluster_kwargs) -> Cluster:
278278
.where(clusters.c.id == created_cluster.id)
279279
):
280280
access_rights_in_db[row.gid] = {
281-
"read": row[cluster_to_groups.c.read],
282-
"write": row[cluster_to_groups.c.write],
283-
"delete": row[cluster_to_groups.c.delete],
281+
"read": row.read,
282+
"write": row.write,
283+
"delete": row.delete,
284284
}
285285

286286
return Cluster(

0 commit comments

Comments
 (0)