Skip to content

Commit 89f470c

Browse files
MHHukiewitzhoh
authored andcommitted
Add parse_volume to fix parsing of MachineVolume types
Co-authored-by: Hugo Herter <[email protected]> Reformat omfg
1 parent fddcc97 commit 89f470c

File tree

3 files changed

+80
-8
lines changed

3 files changed

+80
-8
lines changed

src/aleph/sdk/client/authenticated_http.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
from ..conf import settings
3838
from ..exceptions import BroadcastError, InsufficientFundsError, InvalidMessageError
3939
from ..types import Account, StorageEnum
40-
from ..utils import extended_json_encoder
40+
from ..utils import extended_json_encoder, parse_volume
4141
from .abstract import AuthenticatedAlephClient
4242
from .http import AlephHttpClient
4343

@@ -449,9 +449,7 @@ async def create_program(
449449
# Trigger on HTTP calls.
450450
triggers = {"http": True, "persistent": persistent}
451451

452-
volumes: List[MachineVolume] = [
453-
MachineVolume.parse_obj(volume) for volume in volumes
454-
]
452+
volumes: List[MachineVolume] = [parse_volume(volume) for volume in volumes]
455453

456454
content = ProgramContent(
457455
type="vm-function",
@@ -482,7 +480,7 @@ async def create_program(
482480
if runtime == settings.DEFAULT_RUNTIME_ID
483481
else "",
484482
),
485-
volumes=[MachineVolume.parse_obj(volume) for volume in volumes],
483+
volumes=[parse_volume(volume) for volume in volumes],
486484
time=time.time(),
487485
metadata=metadata,
488486
)
@@ -555,7 +553,7 @@ async def create_instance(
555553
if rootfs == settings.DEFAULT_RUNTIME_ID
556554
else "",
557555
),
558-
volumes=[MachineVolume.parse_obj(volume) for volume in volumes],
556+
volumes=[parse_volume(volume) for volume in volumes],
559557
time=time.time(),
560558
authorized_keys=ssh_keys,
561559
metadata=metadata,

src/aleph/sdk/utils.py

+29-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,23 @@
55
from enum import Enum
66
from pathlib import Path
77
from shutil import make_archive
8-
from typing import Any, Iterable, Optional, Protocol, Tuple, Type, TypeVar, Union
8+
from typing import (
9+
Any,
10+
Iterable,
11+
Mapping,
12+
Optional,
13+
Protocol,
14+
Tuple,
15+
Type,
16+
TypeVar,
17+
Union,
18+
get_args,
19+
)
920
from zipfile import BadZipFile, ZipFile
1021

1122
from aleph_message.models import MessageType
1223
from aleph_message.models.execution.program import Encoding
24+
from aleph_message.models.execution.volume import MachineVolume
1325
from pydantic.json import pydantic_encoder
1426

1527
from aleph.sdk.conf import settings
@@ -150,3 +162,19 @@ def extended_json_encoder(obj: Any) -> Any:
150162
return obj.hour * 3600 + obj.minute * 60 + obj.second + obj.microsecond / 1e6
151163
else:
152164
return pydantic_encoder(obj)
165+
166+
167+
def parse_volume(volume_dict: Union[Mapping, MachineVolume]) -> MachineVolume:
168+
# Python 3.9 does not support `isinstance(volume_dict, MachineVolume)`,
169+
# so we need to iterate over all types.
170+
if any(
171+
isinstance(volume_dict, volume_type) for volume_type in get_args(MachineVolume)
172+
):
173+
return volume_dict
174+
for volume_type in get_args(MachineVolume):
175+
try:
176+
return volume_type.parse_obj(volume_dict)
177+
except ValueError:
178+
continue
179+
else:
180+
raise ValueError(f"Could not parse volume: {volume_dict}")

tests/unit/test_utils.py

+47-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@
1212
StoreMessage,
1313
)
1414
from aleph_message.models.execution.environment import MachineResources
15+
from aleph_message.models.execution.volume import (
16+
EphemeralVolume,
17+
ImmutableVolume,
18+
PersistentVolume,
19+
)
1520

16-
from aleph.sdk.utils import enum_as_str, get_message_type_value
21+
from aleph.sdk.utils import enum_as_str, get_message_type_value, parse_volume
1722

1823

1924
def test_get_message_type_value():
@@ -128,3 +133,44 @@ async def test_prepare_aleph_message(
128133
)
129134

130135
assert message.content.dict() == content
136+
137+
138+
def test_parse_immutable_volume():
139+
volume_dict = {
140+
"ref": "QmX8K1c22WmQBAww5ShWQqwMiFif7XFrJD6iFBj7skQZXW",
141+
"use_latest": True,
142+
"comment": "Dummy hash",
143+
}
144+
volume = parse_volume(volume_dict)
145+
volume = parse_volume(volume)
146+
assert volume
147+
assert isinstance(volume, ImmutableVolume)
148+
149+
150+
def test_parse_ephemeral_volume():
151+
volume_dict = {
152+
"comment": "Dummy hash",
153+
"ephemeral": True,
154+
"size_mib": 1,
155+
}
156+
volume = parse_volume(volume_dict)
157+
volume = parse_volume(volume)
158+
assert volume
159+
assert isinstance(volume, EphemeralVolume)
160+
161+
162+
def test_parse_persistent_volume():
163+
volume_dict = {
164+
"parent": {
165+
"ref": "QmX8K1c22WmQBAww5ShWQqwMiFif7XFrJD6iFBj7skQZXW",
166+
"use_latest": True,
167+
"comment": "Dummy hash",
168+
},
169+
"persistence": "host",
170+
"name": "test",
171+
"size_mib": 1,
172+
}
173+
volume = parse_volume(volume_dict)
174+
volume = parse_volume(volume)
175+
assert volume
176+
assert isinstance(volume, PersistentVolume)

0 commit comments

Comments
 (0)