[sdk/python] Add support for Sequence (#5282)

We currently emit array types as `List[T]` for Python, but `List[T]` is invariant, which causes type checkers like mypy to produce errors when values like `["foo", "bar"]` are passed as args typed as `List[pulumi.Input[str]]` (since `Input[str]` is an alias for `Union[T, Awaitable[T], Output[T]]`. To address this, we should move to using [`Sequence[T]`](https://docs.python.org/3/library/typing.html#typing.Sequence) which is covariant, and does not have this problem.

We actually already do this for `Dict` vs. `Mapping`, emitting map types as `Mapping[str, T]` rather than `Dict[str, T]` because `Mapping[str, T]` is covariant for the value. This change makes us consistent for array types.

These are the SDK changes necessary to support `Sequence[T]`.
This commit is contained in:
Justin Van Patten 2020-09-09 05:22:35 +00:00 committed by GitHub
parent 6cc095be07
commit d0ba9fbdcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 369 additions and 17 deletions

View file

@ -14,6 +14,9 @@ CHANGELOG
- Fix Go SDK plugin acquisition for programs with vendored dependencies
[#5286](https://github.com/pulumi/pulumi/pull/5286)
- Python SDK: Add support for `Sequence[T]` for array types
[#5282](https://github.com/pulumi/pulumi/pull/5282)
## 2.9.2 (2020-08-31)
- Alpha version of the Automation API for Go

View file

@ -17,10 +17,10 @@ out of RPC calls.
"""
import sys
import asyncio
import collections
from collections import abc
import functools
import inspect
from typing import List, Any, Callable, Dict, Mapping, Optional, Tuple, Union, TYPE_CHECKING, cast, get_type_hints
from typing import List, Any, Callable, Dict, Mapping, Optional, Sequence, TYPE_CHECKING, cast
from google.protobuf import struct_pb2
import six
@ -92,7 +92,9 @@ async def serialize_property(value: 'Input[Any]',
Serializes a single Input into a form suitable for remoting to the engine, awaiting
any futures required to do so.
"""
if isinstance(value, list):
# Exclude some built-in types that are instances of Sequence that we don't want to treat as sequences here.
# From: https://github.com/python/cpython/blob/master/Lib/_collections_abc.py
if isinstance(value, abc.Sequence) and not isinstance(value, (tuple, str, range, memoryview, bytes, bytearray)):
props = []
for elem in value:
props.append(await serialize_property(elem, deps, input_transformer))
@ -125,7 +127,7 @@ async def serialize_property(value: 'Input[Any]',
remote_asset = cast('RemoteAsset', value)
obj["uri"] = await serialize_property(remote_asset.uri, deps, input_transformer)
else:
raise AssertionError(f"unknown asset type: {value}")
raise AssertionError(f"unknown asset type: {value!r}")
return obj
@ -147,7 +149,7 @@ async def serialize_property(value: 'Input[Any]',
remote_archive = cast('RemoteArchive', value)
obj["uri"] = await serialize_property(remote_archive.uri, deps, input_transformer)
else:
raise AssertionError(f"unknown archive type: {value}")
raise AssertionError(f"unknown archive type: {value!r}")
return obj
@ -194,7 +196,7 @@ async def serialize_property(value: 'Input[Any]',
value = _types.input_type_to_dict(value)
transform_keys = False
if isinstance(value, Mapping): # pylint: disable=bad-option-value,isinstance-second-argument-not-valid-type
if isinstance(value, abc.Mapping):
obj = {}
for k, v in value.items():
transformed_key = k
@ -426,7 +428,7 @@ def translate_output_properties(output: Any,
# If typ is a dict, get the type for its values, to pass
# along for each key.
origin = _types.get_origin(typ)
if typ is dict or origin in {dict, Dict, Mapping, collections.abc.Mapping}:
if typ is dict or origin in {dict, Dict, Mapping, abc.Mapping}:
args = _types.get_args(typ)
if len(args) == 2 and args[0] is str:
get_type = lambda k: args[1]
@ -456,7 +458,7 @@ def translate_output_properties(output: Any,
# If typ is a list, get the type for its values, to pass
# along for each item.
origin = _types.get_origin(typ)
if typ is list or origin in {list, List}:
if typ is list or origin in {list, List, Sequence, abc.Sequence}:
args = _types.get_args(typ)
if len(args) == 1:
element_type = args[0]

View file

@ -13,7 +13,7 @@
# limitations under the License.
import asyncio
import unittest
from typing import Any, Optional
from typing import Any, Dict, List, Mapping, Optional, Sequence
from google.protobuf import struct_pb2
from pulumi.resource import CustomResource
@ -274,6 +274,26 @@ class NextSerializationTests(unittest.TestCase):
self.assertIsNotNone(error)
self.assertEqual("unexpected input of type MyClass", str(error))
@async_test
async def test_string(self):
# Ensure strings are serialized as strings (and not sequences).
prop = await rpc.serialize_property("hello world", [])
self.assertEqual("hello world", prop)
@async_test
async def test_unsupported_sequences(self):
cases = [
("hi", 42),
range(10),
memoryview(bytes(10)),
bytes(10),
bytearray(10),
]
for case in cases:
with self.assertRaises(ValueError):
await rpc.serialize_property(case, [])
@async_test
async def test_distinguished_unknown_output(self):
fut = asyncio.Future()
@ -530,7 +550,7 @@ class NextSerializationTests(unittest.TestCase):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=false, is_secret=True))
r = out.apply(lambda v: self.create_output("inner", is_known=False, is_secret=True))
self.assertFalse(await r.is_known())
self.assertFalse(await r.is_secret())
@ -937,6 +957,23 @@ class FooArgs:
pulumi.set(self, "first_arg", first_arg)
pulumi.set(self, "second_arg", second_arg)
@input_type
class ListDictInputArgs:
a: List[Input[str]]
b: Sequence[Input[str]]
c: Dict[str, Input[str]]
d: Mapping[str, Input[str]]
def __init__(self,
a: List[Input[str]],
b: Sequence[Input[str]],
c: Dict[str, Input[str]],
d: Mapping[str, Input[str]]):
pulumi.set(self, "a", a)
pulumi.set(self, "b", b)
pulumi.set(self, "c", c)
pulumi.set(self, "d", d)
@input_type
class BarArgs:
@ -951,7 +988,18 @@ class InputTypeSerializationTests(unittest.TestCase):
async def test_simple_input_type(self):
it = FooArgs(first_arg="hello", second_arg=42)
prop = await rpc.serialize_property(it, [])
self.assertDictEqual(prop, {"firstArg": "hello", "secondArg": 42})
self.assertEqual({"firstArg": "hello", "secondArg": 42}, prop)
@async_test
async def test_list_dict_input_type(self):
it = ListDictInputArgs(a=["hi"], b=["there"], c={"hello": "world"}, d={"foo": "bar"})
prop = await rpc.serialize_property(it, [])
self.assertEqual({
"a": ["hi"],
"b": ["there"],
"c": {"hello": "world"},
"d": {"foo": "bar"}
}, prop)
@async_test
async def test_input_type_with_dict_property(self):
@ -964,11 +1012,11 @@ class InputTypeSerializationTests(unittest.TestCase):
it = BarArgs({"foo_bar": "hello", "foo_baz": "world"})
prop = await rpc.serialize_property(it, [], transformer)
# Input type keys are not be transformed, but keys of nested
# Input type keys are not transformed, but keys of nested
# dicts are still transformed.
self.assertDictEqual(prop, {
self.assertEqual({
"tagArgs": {
"c": "hello",
"foo_baz": "world",
},
})
}, prop)

View file

@ -13,7 +13,7 @@
# limitations under the License.
import unittest
from typing import Any, Dict, List, Mapping, Optional
from typing import Any, Dict, List, Mapping, Optional, Sequence
from pulumi.runtime import rpc
import pulumi
@ -65,6 +65,34 @@ class Bar(dict):
return camel_case_to_snake_case.get(prop) or prop
@pulumi.output_type
class BarMappingSequence(dict):
third_arg: Foo = pulumi.property("thirdArg")
third_optional_arg: Optional[Foo] = pulumi.property("thirdOptionalArg")
fourth_arg: Mapping[str, Foo] = pulumi.property("fourthArg")
fourth_optional_arg: Mapping[str, Optional[Foo]] = pulumi.property("fourthOptionalArg")
fifth_arg: Sequence[Foo] = pulumi.property("fifthArg")
fifth_optional_arg: Sequence[Optional[Foo]] = pulumi.property("fifthOptionalArg")
sixth_arg: Mapping[str, Sequence[Foo]] = pulumi.property("sixthArg")
sixth_optional_arg: Mapping[str, Optional[Sequence[Foo]]] = pulumi.property("sixthOptionalArg")
sixth_optional_optional_arg: Mapping[str, Optional[Sequence[Optional[Foo]]]] = pulumi.property("sixthOptionalOptionalArg")
seventh_arg: Sequence[Mapping[str, Foo]] = pulumi.property("seventhArg")
seventh_optional_arg: Sequence[Optional[Mapping[str, Foo]]] = pulumi.property("seventhOptionalArg")
seventh_optional_optional_arg: Sequence[Optional[Mapping[str, Optional[Foo]]]] = pulumi.property("seventhOptionalOptionalArg")
eighth_arg: Sequence[Mapping[str, Sequence[Foo]]] = pulumi.property("eighthArg")
eighth_optional_arg: Sequence[Optional[Mapping[str, Sequence[Foo]]]] = pulumi.property("eighthOptionalArg")
eighth_optional_optional_arg: Sequence[Optional[Mapping[str, Optional[Sequence[Foo]]]]] = pulumi.property("eighthOptionalOptionalArg")
eighth_optional_optional_optional_arg: Sequence[Optional[Mapping[str, Optional[Sequence[Optional[Foo]]]]]] = pulumi.property("eighthOptionalOptionalOptionalArg")
def _translate_property(self, prop: str) -> str:
return camel_case_to_snake_case.get(prop) or prop
@pulumi.output_type
class BarDeclared(dict):
def __init__(self,
@ -185,6 +213,126 @@ class BarDeclared(dict):
return camel_case_to_snake_case.get(prop) or prop
@pulumi.output_type
class BarMappingSequenceDeclared(dict):
def __init__(self,
third_arg: Foo,
third_optional_arg: Optional[Foo],
fourth_arg: Mapping[str, Foo],
fourth_optional_arg: Dict[str, Optional[Foo]],
fifth_arg: Sequence[Foo],
fifth_optional_arg: Sequence[Optional[Foo]],
sixth_arg: Mapping[str, Sequence[Foo]],
sixth_optional_arg: Mapping[str, Optional[Sequence[Foo]]],
sixth_optional_optional_arg: Mapping[str, Optional[Sequence[Optional[Foo]]]],
seventh_arg: Sequence[Mapping[str, Foo]],
seventh_optional_arg: Sequence[Optional[Mapping[str, Foo]]],
seventh_optional_optional_arg: Sequence[Optional[Mapping[str, Optional[Foo]]]],
eighth_arg: Sequence[Mapping[str, Sequence[Foo]]],
eighth_optional_arg: Sequence[Optional[Mapping[str, Sequence[Foo]]]],
eighth_optional_optional_arg: Sequence[Optional[Mapping[str, Optional[Sequence[Foo]]]]],
eighth_optional_optional_optional_arg: Sequence[Optional[Mapping[str, Optional[Sequence[Optional[Foo]]]]]]):
pulumi.set(self, "third_arg", third_arg)
pulumi.set(self, "third_optional_arg", third_optional_arg)
pulumi.set(self, "fourth_arg", fourth_arg)
pulumi.set(self, "fourth_optional_arg", fourth_optional_arg)
pulumi.set(self, "fifth_arg", fifth_arg)
pulumi.set(self, "fifth_optional_arg", fifth_optional_arg)
pulumi.set(self, "sixth_arg", sixth_arg)
pulumi.set(self, "sixth_optional_arg", sixth_optional_arg)
pulumi.set(self, "sixth_optional_optional_arg", sixth_optional_optional_arg)
pulumi.set(self, "seventh_arg", seventh_arg)
pulumi.set(self, "seventh_optional_arg", seventh_optional_arg)
pulumi.set(self, "seventh_optional_optional_arg", seventh_optional_optional_arg)
pulumi.set(self, "eighth_arg", eighth_arg)
pulumi.set(self, "eighth_optional_arg", eighth_optional_arg)
pulumi.set(self, "eighth_optional_optional_arg", eighth_optional_optional_arg)
pulumi.set(self, "eighth_optional_optional_optional_arg", eighth_optional_optional_optional_arg)
@property
@pulumi.getter(name="thirdArg")
def third_arg(self) -> Foo:
...
@property
@pulumi.getter(name="thirdOptionalArg")
def third_optional_arg(self) -> Optional[Foo]:
...
@property
@pulumi.getter(name="fourthArg")
def fourth_arg(self) -> Mapping[str, Foo]:
...
@property
@pulumi.getter(name="fourthOptionalArg")
def fourth_optional_arg(self) -> Mapping[str, Optional[Foo]]:
...
@property
@pulumi.getter(name="fifthArg")
def fifth_arg(self) -> Sequence[Foo]:
...
@property
@pulumi.getter(name="fifthOptionalArg")
def fifth_optional_arg(self) -> Sequence[Optional[Foo]]:
...
@property
@pulumi.getter(name="sixthArg")
def sixth_arg(self) -> Mapping[str, Sequence[Foo]]:
...
@property
@pulumi.getter(name="sixthOptionalArg")
def sixth_optional_arg(self) -> Mapping[str, Optional[Sequence[Foo]]]:
...
@property
@pulumi.getter(name="sixthOptionalOptionalArg")
def sixth_optional_optional_arg(self) -> Mapping[str, Optional[Sequence[Optional[Foo]]]]:
...
@property
@pulumi.getter(name="seventhArg")
def seventh_arg(self) -> Sequence[Mapping[str, Foo]]:
...
@property
@pulumi.getter(name="seventhOptionalArg")
def seventh_optional_arg(self) -> Sequence[Optional[Mapping[str, Foo]]]:
...
@property
@pulumi.getter(name="seventhOptionalOptionalArg")
def seventh_optional_optional_arg(self) -> Sequence[Optional[Mapping[str, Optional[Foo]]]]:
...
@property
@pulumi.getter(name="eighthArg")
def eighth_arg(self) -> Sequence[Mapping[str, Sequence[Foo]]]:
...
@property
@pulumi.getter(name="eighthOptionalArg")
def eighth_optional_arg(self) -> Sequence[Optional[Mapping[str, Sequence[Foo]]]]:
...
@property
@pulumi.getter(name="eighthOptionalOptionalArg")
def eighth_optional_optional_arg(self) -> Sequence[Optional[Mapping[str, Optional[Sequence[Foo]]]]]:
...
@property
@pulumi.getter(name="eighthOptionalOptionalOptionalArg")
def eighth_optional_optional_optional_arg(self) -> Sequence[Optional[Mapping[str, Optional[Sequence[Optional[Foo]]]]]]:
...
def _translate_property(self, prop: str) -> str:
return camel_case_to_snake_case.get(prop) or prop
@pulumi.output_type
class InvalidTypeStr(dict):
value: str = pulumi.property("value")
@ -217,6 +365,10 @@ class InvalidTypeDeclaredOptionalStr(dict):
class InvalidTypeDictStr(dict):
value: Dict[str, str] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeMappingStr(dict):
value: Mapping[str, str] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredDictStr(dict):
def __init__(self, value: Dict[str, str]):
@ -227,10 +379,24 @@ class InvalidTypeDeclaredDictStr(dict):
def value(self) -> Dict[str, str]:
...
@pulumi.output_type
class InvalidTypeDeclaredMappingStr(dict):
def __init__(self, value: Mapping[str, str]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Mapping[str, str]:
...
@pulumi.output_type
class InvalidTypeOptionalDictStr(dict):
value: Optional[Dict[str, str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeOptionalMappingStr(dict):
value: Optional[Mapping[str, str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredOptionalDictStr(dict):
def __init__(self, value: Optional[Dict[str, str]]):
@ -241,10 +407,24 @@ class InvalidTypeDeclaredOptionalDictStr(dict):
def value(self) -> Optional[Dict[str, str]]:
...
@pulumi.output_type
class InvalidTypeDeclaredOptionalMappingStr(dict):
def __init__(self, value: Optional[Mapping[str, str]]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Optional[Mapping[str, str]]:
...
@pulumi.output_type
class InvalidTypeDictOptionalStr(dict):
value: Dict[str, Optional[str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeMappingOptionalStr(dict):
value: Mapping[str, Optional[str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredDictOptionalStr(dict):
def __init__(self, value: Dict[str, Optional[str]]):
@ -255,10 +435,24 @@ class InvalidTypeDeclaredDictOptionalStr(dict):
def value(self) -> Dict[str, Optional[str]]:
...
@pulumi.output_type
class InvalidTypeDeclaredMappingOptionalStr(dict):
def __init__(self, value: Mapping[str, Optional[str]]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Mapping[str, Optional[str]]:
...
@pulumi.output_type
class InvalidTypeOptionalDictOptionalStr(dict):
value: Optional[Dict[str, Optional[str]]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeOptionalMappingOptionalStr(dict):
value: Optional[Mapping[str, Optional[str]]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredOptionalDictOptionalStr(dict):
def __init__(self, value: Optional[Dict[str, Optional[str]]]):
@ -269,10 +463,25 @@ class InvalidTypeDeclaredOptionalDictOptionalStr(dict):
def value(self) -> Optional[Dict[str, Optional[str]]]:
...
@pulumi.output_type
class InvalidTypeDeclaredOptionalMappingOptionalStr(dict):
def __init__(self, value: Optional[Mapping[str, Optional[str]]]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Optional[Mapping[str, Optional[str]]]:
...
@pulumi.output_type
class InvalidTypeListStr(dict):
value: List[str] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeSequenceStr(dict):
value: Sequence[str] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredListStr(dict):
def __init__(self, value: List[str]):
@ -283,10 +492,24 @@ class InvalidTypeDeclaredListStr(dict):
def value(self) -> List[str]:
...
@pulumi.output_type
class InvalidTypeDeclaredSequenceStr(dict):
def __init__(self, value: Sequence[str]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Sequence[str]:
...
@pulumi.output_type
class InvalidTypeOptionalListStr(dict):
value: Optional[List[str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeOptionalSequenceStr(dict):
value: Optional[Sequence[str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredOptionalListStr(dict):
def __init__(self, value: Optional[List[str]]):
@ -297,10 +520,24 @@ class InvalidTypeDeclaredOptionalListStr(dict):
def value(self) -> Optional[List[str]]:
...
@pulumi.output_type
class InvalidTypeDeclaredOptionalSequenceStr(dict):
def __init__(self, value: Optional[Sequence[str]]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Optional[Sequence[str]]:
...
@pulumi.output_type
class InvalidTypeListOptionalStr(dict):
value: List[Optional[str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeSequenceOptionalStr(dict):
value: Sequence[Optional[str]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredListOptionalStr(dict):
def __init__(self, value: List[Optional[str]]):
@ -311,10 +548,24 @@ class InvalidTypeDeclaredListOptionalStr(dict):
def value(self) -> List[Optional[str]]:
...
@pulumi.output_type
class InvalidTypeDeclaredSequenceOptionalStr(dict):
def __init__(self, value: Sequence[Optional[str]]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Sequence[Optional[str]]:
...
@pulumi.output_type
class InvalidTypeOptionalListOptionalStr(dict):
value: Optional[List[Optional[str]]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeOptionalSequenceOptionalStr(dict):
value: Optional[Sequence[Optional[str]]] = pulumi.property("value")
@pulumi.output_type
class InvalidTypeDeclaredOptionalListOptionalStr(dict):
def __init__(self, value: Optional[List[Optional[str]]]):
@ -325,13 +576,25 @@ class InvalidTypeDeclaredOptionalListOptionalStr(dict):
def value(self) -> Optional[List[Optional[str]]]:
...
@pulumi.output_type
class InvalidTypeDeclaredOptionalSequenceOptionalStr(dict):
def __init__(self, value: Optional[Sequence[Optional[str]]]):
pulumi.set(self, "value", value)
@property
@pulumi.getter
def value(self) -> Optional[Sequence[Optional[str]]]:
...
@pulumi.output_type
class OutputTypeWithAny(dict):
value_dict: Any
value_list: Any
value_dict_dict: Mapping[str, Any]
value_dict_dict: Dict[str, Any]
value_dict_mapping: Mapping[str, Any]
value_list_list: List[Any]
value_list_sequence: Sequence[Any]
value_str: Any
@ -492,7 +755,7 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
self.assertIs(result.eighth_optional_optional_optional_arg, result["eighthOptionalOptionalOptionalArg"])
assertFoo(result.eighth_optional_optional_optional_arg[0]["blah"][0], "farewell-opt-opt-opt", 11137)
for typ in [Bar, BarDeclared]:
for typ in [Bar, BarMappingSequence, BarDeclared, BarMappingSequenceDeclared]:
run_test(output)
run_test(convert_properties_to_secrets(output))
@ -522,6 +785,14 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
(InvalidTypeDeclaredDictOptionalStr, {"foo": dict_value}),
(InvalidTypeOptionalDictOptionalStr, {"foo": dict_value}),
(InvalidTypeDeclaredOptionalDictOptionalStr, {"foo": dict_value}),
(InvalidTypeMappingStr, {"foo": dict_value}),
(InvalidTypeDeclaredMappingStr, {"foo": dict_value}),
(InvalidTypeOptionalMappingStr, {"foo": dict_value}),
(InvalidTypeDeclaredOptionalMappingStr, {"foo": dict_value}),
(InvalidTypeMappingOptionalStr, {"foo": dict_value}),
(InvalidTypeDeclaredMappingOptionalStr, {"foo": dict_value}),
(InvalidTypeOptionalMappingOptionalStr, {"foo": dict_value}),
(InvalidTypeDeclaredOptionalMappingOptionalStr, {"foo": dict_value}),
(InvalidTypeDictStr, {"foo": list_value}),
(InvalidTypeDeclaredDictStr, {"foo": list_value}),
@ -531,6 +802,14 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
(InvalidTypeDeclaredDictOptionalStr, {"foo": list_value}),
(InvalidTypeOptionalDictOptionalStr, {"foo": list_value}),
(InvalidTypeDeclaredOptionalDictOptionalStr, {"foo": list_value}),
(InvalidTypeMappingStr, {"foo": list_value}),
(InvalidTypeDeclaredMappingStr, {"foo": list_value}),
(InvalidTypeOptionalMappingStr, {"foo": list_value}),
(InvalidTypeDeclaredOptionalMappingStr, {"foo": list_value}),
(InvalidTypeMappingOptionalStr, {"foo": list_value}),
(InvalidTypeDeclaredMappingOptionalStr, {"foo": list_value}),
(InvalidTypeOptionalMappingOptionalStr, {"foo": list_value}),
(InvalidTypeDeclaredOptionalMappingOptionalStr, {"foo": list_value}),
(InvalidTypeListStr, [dict_value]),
(InvalidTypeDeclaredListStr, [dict_value]),
@ -540,6 +819,14 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
(InvalidTypeDeclaredListOptionalStr, [dict_value]),
(InvalidTypeOptionalListOptionalStr, [dict_value]),
(InvalidTypeDeclaredOptionalListOptionalStr, [dict_value]),
(InvalidTypeSequenceStr, [dict_value]),
(InvalidTypeDeclaredSequenceStr, [dict_value]),
(InvalidTypeOptionalSequenceStr, [dict_value]),
(InvalidTypeDeclaredOptionalSequenceStr, [dict_value]),
(InvalidTypeSequenceOptionalStr, [dict_value]),
(InvalidTypeDeclaredSequenceOptionalStr, [dict_value]),
(InvalidTypeOptionalSequenceOptionalStr, [dict_value]),
(InvalidTypeDeclaredOptionalSequenceOptionalStr, [dict_value]),
(InvalidTypeListStr, [list_value]),
(InvalidTypeDeclaredListStr, [list_value]),
@ -549,6 +836,14 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
(InvalidTypeDeclaredListOptionalStr, [list_value]),
(InvalidTypeOptionalListOptionalStr, [list_value]),
(InvalidTypeDeclaredOptionalListOptionalStr, [list_value]),
(InvalidTypeSequenceStr, [list_value]),
(InvalidTypeDeclaredSequenceStr, [list_value]),
(InvalidTypeOptionalSequenceStr, [list_value]),
(InvalidTypeDeclaredOptionalSequenceStr, [list_value]),
(InvalidTypeSequenceOptionalStr, [list_value]),
(InvalidTypeDeclaredSequenceOptionalStr, [list_value]),
(InvalidTypeOptionalSequenceOptionalStr, [list_value]),
(InvalidTypeDeclaredOptionalSequenceOptionalStr, [list_value]),
]
for typ, value in tests:
@ -565,7 +860,9 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
"value_dict": {"hello": "world"},
"value_list": ["hello"],
"value_dict_dict": {"value": {"hello": "world"}},
"value_dict_mapping": {"value": {"hello": "world"}},
"value_list_list": [["hello"]],
"value_list_sequence": [["hello"]],
"value_str": "hello",
}
result = rpc.translate_output_properties(output, translate_output_property, OutputTypeWithAny)
@ -573,5 +870,7 @@ class TranslateOutputPropertiesTests(unittest.TestCase):
self.assertEqual({"hello": "world"}, result.value_dict)
self.assertEqual(["hello"], result.value_list)
self.assertEqual({"value": {"hello": "world"}}, result.value_dict_dict)
self.assertEqual({"value": {"hello": "world"}}, result.value_dict_mapping)
self.assertEqual([["hello"]], result.value_list_list)
self.assertEqual([["hello"]], result.value_list_sequence)
self.assertEqual("hello", result.value_str)