-
Notifications
You must be signed in to change notification settings - Fork 180
/
PythonServerCodegenVisitor.kt
177 lines (160 loc) · 7.44 KB
/
PythonServerCodegenVisitor.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
* 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
import software.amazon.smithy.build.PluginContext
import software.amazon.smithy.codegen.core.CodegenException
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.knowledge.NullableIndex
import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.model.shapes.StringShape
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.model.shapes.UnionShape
import software.amazon.smithy.model.traits.EnumTrait
import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig
import software.amazon.smithy.rust.codegen.server.python.smithy.generators.PythonServerEnumGenerator
import software.amazon.smithy.rust.codegen.server.python.smithy.generators.PythonServerOperationHandlerGenerator
import software.amazon.smithy.rust.codegen.server.python.smithy.generators.PythonServerServiceGenerator
import software.amazon.smithy.rust.codegen.server.python.smithy.generators.PythonServerStructureGenerator
import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext
import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenVisitor
import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders
import software.amazon.smithy.rust.codegen.server.smithy.customize.ServerCodegenDecorator
import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol
import software.amazon.smithy.rust.codegen.server.smithy.protocols.ServerProtocolLoader
/**
* Entrypoint for Python server-side code generation. This class will walk the in-memory model and
* generate all the needed types by calling the accept() function on the available shapes.
*
* This class inherits from [ServerCodegenVisitor] since it uses most of the functionalities of the super class
* and have to override the symbol provider with [PythonServerSymbolProvider].
*/
class PythonServerCodegenVisitor(
context: PluginContext,
codegenDecorator: ServerCodegenDecorator,
) : ServerCodegenVisitor(context, codegenDecorator) {
init {
val symbolVisitorConfig =
SymbolVisitorConfig(
runtimeConfig = settings.runtimeConfig,
renameExceptions = false,
nullabilityCheckMode = NullableIndex.CheckMode.SERVER,
)
val baseModel = baselineTransform(context.model)
val service = settings.getService(baseModel)
val (protocol, generator) =
ServerProtocolLoader(
codegenDecorator.protocols(
service.id,
ServerProtocolLoader.DefaultProtocols,
),
)
.protocolFor(context.model, service)
protocolGeneratorFactory = generator
model = codegenDecorator.transformModel(service, baseModel)
// `publicConstrainedTypes` must always be `false` for the Python server, since Python generates its own
// wrapper newtypes.
settings = settings.copy(codegenConfig = settings.codegenConfig.copy(publicConstrainedTypes = false))
fun baseSymbolProviderFactory(
model: Model,
serviceShape: ServiceShape,
symbolVisitorConfig: SymbolVisitorConfig,
publicConstrainedTypes: Boolean,
) = PythonCodegenServerPlugin.baseSymbolProvider(model, serviceShape, symbolVisitorConfig, publicConstrainedTypes)
val serverSymbolProviders = ServerSymbolProviders.from(
model,
service,
symbolVisitorConfig,
settings.codegenConfig.publicConstrainedTypes,
::baseSymbolProviderFactory,
)
// Override `codegenContext` which carries the various symbol providers.
codegenContext =
ServerCodegenContext(
model,
serverSymbolProviders.symbolProvider,
service,
protocol,
settings,
serverSymbolProviders.unconstrainedShapeSymbolProvider,
serverSymbolProviders.constrainedShapeSymbolProvider,
serverSymbolProviders.constraintViolationSymbolProvider,
serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider,
)
// Override `rustCrate` which carries the symbolProvider.
rustCrate = RustCrate(context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig)
// Override `protocolGenerator` which carries the symbolProvider.
protocolGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext)
}
/**
* Structure Shape Visitor
*
* For each structure shape, generate:
* - A Rust structure for the shape ([StructureGenerator]).
* - `pyo3::PyClass` trait implementation.
* - A builder for the shape.
*
* This function _does not_ generate any serializers.
*/
override fun structureShape(shape: StructureShape) {
logger.info("[python-server-codegen] Generating a structure $shape")
rustCrate.useShapeWriter(shape) {
// Use Python specific structure generator that adds the #[pyclass] attribute
// and #[pymethods] implementation.
PythonServerStructureGenerator(model, codegenContext.symbolProvider, this, shape).render(CodegenTarget.SERVER)
renderStructureShapeBuilder(shape, this)
}
}
/**
* String Shape Visitor
*
* Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes.
*/
override fun stringShape(shape: StringShape) {
fun pythonServerEnumGeneratorFactory(codegenContext: ServerCodegenContext, writer: RustWriter, shape: StringShape) =
PythonServerEnumGenerator(codegenContext, writer, shape)
stringShape(shape, ::pythonServerEnumGeneratorFactory)
}
/**
* Union Shape Visitor
*
* Generate an `enum` for union shapes.
*
* Note: this does not generate serializers
*/
override fun unionShape(shape: UnionShape) {
throw CodegenException("Union shapes are not supported in Python yet")
}
/**
* Generate service-specific code for the model:
* - Serializers
* - Deserializers
* - Trait implementations
* - Protocol tests
* - Operation structures
* - Python operation handlers
*/
override fun serviceShape(shape: ServiceShape) {
logger.info("[python-server-codegen] Generating a service $shape")
PythonServerServiceGenerator(
rustCrate,
protocolGenerator,
protocolGeneratorFactory.support(),
protocolGeneratorFactory.protocol(codegenContext) as ServerProtocol,
codegenContext,
)
.render()
}
override fun operationShape(shape: OperationShape) {
super.operationShape(shape)
rustCrate.withModule(RustModule.public("python_operation_adaptor")) {
PythonServerOperationHandlerGenerator(codegenContext, shape).render(this)
}
}
}