-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add initial implementation of unions with very broken symbol provider * Add support for creating new unions in Python * Generate getters and static methods for unions * Allow to compile misc model Signed-off-by: Bigo <1781140+crisidev@users.noreply.github.com> * Doesn't work * Now it works * Simplify code a little * Remove leftover from the many tries I did * Finally fixed model generation with unions * Fix wrong import * Update to reflect changes in decorators * Remove debugging output * Simplify symbol provider * Follow PR suggestions * Remove union operation from python example * Return `PyUnionMarker` for wrapped type in `IntoPy` impl --------- Signed-off-by: Bigo <1781140+crisidev@users.noreply.github.com> Co-authored-by: Burak Varlı <burakvar@amazon.co.uk>
- release-2025-03-04
- release-2025-02-20
- release-2025-02-12
- release-2025-02-03
- release-2025-01-28
- release-2025-01-23
- release-2025-01-17
- release-2025-01-14
- release-2024-12-30
- release-2024-12-26
- release-2024-12-16
- release-2024-12-03
- release-2024-11-05
- release-2024-10-30
- release-2024-10-24
- release-2024-10-09
- release-2024-10-05
- release-2024-10-04
- release-2024-10-03
- release-2024-09-26
- release-2024-09-17
- release-2024-09-09
- release-2024-08-28
- release-2024-08-16
- release-2024-08-14
- release-2024-08-08
- release-2024-07-16
- release-2024-07-09
- release-2024-07-03
- release-2024-06-19
- release-2024-06-17
- release-2024-06-12
- release-2024-06-10
- release-2024-06-03
- release-2024-05-28
- release-2024-05-22
- release-2024-05-21
- release-2024-05-08
- release-2024-04-30
- release-2024-04-19
- release-2024-04-11
- release-2024-04-02
- release-2024-03-25
- release-2024-03-12
- release-2024-02-22
- release-2024-02-15
- release-2024-02-08
- release-2024-01-24
- release-2024-01-18
- release-2024-01-10
- release-2023-12-13
- release-2023-12-11
- release-2023-12-08
- release-2023-12-01
- release-2023-11-27
- release-2023-11-26
- release-2023-11-25
- release-2023-11-21
- release-2023-11-17
- release-2023-11-16
- release-2023-11-15
- release-2023-11-14
- release-2023-11-01
- release-2023-10-31
- release-2023-08-22
- release-2023-08-01
- release-2023-05-23
- release-2023-04-26
- release-2023-04-11
- release-2023-03-23
Showing
15 changed files
with
338 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,3 +50,9 @@ target/ | |
|
||
# IDEs | ||
.idea/ | ||
.project | ||
.settings | ||
.classpath | ||
|
||
# tools | ||
.tool-versions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
198 changes: 198 additions & 0 deletions
198
.../amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerUnionGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.rust.codegen.server.python.smithy.generators | ||
|
||
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 | ||
import software.amazon.smithy.model.shapes.UnionShape | ||
import software.amazon.smithy.rust.codegen.core.rustlang.Attribute | ||
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter | ||
import software.amazon.smithy.rust.codegen.core.rustlang.isCopy | ||
import software.amazon.smithy.rust.codegen.core.rustlang.render | ||
import software.amazon.smithy.rust.codegen.core.rustlang.rust | ||
import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock | ||
import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate | ||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate | ||
import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata | ||
import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator | ||
import software.amazon.smithy.rust.codegen.core.smithy.rustType | ||
import software.amazon.smithy.rust.codegen.core.util.isTargetUnit | ||
import software.amazon.smithy.rust.codegen.core.util.toSnakeCase | ||
import software.amazon.smithy.rust.codegen.server.python.smithy.PythonServerCargoDependency | ||
import software.amazon.smithy.rust.codegen.server.python.smithy.pythonType | ||
import software.amazon.smithy.rust.codegen.server.python.smithy.renderAsDocstring | ||
|
||
/* | ||
* Generate unions that are compatible with Python by wrapping the Rust implementation into | ||
* a new structure and implementing `IntoPy` and `FromPyObject` to ensure the ability to extract | ||
* the union inside the Python context. | ||
*/ | ||
class PythonServerUnionGenerator( | ||
model: Model, | ||
private val symbolProvider: SymbolProvider, | ||
private val writer: RustWriter, | ||
shape: UnionShape, | ||
private val renderUnknownVariant: Boolean = true, | ||
) : UnionGenerator(model, symbolProvider, writer, shape, renderUnknownVariant) { | ||
private val sortedMembers: List<MemberShape> = shape.allMembers.values.sortedBy { symbolProvider.toMemberName(it) } | ||
private val unionSymbol = symbolProvider.toSymbol(shape) | ||
|
||
private val pyo3 = PythonServerCargoDependency.PyO3.toType() | ||
|
||
override fun render() { | ||
super.render() | ||
renderPyUnionStruct() | ||
renderPyUnionImpl() | ||
renderPyObjectConverters() | ||
} | ||
|
||
private fun renderPyUnionStruct() { | ||
writer.rust("""##[pyo3::pyclass(name = "${unionSymbol.name}")]""") | ||
val containerMeta = unionSymbol.expectRustMetadata() | ||
containerMeta.render(writer) | ||
writer.rust("struct PyUnionMarker${unionSymbol.name}(pub ${unionSymbol.name});") | ||
} | ||
|
||
private fun renderPyUnionImpl() { | ||
Attribute(pyo3.resolve("pymethods")).render(writer) | ||
writer.rustBlock("impl PyUnionMarker${unionSymbol.name}") { | ||
sortedMembers.forEach { member -> | ||
val funcNamePart = member.memberName.toSnakeCase() | ||
val variantName = symbolProvider.toMemberName(member) | ||
|
||
if (sortedMembers.size == 1) { | ||
Attribute.AllowIrrefutableLetPatterns.render(this) | ||
} | ||
renderNewVariant(writer, model, symbolProvider, member, variantName, funcNamePart, unionSymbol) | ||
renderAsVariant(writer, model, symbolProvider, member, variantName, funcNamePart, unionSymbol) | ||
rust("/// Returns true if this is a [`$variantName`](#T::$variantName).", unionSymbol) | ||
rust("/// :rtype bool:") | ||
rustBlock("pub fn is_$funcNamePart(&self) -> bool") { | ||
rust("self.0.is_$funcNamePart()") | ||
} | ||
} | ||
if (renderUnknownVariant) { | ||
rust("/// Returns true if the union instance is the `Unknown` variant.") | ||
rust("/// :rtype bool:") | ||
rustBlock("pub fn is_unknown(&self) -> bool") { | ||
rust("self.0.is_unknown()") | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun renderPyObjectConverters() { | ||
writer.rustBlockTemplate("impl #{pyo3}::IntoPy<#{pyo3}::PyObject> for ${unionSymbol.name}", "pyo3" to pyo3) { | ||
rustBlockTemplate("fn into_py(self, py: #{pyo3}::Python<'_>) -> #{pyo3}::PyObject", "pyo3" to pyo3) { | ||
rust("PyUnionMarker${unionSymbol.name}(self).into_py(py)") | ||
} | ||
} | ||
writer.rustBlockTemplate("impl<'source> #{pyo3}::FromPyObject<'source> for ${unionSymbol.name}", "pyo3" to pyo3) { | ||
rustBlockTemplate("fn extract(obj: &'source #{pyo3}::PyAny) -> #{pyo3}::PyResult<Self>", "pyo3" to pyo3) { | ||
rust( | ||
""" | ||
let data: PyUnionMarker${unionSymbol.name} = obj.extract()?; | ||
Ok(data.0) | ||
""", | ||
) | ||
} | ||
} | ||
} | ||
|
||
private fun renderNewVariant( | ||
writer: RustWriter, | ||
model: Model, | ||
symbolProvider: SymbolProvider, | ||
member: MemberShape, | ||
variantName: String, | ||
funcNamePart: String, | ||
unionSymbol: Symbol, | ||
) { | ||
if (member.isTargetUnit()) { | ||
Attribute("staticmethod").render(writer) | ||
writer.rust( | ||
"/// Creates a new union instance of [`$variantName`](#T::$variantName)", | ||
unionSymbol, | ||
) | ||
writer.rust("/// :rtype ${unionSymbol.name}:") | ||
writer.rustBlock("pub fn $funcNamePart() -> Self") { | ||
rust("Self(${unionSymbol.name}::$variantName") | ||
} | ||
} else { | ||
val memberSymbol = symbolProvider.toSymbol(member) | ||
val pythonType = memberSymbol.rustType().pythonType() | ||
val targetType = memberSymbol.rustType() | ||
Attribute("staticmethod").render(writer) | ||
writer.rust( | ||
"/// Creates a new union instance of [`$variantName`](#T::$variantName)", | ||
unionSymbol, | ||
) | ||
writer.rust("/// :param data ${pythonType.renderAsDocstring()}:") | ||
writer.rust("/// :rtype ${unionSymbol.name}:") | ||
writer.rustBlock("pub fn $funcNamePart(data: ${targetType.render()}) -> Self") { | ||
rust("Self(${unionSymbol.name}::$variantName(data))") | ||
} | ||
} | ||
} | ||
|
||
private fun renderAsVariant( | ||
writer: RustWriter, | ||
model: Model, | ||
symbolProvider: SymbolProvider, | ||
member: MemberShape, | ||
variantName: String, | ||
funcNamePart: String, | ||
unionSymbol: Symbol, | ||
) { | ||
if (member.isTargetUnit()) { | ||
writer.rust( | ||
"/// Tries to convert the union instance into [`$variantName`].", | ||
) | ||
writer.rust("/// :rtype None:") | ||
writer.rustBlockTemplate("pub fn as_$funcNamePart(&self) -> #{pyo3}::PyResult<()>", "pyo3" to pyo3) { | ||
rustTemplate( | ||
""" | ||
self.0.as_$funcNamePart().map_err(#{pyo3}::exceptions::PyValueError::new_err( | ||
"${unionSymbol.name} variant is not None" | ||
)) | ||
""", | ||
"pyo3" to pyo3, | ||
) | ||
} | ||
} else { | ||
val memberSymbol = symbolProvider.toSymbol(member) | ||
val pythonType = memberSymbol.rustType().pythonType() | ||
val targetSymbol = symbolProvider.toSymbol(model.expectShape(member.target)) | ||
val rustType = memberSymbol.rustType() | ||
writer.rust( | ||
"/// Tries to convert the enum instance into [`$variantName`](#T::$variantName), extracting the inner #D.", | ||
unionSymbol, | ||
targetSymbol, | ||
) | ||
writer.rust("/// :rtype ${pythonType.renderAsDocstring()}:") | ||
writer.rustBlockTemplate("pub fn as_$funcNamePart(&self) -> #{pyo3}::PyResult<${rustType.render()}>", "pyo3" to pyo3) { | ||
val variantType = if (rustType.isCopy()) { | ||
"*variant" | ||
} else { | ||
"variant.clone()" | ||
} | ||
rustTemplate( | ||
""" | ||
match self.0.as_$funcNamePart() { | ||
Ok(variant) => Ok($variantType), | ||
Err(_) => Err(#{pyo3}::exceptions::PyValueError::new_err( | ||
"${unionSymbol.name} variant is not of type ${memberSymbol.rustType().pythonType().renderAsDocstring()}" | ||
)), | ||
} | ||
""", | ||
"pyo3" to pyo3, | ||
) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pokemon-service-client/ | ||
pokemon-service-server-sdk/ | ||
wheels/ | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters