Skip to content

Commit e2252f8

Browse files
author
Andrei Neagu
committed
moved to common library
1 parent f7d71e4 commit e2252f8

File tree

7 files changed

+100
-21
lines changed

7 files changed

+100
-21
lines changed

packages/common-library/requirements/_test.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
coverage
1212
faker
13+
pydantic-settings
1314
pytest
1415
pytest-asyncio
1516
pytest-cov

packages/common-library/requirements/_test.txt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
annotated-types==0.7.0
2+
# via
3+
# -c requirements/_base.txt
4+
# pydantic
15
coverage==7.6.1
26
# via
37
# -r requirements/_test.in
48
# pytest-cov
5-
faker==30.1.0
9+
faker==30.3.0
610
# via -r requirements/_test.in
711
icdiff==2.0.7
812
# via pytest-icdiff
@@ -16,6 +20,17 @@ pluggy==1.5.0
1620
# via pytest
1721
pprintpp==0.4.0
1822
# via pytest-icdiff
23+
pydantic==2.9.2
24+
# via
25+
# -c requirements/../../../requirements/constraints.txt
26+
# -c requirements/_base.txt
27+
# pydantic-settings
28+
pydantic-core==2.23.4
29+
# via
30+
# -c requirements/_base.txt
31+
# pydantic
32+
pydantic-settings==2.5.2
33+
# via -r requirements/_test.in
1934
pytest==8.3.3
2035
# via
2136
# -r requirements/_test.in
@@ -44,7 +59,9 @@ pytest-sugar==1.0.0
4459
python-dateutil==2.9.0.post0
4560
# via faker
4661
python-dotenv==1.0.1
47-
# via -r requirements/_test.in
62+
# via
63+
# -r requirements/_test.in
64+
# pydantic-settings
4865
six==1.16.0
4966
# via python-dateutil
5067
termcolor==2.5.0
@@ -53,3 +70,5 @@ typing-extensions==4.12.2
5370
# via
5471
# -c requirements/_base.txt
5572
# faker
73+
# pydantic
74+
# pydantic-core

packages/common-library/requirements/_tools.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
astroid==3.3.5
22
# via pylint
3-
black==24.8.0
3+
black==24.10.0
44
# via -r requirements/../../../requirements/devenv.txt
55
build==1.2.2.post1
66
# via pip-tools
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
from typing import Annotated, TypeAlias
2+
23
from pydantic import AfterValidator, AnyHttpUrl
34

45

5-
AnyHttpUrlLegacy: TypeAlias = Annotated[str, AnyHttpUrl, AfterValidator(lambda u: u.rstrip("/"))]
6+
def _strip_last_slash(url: str) -> str:
7+
return url.rstrip("/")
8+
9+
10+
AnyHttpUrlLegacy: TypeAlias = Annotated[
11+
str, AnyHttpUrl, AfterValidator(_strip_last_slash)
12+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import datetime
2+
3+
from pydantic import field_validator
4+
5+
6+
def _get_float_string_as_seconds(
7+
v: datetime.timedelta | str | float,
8+
) -> datetime.timedelta | float | str:
9+
if isinstance(v, str):
10+
try:
11+
return float(v)
12+
except ValueError:
13+
# returns format like "1:00:00"
14+
return v
15+
return v
16+
17+
18+
def validate_timedelta_in_legacy_mode(field: str):
19+
"""Transforms a float/int number into a valid datetime as it used to work in the past"""
20+
return field_validator(field, mode="before")(_get_float_string_as_seconds)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from datetime import timedelta
2+
3+
import pytest
4+
from common_library.pydantic_settings_validators import (
5+
validate_timedelta_in_legacy_mode,
6+
)
7+
from faker import Faker
8+
from pydantic import Field
9+
from pydantic_settings import BaseSettings, SettingsConfigDict
10+
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
11+
12+
13+
def test_validate_timedelta_in_legacy_mode(
14+
monkeypatch: pytest.MonkeyPatch, faker: Faker
15+
):
16+
class Settings(BaseSettings):
17+
APP_NAME: str
18+
REQUEST_TIMEOUT: timedelta = Field(default=timedelta(seconds=40))
19+
20+
_legacy_parsing_request_timeout = validate_timedelta_in_legacy_mode(
21+
"REQUEST_TIMEOUT"
22+
)
23+
24+
model_config = SettingsConfigDict()
25+
26+
app_name = faker.pystr()
27+
env_vars: dict[str, str] = {"APP_NAME": app_name}
28+
29+
# without timedelta
30+
setenvs_from_dict(monkeypatch, env_vars)
31+
settings = Settings()
32+
print(settings.model_dump())
33+
assert settings.APP_NAME == app_name
34+
assert settings.REQUEST_TIMEOUT == timedelta(seconds=40)
35+
36+
# with timedelta in seconds
37+
env_vars["REQUEST_TIMEOUT"] = "5555"
38+
setenvs_from_dict(monkeypatch, env_vars)
39+
settings = Settings()
40+
print(settings.model_dump())
41+
assert settings.APP_NAME == app_name
42+
assert settings.REQUEST_TIMEOUT == timedelta(seconds=5555)

services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/settings.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import datetime
22
from functools import cached_property
33

4-
from pydantic import Field, field_validator, parse_obj_as, validator
4+
from common_library.pydantic_settings_validators import (
5+
validate_timedelta_in_legacy_mode,
6+
)
7+
from pydantic import Field, parse_obj_as, validator
58
from settings_library.application import BaseApplicationSettings
69
from settings_library.basic_types import LogLevel, VersionTag
710
from settings_library.director_v2 import DirectorV2Settings
@@ -43,22 +46,9 @@ class _BaseApplicationSettings(BaseApplicationSettings, MixinLoggingSettings):
4346
),
4447
)
4548

46-
# TODO: this should be a common validator put in some common library and not here to allow reuse
47-
# wherever we used timedelta this should be in place otherwise it will fail where we overwrite the
48-
# values via env vars
49-
# GCR we need to talk where to place this one
50-
@field_validator("DYNAMIC_SCHEDULER_STOP_SERVICE_TIMEOUT", mode="before")
51-
@classmethod
52-
def interpret_t_as_seconds(
53-
cls, v: datetime.timedelta | str | float
54-
) -> datetime.timedelta | float | str:
55-
if isinstance(v, str):
56-
try:
57-
return float(v)
58-
except ValueError:
59-
# returns format like "1:00:00"
60-
return v
61-
return v
49+
_legacy_parsing_dynamic_scheduler_stop_service_timeout = (
50+
validate_timedelta_in_legacy_mode("DYNAMIC_SCHEDULER_STOP_SERVICE_TIMEOUT")
51+
)
6252

6353
@cached_property
6454
def LOG_LEVEL(self): # noqa: N802

0 commit comments

Comments
 (0)