Skip to content

Commit 588c3f2

Browse files
Replace code generated request pipeline
This replaces the code generated request pipeline with the hand-written one.
1 parent aca3623 commit 588c3f2

19 files changed

+158
-3490
lines changed

codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java

Lines changed: 77 additions & 730 deletions
Large diffs are not rendered by default.

codegen/core/src/main/java/software/amazon/smithy/python/codegen/DirectedPythonClientCodegen.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,6 @@ public void generateService(GenerateServiceDirective<GenerationContext, PythonSe
124124
if (protocolGenerator == null) {
125125
return;
126126
}
127-
128-
protocolGenerator.generateSharedSerializerComponents(directive.context());
129-
protocolGenerator.generateRequestSerializers(directive.context());
130-
131-
protocolGenerator.generateSharedDeserializerComponents(directive.context());
132-
protocolGenerator.generateResponseDeserializers(directive.context());
133-
134127
protocolGenerator.generateProtocolTests(directive.context());
135128
}
136129

codegen/core/src/main/java/software/amazon/smithy/python/codegen/HttpProtocolTestGenerator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ private void generateRequestTest(OperationShape operation, HttpRequestTestCase t
184184
writer.write("""
185185
config = $T(
186186
endpoint_uri="https://$L/$L",
187-
http_client = $T(),
187+
transport = $T(),
188188
retry_strategy=SimpleRetryStrategy(max_attempts=1),
189189
)
190190
""",
@@ -430,7 +430,7 @@ private void generateResponseTest(OperationShape operation, HttpResponseTestCase
430430
writer.write("""
431431
config = $T(
432432
endpoint_uri="https://example.com",
433-
http_client = $T(
433+
transport = $T(
434434
status=$L,
435435
headers=$J,
436436
body=b$S,
@@ -483,7 +483,7 @@ private void generateErrorResponseTest(
483483
writer.write("""
484484
config = $T(
485485
endpoint_uri="https://example.com",
486-
http_client = $T(
486+
transport = $T(
487487
status=$L,
488488
headers=$J,
489489
body=b$S,

codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ public final class SmithyPythonDependency {
7373
Type.DEPENDENCY,
7474
false);
7575

76+
/**
77+
* Smithy core functionality for AWS.
78+
*/
79+
public static final PythonDependency SMITHY_AWS_CORE = new PythonDependency(
80+
"smithy_aws_core",
81+
"<0.1.0",
82+
Type.DEPENDENCY,
83+
false);
84+
7685
/**
7786
* testing framework used in generated functional tests.
7887
*/

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ConfigGenerator.java

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -117,38 +117,58 @@ public ConfigGenerator(PythonSettings settings, GenerationContext context) {
117117
this.settings = settings;
118118
}
119119

120-
private static List<ConfigProperty> getHttpProperties(GenerationContext context) {
121-
var properties = new ArrayList<ConfigProperty>(HTTP_PROPERTIES.size() + 2);
122-
var clientBuilder = ConfigProperty.builder()
123-
.name("http_client")
120+
private static List<ConfigProperty> getProtocolProperties(GenerationContext context) {
121+
var properties = new ArrayList<ConfigProperty>();
122+
var protocolBuilder = ConfigProperty.builder()
123+
.name("protocol")
124124
.type(Symbol.builder()
125-
.name("HTTPClient")
126-
.namespace("smithy_http.aio.interfaces", ".")
127-
.addDependency(SmithyPythonDependency.SMITHY_HTTP)
125+
.name("ClientProtocol[Any, Any]")
126+
.addReference(Symbol.builder()
127+
.name("ClientProtocol")
128+
.namespace("smithy_core.aio.interfaces", ".")
129+
.build())
130+
.build())
131+
.documentation("The protocol to serialize and deserialize requests with.")
132+
.initialize(w -> {
133+
w.write("self.protocol = protocol or $T()",
134+
context.protocolGenerator().getProtocolSymbol(context));
135+
});
136+
137+
var transportBuilder = ConfigProperty.builder()
138+
.name("transport")
139+
.type(Symbol.builder()
140+
.name("ClientTransport[Any, Any]")
141+
.addReference(Symbol.builder()
142+
.name("ClientTransport")
143+
.namespace("smithy_core.aio.interfaces", ".")
144+
.build())
128145
.build())
129-
.documentation("The HTTP client used to make requests.")
130-
.nullable(false);
146+
.documentation("The transport to use to send requests (e.g. an HTTP client).");
131147

132-
if (usesHttp2(context)) {
133-
clientBuilder
134-
.initialize(writer -> {
135-
writer.addDependency(SmithyPythonDependency.SMITHY_HTTP.withOptionalDependencies("awscrt"));
136-
writer.addImport("smithy_http.aio.crt", "AWSCRTHTTPClient");
137-
writer.write("self.http_client = http_client or AWSCRTHTTPClient()");
138-
});
148+
if (context.applicationProtocol().isHttpProtocol()) {
149+
properties.addAll(HTTP_PROPERTIES);
150+
if (usesHttp2(context)) {
151+
transportBuilder
152+
.initialize(writer -> {
153+
writer.addDependency(SmithyPythonDependency.SMITHY_HTTP.withOptionalDependencies("awscrt"));
154+
writer.addImport("smithy_http.aio.crt", "AWSCRTHTTPClient");
155+
writer.write("self.transport = transport or AWSCRTHTTPClient()");
156+
});
139157

140-
} else {
141-
clientBuilder
142-
.initialize(writer -> {
143-
writer.addDependency(SmithyPythonDependency.SMITHY_HTTP.withOptionalDependencies("aiohttp"));
144-
writer.addImport("smithy_http.aio.aiohttp", "AIOHTTPClient");
145-
writer.write("self.http_client = http_client or AIOHTTPClient()");
146-
});
158+
} else {
159+
transportBuilder
160+
.initialize(writer -> {
161+
writer.addDependency(
162+
SmithyPythonDependency.SMITHY_HTTP.withOptionalDependencies("aiohttp"));
163+
writer.addImport("smithy_http.aio.aiohttp", "AIOHTTPClient");
164+
writer.write("self.transport = transport or AIOHTTPClient()");
165+
});
166+
}
147167
}
148-
properties.add(clientBuilder.build());
149168

150-
properties.addAll(HTTP_PROPERTIES);
151-
return List.copyOf(properties);
169+
properties.add(protocolBuilder.build());
170+
properties.add(transportBuilder.build());
171+
return properties;
152172
}
153173

154174
private static boolean usesHttp2(GenerationContext context) {
@@ -289,6 +309,7 @@ private void generateConfig(GenerationContext context, PythonWriter writer) {
289309
// Initialize a set of config properties with our base properties.
290310
var properties = new TreeSet<>(Comparator.comparing(ConfigProperty::name));
291311
properties.addAll(BASE_PROPERTIES);
312+
properties.addAll(getProtocolProperties(context));
292313

293314
// Add in auth configuration if the service supports auth.
294315
var serviceIndex = ServiceIndex.of(context.model());
@@ -297,13 +318,6 @@ private void generateConfig(GenerationContext context, PythonWriter writer) {
297318
writer.onSection(new AddAuthHelper());
298319
}
299320

300-
// Smithy is transport agnostic, so we don't add http-related properties by default.
301-
// Nevertheless, HTTP is the most common use case so we standardize those settings
302-
// and add them in if the protocol is going to need them.
303-
if (context.applicationProtocol().isHttpProtocol()) {
304-
properties.addAll(getHttpProperties(context));
305-
}
306-
307321
var model = context.model();
308322
var service = context.settings().service(model);
309323

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/MemberSerializerGenerator.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import software.amazon.smithy.model.shapes.StructureShape;
3030
import software.amazon.smithy.model.shapes.TimestampShape;
3131
import software.amazon.smithy.model.shapes.UnionShape;
32+
import software.amazon.smithy.model.traits.StreamingTrait;
3233
import software.amazon.smithy.python.codegen.GenerationContext;
3334
import software.amazon.smithy.python.codegen.SymbolProperties;
3435
import software.amazon.smithy.python.codegen.writer.PythonWriter;
@@ -107,7 +108,11 @@ private void writeSchema() {
107108

108109
@Override
109110
public Void blobShape(BlobShape shape) {
110-
writeSerializer(shape);
111+
if (shape.hasTrait(StreamingTrait.class)) {
112+
writeSerializer("data_stream");
113+
} else {
114+
writeSerializer(shape);
115+
}
111116
return null;
112117
}
113118

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ProtocolGenerator.java

Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,10 @@
44
*/
55
package software.amazon.smithy.python.codegen.generators;
66

7-
import static java.lang.String.format;
8-
97
import software.amazon.smithy.codegen.core.Symbol;
108
import software.amazon.smithy.model.shapes.ShapeId;
11-
import software.amazon.smithy.model.shapes.ToShapeId;
129
import software.amazon.smithy.python.codegen.ApplicationProtocol;
1310
import software.amazon.smithy.python.codegen.GenerationContext;
14-
import software.amazon.smithy.python.codegen.writer.PythonWriter;
15-
import software.amazon.smithy.utils.CaseUtils;
1611
import software.amazon.smithy.utils.SmithyUnstableApi;
1712

1813
/**
@@ -46,115 +41,12 @@ default String getName() {
4641
*/
4742
ApplicationProtocol getApplicationProtocol(GenerationContext context);
4843

49-
/**
50-
* Generates the name of a serializer function for shapes of a service that is not protocol-specific.
51-
*
52-
* @param context The code generation context.
53-
* @param shapeId The shape the serializer function is being generated for.
54-
* @return Returns the generated function name.
55-
*/
56-
default String getSerializationFunctionName(GenerationContext context, ToShapeId shapeId) {
57-
var name = context.settings().service(context.model()).getContextualName(shapeId);
58-
return "_serialize_" + CaseUtils.toSnakeCase(name);
59-
}
60-
61-
/**
62-
* Generates the symbol for a serializer function for shapes of a service that is not protocol-specific.
63-
*
64-
* @param context The code generation context.
65-
* @param shapeId The shape the serializer function is being generated for.
66-
* @return Returns the generated symbol.
67-
*/
68-
default Symbol getSerializationFunction(GenerationContext context, ToShapeId shapeId) {
69-
return Symbol.builder()
70-
.name(getSerializationFunctionName(context, shapeId))
71-
.namespace(format("%s.serialize", context.settings().moduleName()), "")
72-
.definitionFile(format("./src/%s/serialize.py", context.settings().moduleName()))
73-
.build();
74-
}
75-
76-
/**
77-
* Generates the name of a deserializer function for shapes of a service that is not protocol-specific.
78-
*
79-
* @param context The code generation context.
80-
* @param shapeId The shape the deserializer function is being generated for.
81-
* @return Returns the generated function name.
82-
*/
83-
default String getDeserializationFunctionName(GenerationContext context, ToShapeId shapeId) {
84-
var name = context.settings().service(context.model()).getContextualName(shapeId);
85-
return "_deserialize_" + CaseUtils.toSnakeCase(name);
86-
}
87-
88-
/**
89-
* Generates the symbol for a deserializer function for shapes of a service that is not protocol-specific.
90-
*
91-
* @param context The code generation context.
92-
* @param shapeId The shape the deserializer function is being generated for.
93-
* @return Returns the generated symbol.
94-
*/
95-
default Symbol getDeserializationFunction(GenerationContext context, ToShapeId shapeId) {
96-
return Symbol.builder()
97-
.name(getDeserializationFunctionName(context, shapeId))
98-
.namespace(format("%s.deserialize", context.settings().moduleName()), "")
99-
.definitionFile(format("./src/%s/deserialize.py", context.settings().moduleName()))
100-
.build();
101-
}
102-
103-
/**
104-
* Generates the symbol for the error deserializer function for an shape of a service that is not
105-
* protocol-specific.
106-
*
107-
* @param context The code generation context.
108-
* @param shapeId The shape id of the shape the error deserializer function is being generated for.
109-
* @return Returns the generated symbol.
110-
*/
111-
default Symbol getErrorDeserializationFunction(GenerationContext context, ToShapeId shapeId) {
112-
var name = context.settings().service(context.model()).getContextualName(shapeId);
113-
return Symbol.builder()
114-
.name("_deserialize_error_" + CaseUtils.toSnakeCase(name))
115-
.namespace(format("%s.deserialize", context.settings().moduleName()), "")
116-
.definitionFile(format("./src/%s/deserialize.py", context.settings().moduleName()))
117-
.build();
118-
}
119-
120-
/**
121-
* Generates any standard code for service request/response serde.
122-
*
123-
* @param context Serde context.
124-
*/
125-
default void generateSharedSerializerComponents(GenerationContext context) {}
126-
127-
/**
128-
* Generates the code used to serialize the shapes of a service
129-
* for requests.
130-
*
131-
* @param context Serialization context.
132-
*/
133-
void generateRequestSerializers(GenerationContext context);
134-
135-
/**
136-
* Generates any standard code for service response deserialization.
137-
*
138-
* @param context Serde context.
139-
*/
140-
default void generateSharedDeserializerComponents(GenerationContext context) {}
141-
142-
/**
143-
* Generates the code used to deserialize the shapes of a service
144-
* for responses.
145-
*
146-
* @param context Deserialization context.
147-
*/
148-
void generateResponseDeserializers(GenerationContext context);
44+
Symbol getProtocolSymbol(GenerationContext context);
14945

15046
/**
15147
* Generates the code for validating the generated protocol's serializers and deserializers.
15248
*
15349
* @param context Generation context
15450
*/
15551
default void generateProtocolTests(GenerationContext context) {}
156-
157-
default void wrapInputStream(GenerationContext context, PythonWriter writer) {}
158-
159-
default void wrapOutputStream(GenerationContext context, PythonWriter writer) {}
16052
}

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,6 @@ def serialize(self, serializer: ShapeSerializer):
352352
353353
""");
354354

355-
// This removes any http-bound members from the serialization method since it's
356-
// not yet supported.
357-
// TODO: remove this once serialization of http binding members is added.
358355
var serializeableMembers = filterMembers();
359356
writer.write("def serialize_members(self, serializer: ShapeSerializer):").indent();
360357
if (serializeableMembers.isEmpty()) {
@@ -381,32 +378,12 @@ def serialize(self, serializer: ShapeSerializer):
381378
}
382379

383380
private List<MemberShape> filterMembers() {
384-
var httpIndex = HttpBindingIndex.of(model);
385-
var operationIndex = OperationIndex.of(model);
386-
if (shape.hasTrait(InputTrait.class)) {
387-
var operation = operationIndex.getInputBindings(shape).iterator().next();
388-
var bindings = httpIndex.getRequestBindings(operation);
389-
return shape.members()
390-
.stream()
391-
.filter(member -> filterMember(member, bindings))
392-
.toList();
393-
} else if (shape.hasTrait(OutputTrait.class)) {
394-
var operation = operationIndex.getOutputBindings(shape).iterator().next();
395-
var bindings = httpIndex.getResponseBindings(operation);
396-
return shape.members()
397-
.stream()
398-
.filter(member -> filterMember(member, bindings))
399-
.toList();
400-
}
401-
return shape.members().stream().toList();
402-
}
403-
404-
private boolean filterMember(MemberShape member, Map<String, HttpBinding> bindings) {
405-
if (bindings.containsKey(member.getMemberName())) {
406-
var binding = bindings.get(member.getMemberName());
407-
return binding.getLocation() == HttpBinding.Location.DOCUMENT;
408-
}
409-
return true;
381+
return shape.members().stream()
382+
.filter(member -> {
383+
var target = model.expectShape(member.getTarget());
384+
return !(target.hasTrait(StreamingTrait.class) && target.isUnionShape());
385+
})
386+
.toList();
410387
}
411388

412389
private boolean isNullable(MemberShape member) {

0 commit comments

Comments
 (0)