Skip to content

Commit bac03b9

Browse files
authored
♻️ Replace auto-generated storage python client (ITISFoundation#2578)
* removed storage auto-generated client * created aiohttp-based simple client * wait for director-v0 to be up * improve wait time and logging * added docker registry * @GitHK review: wait max 1hour
1 parent 89fef0d commit bac03b9

File tree

129 files changed

+1137
-7600
lines changed

Some content is hidden

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

129 files changed

+1137
-7600
lines changed

api/specs/storage/openapi.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ paths:
240240
content:
241241
application/json:
242242
schema:
243-
$ref: "#/components/schemas/FileMetaDataEnveloped"
243+
$ref: "#/components/schemas/FileMetaEnvelope"
244244
default:
245245
$ref: "#/components/responses/DefaultErrorResponse"
246246
patch:
@@ -268,7 +268,7 @@ paths:
268268
content:
269269
application/json:
270270
schema:
271-
$ref: "#/components/schemas/FileMetaDataEnveloped"
271+
$ref: "#/components/schemas/FileMetaEnvelope"
272272
default:
273273
$ref: "#/components/responses/DefaultErrorResponse"
274274

@@ -480,7 +480,7 @@ paths:
480480
content:
481481
application/json:
482482
schema:
483-
$ref: "#/components/schemas/FileMetaDataEnveloped"
483+
$ref: "#/components/schemas/FileMetaEnvelope"
484484
default:
485485
$ref: "#/components/responses/DefaultErrorResponse"
486486
components:
@@ -738,7 +738,7 @@ components:
738738
nullable: true
739739
default: null
740740

741-
DatasetMetaDataEnveloped:
741+
DatasetMetaEnvelope:
742742
type: object
743743
required:
744744
- data
@@ -766,7 +766,7 @@ components:
766766
items:
767767
$ref: "#/components/schemas/DatasetMetaData"
768768

769-
FileMetaDataEnveloped:
769+
FileMetaEnvelope:
770770
type: object
771771
required:
772772
- data

api/specs/webserver/components/schemas/datasets.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
DatasetMetaDataEnveloped:
1+
DatasetMetaEnvelope:
22
type: object
33
required:
44
- data
55
properties:
66
data:
7-
$ref: '#DatasetMetaData'
7+
$ref: "#DatasetMetaData"
88
error:
99
nullable: true
1010
default: null
@@ -17,10 +17,10 @@ DatasetMetaData:
1717
display_name:
1818
type: string
1919
example:
20-
dataset_uuid: 'N:id-aaaa'
20+
dataset_uuid: "N:id-aaaa"
2121
display_name: "simcore-testing"
2222

2323
DatasetMetaDataArray:
2424
type: array
2525
items:
26-
$ref: '#/DatasetMetaData'
26+
$ref: "#/DatasetMetaData"

api/specs/webserver/components/schemas/files.yaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
FileMetaDataEnveloped:
1+
FileMetaEnvelope:
22
type: object
33
required:
44
- data
55
properties:
66
data:
7-
$ref: '#/FileMetaData'
7+
$ref: "#/FileMetaData"
88
error:
99
nullable: true
1010
default: null
@@ -50,9 +50,9 @@ FileMetaData:
5050
file_size:
5151
type: integer
5252
parent_id:
53-
type: string
53+
type: string
5454
example:
55-
file_uuid: 'simcore-testing/105/1000/3'
55+
file_uuid: "simcore-testing/105/1000/3"
5656
location_id: "0"
5757
location_name: "simcore.s3"
5858
bucket_name: "simcore-testing"
@@ -72,8 +72,7 @@ FileMetaData:
7272
file_size: 73
7373
parent_id: "N:collection:e263da07-2d89-45a6-8b0f-61061b913873"
7474

75-
7675
FileMetaDataArray:
7776
type: array
7877
items:
79-
$ref: '#/FileMetaData'
78+
$ref: "#/FileMetaData"

ci/github/integration-testing/simcore-sdk.bash

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ install() {
1717
# pull the test images if registry is set up, else build the images
1818
make pull-version || (make build tag-version)
1919
make info-images
20-
# pip3 install services/storage/client-sdk/python
2120
}
2221

2322
test() {

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

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
from uuid import UUID
1313

1414
from pydantic import BaseModel, Field, constr
15+
from pydantic.networks import AnyUrl
1516

1617
from .basic_regex import UUID_RE
18+
from .generics import ListModel
1719

1820

1921
# /
@@ -24,11 +26,6 @@ class HealthCheck(BaseModel):
2426
version: Optional[str]
2527

2628

27-
class HealthCheckEnveloped(BaseModel):
28-
data: HealthCheck
29-
error: Any
30-
31-
3229
# /check/{action}:
3330
class Fake(BaseModel):
3431
path_value: str
@@ -49,19 +46,7 @@ class Config:
4946
}
5047

5148

52-
class FileLocationArray(BaseModel):
53-
__root__: List[FileLocation]
54-
55-
56-
class FileLocationEnveloped(BaseModel):
57-
data: FileLocation
58-
error: Any
59-
60-
61-
class FileLocationArrayEnveloped(BaseModel):
62-
data: FileLocationArray
63-
error: Any
64-
49+
FileLocationArray = ListModel[FileLocation]
6550

6651
# /locations/{location_id}/datasets
6752

@@ -101,18 +86,7 @@ class Config:
10186
}
10287

10388

104-
class DatasetMetaDataArray(BaseModel):
105-
__root__: List[DatasetMetaData] = []
106-
107-
108-
class DatasetMetaDataEnveloped(BaseModel):
109-
data: DatasetMetaData
110-
error: Any
111-
112-
113-
class DatasetMetaDataArrayEnveloped(BaseModel):
114-
data: DatasetMetaDataArray
115-
error: Any
89+
DatasetMetaDataArray = ListModel[DatasetMetaData]
11690

11791

11892
# /locations/{location_id}/files/metadata:
@@ -215,26 +189,11 @@ class FileMetaDataArray(BaseModel):
215189
__root__: List[FileMetaData] = []
216190

217191

218-
class FileMetaDataEnveloped(BaseModel):
219-
data: FileMetaData
220-
error: Any
221-
222-
223-
class FileMetaDataArrayEnveloped(BaseModel):
224-
data: FileMetaDataArray
225-
error: Any
226-
227-
228192
# /locations/{location_id}/files/{fileId}
229193

230194

231195
class PresignedLink(BaseModel):
232-
link: str
233-
234-
235-
class PresignedLinkEnveloped(BaseModel):
236-
data: PresignedLink
237-
error: Any
196+
link: AnyUrl
238197

239198

240199
# /simcore-s3/
@@ -279,18 +238,3 @@ class Error(BaseModel):
279238
logs: Optional[List[LogMessage]] = Field(description="Log messages")
280239
errors: Optional[List[ErrorItem]] = Field(description="Errors metadata")
281240
status: Optional[int] = Field(description="HTTP error code")
282-
283-
284-
class LogMessageEnveloped(BaseModel):
285-
data: LogMessage
286-
error: Any
287-
288-
289-
class FakeEnveloped(BaseModel):
290-
data: Fake
291-
error: Any
292-
293-
294-
class ErrorEnveloped(BaseModel):
295-
data: Any
296-
error: Error
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from typing import (
2+
Any,
3+
Dict,
4+
Generic,
5+
ItemsView,
6+
Iterator,
7+
KeysView,
8+
List,
9+
Optional,
10+
TypeVar,
11+
ValuesView,
12+
)
13+
14+
from pydantic import validator
15+
from pydantic.generics import GenericModel
16+
17+
DictKey = TypeVar("DictKey")
18+
DictValue = TypeVar("DictValue")
19+
20+
21+
class DictModel(GenericModel, Generic[DictKey, DictValue]):
22+
__root__: Dict[DictKey, DictValue]
23+
24+
def __getitem__(self, k: DictKey) -> DictValue:
25+
return self.__root__.__getitem__(k)
26+
27+
def __setitem__(self, k: DictKey, v: DictValue) -> None:
28+
self.__root__.__setitem__(k, v)
29+
30+
def items(self) -> ItemsView[DictKey, DictValue]:
31+
return self.__root__.items()
32+
33+
def keys(self) -> KeysView[DictKey]:
34+
return self.__root__.keys()
35+
36+
def values(self) -> ValuesView[DictValue]:
37+
return self.__root__.values()
38+
39+
def __iter__(self) -> Iterator[DictKey]:
40+
return self.__root__.__iter__()
41+
42+
def get(self, key: DictKey, default: Optional[DictValue] = None):
43+
return self.__root__.get(key, default)
44+
45+
def __len__(self) -> int:
46+
return self.__root__.__len__()
47+
48+
49+
DataT = TypeVar("DataT")
50+
51+
52+
class ListModel(GenericModel, Generic[DataT]):
53+
__root__: List[DataT]
54+
55+
def __iter__(self):
56+
return iter(self.__root__)
57+
58+
def __getitem__(self, item):
59+
return self.__root__[item]
60+
61+
def __len__(self):
62+
return len(self.__root__)
63+
64+
65+
class Envelope(GenericModel, Generic[DataT]):
66+
data: Optional[DataT]
67+
error: Optional[Any]
68+
69+
@validator("error")
70+
@classmethod
71+
def data_and_error_cannot_be_populated_together(cls, v, values):
72+
if v is not None and values.get("data") is not None:
73+
raise ValueError(
74+
"both data and error cannot contain values at the same time"
75+
)
76+
return v
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from pathlib import Path
2+
from typing import Any
3+
4+
import pytest
5+
from faker import Faker
6+
from models_library.generics import DictModel, Envelope
7+
8+
9+
def test_dict_base_model():
10+
some_dict = {
11+
"a key": 123,
12+
"another key": "a string value",
13+
"yet another key": Path("some_path"),
14+
}
15+
some_instance = DictModel[str, Any].parse_obj(some_dict)
16+
assert some_instance
17+
18+
# test some typical dict methods
19+
assert len(some_instance) == 3
20+
for k, k2 in zip(some_dict, some_instance):
21+
assert k == k2
22+
23+
for k, k2 in zip(some_dict.keys(), some_instance.keys()):
24+
assert k == k2
25+
26+
for v, v2 in zip(some_dict.values(), some_instance.values()):
27+
assert v == v2
28+
29+
for i, i2 in zip(some_dict.items(), some_instance.items()):
30+
assert i == i2
31+
32+
assert some_instance.get("a key") == 123
33+
assert some_instance.get("a non existing key") is None
34+
35+
assert some_instance["a key"] == 123
36+
with pytest.raises(KeyError):
37+
some_instance["a non existing key"] # pylint: disable=pointless-statement
38+
some_instance["a new key"] = 23
39+
assert some_instance["a new key"] == 23
40+
41+
42+
def test_data_enveloped(faker: Faker):
43+
some_enveloped_string = Envelope[str]()
44+
assert some_enveloped_string
45+
assert not some_enveloped_string.data
46+
assert not some_enveloped_string.error
47+
48+
random_float = faker.pyfloat()
49+
some_enveloped_float = Envelope[float](data=random_float)
50+
assert some_enveloped_float
51+
assert some_enveloped_float.data == random_float
52+
assert not some_enveloped_float.error
53+
54+
random_text = faker.text()
55+
some_enveloped_bool = Envelope[bool](error=random_text)
56+
assert some_enveloped_bool
57+
assert not some_enveloped_bool.data
58+
assert some_enveloped_bool.error == random_text
59+
60+
with pytest.raises(ValueError):
61+
Envelope[int](data=213, error="some error message")

packages/pytest-simcore/src/pytest_simcore/environment_configs.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,26 @@
55

66
from copy import deepcopy
77
from pathlib import Path
8-
from typing import Dict, Union
8+
from typing import Dict
99

1010
import dotenv
1111
import pytest
12+
from _pytest.monkeypatch import MonkeyPatch
1213

1314

1415
@pytest.fixture(scope="session")
15-
def env_devel_dict(env_devel_file: Path) -> Dict[str, Union[str, None]]:
16+
def env_devel_dict(env_devel_file: Path) -> Dict[str, str]:
1617
assert env_devel_file.exists()
1718
assert env_devel_file.name == ".env-devel"
1819
environ = dotenv.dotenv_values(env_devel_file, verbose=True, interpolate=True)
19-
return environ
20+
assert all(v is not None for v in environ.values())
21+
return environ # type: ignore
2022

2123

2224
@pytest.fixture(scope="function")
23-
def mock_env_devel_environment(env_devel_dict, monkeypatch):
25+
def mock_env_devel_environment(
26+
env_devel_dict: Dict[str, str], monkeypatch: MonkeyPatch
27+
) -> Dict[str, str]:
2428
for key, value in env_devel_dict.items():
25-
monkeypatch.setenv(key, value)
29+
monkeypatch.setenv(key, str(value))
2630
return deepcopy(env_devel_dict)

0 commit comments

Comments
 (0)