Skip to content

Commit d539aa5

Browse files
committed
Merge branch 'master' into 1922-disable-client-disconnect-mechanism
2 parents d6f9784 + 64695c3 commit d539aa5

File tree

43 files changed

+827
-360
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+827
-360
lines changed

.github/prompts/pydantic-annotated-fields.prompt.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Follow these guidelines:
1313
4. Add the import: `from common_library.basic_types import DEFAULT_FACTORY` if it's not already present.
1414
5. If `Field()` has no parameters (empty), don't use Annotated at all. Just use: `field_name: field_type = default_value`.
1515
6. Leave any model validations, `model_config` settings, and `field_validators` untouched.
16-
16+
7. Must keep the original Field descriptions and validation parameters intact (except for the `default` parameter).
1717

1818
## Examples
1919

api/specs/web-server/_auth.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# pylint: disable=too-many-arguments
55

66

7-
from typing import Any
7+
from typing import Annotated, Any
88

99
from fastapi import APIRouter, status
1010
from models_library.api_schemas_webserver.auth import (
@@ -211,13 +211,16 @@ async def change_email(_body: ChangeEmailBody):
211211

212212

213213
class PasswordCheckSchema(BaseModel):
214-
strength: confloat(ge=0.0, le=1.0) = Field( # type: ignore
215-
...,
216-
description="The strength of the password ranges from 0 (extremely weak) and 1 (extremely strong)",
217-
)
218-
rating: str | None = Field(
219-
None, description="Human readable rating from infinitely weak to very strong"
220-
)
214+
strength: Annotated[
215+
confloat(ge=0.0, le=1.0),
216+
Field(
217+
description="The strength of the password ranges from 0 (extremely weak) and 1 (extremely strong)",
218+
),
219+
]
220+
rating: Annotated[
221+
str | None,
222+
Field(description="Human readable rating from infinitely weak to very strong"),
223+
] = None
221224
improvements: Any | None = None
222225

223226

packages/aws-library/src/aws_library/ec2/_models.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Annotated, Final, TypeAlias
66

77
import sh # type: ignore[import-untyped]
8+
from common_library.basic_types import DEFAULT_FACTORY
89
from models_library.docker import DockerGenericTag
910
from pydantic import (
1011
BaseModel,
@@ -143,23 +144,32 @@ class EC2InstanceConfig:
143144

144145
class EC2InstanceBootSpecific(BaseModel):
145146
ami_id: AMIIdStr
146-
custom_boot_scripts: list[CommandStr] = Field(
147-
default_factory=list,
148-
description="script(s) to run on EC2 instance startup (be careful!), "
149-
"each entry is run one after the other using '&&' operator",
150-
)
151-
pre_pull_images: list[DockerGenericTag] = Field(
152-
default_factory=list,
153-
description="a list of docker image/tags to pull on instance cold start",
154-
)
155-
pre_pull_images_cron_interval: datetime.timedelta = Field(
156-
default=datetime.timedelta(minutes=30),
157-
description="time interval between pulls of images (minimum is 1 minute) "
158-
"(default to seconds, or see https://pydantic-docs.helpmanual.io/usage/types/#datetime-types for string formating)",
159-
)
160-
buffer_count: NonNegativeInt = Field(
161-
default=0, description="number of buffer EC2s to keep (defaults to 0)"
162-
)
147+
custom_boot_scripts: Annotated[
148+
list[CommandStr],
149+
Field(
150+
default_factory=list,
151+
description="script(s) to run on EC2 instance startup (be careful!), "
152+
"each entry is run one after the other using '&&' operator",
153+
),
154+
] = DEFAULT_FACTORY
155+
pre_pull_images: Annotated[
156+
list[DockerGenericTag],
157+
Field(
158+
default_factory=list,
159+
description="a list of docker image/tags to pull on instance cold start",
160+
),
161+
] = DEFAULT_FACTORY
162+
pre_pull_images_cron_interval: Annotated[
163+
datetime.timedelta,
164+
Field(
165+
description="time interval between pulls of images (minimum is 1 minute) "
166+
"(default to seconds, or see https://pydantic-docs.helpmanual.io/usage/types/#datetime-types for string formating)",
167+
),
168+
] = datetime.timedelta(minutes=30)
169+
buffer_count: Annotated[
170+
NonNegativeInt,
171+
Field(description="number of buffer EC2s to keep (defaults to 0)"),
172+
] = 0
163173

164174
@field_validator("custom_boot_scripts")
165175
@classmethod

packages/aws-library/src/aws_library/s3/_models.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import datetime
22
from pathlib import Path
3-
from typing import TypeAlias, cast
3+
from typing import Annotated, TypeAlias, cast
44

55
from models_library.api_schemas_storage.storage_schemas import ETag
66
from models_library.basic_types import SHA256Str
@@ -54,9 +54,10 @@ def as_path(self) -> Path:
5454

5555
class S3DirectoryMetaData(BaseModel, frozen=True):
5656
prefix: S3ObjectPrefix
57-
size: ByteSize | None = Field(
58-
..., description="Size of the directory if computed, None if unknown"
59-
)
57+
size: Annotated[
58+
ByteSize | None,
59+
Field(description="Size of the directory if computed, None if unknown"),
60+
]
6061

6162
def as_path(self) -> Path:
6263
return self.prefix

packages/celery-library/src/celery_library/signals.py

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

55
from celery import Celery # type: ignore[import-untyped]
66
from celery.worker.worker import WorkController # type: ignore[import-untyped]
7-
from servicelib.celery.app_server import STARTUP_TIMEOUT, BaseAppServer
7+
from servicelib.celery.app_server import BaseAppServer
88
from servicelib.logging_utils import log_context
99
from settings_library.celery import CelerySettings
1010

@@ -26,8 +26,6 @@ def _init(startup_complete_event: threading.Event) -> None:
2626
loop = asyncio.new_event_loop()
2727
asyncio.set_event_loop(loop)
2828

29-
shutdown_event = asyncio.Event()
30-
3129
async def _setup_task_manager():
3230
assert sender.app # nosec
3331
assert isinstance(sender.app, Celery) # nosec
@@ -42,9 +40,7 @@ async def _setup_task_manager():
4240
app_server.event_loop = loop
4341

4442
loop.run_until_complete(_setup_task_manager())
45-
loop.run_until_complete(
46-
app_server.startup(startup_complete_event, shutdown_event)
47-
)
43+
loop.run_until_complete(app_server.lifespan(startup_complete_event))
4844

4945
thread = threading.Thread(
5046
group=None,
@@ -55,12 +51,12 @@ async def _setup_task_manager():
5551
)
5652
thread.start()
5753

58-
startup_complete_event.wait(STARTUP_TIMEOUT * 1.1)
54+
startup_complete_event.wait()
5955

6056

6157
def on_worker_shutdown(sender, **_kwargs) -> None:
6258
with log_context(_logger, logging.INFO, "Worker shutdown"):
6359
assert isinstance(sender.app, Celery)
6460
app_server = get_app_server(sender.app)
6561

66-
app_server.event_loop.run_until_complete(app_server.shutdown())
62+
app_server.shutdown_event.set()

packages/celery-library/tests/conftest.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# pylint: disable=unused-argument
33

44
import datetime
5+
import threading
56
from collections.abc import AsyncIterator, Callable
67
from functools import partial
78
from typing import Any
@@ -30,10 +31,7 @@
3031

3132

3233
class FakeAppServer(BaseAppServer):
33-
async def on_startup(self) -> None:
34-
pass
35-
36-
async def on_shutdown(self) -> None:
34+
async def lifespan(self, startup_completed_event: threading.Event) -> None:
3735
pass
3836

3937

packages/common-library/tests/test_pydantic_fields_extension.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
from typing import Any, Callable, Literal
1+
from collections.abc import Callable
2+
from typing import Any, Literal
23

34
import pytest
45
from common_library.pydantic_fields_extension import get_type, is_literal, is_nullable
5-
from pydantic import BaseModel, Field
6+
from pydantic import BaseModel
67

78

89
class MyModel(BaseModel):
910
a: int
10-
b: float | None = Field(...)
11+
b: float | None
1112
c: str = "bla"
1213
d: bool | None = None
1314
e: Literal["bla"]

packages/common-library/tests/test_pydantic_validators.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
validate_numeric_string_as_timedelta,
88
)
99
from faker import Faker
10-
from pydantic import BeforeValidator, Field
10+
from pydantic import BeforeValidator
1111
from pydantic_settings import BaseSettings, SettingsConfigDict
1212
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
1313

@@ -17,7 +17,7 @@ class Settings(BaseSettings):
1717
APP_NAME: str
1818
REQUEST_TIMEOUT: Annotated[
1919
timedelta, BeforeValidator(_validate_legacy_timedelta_str)
20-
] = Field(default=timedelta(hours=1))
20+
] = timedelta(hours=1)
2121

2222
model_config = SettingsConfigDict()
2323

@@ -45,7 +45,7 @@ def test_validate_timedelta_in_legacy_mode(
4545
):
4646
class Settings(BaseSettings):
4747
APP_NAME: str
48-
REQUEST_TIMEOUT: timedelta = Field(default=timedelta(seconds=40))
48+
REQUEST_TIMEOUT: timedelta = timedelta(seconds=40)
4949

5050
_validate_request_timeout = validate_numeric_string_as_timedelta(
5151
"REQUEST_TIMEOUT"

packages/dask-task-models-library/src/dask_task_models_library/container_tasks/io.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,15 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
7575

7676
class FileUrl(BaseModel):
7777
url: AnyUrl
78-
file_mapping: str | None = Field(
79-
default=None,
80-
description="Local file relpath name (if given), otherwise it takes the url filename",
81-
)
82-
file_mime_type: str | None = Field(
83-
default=None, description="the file MIME type", pattern=MIME_TYPE_RE
84-
)
78+
file_mapping: Annotated[
79+
str | None,
80+
Field(
81+
description="Local file relpath name (if given), otherwise it takes the url filename"
82+
),
83+
] = None
84+
file_mime_type: Annotated[
85+
str | None, Field(description="the file MIME type", pattern=MIME_TYPE_RE)
86+
] = None
8587

8688
@staticmethod
8789
def _update_json_schema_extra(schema: JsonDict) -> None:

packages/models-library/src/models_library/api_schemas__common/errors.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import http
2-
from typing import Any
2+
from typing import Annotated, Any
33

44
from pydantic import BaseModel, Field
55

66
from ..basic_types import IDStr
77

88

99
class DefaultApiError(BaseModel):
10-
name: IDStr = Field(
11-
...,
12-
description="Error identifier as a code or a name. "
13-
"Mainly for machine-machine communication purposes.",
10+
name: Annotated[IDStr, Field(description="Exception's class name")]
11+
detail: Annotated[Any | None, Field(description="Human readable error message")] = (
12+
None
1413
)
15-
detail: Any | None = Field(default=None, description="Human readable error message")
1614

1715
@classmethod
1816
def from_status_code(

0 commit comments

Comments
 (0)