Skip to content

Commit 053668e

Browse files
authored
Merge pull request #1573 from talyz/mapping-types
ImmutableValidatedObject: Support nested Mapping types
2 parents 2cfc2cb + e43c82f commit 053668e

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

nixops/util.py

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
import re
1818
import typing
1919
import typeguard # type: ignore
20-
import inspect
2120
import shlex
21+
import collections.abc
22+
from inspect import isclass
2223
from typing import (
2324
Callable,
2425
List,
@@ -149,21 +150,33 @@ def _transform_value(key: Any, value: Any) -> Any:
149150
if not ann:
150151
return value
151152

152-
if inspect.isclass(ann) and issubclass(ann, ImmutableValidatedObject):
153+
if isclass(ann) and issubclass(ann, ImmutableValidatedObject):
153154
value = ann(**value)
154155

155-
# Support Sequence[ImmutableValidatedObject]
156-
if isinstance(value, tuple) and not isinstance(ann, str):
157-
new_value = []
158-
for v in value:
159-
for subann in ann.__args__: # type: ignore
160-
if inspect.isclass(subann) and issubclass(
161-
subann, ImmutableValidatedObject
162-
):
163-
new_value.append(subann(**v))
164-
else:
165-
new_value.append(v)
166-
value = tuple(new_value)
156+
# Support containers of ImmutableValidatedObjects
157+
match typing.get_origin(ann):
158+
159+
case collections.abc.Sequence:
160+
sequence: List = []
161+
for v in value:
162+
for subann in typing.get_args(ann):
163+
if isclass(subann) and issubclass(
164+
subann, ImmutableValidatedObject
165+
):
166+
sequence.append(subann(**v))
167+
else:
168+
sequence.append(v)
169+
value = tuple(sequence)
170+
171+
case collections.abc.Mapping:
172+
_, value_ann = typing.get_args(ann)
173+
if isclass(value_ann) and issubclass(
174+
value_ann, ImmutableValidatedObject
175+
):
176+
mapping: Dict = {}
177+
for k, v in value.items():
178+
mapping[k] = value_ann(**v)
179+
value = mapping
167180

168181
typeguard.check_type(value, ann)
169182

tests/unit/test_util.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Sequence
1+
from typing import Any, Sequence, Mapping
22
import json
33
from nixops.logger import Logger
44
from io import StringIO
@@ -121,4 +121,14 @@ class B(A):
121121
class WithSequence(util.ImmutableValidatedObject):
122122
subs: Sequence[SubResource]
123123

124-
WithSequence(subs=[SubResource(x=1), SubResource(x=2)])
124+
seq = WithSequence(subs=[{"x": 1}, {"x": 2}])
125+
for i in seq.subs:
126+
self.assertIsInstance(i, SubResource)
127+
128+
# Test Mapping[str, ImmutableValidatedObject]
129+
class WithMapping(util.ImmutableValidatedObject):
130+
mapping: Mapping[str, SubResource]
131+
132+
mapped = WithMapping(mapping={"aaa": {"x": 1}, "bbb": {"x": 2}})
133+
for _, v in mapped.mapping.items():
134+
self.assertIsInstance(v, SubResource)

0 commit comments

Comments
 (0)