From 9fd2499388745cf63d194a47bf247e5e24f4a7db Mon Sep 17 00:00:00 2001 From: Romain Marcadier-Muller Date: Tue, 12 Nov 2019 09:11:10 +0100 Subject: [PATCH] fix(python): correctly handle nested structs-as-dict (#973) * fix(python): correctly handle nested structs-as-dict Added code to up-cast from `dict` to the relevant struct type in the generated python code whenever the value type is some unambiguous struct. Whenever a UNION of types is involved, the user must construct the struct type themselves, as the runtime would then have no way to choose which type should be used on it's own without additional information. * add None explicit test --- packages/jsii-calc/lib/compliance.ts | 33 ++++ packages/jsii-calc/test/assembly.jsii | 118 ++++++++++++- packages/jsii-kernel/lib/serialization.ts | 5 + packages/jsii-pacmak/lib/targets/python.ts | 9 +- .../.jsii | 118 ++++++++++++- .../CalculatorNamespace/INestedStruct.cs | 21 +++ .../Tests/CalculatorNamespace/IRootStruct.cs | 37 +++++ .../Tests/CalculatorNamespace/NestedStruct.cs | 22 +++ .../CalculatorNamespace/NestedStructProxy.cs | 25 +++ .../Tests/CalculatorNamespace/RootStruct.cs | 36 ++++ .../CalculatorNamespace/RootStructProxy.cs | 38 +++++ .../RootStructValidator.cs | 28 ++++ .../amazon/jsii/tests/calculator/$Module.java | 3 + .../jsii/tests/calculator/NestedStruct.java | 118 +++++++++++++ .../jsii/tests/calculator/RootStruct.java | 156 ++++++++++++++++++ .../tests/calculator/RootStructValidator.java | 28 ++++ .../python/src/jsii_calc/__init__.py | 103 +++++++++++- .../tests/test_compliance.py | 12 ++ .../test/__snapshots__/jsii-tree.test.js.snap | 40 +++++ .../__snapshots__/type-system.test.js.snap | 1 + 20 files changed, 947 insertions(+), 4 deletions(-) create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/INestedStruct.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IRootStruct.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStruct.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStructProxy.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStruct.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructProxy.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructValidator.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/NestedStruct.java create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStruct.java create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStructValidator.java diff --git a/packages/jsii-calc/lib/compliance.ts b/packages/jsii-calc/lib/compliance.ts index 49d91b6bbc..8a21f271bd 100644 --- a/packages/jsii-calc/lib/compliance.ts +++ b/packages/jsii-calc/lib/compliance.ts @@ -2175,3 +2175,36 @@ class PrivateBell implements IBell { this.rung = true; } } + +/** + * This is here to check that we can pass a nested struct into a kwargs by specifying it as an + * in-line dictionary. This is cheating with the declared types, but Python people don't play by + * the rules much apparently. + */ +export interface RootStruct { + /** + * May not be empty. + */ + readonly stringProp: string; + readonly nestedStruct?: NestedStruct; +} +export interface NestedStruct { + /** + * When provided, must be > 0. + */ + readonly numberProp: number; +} +export class RootStructValidator { + public static validate(struct: RootStruct): void { + if (!struct.stringProp) { + throw new Error('Missing required field: stringProp'); + } + if (struct.nestedStruct) { + if (struct.nestedStruct.numberProp <= 0) { + throw new Error('numberProp must be > 0'); + } + } + } + + private constructor() { } +} diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index 951dc349a5..5550b1c509 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -6799,6 +6799,38 @@ } ] }, + "jsii-calc.NestedStruct": { + "assembly": "jsii-calc", + "datatype": true, + "docs": { + "stability": "experimental" + }, + "fqn": "jsii-calc.NestedStruct", + "kind": "interface", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2191 + }, + "name": "NestedStruct", + "properties": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "When provided, must be > 0." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2195 + }, + "name": "numberProp", + "type": { + "primitive": "number" + } + } + ] + }, "jsii-calc.NodeStandardLibrary": { "assembly": "jsii-calc", "docs": { @@ -8215,6 +8247,90 @@ } ] }, + "jsii-calc.RootStruct": { + "assembly": "jsii-calc", + "datatype": true, + "docs": { + "remarks": "This is cheating with the declared types, but Python people don't play by\nthe rules much apparently.", + "stability": "experimental", + "summary": "This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary." + }, + "fqn": "jsii-calc.RootStruct", + "kind": "interface", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2184 + }, + "name": "RootStruct", + "properties": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "May not be empty." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2188 + }, + "name": "stringProp", + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "stability": "experimental" + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2189 + }, + "name": "nestedStruct", + "optional": true, + "type": { + "fqn": "jsii-calc.NestedStruct" + } + } + ] + }, + "jsii-calc.RootStructValidator": { + "assembly": "jsii-calc", + "docs": { + "stability": "experimental" + }, + "fqn": "jsii-calc.RootStructValidator", + "kind": "class", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2197 + }, + "methods": [ + { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2198 + }, + "name": "validate", + "parameters": [ + { + "name": "struct", + "type": { + "fqn": "jsii-calc.RootStruct" + } + } + ], + "static": true + } + ], + "name": "RootStructValidator" + }, "jsii-calc.RuntimeTypeChecking": { "assembly": "jsii-calc", "docs": { @@ -10797,5 +10913,5 @@ } }, "version": "0.20.3", - "fingerprint": "r/K0k7ocrPmzUuFsCAvxLY2UdNEi6r/ruaoO3PnHiCA=" + "fingerprint": "1F+uskR3++T5mjRcWge9oG3H/jJvXm1C3IhR1AwsBTE=" } diff --git a/packages/jsii-kernel/lib/serialization.ts b/packages/jsii-kernel/lib/serialization.ts index 3c87b1bea5..4961b1cb8d 100644 --- a/packages/jsii-kernel/lib/serialization.ts +++ b/packages/jsii-kernel/lib/serialization.ts @@ -360,6 +360,11 @@ export const SERIALIZERS: {[k: string]: Serializer} = { value = data; } + // Python, for example, allows using plain mapping objects instead of Structs (dyanmic typing, YOLO!) + if (api.isWireMap(value)) { + value = value[api.TOKEN_MAP]; + } + value = validateRequiredProps(value as any, namedType.fqn, props); // Return a dict COPY, we have by-value semantics anyway. diff --git a/packages/jsii-pacmak/lib/targets/python.ts b/packages/jsii-pacmak/lib/targets/python.ts index 54bfeab317..d9032d23a7 100644 --- a/packages/jsii-pacmak/lib/targets/python.ts +++ b/packages/jsii-pacmak/lib/targets/python.ts @@ -661,6 +661,13 @@ class Struct extends BasePythonClassType { code.openBlock(`def __init__(${constructorArguments.join(', ')})`); this.emitConstructorDocstring(code); + // Re-type struct arguments that were passed as "dict" + for (const member of members.filter(m => m.isStruct(this.generator))) { + // Note that "None" is NOT an instance of dict (that's convenient!) + const typeName = resolver.resolve(member.type, { ignoreOptional: true }); + code.line(`if isinstance(${member.pythonName}, dict): ${member.pythonName} = ${typeName}(**${member.pythonName})`); + } + // Required properties, those will always be put into the dict code.line('self._values = {'); for (const member of members.filter(m => !m.optional)) { @@ -719,7 +726,7 @@ class StructField implements PythonBase { public readonly pythonName: string; public readonly jsiiName: string; public readonly docs?: spec.Docs; - private readonly type: spec.OptionalValue; + public readonly type: spec.OptionalValue; public constructor(public readonly prop: spec.Property) { this.pythonName = toPythonPropertyName(prop.name); diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii index 951dc349a5..5550b1c509 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii @@ -6799,6 +6799,38 @@ } ] }, + "jsii-calc.NestedStruct": { + "assembly": "jsii-calc", + "datatype": true, + "docs": { + "stability": "experimental" + }, + "fqn": "jsii-calc.NestedStruct", + "kind": "interface", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2191 + }, + "name": "NestedStruct", + "properties": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "When provided, must be > 0." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2195 + }, + "name": "numberProp", + "type": { + "primitive": "number" + } + } + ] + }, "jsii-calc.NodeStandardLibrary": { "assembly": "jsii-calc", "docs": { @@ -8215,6 +8247,90 @@ } ] }, + "jsii-calc.RootStruct": { + "assembly": "jsii-calc", + "datatype": true, + "docs": { + "remarks": "This is cheating with the declared types, but Python people don't play by\nthe rules much apparently.", + "stability": "experimental", + "summary": "This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary." + }, + "fqn": "jsii-calc.RootStruct", + "kind": "interface", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2184 + }, + "name": "RootStruct", + "properties": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "May not be empty." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2188 + }, + "name": "stringProp", + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "stability": "experimental" + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2189 + }, + "name": "nestedStruct", + "optional": true, + "type": { + "fqn": "jsii-calc.NestedStruct" + } + } + ] + }, + "jsii-calc.RootStructValidator": { + "assembly": "jsii-calc", + "docs": { + "stability": "experimental" + }, + "fqn": "jsii-calc.RootStructValidator", + "kind": "class", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2197 + }, + "methods": [ + { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2198 + }, + "name": "validate", + "parameters": [ + { + "name": "struct", + "type": { + "fqn": "jsii-calc.RootStruct" + } + } + ], + "static": true + } + ], + "name": "RootStructValidator" + }, "jsii-calc.RuntimeTypeChecking": { "assembly": "jsii-calc", "docs": { @@ -10797,5 +10913,5 @@ } }, "version": "0.20.3", - "fingerprint": "r/K0k7ocrPmzUuFsCAvxLY2UdNEi6r/ruaoO3PnHiCA=" + "fingerprint": "1F+uskR3++T5mjRcWge9oG3H/jJvXm1C3IhR1AwsBTE=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/INestedStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/INestedStruct.cs new file mode 100644 index 0000000000..6071669e9f --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/INestedStruct.cs @@ -0,0 +1,21 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// + /// stability: Experimental + /// + [JsiiInterface(nativeType: typeof(INestedStruct), fullyQualifiedName: "jsii-calc.NestedStruct")] + public interface INestedStruct + { + /// When provided, must be > 0. + /// + /// stability: Experimental + /// + [JsiiProperty(name: "numberProp", typeJson: "{\"primitive\":\"number\"}")] + double NumberProp + { + get; + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IRootStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IRootStruct.cs new file mode 100644 index 0000000000..8da60016ad --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IRootStruct.cs @@ -0,0 +1,37 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary. + /// + /// This is cheating with the declared types, but Python people don't play by + /// the rules much apparently. + /// stability: Experimental + /// + [JsiiInterface(nativeType: typeof(IRootStruct), fullyQualifiedName: "jsii-calc.RootStruct")] + public interface IRootStruct + { + /// May not be empty. + /// + /// stability: Experimental + /// + [JsiiProperty(name: "stringProp", typeJson: "{\"primitive\":\"string\"}")] + string StringProp + { + get; + } + + /// + /// stability: Experimental + /// + [JsiiProperty(name: "nestedStruct", typeJson: "{\"fqn\":\"jsii-calc.NestedStruct\"}", isOptional: true)] + [Amazon.JSII.Runtime.Deputy.JsiiOptional] + Amazon.JSII.Tests.CalculatorNamespace.INestedStruct NestedStruct + { + get + { + return null; + } + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStruct.cs new file mode 100644 index 0000000000..172b65ed76 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStruct.cs @@ -0,0 +1,22 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// + /// stability: Experimental + /// + [JsiiByValue(fqn: "jsii-calc.NestedStruct")] + public class NestedStruct : Amazon.JSII.Tests.CalculatorNamespace.INestedStruct + { + /// When provided, must be > 0. + /// + /// stability: Experimental + /// + [JsiiProperty(name: "numberProp", typeJson: "{\"primitive\":\"number\"}", isOverride: true)] + public double NumberProp + { + get; + set; + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStructProxy.cs new file mode 100644 index 0000000000..88ca5ac977 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/NestedStructProxy.cs @@ -0,0 +1,25 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// + /// stability: Experimental + /// + [JsiiTypeProxy(nativeType: typeof(INestedStruct), fullyQualifiedName: "jsii-calc.NestedStruct")] + internal sealed class NestedStructProxy : DeputyBase, Amazon.JSII.Tests.CalculatorNamespace.INestedStruct + { + private NestedStructProxy(ByRefValue reference): base(reference) + { + } + + /// When provided, must be > 0. + /// + /// stability: Experimental + /// + [JsiiProperty(name: "numberProp", typeJson: "{\"primitive\":\"number\"}")] + public double NumberProp + { + get => GetInstanceProperty(); + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStruct.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStruct.cs new file mode 100644 index 0000000000..9758519697 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStruct.cs @@ -0,0 +1,36 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary. + /// + /// This is cheating with the declared types, but Python people don't play by + /// the rules much apparently. + /// stability: Experimental + /// + [JsiiByValue(fqn: "jsii-calc.RootStruct")] + public class RootStruct : Amazon.JSII.Tests.CalculatorNamespace.IRootStruct + { + /// May not be empty. + /// + /// stability: Experimental + /// + [JsiiProperty(name: "stringProp", typeJson: "{\"primitive\":\"string\"}", isOverride: true)] + public string StringProp + { + get; + set; + } + + /// + /// stability: Experimental + /// + [JsiiOptional] + [JsiiProperty(name: "nestedStruct", typeJson: "{\"fqn\":\"jsii-calc.NestedStruct\"}", isOptional: true, isOverride: true)] + public Amazon.JSII.Tests.CalculatorNamespace.INestedStruct NestedStruct + { + get; + set; + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructProxy.cs new file mode 100644 index 0000000000..7816bebc5a --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructProxy.cs @@ -0,0 +1,38 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary. + /// + /// This is cheating with the declared types, but Python people don't play by + /// the rules much apparently. + /// stability: Experimental + /// + [JsiiTypeProxy(nativeType: typeof(IRootStruct), fullyQualifiedName: "jsii-calc.RootStruct")] + internal sealed class RootStructProxy : DeputyBase, Amazon.JSII.Tests.CalculatorNamespace.IRootStruct + { + private RootStructProxy(ByRefValue reference): base(reference) + { + } + + /// May not be empty. + /// + /// stability: Experimental + /// + [JsiiProperty(name: "stringProp", typeJson: "{\"primitive\":\"string\"}")] + public string StringProp + { + get => GetInstanceProperty(); + } + + /// + /// stability: Experimental + /// + [JsiiOptional] + [JsiiProperty(name: "nestedStruct", typeJson: "{\"fqn\":\"jsii-calc.NestedStruct\"}", isOptional: true)] + public Amazon.JSII.Tests.CalculatorNamespace.INestedStruct NestedStruct + { + get => GetInstanceProperty(); + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructValidator.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructValidator.cs new file mode 100644 index 0000000000..69bfd315bf --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/RootStructValidator.cs @@ -0,0 +1,28 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// + /// stability: Experimental + /// + [JsiiClass(nativeType: typeof(Amazon.JSII.Tests.CalculatorNamespace.RootStructValidator), fullyQualifiedName: "jsii-calc.RootStructValidator")] + public class RootStructValidator : DeputyBase + { + protected RootStructValidator(ByRefValue reference): base(reference) + { + } + + protected RootStructValidator(DeputyProps props): base(props) + { + } + + /// + /// stability: Experimental + /// + [JsiiMethod(name: "validate", parametersJson: "[{\"name\":\"struct\",\"type\":{\"fqn\":\"jsii-calc.RootStruct\"}}]")] + public static void Validate(Amazon.JSII.Tests.CalculatorNamespace.IRootStruct @struct) + { + InvokeStaticVoidMethod(typeof(Amazon.JSII.Tests.CalculatorNamespace.RootStructValidator), new System.Type[]{typeof(Amazon.JSII.Tests.CalculatorNamespace.IRootStruct)}, new object[]{@struct}); + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java index be82ab3d32..9c27fed73b 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java @@ -125,6 +125,7 @@ protected Class resolveClass(final String fqn) throws ClassNotFoundException case "jsii-calc.LoadBalancedFargateServiceProps": return software.amazon.jsii.tests.calculator.LoadBalancedFargateServiceProps.class; case "jsii-calc.Multiply": return software.amazon.jsii.tests.calculator.Multiply.class; case "jsii-calc.Negate": return software.amazon.jsii.tests.calculator.Negate.class; + case "jsii-calc.NestedStruct": return software.amazon.jsii.tests.calculator.NestedStruct.class; case "jsii-calc.NodeStandardLibrary": return software.amazon.jsii.tests.calculator.NodeStandardLibrary.class; case "jsii-calc.NullShouldBeTreatedAsUndefined": return software.amazon.jsii.tests.calculator.NullShouldBeTreatedAsUndefined.class; case "jsii-calc.NullShouldBeTreatedAsUndefinedData": return software.amazon.jsii.tests.calculator.NullShouldBeTreatedAsUndefinedData.class; @@ -144,6 +145,8 @@ protected Class resolveClass(final String fqn) throws ClassNotFoundException case "jsii-calc.PythonReservedWords": return software.amazon.jsii.tests.calculator.PythonReservedWords.class; case "jsii-calc.ReferenceEnumFromScopedPackage": return software.amazon.jsii.tests.calculator.ReferenceEnumFromScopedPackage.class; case "jsii-calc.ReturnsPrivateImplementationOfInterface": return software.amazon.jsii.tests.calculator.ReturnsPrivateImplementationOfInterface.class; + case "jsii-calc.RootStruct": return software.amazon.jsii.tests.calculator.RootStruct.class; + case "jsii-calc.RootStructValidator": return software.amazon.jsii.tests.calculator.RootStructValidator.class; case "jsii-calc.RuntimeTypeChecking": return software.amazon.jsii.tests.calculator.RuntimeTypeChecking.class; case "jsii-calc.SecondLevelStruct": return software.amazon.jsii.tests.calculator.SecondLevelStruct.class; case "jsii-calc.SingleInstanceTwoTypes": return software.amazon.jsii.tests.calculator.SingleInstanceTwoTypes.class; diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/NestedStruct.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/NestedStruct.java new file mode 100644 index 0000000000..8671fb1fd4 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/NestedStruct.java @@ -0,0 +1,118 @@ +package software.amazon.jsii.tests.calculator; + +/** + * EXPERIMENTAL + */ +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.NestedStruct") +@software.amazon.jsii.Jsii.Proxy(NestedStruct.Jsii$Proxy.class) +@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) +public interface NestedStruct extends software.amazon.jsii.JsiiSerializable { + + /** + * When provided, must be > 0. + * + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + java.lang.Number getNumberProp(); + + /** + * @return a {@link Builder} of {@link NestedStruct} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + static Builder builder() { + return new Builder(); + } + /** + * A builder for {@link NestedStruct} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public static final class Builder { + private java.lang.Number numberProp; + + /** + * Sets the value of NumberProp + * @param numberProp When provided, must be > 0. This parameter is required. + * @return {@code this} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public Builder numberProp(java.lang.Number numberProp) { + this.numberProp = numberProp; + return this; + } + + /** + * Builds the configured instance. + * @return a new instance of {@link NestedStruct} + * @throws NullPointerException if any required attribute was not provided + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public NestedStruct build() { + return new Jsii$Proxy(numberProp); + } + } + + /** + * An implementation for {@link NestedStruct} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + final class Jsii$Proxy extends software.amazon.jsii.JsiiObject implements NestedStruct { + private final java.lang.Number numberProp; + + /** + * Constructor that initializes the object based on values retrieved from the JsiiObject. + * @param objRef Reference to the JSII managed object. + */ + protected Jsii$Proxy(final software.amazon.jsii.JsiiObjectRef objRef) { + super(objRef); + this.numberProp = this.jsiiGet("numberProp", java.lang.Number.class); + } + + /** + * Constructor that initializes the object based on literal property values passed by the {@link Builder}. + */ + private Jsii$Proxy(final java.lang.Number numberProp) { + super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); + this.numberProp = java.util.Objects.requireNonNull(numberProp, "numberProp is required"); + } + + @Override + public java.lang.Number getNumberProp() { + return this.numberProp; + } + + @Override + public com.fasterxml.jackson.databind.JsonNode $jsii$toJson() { + final com.fasterxml.jackson.databind.ObjectMapper om = software.amazon.jsii.JsiiObjectMapper.INSTANCE; + final com.fasterxml.jackson.databind.node.ObjectNode data = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode(); + + data.set("numberProp", om.valueToTree(this.getNumberProp())); + + final com.fasterxml.jackson.databind.node.ObjectNode struct = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode(); + struct.set("fqn", om.valueToTree("jsii-calc.NestedStruct")); + struct.set("data", data); + + final com.fasterxml.jackson.databind.node.ObjectNode obj = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode(); + obj.set("$jsii.struct", struct); + + return obj; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NestedStruct.Jsii$Proxy that = (NestedStruct.Jsii$Proxy) o; + + return this.numberProp.equals(that.numberProp); + } + + @Override + public int hashCode() { + int result = this.numberProp.hashCode(); + return result; + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStruct.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStruct.java new file mode 100644 index 0000000000..0f00c684db --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStruct.java @@ -0,0 +1,156 @@ +package software.amazon.jsii.tests.calculator; + +/** + * This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary. + * + * This is cheating with the declared types, but Python people don't play by + * the rules much apparently. + * + * EXPERIMENTAL + */ +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.RootStruct") +@software.amazon.jsii.Jsii.Proxy(RootStruct.Jsii$Proxy.class) +@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) +public interface RootStruct extends software.amazon.jsii.JsiiSerializable { + + /** + * May not be empty. + * + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + java.lang.String getStringProp(); + + /** + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + default software.amazon.jsii.tests.calculator.NestedStruct getNestedStruct() { + return null; + } + + /** + * @return a {@link Builder} of {@link RootStruct} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + static Builder builder() { + return new Builder(); + } + /** + * A builder for {@link RootStruct} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public static final class Builder { + private java.lang.String stringProp; + private software.amazon.jsii.tests.calculator.NestedStruct nestedStruct; + + /** + * Sets the value of StringProp + * @param stringProp May not be empty. This parameter is required. + * @return {@code this} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public Builder stringProp(java.lang.String stringProp) { + this.stringProp = stringProp; + return this; + } + + /** + * Sets the value of NestedStruct + * @param nestedStruct the value to be set. + * @return {@code this} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public Builder nestedStruct(software.amazon.jsii.tests.calculator.NestedStruct nestedStruct) { + this.nestedStruct = nestedStruct; + return this; + } + + /** + * Builds the configured instance. + * @return a new instance of {@link RootStruct} + * @throws NullPointerException if any required attribute was not provided + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public RootStruct build() { + return new Jsii$Proxy(stringProp, nestedStruct); + } + } + + /** + * An implementation for {@link RootStruct} + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + final class Jsii$Proxy extends software.amazon.jsii.JsiiObject implements RootStruct { + private final java.lang.String stringProp; + private final software.amazon.jsii.tests.calculator.NestedStruct nestedStruct; + + /** + * Constructor that initializes the object based on values retrieved from the JsiiObject. + * @param objRef Reference to the JSII managed object. + */ + protected Jsii$Proxy(final software.amazon.jsii.JsiiObjectRef objRef) { + super(objRef); + this.stringProp = this.jsiiGet("stringProp", java.lang.String.class); + this.nestedStruct = this.jsiiGet("nestedStruct", software.amazon.jsii.tests.calculator.NestedStruct.class); + } + + /** + * Constructor that initializes the object based on literal property values passed by the {@link Builder}. + */ + private Jsii$Proxy(final java.lang.String stringProp, final software.amazon.jsii.tests.calculator.NestedStruct nestedStruct) { + super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); + this.stringProp = java.util.Objects.requireNonNull(stringProp, "stringProp is required"); + this.nestedStruct = nestedStruct; + } + + @Override + public java.lang.String getStringProp() { + return this.stringProp; + } + + @Override + public software.amazon.jsii.tests.calculator.NestedStruct getNestedStruct() { + return this.nestedStruct; + } + + @Override + public com.fasterxml.jackson.databind.JsonNode $jsii$toJson() { + final com.fasterxml.jackson.databind.ObjectMapper om = software.amazon.jsii.JsiiObjectMapper.INSTANCE; + final com.fasterxml.jackson.databind.node.ObjectNode data = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode(); + + data.set("stringProp", om.valueToTree(this.getStringProp())); + if (this.getNestedStruct() != null) { + data.set("nestedStruct", om.valueToTree(this.getNestedStruct())); + } + + final com.fasterxml.jackson.databind.node.ObjectNode struct = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode(); + struct.set("fqn", om.valueToTree("jsii-calc.RootStruct")); + struct.set("data", data); + + final com.fasterxml.jackson.databind.node.ObjectNode obj = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode(); + obj.set("$jsii.struct", struct); + + return obj; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RootStruct.Jsii$Proxy that = (RootStruct.Jsii$Proxy) o; + + if (!stringProp.equals(that.stringProp)) return false; + return this.nestedStruct != null ? this.nestedStruct.equals(that.nestedStruct) : that.nestedStruct == null; + } + + @Override + public int hashCode() { + int result = this.stringProp.hashCode(); + result = 31 * result + (this.nestedStruct != null ? this.nestedStruct.hashCode() : 0); + return result; + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStructValidator.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStructValidator.java new file mode 100644 index 0000000000..c6a862f870 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/RootStructValidator.java @@ -0,0 +1,28 @@ +package software.amazon.jsii.tests.calculator; + +/** + * EXPERIMENTAL + */ +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.RootStructValidator") +public class RootStructValidator extends software.amazon.jsii.JsiiObject { + + protected RootStructValidator(final software.amazon.jsii.JsiiObjectRef objRef) { + super(objRef); + } + + protected RootStructValidator(final software.amazon.jsii.JsiiObject.InitializationMode initializationMode) { + super(initializationMode); + } + + /** + * EXPERIMENTAL + * + * @param struct This parameter is required. + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public static void validate(final software.amazon.jsii.tests.calculator.RootStruct struct) { + software.amazon.jsii.JsiiObject.jsiiStaticCall(software.amazon.jsii.tests.calculator.RootStructValidator.class, "validate", Void.class, new Object[] { java.util.Objects.requireNonNull(struct, "struct is required") }); + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py b/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py index 61ab803b61..6a52bf4e90 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py +++ b/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py @@ -4875,6 +4875,38 @@ def value(self) -> jsii.Number: return jsii.get(self, "value") +@jsii.data_type(jsii_type="jsii-calc.NestedStruct", jsii_struct_bases=[], name_mapping={'number_prop': 'numberProp'}) +class NestedStruct(): + def __init__(self, *, number_prop: jsii.Number): + """ + :param number_prop: When provided, must be > 0. + + stability + :stability: experimental + """ + self._values = { + 'number_prop': number_prop, + } + + @property + def number_prop(self) -> jsii.Number: + """When provided, must be > 0. + + stability + :stability: experimental + """ + return self._values.get('number_prop') + + def __eq__(self, rhs) -> bool: + return isinstance(rhs, self.__class__) and rhs._values == self._values + + def __ne__(self, rhs) -> bool: + return not (rhs == self) + + def __repr__(self) -> str: + return 'NestedStruct(%s)' % ', '.join(k + '=' + repr(v) for k, v in self._values.items()) + + class NodeStandardLibrary(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.NodeStandardLibrary"): """Test fixture to verify that jsii modules can use the node standard library. @@ -5777,6 +5809,74 @@ def private_implementation(self) -> "IPrivatelyImplemented": return jsii.get(self, "privateImplementation") +@jsii.data_type(jsii_type="jsii-calc.RootStruct", jsii_struct_bases=[], name_mapping={'string_prop': 'stringProp', 'nested_struct': 'nestedStruct'}) +class RootStruct(): + def __init__(self, *, string_prop: str, nested_struct: typing.Optional["NestedStruct"]=None): + """This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary. + + This is cheating with the declared types, but Python people don't play by + the rules much apparently. + + :param string_prop: May not be empty. + :param nested_struct: + + stability + :stability: experimental + """ + if isinstance(nested_struct, dict): nested_struct = NestedStruct(**nested_struct) + self._values = { + 'string_prop': string_prop, + } + if nested_struct is not None: self._values["nested_struct"] = nested_struct + + @property + def string_prop(self) -> str: + """May not be empty. + + stability + :stability: experimental + """ + return self._values.get('string_prop') + + @property + def nested_struct(self) -> typing.Optional["NestedStruct"]: + """ + stability + :stability: experimental + """ + return self._values.get('nested_struct') + + def __eq__(self, rhs) -> bool: + return isinstance(rhs, self.__class__) and rhs._values == self._values + + def __ne__(self, rhs) -> bool: + return not (rhs == self) + + def __repr__(self) -> str: + return 'RootStruct(%s)' % ', '.join(k + '=' + repr(v) for k, v in self._values.items()) + + +class RootStructValidator(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.RootStructValidator"): + """ + stability + :stability: experimental + """ + @jsii.member(jsii_name="validate") + @classmethod + def validate(cls, *, string_prop: str, nested_struct: typing.Optional["NestedStruct"]=None) -> None: + """ + :param struct: - + :param string_prop: May not be empty. + :param nested_struct: + + stability + :stability: experimental + """ + struct = RootStruct(string_prop=string_prop, nested_struct=nested_struct) + + return jsii.sinvoke(cls, "validate", [struct]) + + class RuntimeTypeChecking(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.RuntimeTypeChecking"): """ stability @@ -6265,6 +6365,7 @@ def __init__(self, *, required_string: str, optional_boolean: typing.Optional[bo stability :stability: experimental """ + if isinstance(optional_struct_a, dict): optional_struct_a = StructA(**optional_struct_a) self._values = { 'required_string': required_string, } @@ -7558,6 +7659,6 @@ def parts(self, value: typing.List[scope.jsii_calc_lib.Value]): return jsii.set(self, "parts", value) -__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AnonymousImplementationProvider", "AsyncVirtualMethods", "AugmentableClass", "Bell", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithCollections", "ClassWithDocs", "ClassWithJavaReservedWords", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumerCanRingBell", "ConsumersOfThisCrazyTypeSystem", "DataRenderer", "DefaultedConstructorArgument", "DeprecatedClass", "DeprecatedEnum", "DeprecatedStruct", "DerivedClassHasNoProperties", "DerivedStruct", "DiamondInheritanceBaseLevelStruct", "DiamondInheritanceFirstMidLevelStruct", "DiamondInheritanceSecondMidLevelStruct", "DiamondInheritanceTopLevelStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EnumDispenser", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExperimentalClass", "ExperimentalEnum", "ExperimentalStruct", "ExportedBaseClass", "ExtendsInternalInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnonymousImplementationProvider", "IAnonymouslyImplementMe", "IAnotherPublicInterface", "IBell", "IBellRinger", "IConcreteBellRinger", "IDeprecatedInterface", "IExperimentalInterface", "IExtendsPrivateInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IJSII417Derived", "IJSII417PublicBaseOfBase", "IJsii487External", "IJsii487External2", "IJsii496", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "IStableInterface", "ImplementInternalInterface", "Implementation", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "InterfacesMaker", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "Jsii487Derived", "Jsii496Derived", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalArgumentInvoker", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverridableProtectedMember", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SecondLevelStruct", "SingleInstanceTwoTypes", "SingletonInt", "SingletonIntEnum", "SingletonString", "SingletonStringEnum", "StableClass", "StableEnum", "StableStruct", "StaticContext", "Statics", "StringEnum", "StripInternal", "StructA", "StructB", "StructPassing", "StructUnionConsumer", "StructWithJavaReservedWords", "Sum", "SupportsNiceJavaBuilder", "SupportsNiceJavaBuilderProps", "SupportsNiceJavaBuilderWithRequiredProps", "SyncVirtualMethods", "Thrower", "TopLevelStruct", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicInvoker", "VariadicMethod", "VirtualMethodPlayground", "VoidCallback", "WithPrivatePropertyInConstructor", "__jsii_assembly__", "composition"] +__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AnonymousImplementationProvider", "AsyncVirtualMethods", "AugmentableClass", "Bell", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithCollections", "ClassWithDocs", "ClassWithJavaReservedWords", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumerCanRingBell", "ConsumersOfThisCrazyTypeSystem", "DataRenderer", "DefaultedConstructorArgument", "DeprecatedClass", "DeprecatedEnum", "DeprecatedStruct", "DerivedClassHasNoProperties", "DerivedStruct", "DiamondInheritanceBaseLevelStruct", "DiamondInheritanceFirstMidLevelStruct", "DiamondInheritanceSecondMidLevelStruct", "DiamondInheritanceTopLevelStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EnumDispenser", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExperimentalClass", "ExperimentalEnum", "ExperimentalStruct", "ExportedBaseClass", "ExtendsInternalInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnonymousImplementationProvider", "IAnonymouslyImplementMe", "IAnotherPublicInterface", "IBell", "IBellRinger", "IConcreteBellRinger", "IDeprecatedInterface", "IExperimentalInterface", "IExtendsPrivateInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IJSII417Derived", "IJSII417PublicBaseOfBase", "IJsii487External", "IJsii487External2", "IJsii496", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "IStableInterface", "ImplementInternalInterface", "Implementation", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "InterfacesMaker", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "Jsii487Derived", "Jsii496Derived", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NestedStruct", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalArgumentInvoker", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverridableProtectedMember", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RootStruct", "RootStructValidator", "RuntimeTypeChecking", "SecondLevelStruct", "SingleInstanceTwoTypes", "SingletonInt", "SingletonIntEnum", "SingletonString", "SingletonStringEnum", "StableClass", "StableEnum", "StableStruct", "StaticContext", "Statics", "StringEnum", "StripInternal", "StructA", "StructB", "StructPassing", "StructUnionConsumer", "StructWithJavaReservedWords", "Sum", "SupportsNiceJavaBuilder", "SupportsNiceJavaBuilderProps", "SupportsNiceJavaBuilderWithRequiredProps", "SyncVirtualMethods", "Thrower", "TopLevelStruct", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicInvoker", "VariadicMethod", "VirtualMethodPlayground", "VoidCallback", "WithPrivatePropertyInConstructor", "__jsii_assembly__", "composition"] publication.publish() diff --git a/packages/jsii-python-runtime/tests/test_compliance.py b/packages/jsii-python-runtime/tests/test_compliance.py index 7895a6cfdd..6c63c97889 100644 --- a/packages/jsii-python-runtime/tests/test_compliance.py +++ b/packages/jsii-python-runtime/tests/test_compliance.py @@ -48,6 +48,8 @@ EraseUndefinedHashValues, EraseUndefinedHashValuesOptions, VariadicMethod, + RootStruct, + RootStructValidator, StructPassing, TopLevelStruct, SecondLevelStruct, @@ -1000,6 +1002,16 @@ def test_consumer_calls_method_privateclass(): def test_consumer_calls_method_typed_as_class(): assert ConsumerCanRingBell().when_typed_as_class(PythonConcreteBellRinger()) +def test_can_pass_nested_struct_as_dict(): + # Those shouldn't raise: + RootStructValidator.validate(string_prop= 'Pickle Rick!!!') + RootStructValidator.validate(string_prop= 'Pickle Rick!!!', nested_struct= None) + RootStructValidator.validate( + string_prop= 'Pickle Rick!!!', + nested_struct= { + 'number_prop': 1337 + } + ) @jsii.implements(IBellRinger) class PythonBellRinger: diff --git a/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap b/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap index 4eeb29d4e8..5ddff0ad79 100644 --- a/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap +++ b/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap @@ -1126,6 +1126,14 @@ exports[`jsii-tree --all 1`] = ` │ │ └─┬ privateImplementation property (experimental) │ │ ├── immutable │ │ └── type: jsii-calc.IPrivatelyImplemented + │ ├─┬ class RootStructValidator (experimental) + │ │ └─┬ members + │ │ └─┬ static validate(struct) method (experimental) + │ │ ├── static + │ │ ├─┬ parameters + │ │ │ └─┬ struct + │ │ │ └── type: jsii-calc.RootStruct + │ │ └── returns: void │ ├─┬ class RuntimeTypeChecking (experimental) │ │ └─┬ members │ │ ├── () initializer (experimental) @@ -1886,6 +1894,12 @@ exports[`jsii-tree --all 1`] = ` │ │ ├── abstract │ │ ├── immutable │ │ └── type: Optional + │ ├─┬ interface NestedStruct (experimental) + │ │ └─┬ members + │ │ └─┬ numberProp property (experimental) + │ │ ├── abstract + │ │ ├── immutable + │ │ └── type: number │ ├─┬ interface NullShouldBeTreatedAsUndefinedData (experimental) │ │ └─┬ members │ │ ├─┬ arrayWithThreeElementsAndUndefinedAsSecondArgument property (experimental) @@ -1902,6 +1916,16 @@ exports[`jsii-tree --all 1`] = ` │ │ ├── abstract │ │ ├── immutable │ │ └── type: Optional + │ ├─┬ interface RootStruct (experimental) + │ │ └─┬ members + │ │ ├─┬ stringProp property (experimental) + │ │ │ ├── abstract + │ │ │ ├── immutable + │ │ │ └── type: string + │ │ └─┬ nestedStruct property (experimental) + │ │ ├── abstract + │ │ ├── immutable + │ │ └── type: Optional │ ├─┬ interface SecondLevelStruct (experimental) │ │ └─┬ members │ │ ├─┬ deeperRequiredProp property (experimental) @@ -2255,6 +2279,7 @@ exports[`jsii-tree --inheritance 1`] = ` │ ├── class PythonReservedWords │ ├── class ReferenceEnumFromScopedPackage │ ├── class ReturnsPrivateImplementationOfInterface + │ ├── class RootStructValidator │ ├── class RuntimeTypeChecking │ ├── class SingleInstanceTwoTypes │ ├── class SingletonInt @@ -2354,8 +2379,10 @@ exports[`jsii-tree --inheritance 1`] = ` │ ├── interface Hello │ ├── interface Hello │ ├── interface LoadBalancedFargateServiceProps + │ ├── interface NestedStruct │ ├── interface NullShouldBeTreatedAsUndefinedData │ ├── interface OptionalStruct + │ ├── interface RootStruct │ ├── interface SecondLevelStruct │ ├── interface StableStruct │ ├── interface StructA @@ -2914,6 +2941,9 @@ exports[`jsii-tree --members 1`] = ` │ │ └─┬ members │ │ ├── () initializer │ │ └── privateImplementation property + │ ├─┬ class RootStructValidator + │ │ └─┬ members + │ │ └── static validate(struct) method │ ├─┬ class RuntimeTypeChecking │ │ └─┬ members │ │ ├── () initializer @@ -3219,6 +3249,9 @@ exports[`jsii-tree --members 1`] = ` │ │ ├── memoryMiB property │ │ ├── publicLoadBalancer property │ │ └── publicTasks property + │ ├─┬ interface NestedStruct + │ │ └─┬ members + │ │ └── numberProp property │ ├─┬ interface NullShouldBeTreatedAsUndefinedData │ │ └─┬ members │ │ ├── arrayWithThreeElementsAndUndefinedAsSecondArgument property @@ -3226,6 +3259,10 @@ exports[`jsii-tree --members 1`] = ` │ ├─┬ interface OptionalStruct │ │ └─┬ members │ │ └── field property + │ ├─┬ interface RootStruct + │ │ └─┬ members + │ │ ├── stringProp property + │ │ └── nestedStruct property │ ├─┬ interface SecondLevelStruct │ │ └─┬ members │ │ ├── deeperRequiredProp property @@ -3439,6 +3476,7 @@ exports[`jsii-tree --types 1`] = ` │ ├── class PythonReservedWords │ ├── class ReferenceEnumFromScopedPackage │ ├── class ReturnsPrivateImplementationOfInterface + │ ├── class RootStructValidator │ ├── class RuntimeTypeChecking │ ├── class SingleInstanceTwoTypes │ ├── class SingletonInt @@ -3510,8 +3548,10 @@ exports[`jsii-tree --types 1`] = ` │ ├── interface Hello │ ├── interface Hello │ ├── interface LoadBalancedFargateServiceProps + │ ├── interface NestedStruct │ ├── interface NullShouldBeTreatedAsUndefinedData │ ├── interface OptionalStruct + │ ├── interface RootStruct │ ├── interface SecondLevelStruct │ ├── interface StableStruct │ ├── interface StructA diff --git a/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap b/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap index 4609005af1..b46dddb198 100644 --- a/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap +++ b/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap @@ -90,6 +90,7 @@ Array [ "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", + "RootStructValidator", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "SingletonInt",