Skip to content

Commit

Permalink
Merge branch 'robin-aws/support-dependencies-on-rust' of github.com:s…
Browse files Browse the repository at this point in the history
…mithy-lang/smithy-dafny into robin-aws/support-dependencies-on-rust
  • Loading branch information
robin-aws committed Oct 7, 2024
2 parents 4abccec + 1be466d commit a70f30c
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 30 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ format_java_misc-check: setup_prettier
setup_prettier:
npm i --no-save prettier@3 [email protected]

# Install packages via `python3 -m pip`,
# which is the syntax Smithy-Python and Smithy-Dafny Python use
# to invoke these packages.
# This helps ensure these packages are installed to the correct Python installation.
setup_smithy_dafny_python:
python3 -m pip install docformatter black

setup_python: setup_smithy_dafny_python
setup_python:
python3 -m pip install poetry

mvn_local_deploy_polymorph_dependencies: mvn_local_deploy_polymorph_rust_dependencies mvn_local_deploy_polymorph_python_dependencies

mvn_local_deploy_polymorph_rust_dependencies:
Expand Down
11 changes: 11 additions & 0 deletions SmithyDafnyMakefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,17 @@ clean: _clean

########################## Python targets

# Install packages via `python3 -m pip`,
# which is the syntax Smithy-Python and Smithy-Dafny Python use
# to invoke these packages.
# This helps ensure these packages are installed to the correct Python installation.
setup_smithy_dafny_python:
python3 -m pip install docformatter black

setup_python: setup_smithy_dafny_python
setup_python:
python3 -m pip install poetry

net: polymorph_dafny transpile_python polymorph_python test_python

# Python MUST transpile dependencies first to generate .dtr files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
public class UnionGenerator implements Runnable {

protected final Model model;
private final SymbolProvider symbolProvider;
protected final SymbolProvider symbolProvider;
protected final PythonWriter writer;
private final UnionShape shape;
private final Set<Shape> recursiveShapes;
Expand Down Expand Up @@ -68,6 +68,26 @@ protected void writeInitMethodForMember(MemberShape member, Symbol memberSymbol,
});
}

protected void writeFromDictMethod(MemberShape member, Symbol memberSymbol, Shape target, Symbol targetSymbol) {
writer.write("@staticmethod");
writer.openBlock("def from_dict(d: Dict[str, Any]) -> $S:", "", memberSymbol.getName(), () -> {
writer.write("""
if (len(d) != 1):
raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}")
""");
if (target.isStructureShape()) {
writer.write("return $T($T.from_dict(d[$S]))", memberSymbol, targetSymbol,
member.getMemberName());
} else if (targetSymbol.getProperty("fromDict").isPresent()) {
var targetFromDictSymbol = targetSymbol.expectProperty("fromDict", Symbol.class);
writer.write("return $T($T(d[$S]))",
memberSymbol, targetFromDictSymbol, member.getMemberName());
} else {
writer.write("return $T(d[$S])", memberSymbol, member.getMemberName());
}
});
}

@Override
public void run() {
var parentName = symbolProvider.toSymbol(shape).getName();
Expand Down Expand Up @@ -100,23 +120,7 @@ public void run() {
}
});

writer.write("@staticmethod");
writer.openBlock("def from_dict(d: Dict[str, Any]) -> $S:", "", memberSymbol.getName(), () -> {
writer.write("""
if (len(d) != 1):
raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}")
""");
if (target.isStructureShape()) {
writer.write("return $T($T.from_dict(d[$S]))", memberSymbol, targetSymbol,
member.getMemberName());
} else if (targetSymbol.getProperty("fromDict").isPresent()) {
var targetFromDictSymbol = targetSymbol.expectProperty("fromDict", Symbol.class);
writer.write("return $T($T(d[$S]))",
memberSymbol, targetFromDictSymbol, member.getMemberName());
} else {
writer.write("return $T(d[$S])", memberSymbol, member.getMemberName());
}
});
writeFromDictMethod(member, memberSymbol, target, targetSymbol);

writer.write("""
def __repr__(self) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class PythonTestModels extends TestModelTest {

@ParameterizedTest
@MethodSource("discoverTestModels")
void testModelsForJava(String relativeTestModelPath) {
void testModelsForPython(String relativeTestModelPath) {
Assumptions.assumeFalse(DISABLED_TESTS.contains(relativeTestModelPath));

Path testModelPath = getTestModelPath(relativeTestModelPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,17 +365,6 @@ private void generateNativeWrapperFunctionDefinitionForResource(
.expectShape(codegenContext.settings().getService())
.asServiceShape()
.get();
List<ShapeId> serviceDependencyErrors = serviceShape.getErrors();
// Services don't specify a "default" error.
// Pick the first one off its list of errors.
// Crypto Tools currently only specifies one error per service, so this works perfectly, but may not
// extend well.
// This will need to be updated.
if (serviceDependencyErrors.size() > 1) {
throw new IllegalArgumentException(
"Only 1 service-modelled error per service supported"
);
}

writer.addStdlibImport(
SmithyNameResolver.getPythonModuleSmithygeneratedPathForSmithyNamespace(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
package software.amazon.polymorph.smithypython.localservice.extensions;

import static java.lang.String.format;

import java.util.Set;
import software.amazon.polymorph.smithypython.localservice.ConstraintUtils;
import software.amazon.polymorph.traits.ReferenceTrait;
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.shapes.MemberShape;
Expand Down Expand Up @@ -40,4 +44,134 @@ protected void writeInitMethodConstraintsChecksForMember(
"value"
);
}

/**
* Override Smithy-Python writeFromDictMethod to handle members with {@code ReferenceTrait.class}.
* @param member
* @param memberSymbol
* @param target
* @param targetSymbol
*/
@Override
protected void writeFromDictMethod(
MemberShape member,
Symbol memberSymbol,
Shape target,
Symbol targetSymbol
) {
writer.write("@staticmethod");
writer.openBlock(
"def from_dict(d: Dict[str, Any]) -> $S:",
"",
memberSymbol.getName(),
() -> {
// Block below is changed from Smithy-Python.
// Import any modules required for reference shapes to convert from_dict.
// Import within function to avoid circular imports from top-level imports
if (target.hasTrait(ReferenceTrait.class)) {
writer.write(
"from $L import $L",
targetSymbol.getNamespace(),
targetSymbol.getName()
);
}

writer.write(
"""
if (len(d) != 1):
raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}")
"""
);

// Block below is changed from Smithy-Python.
// If shape has ReferenceTrait, write it as literal;
// it has been imported within the context of the function.
// Else, write as Smithy-Python default: $T.
String targetSymbolFormat = target.hasTrait(ReferenceTrait.class)
? "$L"
: "$T";
var targetSymbolValue = target.hasTrait(ReferenceTrait.class)
? targetSymbol.getName()
: targetSymbol;

if (target.isStructureShape()) {
writer.write(
format("return $T(%s.from_dict(d[$S]))", targetSymbolFormat),
memberSymbol,
targetSymbolValue,
member.getMemberName()
);
} else if (targetSymbol.getProperty("fromDict").isPresent()) {
var targetFromDictSymbol = targetSymbol.expectProperty(
"fromDict",
Symbol.class
);
writer.write(
"return $T($T(d[$S]))",
memberSymbol,
targetFromDictSymbol,
member.getMemberName()
);
} else {
writer.write(
"return $T(d[$S])",
memberSymbol,
member.getMemberName()
);
}
}
);
}

/**
* If a Union member has {@code ReferenceTrait.class}, handle it here.
* Otherwise, defer to Smithy-Python writeInitMethodForMember.
* @param member
* @param memberSymbol
* @param targetShape
* @param targetSymbol
*/
@Override
protected void writeInitMethodForMember(
MemberShape member,
Symbol memberSymbol,
Shape targetShape,
Symbol targetSymbol
) {
// Override Smithy-Python to handle shapes with ReferenceTraits
if (targetShape.hasTrait(ReferenceTrait.class)) {
Shape referentShape = model.expectShape(
targetShape.expectTrait(ReferenceTrait.class).getReferentId()
);

// Use forward reference for reference traits to avoid circular import
String memberType =
symbolProvider.toSymbol(referentShape).getNamespace() +
"." +
symbolProvider.toSymbol(referentShape).getName();

String formatString = format(
"def __init__(self, value: '%s'):",
memberType
);
writer.openBlock(
formatString,
"",
() -> {
writeInitMethodConstraintsChecksForMember(
member,
memberSymbol.getName()
);
writer.write("self.value = value");
}
);
} else {
super.writeInitMethodForMember(
member,
memberSymbol,
targetShape,
targetSymbol
);
}
}
}

0 comments on commit a70f30c

Please sign in to comment.