Skip to content

Commit 7410516

Browse files
authored
⬆️Migration: Storage (#6599)
1 parent 82c69d0 commit 7410516

File tree

46 files changed

+682
-411
lines changed

Some content is hidden

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

46 files changed

+682
-411
lines changed

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from boto3.s3.transfer import TransferConfig
1414
from botocore import exceptions as botocore_exc
1515
from botocore.client import Config
16-
from common_library.pydantic_networks_extension import AnyUrlLegacy
1716
from models_library.api_schemas_storage import ETag, S3BucketName, UploadedPart
1817
from models_library.basic_types import SHA256Str
1918
from pydantic import AnyUrl, ByteSize, TypeAdapter
@@ -255,7 +254,7 @@ async def create_single_presigned_download_link(
255254
bucket: S3BucketName,
256255
object_key: S3ObjectKey,
257256
expiration_secs: int,
258-
) -> str:
257+
) -> AnyUrl:
259258
# NOTE: ensure the bucket/object exists, this will raise if not
260259
await self._client.head_bucket(Bucket=bucket)
261260
await self._client.head_object(Bucket=bucket, Key=object_key)
@@ -264,20 +263,20 @@ async def create_single_presigned_download_link(
264263
Params={"Bucket": bucket, "Key": object_key},
265264
ExpiresIn=expiration_secs,
266265
)
267-
return f"{TypeAdapter(AnyUrlLegacy).validate_python(generated_link)}"
266+
return TypeAdapter(AnyUrl).validate_python(generated_link)
268267

269268
@s3_exception_handler(_logger)
270269
async def create_single_presigned_upload_link(
271270
self, *, bucket: S3BucketName, object_key: S3ObjectKey, expiration_secs: int
272-
) -> str:
271+
) -> AnyUrl:
273272
# NOTE: ensure the bucket/object exists, this will raise if not
274273
await self._client.head_bucket(Bucket=bucket)
275274
generated_link = await self._client.generate_presigned_url(
276275
"put_object",
277276
Params={"Bucket": bucket, "Key": object_key},
278277
ExpiresIn=expiration_secs,
279278
)
280-
return f"{TypeAdapter(AnyUrlLegacy).validate_python(generated_link)}"
279+
return TypeAdapter(AnyUrl).validate_python(generated_link)
281280

282281
@s3_exception_handler(_logger)
283282
async def create_multipart_upload_links(
@@ -474,6 +473,6 @@ def is_multipart(file_size: ByteSize) -> bool:
474473

475474
@staticmethod
476475
def compute_s3_url(*, bucket: S3BucketName, object_key: S3ObjectKey) -> AnyUrl:
477-
return TypeAdapter(AnyUrlLegacy).validate_python(
476+
return TypeAdapter(AnyUrl).validate_python(
478477
f"s3://{bucket}/{urllib.parse.quote(object_key)}"
479478
)

packages/aws-library/tests/test_s3_client.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ async def test_create_single_presigned_upload_link(
742742
create_file_of_size: Callable[[ByteSize], Path],
743743
default_expiration_time_seconds: int,
744744
upload_to_presigned_link: Callable[
745-
[Path, str, S3BucketName, S3ObjectKey], Awaitable[None]
745+
[Path, AnyUrl, S3BucketName, S3ObjectKey], Awaitable[None]
746746
],
747747
):
748748
file = create_file_of_size(TypeAdapter(ByteSize).validate_python("1Mib"))
@@ -1289,20 +1289,24 @@ def test_is_multipart(file_size: ByteSize, expected_multipart: bool):
12891289
(
12901290
"some-bucket",
12911291
"an/object/separate/by/slashes",
1292-
"s3://some-bucket/an/object/separate/by/slashes",
1292+
TypeAdapter(AnyUrl).validate_python(
1293+
"s3://some-bucket/an/object/separate/by/slashes"
1294+
),
12931295
),
12941296
(
12951297
"some-bucket",
12961298
"an/object/separate/by/slashes-?/3#$",
1297-
r"s3://some-bucket/an/object/separate/by/slashes-%3F/3%23%24",
1299+
TypeAdapter(AnyUrl).validate_python(
1300+
r"s3://some-bucket/an/object/separate/by/slashes-%3F/3%23%24"
1301+
),
12981302
),
12991303
],
13001304
)
13011305
def test_compute_s3_url(
13021306
bucket: S3BucketName, object_key: S3ObjectKey, expected_s3_url: AnyUrl
13031307
):
13041308
assert (
1305-
str(SimcoreS3API.compute_s3_url(bucket=bucket, object_key=object_key))
1309+
SimcoreS3API.compute_s3_url(bucket=bucket, object_key=object_key)
13061310
== expected_s3_url
13071311
)
13081312

packages/common-library/src/common_library/pydantic_networks_extension.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
from typing import Annotated, TypeAlias
22

3-
from pydantic import AfterValidator, AnyHttpUrl, AnyUrl, HttpUrl
3+
from pydantic import AfterValidator, AnyHttpUrl, HttpUrl
44
from pydantic_core import Url
55

66

77
def _strip_last_slash(url: Url) -> str:
88
return f"{url}".rstrip("/")
99

1010

11-
AnyUrlLegacy: TypeAlias = Annotated[
12-
AnyUrl,
13-
AfterValidator(_strip_last_slash),
14-
]
15-
1611
AnyHttpUrlLegacy: TypeAlias = Annotated[
1712
AnyHttpUrl,
1813
AfterValidator(_strip_last_slash),

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from datetime import datetime
1010
from enum import Enum
11-
from typing import Annotated, Any, TypeAlias
11+
from typing import Annotated, Any, Literal, Self, TypeAlias
1212
from uuid import UUID
1313

1414
from pydantic import (
@@ -107,6 +107,10 @@ class DatasetMetaDataGet(BaseModel):
107107
)
108108

109109

110+
UNDEFINED_SIZE_TYPE: TypeAlias = Literal[-1]
111+
UNDEFINED_SIZE: UNDEFINED_SIZE_TYPE = -1
112+
113+
110114
# /locations/{location_id}/files/metadata:
111115
# /locations/{location_id}/files/{file_id}/metadata:
112116
class FileMetaDataGet(BaseModel):
@@ -130,8 +134,8 @@ class FileMetaDataGet(BaseModel):
130134
)
131135
created_at: datetime
132136
last_modified: datetime
133-
file_size: ByteSize | int = Field(
134-
default=-1, description="File size in bytes (-1 means invalid)"
137+
file_size: UNDEFINED_SIZE_TYPE | ByteSize = Field(
138+
default=UNDEFINED_SIZE, description="File size in bytes (-1 means invalid)"
135139
)
136140
entity_tag: ETag | None = Field(
137141
default=None,
@@ -149,7 +153,7 @@ class FileMetaDataGet(BaseModel):
149153
)
150154

151155
model_config = ConfigDict(
152-
extra="forbid",
156+
extra="ignore",
153157
from_attributes=True,
154158
json_schema_extra={
155159
"examples": [
@@ -312,19 +316,18 @@ class FoldersBody(BaseModel):
312316
nodes_map: dict[NodeID, NodeID] = Field(default_factory=dict)
313317

314318
@model_validator(mode="after")
315-
@classmethod
316-
def ensure_consistent_entries(cls, values):
317-
source_node_keys = (NodeID(n) for n in values["source"].get("workbench", {}))
318-
if set(source_node_keys) != set(values["nodes_map"].keys()):
319+
def ensure_consistent_entries(self) -> Self:
320+
source_node_keys = (NodeID(n) for n in self.source.get("workbench", {}))
321+
if set(source_node_keys) != set(self.nodes_map.keys()):
319322
msg = "source project nodes do not fit with nodes_map entries"
320323
raise ValueError(msg)
321324
destination_node_keys = (
322-
NodeID(n) for n in values["destination"].get("workbench", {})
325+
NodeID(n) for n in self.destination.get("workbench", {})
323326
)
324-
if set(destination_node_keys) != set(values["nodes_map"].values()):
327+
if set(destination_node_keys) != set(self.nodes_map.values()):
325328
msg = "destination project nodes do not fit with nodes_map values"
326329
raise ValueError(msg)
327-
return values
330+
return self
328331

329332

330333
class SoftCopyBody(BaseModel):

packages/models-library/src/models_library/utils/json_serialization.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import orjson
2626
from pydantic import NameEmail, SecretBytes, SecretStr
27+
from pydantic_core import Url
2728
from pydantic_extra_types.color import Color
2829

2930

@@ -84,6 +85,7 @@ def decimal_encoder(dec_value: Decimal) -> int | float:
8485
SecretBytes: str,
8586
SecretStr: str,
8687
set: list,
88+
Url: str,
8789
UUID: str,
8890
}
8991

packages/settings-library/src/settings_library/node_ports.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from datetime import timedelta
2-
from typing import Final
2+
from typing import Final, Self
33

44
from pydantic import Field, NonNegativeInt, PositiveInt, SecretStr, model_validator
55

@@ -22,14 +22,13 @@ def auth_required(self) -> bool:
2222
return self.STORAGE_USERNAME is not None and self.STORAGE_PASSWORD is not None
2323

2424
@model_validator(mode="after")
25-
@classmethod
26-
def _validate_auth_fields(cls, values):
27-
username = values.STORAGE_USERNAME
28-
password = values.STORAGE_PASSWORD
25+
def _validate_auth_fields(self) -> Self:
26+
username = self.STORAGE_USERNAME
27+
password = self.STORAGE_PASSWORD
2928
if (username is None) != (password is None):
3029
msg = f"Both {username=} and {password=} must be either set or unset!"
3130
raise ValueError(msg)
32-
return values
31+
return self
3332

3433

3534
class NodePortsSettings(BaseCustomSettings):

packages/settings-library/src/settings_library/utils_cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
import os
44
from collections.abc import Callable
5+
from enum import Enum
56
from pprint import pformat
67
from typing import Any
78

@@ -64,7 +65,8 @@ def print_as_envfile(
6465

6566
if verbose and field.description:
6667
typer.echo(f"# {field.description}")
67-
68+
if isinstance(value, Enum):
69+
value = value.value
6870
typer.echo(f"{name}={value}")
6971

7072

packages/simcore-sdk/src/simcore_sdk/node_data/data_manager.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from models_library.projects import ProjectID
77
from models_library.projects_nodes_io import NodeID, StorageFileID
88
from models_library.users import UserID
9-
from pydantic import ByteSize, TypeAdapter
9+
from pydantic import TypeAdapter
1010
from servicelib.archiving_utils import unarchive_dir
1111
from servicelib.logging_utils import log_context
1212
from servicelib.progress_bar import ProgressBarData
@@ -184,15 +184,6 @@ async def _delete_legacy_archive(
184184
)
185185

186186

187-
async def get_remote_size(
188-
*, user_id: UserID, project_id: ProjectID, node_uuid: NodeID, source_path: Path
189-
) -> ByteSize:
190-
s3_object = __create_s3_object_key(project_id, node_uuid, source_path)
191-
return await filemanager.get_path_size(
192-
user_id=user_id, store_id=SIMCORE_LOCATION, s3_object=s3_object
193-
)
194-
195-
196187
async def push(
197188
user_id: UserID,
198189
project_id: ProjectID,

packages/simcore-sdk/src/simcore_sdk/node_ports_common/filemanager.py

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from models_library.basic_types import IDStr, SHA256Str
1616
from models_library.projects_nodes_io import LocationID, LocationName, StorageFileID
1717
from models_library.users import UserID
18-
from pydantic import AnyUrl, ByteSize, TypeAdapter, parse_obj_as
18+
from pydantic import AnyUrl, ByteSize, TypeAdapter
1919
from servicelib.file_utils import create_sha256_checksum
2020
from servicelib.progress_bar import ProgressBarData
2121
from settings_library.aws_s3_cli import AwsS3CliSettings
@@ -189,7 +189,9 @@ async def download_path_from_s3(
189189
aws_s3_cli_settings,
190190
progress_bar,
191191
local_directory_path=local_path,
192-
download_s3_link=TypeAdapter(AnyUrl).validate_python(f"{download_link}"),
192+
download_s3_link=TypeAdapter(AnyUrl).validate_python(
193+
f"{download_link}"
194+
),
193195
)
194196
elif r_clone_settings:
195197
await r_clone.sync_s3_to_local(
@@ -572,21 +574,6 @@ async def get_file_metadata(
572574
)
573575

574576

575-
async def get_path_size(
576-
user_id: UserID,
577-
store_id: LocationID,
578-
s3_object: StorageFileID,
579-
client_session: ClientSession | None = None,
580-
) -> ByteSize:
581-
file_metadata: FileMetaDataGet = await _get_file_meta_data(
582-
user_id=user_id,
583-
store_id=store_id,
584-
s3_object=s3_object,
585-
client_session=client_session,
586-
)
587-
return ByteSize(file_metadata.file_size)
588-
589-
590577
async def delete_file(
591578
user_id: UserID,
592579
store_id: LocationID,

scripts/release/monitor_release/settings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
from pathlib import Path
3-
from typing import Final
3+
from typing import Final, Self
44

55
from dotenv import load_dotenv
66
from pydantic import BaseModel, Field, HttpUrl, TypeAdapter, model_validator
@@ -47,7 +47,7 @@ class ReleaseSettings(BaseSettings):
4747
model_config = SettingsConfigDict(extra="ignore")
4848

4949
@model_validator(mode="after")
50-
def deduce_portainer_url(self):
50+
def deduce_portainer_url(self) -> Self:
5151
self.portainer_url = TypeAdapter(HttpUrl).validate_python(
5252
f"https://{self.PORTAINER_DOMAIN}"
5353
)

0 commit comments

Comments
 (0)