diff --git a/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/SetupGenerator.java b/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/SetupGenerator.java index 14dfa9924..1fe3cf3fc 100644 --- a/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/SetupGenerator.java +++ b/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/SetupGenerator.java @@ -39,9 +39,6 @@ static void generateSetup( PythonSettings settings, GenerationContext context ) { - var dependencies = SymbolDependency.gatherDependencies(context.writerDelegator().getDependencies().stream()); - writePyproject(settings, context.writerDelegator(), dependencies); - writeReadme(settings, context); } /** diff --git a/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/StructureGenerator.java b/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/StructureGenerator.java index ce9f675af..e0b5bdf33 100644 --- a/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/StructureGenerator.java +++ b/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/StructureGenerator.java @@ -244,7 +244,7 @@ protected void writeInitMethodParameterForOptionalMember(boolean isError, Member } - private boolean isOptionalDefault(MemberShape member) { + protected boolean isOptionalDefault(MemberShape member) { // If a member with a default value isn't required, it's optional. // see: https://smithy.io/2.0/spec/type-refinement-traits.html#smithy-api-default-trait var target = model.expectShape(member.getTarget()); diff --git a/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/UnionGenerator.java b/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/UnionGenerator.java index e0ae84dd2..ad6a5159c 100644 --- a/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/UnionGenerator.java +++ b/codegen/smithy-dafny-codegen-modules/smithy-python/codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/UnionGenerator.java @@ -29,11 +29,11 @@ /** * Renders unions. */ -public final class UnionGenerator implements Runnable { +public class UnionGenerator implements Runnable { - private final Model model; + protected final Model model; private final SymbolProvider symbolProvider; - private final PythonWriter writer; + protected final PythonWriter writer; private final UnionShape shape; private final Set recursiveShapes; @@ -51,6 +51,10 @@ public UnionGenerator( this.recursiveShapes = recursiveShapes; } + protected void writeInitMethodConstraintsChecksForMember(MemberShape member, String memberName) { + // Stub method that can be overridden by other codegens. + } + @Override public void run() { var parentName = symbolProvider.toSymbol(shape).getName(); @@ -70,6 +74,7 @@ public void run() { writer.writeDocs(trait.getValue()); }); writer.openBlock("def __init__(self, value: $T):", "", targetSymbol, () -> { + writeInitMethodConstraintsChecksForMember(member, memberSymbol.getName()); writer.write("self.value = value"); }); diff --git a/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/pyproject.toml b/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/pyproject.toml index 5c605d3c0..6f61403ec 100644 --- a/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/pyproject.toml +++ b/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ ] dependencies = [ "awscrt>=0.15,<1.0", - "aiohttp>=3.8.3,<3.9.0" + "aiohttp>=3.9.0" ] [project.urls] diff --git a/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/requirements.txt b/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/requirements.txt index 41f99328f..a65376bc3 100644 --- a/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/requirements.txt +++ b/codegen/smithy-dafny-codegen-modules/smithy-python/python-packages/smithy-python/requirements.txt @@ -1,2 +1,2 @@ awscrt>=0.15,<1.0 -aiohttp>=3.8.3,<3.9.0 +aiohttp>=3.9.0 diff --git a/codegen/smithy-dafny-codegen/build.gradle.kts b/codegen/smithy-dafny-codegen/build.gradle.kts index b6035a37f..6cfb66510 100644 --- a/codegen/smithy-dafny-codegen/build.gradle.kts +++ b/codegen/smithy-dafny-codegen/build.gradle.kts @@ -45,6 +45,9 @@ dependencies { implementation("software.amazon.awssdk:codegen:2.20.26") implementation("com.squareup:javapoet:1.13.0") + // Smithy-Python + implementation(project(":smithy-python-codegen")) + // Used for parsing-based tests testImplementation("org.antlr:antlr4:4.9.2") } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithydafny/DafnyApiCodegen.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithydafny/DafnyApiCodegen.java index e05350ca1..09b2126c0 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithydafny/DafnyApiCodegen.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithydafny/DafnyApiCodegen.java @@ -129,10 +129,7 @@ public Map generate() { namespace ); final TokenTree typesModuleHeader = Token.of( - "module {:extern \"%s\" } %s".formatted( - DafnyNameResolverHelpers.dafnyExternNamespaceForShapeId( - serviceShape.getId() - ), + "module %s".formatted( typesModuleName ) ); diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/README.md b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/README.md new file mode 100644 index 000000000..003b29b55 --- /dev/null +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/README.md @@ -0,0 +1,23 @@ +TODO-Python: Add more content here + +Top-level file overview: + +``` +├── awssdk - Generates a boto3 wrapper to call from Dafny-generated Python code +├── common - Common code across generation targets +├── localservice - Generates a Smithy client that wraps a Dafny-generated Python localService implementation +└── wrappedlocalservice - Generates a wrapper for the `localservice` code to call the Smithy client from Dafny-generated Python code +``` + +Each subfolder follows a similar structure: + +``` +├── customize - Classes referenced from a plugin's `PythonIntegration.customize` function. +│ Generates new files or adds new code to Smithy-Python generated files. +├── extensions - Classes that extend or replace Smithy-Python codegen components. +├── nameresolver - Utility classes to map Smithy model shapes to strings used in generated code. +└── shapevisitor - Classes that generate code to convert to/from Smithy client Python shapes + │ (or AWS SDK shapes) and Dafny implementation shapes. + └── conversionwriter - Classes that generate functions that convert to/from Smithy client Python shapes + (or AWS SDK shapes) and Dafny implementation shapes for StructureShapes and UnionShapes. +``` \ No newline at end of file diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/awssdk/extensions/DafnyPythonAwsSdkClientCodegenPlugin.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/awssdk/extensions/DafnyPythonAwsSdkClientCodegenPlugin.java index ac0e8a3d0..adbfc4e45 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/awssdk/extensions/DafnyPythonAwsSdkClientCodegenPlugin.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/awssdk/extensions/DafnyPythonAwsSdkClientCodegenPlugin.java @@ -26,7 +26,7 @@ * from the PythonClientCodegenPlugin by not calling `runner.performDefaultCodegenTransforms()` and * `runner.createDedicatedInputsAndOutputs()`. These methods transform the model in ways such that the * model does not align with the generated Dafny code. This Plugin also attaches a - * DafnyAwsSdkProtocolTrait to the ServiceShape provided in settings. AWS SDKs do not consistently + * {@link DafnyAwsSdkProtocolTrait} to the ServiceShape provided in settings. AWS SDKs do not consistently * label a protocol, and Smithy-Python requires that a protocol is assigned. Rather than declare * that we are using some protocol (e.g. `restJson1`) then not use that in practice, it is more * proper to define some custom protocol and use that. @@ -67,10 +67,10 @@ public String getName() { @Override public void execute(PluginContext context) { - CodegenDirector runner = + final CodegenDirector runner = new CodegenDirector<>(); - PythonSettings settings = PythonSettings.from(context.getSettings()); + final PythonSettings settings = PythonSettings.from(context.getSettings()); settings.setProtocol(DafnyAwsSdkProtocolTrait.ID); runner.settings(settings); runner.directedCodegen(new DirectedDafnyPythonAwsSdkCodegen()); @@ -81,7 +81,7 @@ public void execute(PluginContext context) { // Add a DafnyAwsSdkProtocolTrait to the service as a contextual indicator highlighting // that the DafnyPythonAwsSdk protocol should be used. - ServiceShape serviceShape = + final ServiceShape serviceShape = context.getModel().expectShape(settings.getService()).asServiceShape().get(); runner.model(addAwsSdkProtocolTrait(context.getModel(), serviceShape)); diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/DafnyNameResolver.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/DafnyNameResolver.java index cb6a439da..bfe32e145 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/DafnyNameResolver.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/DafnyNameResolver.java @@ -13,12 +13,17 @@ import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.shapes.UnionShape; +import software.amazon.polymorph.traits.PositionalTrait; import software.amazon.smithy.model.traits.EnumTrait; import software.amazon.smithy.model.traits.ErrorTrait; import software.amazon.smithy.python.codegen.GenerationContext; import software.amazon.smithy.python.codegen.PythonWriter; import software.amazon.smithy.utils.CaseUtils; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import static software.amazon.polymorph.smithydafny.DafnyNameResolver.dafnyTypesModuleName; /** @@ -27,6 +32,31 @@ */ public class DafnyNameResolver { + // The source of truth here is Dafny's PythonCodeGenerator: + // https://github.com/dafny-lang/dafny/blob/709edd1b938afad604dfad62b86c884d6ec5a44b/Source/DafnyCore/Backends/Python/PythonCodeGenerator.cs#L63-L66 + // If a word is in this set, Dafny will apply "mangling" to it by appending an `_`. + // Smithy-Dafny needs to know this set so it can also apply mangling and append an `_` to these words. + private static Set dafnyReservedWords = new HashSet<>(Arrays.asList("False", "None", "True", "and", "as" + , "assert", "async", "await", "break", "class", "continue", "def", "del", "enum", "elif", "else", "except" + , "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass" + , "raise", "return", "try", "while", "with", "yield")); + + /** + * "Mangle" any Dafny reserved words by adding an "_". + * This should be applied to all imports for types generated by Dafny. + * A lot of Smithy-Python code aliases imports for types generated by Dafny. + * ex. `import XXX_XXX as DafnyXXX`, + * so this only needs to apply to types imported directly from Dafny. + * @param name + * @return + */ + public static String mangleDafnyType(String name) { + if (dafnyReservedWords.contains(name)) { + return name + "_"; + } + return name; + } + /** * Returns the name of the Python module containing Dafny-generated Python code from the `types` * module from the same Dafny project for the provided Shape. ex. example.namespace.ExampleShape @@ -184,7 +214,9 @@ public static String getDafnyTypeForStringShapeWithEnumTrait( "Argument is not a StringShape with EnumTrait: " + stringShape.getId()); } - return stringShape.getId().getName() + "_" + enumValue.replace("_", "__"); + return mangleDafnyType(stringShape.getId().getName()) + + "_" + + mangleDafnyType(enumValue.replace("_", "__")); } public static void importDafnyTypeForStringShapeWithEnumTrait( @@ -234,6 +266,11 @@ else if (context.model().expectShape(shapeId).hasTrait(ErrorTrait.class)) { importDafnyTypeForError(writer, shapeId, context); } + else if (context.model().expectShape(shapeId).hasTrait(PositionalTrait.class)) { + // Don't import positional shapes; their underlying types are discovered and imported + return; + } + else { // When generating a Dafny import, must ALWAYS first import module_ to avoid circular // dependencies @@ -241,7 +278,8 @@ else if (context.model().expectShape(shapeId).hasTrait(ErrorTrait.class)) { String name = shapeId.getName(); writer.addStdlibImport( getDafnyPythonTypesModuleNameForShape(shapeId, context), - name.replace("_", "__") + "_" + name.replace("_", "__"), + // Mangling for "normal" repeated types only appears to apply to the first name + mangleDafnyType(name.replace("_", "__")) + "_" + name.replace("_", "__"), getDafnyTypeForShape(shapeId)); } } @@ -415,4 +453,5 @@ public static void importGenericDafnyErrorTypeForNamespace( writer.addStdlibImport(getDafnyGeneratedPathForSmithyNamespace(namespace) + ".module_"); writer.addStdlibImport(getDafnyTypesModuleNameForSmithyNamespace(namespace, context), "Error"); } + } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/SmithyNameResolver.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/SmithyNameResolver.java index 46b2f8f0f..458dae0b6 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/SmithyNameResolver.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/common/nameresolver/SmithyNameResolver.java @@ -284,7 +284,7 @@ public static String getPythonModuleSmithygeneratedPathForSmithyNamespace( // In the case of a wrappedLocalService shim in a different namespace, // the default modulename should not be used, // and we need a mechanism to override the default modulename. - // If the smithy.api namespace has a dependency-module-name mapping, use that. + // If the smithy.api namespace has a dependency-library-name mapping, use that. try { pythonModuleName = getPythonModuleNameForSmithyNamespace(smithyNamespace); } catch (IllegalArgumentException e) { diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/ConstraintUtils.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/ConstraintUtils.java new file mode 100644 index 000000000..e2fbfb705 --- /dev/null +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/ConstraintUtils.java @@ -0,0 +1,149 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package software.amazon.polymorph.smithypython.localservice; + +import software.amazon.polymorph.utils.ConstrainTraitUtils; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.MemberShape; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.traits.LengthTrait; +import software.amazon.smithy.model.traits.RangeTrait; +import software.amazon.smithy.python.codegen.PythonWriter; + +public class ConstraintUtils { + public static void writeInitMethodConstraintsChecksForMember( + PythonWriter writer, Model model, MemberShape member, String memberName) { + // RangeTrait + Shape targetShape = model.expectShape(member.getTarget()); + if (targetShape.hasTrait(RangeTrait.class)) { + RangeTrait rangeTrait = targetShape.getTrait(RangeTrait.class).get(); + if (rangeTrait.getMin().isPresent()) { + writeRangeTraitMinCheckForMember(writer, model, member, memberName, rangeTrait); + } + if (rangeTrait.getMax().isPresent()) { + writeRangeTraitMaxCheckForMember(writer, model, member, memberName, rangeTrait); + } + } + + // LengthTrait + if (targetShape.hasTrait(LengthTrait.class)) { + LengthTrait lengthTrait = targetShape.getTrait(LengthTrait.class).get(); + if (lengthTrait.getMin().isPresent()) { + writeLengthTraitMinCheckForMember(writer, memberName, lengthTrait); + } + if (lengthTrait.getMax().isPresent()) { + writeLengthTraitMaxCheckForMember(writer, memberName, lengthTrait); + } + } + } + + /** + * Write validation for {@link LengthTrait} min value. Called from __init__. + * + * @param memberName + * @param lengthTrait + */ + protected static void writeLengthTraitMinCheckForMember( + PythonWriter writer, String memberName, LengthTrait lengthTrait) { + String min = ConstrainTraitUtils.LengthTraitUtils.min(lengthTrait); + writer.openBlock( + "if ($1L is not None) and (len($1L) < $2L):", + "", + memberName, + min, + () -> { + writer.write( + """ + raise ValueError("The size of $1L must be greater than or equal to $2L") + """, + memberName, + min); + }); + } + + /** + * Write validation for {@link LengthTrait} max value. Called from __init__. + * + * @param memberName + * @param lengthTrait + */ + protected static void writeLengthTraitMaxCheckForMember( + PythonWriter writer, String memberName, LengthTrait lengthTrait) { + String max = ConstrainTraitUtils.LengthTraitUtils.max(lengthTrait); + writer.openBlock( + "if ($1L is not None) and (len($1L) > $2L):", + "", + memberName, + max, + () -> { + writer.write( + """ + raise ValueError("The size of $1L must be less than or equal to $2L") + """, + memberName, + max); + }); + } + + /** + * Write validation for {@link RangeTrait} min value. Called from __init__. + * + * @param member + * @param memberName + * @param rangeTrait + */ + protected static void writeRangeTraitMinCheckForMember( + PythonWriter writer, + Model model, + MemberShape member, + String memberName, + RangeTrait rangeTrait) { + String min = + ConstrainTraitUtils.RangeTraitUtils.minAsShapeType( + model.expectShape(member.getTarget()), rangeTrait); + writer.openBlock( + "if ($1L is not None) and ($1L < $2L):", + "", + memberName, + min, + () -> { + writer.write( + """ + raise ValueError("$1L must be greater than or equal to $2L") + """, + memberName, + min); + }); + } + + /** + * Write validation for {@link RangeTrait} max value. Called from __init__. + * + * @param member + * @param memberName + * @param rangeTrait + */ + protected static void writeRangeTraitMaxCheckForMember( + PythonWriter writer, + Model model, + MemberShape member, + String memberName, + RangeTrait rangeTrait) { + String max = + ConstrainTraitUtils.RangeTraitUtils.maxAsShapeType( + model.expectShape(member.getTarget()), rangeTrait); + writer.openBlock( + "if ($1L is not None) and ($1L > $2L):", + "", + memberName, + max, + () -> { + writer.write( + """ + raise ValueError("$1L must be less than or equal to $2L") + """, + memberName, + max); + }); + } +} diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/DafnyPythonLocalServiceProtocolGenerator.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/DafnyPythonLocalServiceProtocolGenerator.java index aca63f731..2378105c3 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/DafnyPythonLocalServiceProtocolGenerator.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/DafnyPythonLocalServiceProtocolGenerator.java @@ -10,6 +10,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; + import software.amazon.polymorph.smithypython.awssdk.nameresolver.AwsSdkNameResolver; import software.amazon.polymorph.smithypython.common.nameresolver.DafnyNameResolver; import software.amazon.polymorph.smithypython.common.nameresolver.SmithyNameResolver; @@ -301,7 +302,7 @@ private void generateOperationResponseDeserializer( writer.write( """ if input.IsFailure(): - return await _deserialize_error(input.error) + return _deserialize_error(input.error) return $L """, output); @@ -353,7 +354,7 @@ private void generateErrorResponseDeserializerSection(GenerationContext context) writer.addImport(".errors", "CollectionOfErrors"); writer.addStdlibImport("_dafny"); writer.openBlock( - "async def _deserialize_error(error: Error) -> ServiceError:", + "def _deserialize_error(error: Error) -> ServiceError:", "", () -> { writer.write( @@ -363,7 +364,7 @@ private void generateErrorResponseDeserializerSection(GenerationContext context) elif error.is_CollectionOfErrors: return CollectionOfErrors( message=_dafny.string_of(error.message), - list=[await _deserialize_error(dafny_e) for dafny_e in error.list], + list=[_deserialize_error(dafny_e) for dafny_e in error.list], )"""); // Write converters for errors modelled on this local service @@ -467,31 +468,17 @@ private void generateErrorResponseDeserializerSectionForLocalServiceDependencyEr + "_deserialize_error"); // Generate deserializer for dependency that defers to its `_deserialize_error` String serviceDependencyErrorDafnyName = - software.amazon.polymorph.smithydafny.DafnyNameResolver.dafnyBaseModuleName(serviceShape.getId().getNamespace()); - - // Import this service's Dafny error - ServiceShape dependencyServiceShape = - context.model().expectShape(serviceDependencyShapeId).asServiceShape().get(); - List serviceDependencyErrors = dependencyServiceShape.getErrors(); - if (serviceDependencyErrors.size() > 1) { - throw new IllegalArgumentException( - "Only 1 service-modelled error per service supported"); - } - - ShapeId serviceDependencyError = serviceDependencyErrors.get(0); - - DafnyNameResolver.importDafnyTypeForError(writer, serviceDependencyError, context); + software.amazon.polymorph.smithydafny.DafnyNameResolver.dafnyBaseModuleName(serviceDependencyShapeId.getNamespace()); writer.write( """ elif error.is_$L: - return $L(await $L($L(message=error.$L)))""", + return $L($L(error.$L))""", serviceDependencyErrorDafnyName, serviceDependencyShapeId.getName(), SmithyNameResolver.getServiceSmithygeneratedDirectoryNameForNamespace( serviceDependencyShapeId.getNamespace()) + "_deserialize_error", - DafnyNameResolver.getDafnyTypeForError(serviceDependencyError), serviceDependencyErrorDafnyName); } } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ErrorsFileWriter.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ErrorsFileWriter.java index dd9667df9..d355ac35d 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ErrorsFileWriter.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ErrorsFileWriter.java @@ -335,7 +335,7 @@ private void generateSmithyErrorToDafnyErrorBlock( """, DafnyNameResolver.getDafnyPythonTypesModuleNameForShape(serviceShape.getId(), codegenContext)); writer.addStdlibImport("_dafny"); - // Add service-specific OpaqueError + // Service-specific OpaqueError; we know it has obj writer.write( """ if isinstance(e, OpaqueError): @@ -343,6 +343,14 @@ private void generateSmithyErrorToDafnyErrorBlock( """, DafnyNameResolver.getDafnyPythonTypesModuleNameForShape(serviceShape.getId(), codegenContext)); writer.addStdlibImport(DafnyNameResolver.getDafnyGeneratedPathForSmithyNamespace(serviceShape.getId().getNamespace())); + // Nothing found, we know nothing about this error. Cast as opaque + writer.write( + """ + else: + return $L.Error_Opaque(obj=e) + """, + DafnyNameResolver.getDafnyPythonTypesModuleNameForShape(serviceShape.getId(), codegenContext)); + writer.addStdlibImport(DafnyNameResolver.getDafnyGeneratedPathForSmithyNamespace(serviceShape.getId().getNamespace())); } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ReferencesFileWriter.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ReferencesFileWriter.java index fcfe98be0..a490f1346 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ReferencesFileWriter.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/customize/ReferencesFileWriter.java @@ -11,6 +11,7 @@ import software.amazon.polymorph.smithypython.common.nameresolver.DafnyNameResolver; import software.amazon.polymorph.smithypython.common.nameresolver.SmithyNameResolver; import software.amazon.polymorph.smithypython.common.shapevisitor.ShapeVisitorResolver; +import software.amazon.polymorph.traits.ExtendableTrait; import software.amazon.smithy.codegen.core.Symbol; import software.amazon.smithy.model.shapes.*; import software.amazon.smithy.model.traits.DocumentationTrait; @@ -44,7 +45,9 @@ public void generateResourceInterfaceAndImplementation( ResourceShape resourceShape, GenerationContext codegenContext, PythonWriter writer) { if (shouldGenerateResourceForShape(resourceShape, codegenContext)) { generatedResourceShapes.add(resourceShape.getId()); - generateResourceInterface(resourceShape, codegenContext, writer); + if (resourceShape.hasTrait(ExtendableTrait.class)) { + generateResourceInterface(resourceShape, codegenContext, writer); + } generateResourceImplementation(resourceShape, codegenContext, writer); } } @@ -120,7 +123,7 @@ protected void generateResourceImplementation( // Write implementation for resource shape writer.write( """ - class $1L(I$1L): + class $1L$6L: ${5C|} _impl: $2L @@ -138,7 +141,13 @@ def __init__(self, _impl: $2L): writer.consumer( w -> generateSmithyOperationFunctionDefinitionForResource(context, resourceShape, w)), writer.consumer(w -> generateDictConvertersForResource(resourceShape, w)), - writer.consumer(w -> writeDocsForResourceOrInterfaceClass(w, resourceShape, context))); + writer.consumer(w -> writeDocsForResourceOrInterfaceClass(w, resourceShape, context)), + // Only extend interface if extendable; + // otherwise doesn't extend anything + resourceShape.hasTrait(ExtendableTrait.class) + ? "(I%1$s)".formatted(resourceShape.getId().getName()) + : "" + ); } /** @@ -263,14 +272,11 @@ private void generateNativeWrapperFunctionDefinitionForResource( throw new IllegalArgumentException( "Only 1 service-modelled error per service supported"); } - String defaultWrappingError = - !serviceShape.getErrors().isEmpty() - ? DafnyNameResolver.getDafnyTypeForError(serviceDependencyErrors.get(0)) - : "Error"; - writer.addStdlibImport( - DafnyNameResolver.getDafnyPythonTypesModuleNameForShape(serviceShape, codegenContext), - defaultWrappingError); + writer.addStdlibImport(SmithyNameResolver.getPythonModuleSmithygeneratedPathForSmithyNamespace( + serviceShape.getId().getNamespace(), codegenContext.settings()) + ".errors", + "_smithy_error_to_dafny_error" + ); writer.openBlock( "def $L(self, dafny_input: '$L') -> '$L':", @@ -295,9 +301,7 @@ private void generateNativeWrapperFunctionDefinitionForResource( ) return Wrappers.Result_Success(dafny_output) except Exception as e: - error = $L( - message=str(e) - ) + error = _smithy_error_to_dafny_error(e) return Wrappers.Result_Failure(error) """, SmithyNameResolver.getPythonModuleSmithygeneratedPathForSmithyNamespace( @@ -310,8 +314,8 @@ private void generateNativeWrapperFunctionDefinitionForResource( targetShapeOutput.getId().getNamespace(), codegenContext) + ".smithy_to_dafny." + SmithyNameResolver.getSmithyToDafnyFunctionNameForShape( - targetShapeOutput, codegenContext), - defaultWrappingError); + targetShapeOutput, codegenContext) + ); writer.addStdlibImport("standard_library.internaldafny.generated", "Wrappers"); }); } @@ -373,7 +377,6 @@ private void generateSmithyOperationFunctionDefinitionForResource( "if dafny_output.IsFailure():", "", () -> { - writer.addStdlibImport("asyncio"); // Import inline to avoid circular dependency writer.write( "from $L import $L as $L", @@ -389,7 +392,7 @@ private void generateSmithyOperationFunctionDefinitionForResource( targetShapeOutput.getId().getNamespace()) + "_deserialize_error"); writer.write( - "raise asyncio.run($L(dafny_output.error))", + "raise $L(dafny_output.error)", SmithyNameResolver.getServiceSmithygeneratedDirectoryNameForNamespace( targetShapeOutput.getId().getNamespace()) + "_deserialize_error"); diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceStructureGenerator.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceStructureGenerator.java index 0a06ed58b..b0b3cbfc2 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceStructureGenerator.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceStructureGenerator.java @@ -2,22 +2,20 @@ import static java.lang.String.format; -import java.time.ZonedDateTime; import java.util.Set; import software.amazon.polymorph.smithypython.common.nameresolver.SmithyNameResolver; import software.amazon.polymorph.traits.PositionalTrait; import software.amazon.polymorph.traits.ReferenceTrait; import software.amazon.polymorph.utils.ConstrainTraitUtils; +import software.amazon.polymorph.smithypython.localservice.ConstraintUtils; import software.amazon.smithy.codegen.core.Symbol; import software.amazon.smithy.codegen.core.SymbolProvider; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.knowledge.NullableIndex; -import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.*; -import software.amazon.smithy.python.codegen.CodegenUtils; import software.amazon.smithy.python.codegen.PythonSettings; import software.amazon.smithy.python.codegen.PythonWriter; import software.amazon.smithy.python.codegen.StructureGenerator; @@ -420,7 +418,7 @@ protected void writeFromDict(boolean isError) { * @param memberName */ protected void writeInitMethodAssignerForRequiredMember(MemberShape member, String memberName) { - writeInitMethodConstraintsChecksForMember(member, memberName); + ConstraintUtils.writeInitMethodConstraintsChecksForMember(writer, model, member, memberName); writer.write("self.$1L = $1L", memberName); } @@ -431,139 +429,8 @@ protected void writeInitMethodAssignerForRequiredMember(MemberShape member, Stri * @param memberName */ protected void writeInitMethodAssignerForOptionalMember(MemberShape member, String memberName) { - writeInitMethodConstraintsChecksForMember(member, memberName); + ConstraintUtils.writeInitMethodConstraintsChecksForMember(writer, model, member, memberName); writer.write( "self.$1L = $1L if $1L is not None else $2L", memberName, getDefaultValue(writer, member)); } - - /** - * Write checks for supported constraint traits. - * Currently, {@link RangeTrait} and {@link LengthTrait} are supported. - * @param member - * @param memberName - */ - protected void writeInitMethodConstraintsChecksForMember(MemberShape member, String memberName) { - // RangeTrait - Shape targetShape = model.expectShape(member.getTarget()); - if (targetShape.hasTrait(RangeTrait.class)) { - RangeTrait rangeTrait = targetShape.getTrait(RangeTrait.class).get(); - if (rangeTrait.getMin().isPresent()) { - writeRangeTraitMinCheckForMember(member, memberName, rangeTrait); - } - if (rangeTrait.getMax().isPresent()) { - writeRangeTraitMaxCheckForMember(member, memberName, rangeTrait); - } - } - - // LengthTrait - if (targetShape.hasTrait(LengthTrait.class)) { - LengthTrait lengthTrait = targetShape.getTrait(LengthTrait.class).get(); - if (lengthTrait.getMin().isPresent()) { - writeLengthTraitMinCheckForMember(memberName, lengthTrait); - } - if (lengthTrait.getMax().isPresent()) { - writeLengthTraitMaxCheckForMember(memberName, lengthTrait); - } - } - } - - /** - * Write validation for {@link LengthTrait} min value. Called from __init__. - * - * @param memberName - * @param lengthTrait - */ - protected void writeLengthTraitMinCheckForMember(String memberName, LengthTrait lengthTrait) { - String min = ConstrainTraitUtils.LengthTraitUtils.min(lengthTrait); - writer.openBlock( - "if ($1L is not None) and (len($1L) < $2L):", - "", - memberName, - min, - () -> { - writer.write( - """ - raise ValueError("The size of $1L must be greater than or equal to $2L") - """, - memberName, - min); - }); - } - - /** - * Write validation for {@link LengthTrait} max value. Called from __init__. - * - * @param memberName - * @param lengthTrait - */ - protected void writeLengthTraitMaxCheckForMember(String memberName, LengthTrait lengthTrait) { - String max = ConstrainTraitUtils.LengthTraitUtils.max(lengthTrait); - writer.openBlock( - "if ($1L is not None) and (len($1L) > $2L):", - "", - memberName, - max, - () -> { - writer.write( - """ - raise ValueError("The size of $1L must be less than or equal to $2L") - """, - memberName, - max); - }); - } - - /** - * Write validation for {@link RangeTrait} min value. Called from __init__. - * - * @param member - * @param memberName - * @param rangeTrait - */ - protected void writeRangeTraitMinCheckForMember( - MemberShape member, String memberName, RangeTrait rangeTrait) { - String min = - ConstrainTraitUtils.RangeTraitUtils.minAsShapeType( - model.expectShape(member.getTarget()), rangeTrait); - writer.openBlock( - "if ($1L is not None) and ($1L < $2L):", - "", - memberName, - min, - () -> { - writer.write( - """ - raise ValueError("$1L must be greater than or equal to $2L") - """, - memberName, - min); - }); - } - - /** - * Write validation for {@link RangeTrait} max value. Called from __init__. - * - * @param member - * @param memberName - * @param rangeTrait - */ - protected void writeRangeTraitMaxCheckForMember( - MemberShape member, String memberName, RangeTrait rangeTrait) { - String max = - ConstrainTraitUtils.RangeTraitUtils.maxAsShapeType( - model.expectShape(member.getTarget()), rangeTrait); - writer.openBlock( - "if ($1L is not None) and ($1L > $2L):", - "", - memberName, - max, - () -> { - writer.write( - """ - raise ValueError("$1L must be less than or equal to $2L") - """, - memberName, - max); - }); - } } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceUnionGenerator.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceUnionGenerator.java new file mode 100644 index 000000000..a9217953f --- /dev/null +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DafnyPythonLocalServiceUnionGenerator.java @@ -0,0 +1,31 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package software.amazon.polymorph.smithypython.localservice.extensions; + +import software.amazon.polymorph.smithypython.localservice.ConstraintUtils; +import software.amazon.smithy.codegen.core.SymbolProvider; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.MemberShape; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.UnionShape; +import software.amazon.smithy.python.codegen.PythonWriter; +import software.amazon.smithy.python.codegen.UnionGenerator; + +import java.util.Set; + +/** + * Extend Smithy-Python's UnionGenerator to write Constraint traits. + */ +public class DafnyPythonLocalServiceUnionGenerator extends UnionGenerator { + + public DafnyPythonLocalServiceUnionGenerator(Model model, SymbolProvider symbolProvider, PythonWriter writer, UnionShape shape, Set recursiveShapes) { + super(model, symbolProvider, writer, shape, recursiveShapes); + } + + @Override + protected void writeInitMethodConstraintsChecksForMember(MemberShape member, String memberName) { + // Smithy-Python UnionGenerator hardcodes "value" as union values + ConstraintUtils.writeInitMethodConstraintsChecksForMember(writer, model, member, "value"); + } +} + diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DirectedDafnyPythonLocalServiceCodegen.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DirectedDafnyPythonLocalServiceCodegen.java index 953869760..fe315e0bb 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DirectedDafnyPythonLocalServiceCodegen.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/localservice/extensions/DirectedDafnyPythonLocalServiceCodegen.java @@ -292,8 +292,8 @@ public void generateUnion(GenerateUnionDirective { - UnionGenerator generator = - new UnionGenerator( + DafnyPythonLocalServiceUnionGenerator generator = + new DafnyPythonLocalServiceUnionGenerator( directive.model(), directive.symbolProvider(), writer, diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/customize/ShimFileWriter.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/customize/ShimFileWriter.java index c0bf72632..57cf4b52c 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/customize/ShimFileWriter.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/customize/ShimFileWriter.java @@ -123,44 +123,39 @@ private void generateOperationsBlock( ShapeVisitorResolver.getToNativeShapeVisitorForShape( targetShapeInput, codegenContext, "input", writer)); + Shape targetShape = codegenContext.model().expectShape(operationShape.getOutputShape()); + // Generate code that converts the output from Smithy type to the corresponding Dafny + // type. + // This has a side effect of possibly writing transformation code at the writer's + // current position. + String output = + targetShape.accept( + ShapeVisitorResolver.getToDafnyShapeVisitorForShape( + targetShape, codegenContext, "smithy_client_response", writer)); + // Generate code that: // 1) "unwraps" the request (converts from the Dafny type to the Smithy type), // 2) calls Smithy client, // 3) wraps Smithy failures as Dafny failures writer.write( - """ - smithy_client_request: $L.$L = $L + """ try: + smithy_client_request: $L.$L = $L smithy_client_response = self._impl.$L(smithy_client_request) - except ServiceError as e: + return Wrappers.Result_Success($L) + except Exception as e: return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) - """, SmithyNameResolver.getSmithyGeneratedModelLocationForShape(inputShape, codegenContext), inputShape.getName(), input, - codegenContext.symbolProvider().toSymbol(operationShape).getName()); + codegenContext.symbolProvider().toSymbol(operationShape).getName(), + SmithyNameResolver.isUnitShape(outputShape) ? "None" : output + ); writer.addStdlibImport(SmithyNameResolver.getPythonModuleSmithygeneratedPathForSmithyNamespace( serviceShape.getId().getNamespace(), codegenContext.settings()) + ".errors", "_smithy_error_to_dafny_error"); - - Shape targetShape = codegenContext.model().expectShape(operationShape.getOutputShape()); - // Generate code that converts the output from Smithy type to the corresponding Dafny - // type. - // This has a side effect of possibly writing transformation code at the writer's - // current position. - String output = - targetShape.accept( - ShapeVisitorResolver.getToDafnyShapeVisitorForShape( - targetShape, codegenContext, "smithy_client_response", writer)); - - // Generate code that wraps Smithy success shapes as Dafny success shapes - writer.write( - """ - return Wrappers.Result_Success($L) - """, - SmithyNameResolver.isUnitShape(outputShape) ? "None" : output); - }); + }); } } } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/extensions/DafnyPythonWrappedLocalServiceSymbolVisitor.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/extensions/DafnyPythonWrappedLocalServiceSymbolVisitor.java index d44742517..f5ed51e3f 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/extensions/DafnyPythonWrappedLocalServiceSymbolVisitor.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/smithypython/wrappedlocalservice/extensions/DafnyPythonWrappedLocalServiceSymbolVisitor.java @@ -1,3 +1,6 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + package software.amazon.polymorph.smithypython.wrappedlocalservice.extensions; import static java.lang.String.format; diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/traits/DafnyAwsSdkProtocolTrait.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/traits/DafnyAwsSdkProtocolTrait.java index d6779d5ea..3b9606d3c 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/traits/DafnyAwsSdkProtocolTrait.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/traits/DafnyAwsSdkProtocolTrait.java @@ -59,7 +59,7 @@ public SmithyBuilder toBuilder() { return builder().sourceLocation(getSourceLocation()); } - /** Builder for {@link MutableLocalStateTrait}. */ + /** Builder for {@link DafnyAwsSdkProtocolTrait}. */ public static final class Builder extends AbstractTraitBuilder { @@ -72,6 +72,6 @@ public DafnyAwsSdkProtocolTrait build() { } public static Shape getDefinition() { - return StructureShape.builder().id(MutableLocalStateTrait.ID).build(); + return StructureShape.builder().id(DafnyAwsSdkProtocolTrait.ID).build(); } } diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/utils/ModelUtils.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/utils/ModelUtils.java index 381b76793..192fe036d 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/utils/ModelUtils.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/polymorph/utils/ModelUtils.java @@ -591,6 +591,71 @@ public static Model addMissingErrorMessageMembers(Model model) { ); } + /** + * Return a builder for the provided shape. + * @param shape + * @return + */ + public static AbstractShapeBuilder getBuilderForShape(Shape shape) { + // This is painful, but there is nothing like `shape.getUnderlyingShapeType`... + // instead, check every possible shape for its builder... + AbstractShapeBuilder builder; + if (shape.isBlobShape()) { + builder = shape.asBlobShape().get().toBuilder(); + } else if (shape.isBooleanShape()) { + builder = shape.asBooleanShape().get().toBuilder(); + } else if (shape.isDocumentShape()) { + builder = shape.asDocumentShape().get().toBuilder(); + } else if (shape.isStringShape()) { + builder = shape.asStringShape().get().toBuilder(); + } else if (shape.isTimestampShape()) { + builder = shape.asTimestampShape().get().toBuilder(); + } else if (shape.isByteShape()) { + builder = shape.asByteShape().get().toBuilder(); + } else if (shape.isIntegerShape()) { + builder = shape.asIntegerShape().get().toBuilder(); + } else if (shape.isFloatShape()) { + builder = shape.asFloatShape().get().toBuilder(); + } else if (shape.isBigIntegerShape()) { + builder = shape.asBigIntegerShape().get().toBuilder(); + } else if (shape.isShortShape()) { + builder = shape.asShortShape().get().toBuilder(); + } else if (shape.isLongShape()) { + builder = shape.asLongShape().get().toBuilder(); + } else if (shape.isDoubleShape()) { + builder = shape.asDoubleShape().get().toBuilder(); + } else if (shape.isBigDecimalShape()) { + builder = shape.asBigDecimalShape().get().toBuilder(); + } else if (shape.isListShape()) { + builder = shape.asListShape().get().toBuilder(); + } else if (shape.isSetShape()) { + builder = shape.asSetShape().get().toBuilder(); + } else if (shape.isMapShape()) { + builder = shape.asMapShape().get().toBuilder(); + } else if (shape.isStructureShape()) { + builder = shape.asStructureShape().get().toBuilder(); + } else if (shape.isUnionShape()) { + builder = shape.asUnionShape().get().toBuilder(); + } else if (shape.isServiceShape()) { + builder = shape.asServiceShape().get().toBuilder(); + } else if (shape.isOperationShape()) { + builder = shape.asOperationShape().get().toBuilder(); + } else if (shape.isResourceShape()) { + builder = shape.asResourceShape().get().toBuilder(); + } else if (shape.isMemberShape()) { + builder = shape.asMemberShape().get().toBuilder(); + } else if (shape.isEnumShape()) { + builder = shape.asEnumShape().get().toBuilder(); + } else if (shape.isIntEnumShape()) { + builder = shape.asIntEnumShape().get().toBuilder(); + } else { + // Unfortunately, there is no "default" shape... + // The above should cover all shapes; if not, new shapes need to be added above. + throw new IllegalArgumentException("Unable to process @javadoc trait on unsupported shape type: " + shape); + } + return builder; + } + public static Optional getDocumentationOrJavadoc(Shape shape) { return shape .getTrait(DocumentationTrait.class) diff --git a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/smithy/dafny/codegen/DafnyClientCodegenPluginSettings.java b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/smithy/dafny/codegen/DafnyClientCodegenPluginSettings.java index 872294dcf..5846518cc 100644 --- a/codegen/smithy-dafny-codegen/src/main/java/software/amazon/smithy/dafny/codegen/DafnyClientCodegenPluginSettings.java +++ b/codegen/smithy-dafny-codegen/src/main/java/software/amazon/smithy/dafny/codegen/DafnyClientCodegenPluginSettings.java @@ -102,6 +102,7 @@ static Optional fromObject( case "DOTNET", "CSHARP", "CS" -> Stream.of( CodegenEngine.TargetLanguage.DOTNET ); + case "PYTHON" -> Stream.of(CodegenEngine.TargetLanguage.PYTHON); case "DAFNY" -> { LOGGER.error( "Dafny code is always generated, and shouldn't be specified explicitly" diff --git a/codegen/smithy-dafny-codegen/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integration.PythonIntegration b/codegen/smithy-dafny-codegen/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integration.PythonIntegration new file mode 100644 index 000000000..4877aa10e --- /dev/null +++ b/codegen/smithy-dafny-codegen/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integration.PythonIntegration @@ -0,0 +1,8 @@ +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +software.amazon.polymorph.smithypython.localservice.DafnyPythonLocalServiceIntegration +software.amazon.polymorph.smithypython.wrappedlocalservice.DafnyPythonWrappedLocalServiceIntegration +software.amazon.polymorph.smithypython.awssdk.DafnyPythonAwsSdkIntegration \ No newline at end of file