Skip to content

Commit 3e8fb33

Browse files
committed
Generic hook for EndpointsGenerator w/ default StaticEndpointsGenerator.
1 parent 68252bd commit 3e8fb33

File tree

7 files changed

+157
-71
lines changed

7 files changed

+157
-71
lines changed

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

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -432,39 +432,7 @@ async def _handle_attempt(
432432

433433
writer.pushState(new ResolveEndpointSection());
434434
if (context.applicationProtocol().isHttpProtocol()) {
435-
writer.addDependency(SmithyPythonDependency.SMITHY_CORE);
436-
writer.addDependency(SmithyPythonDependency.SMITHY_HTTP);
437-
// TODO: implement the endpoints 2.0 spec and remove the hard-coded handling of static params.
438-
writer.addImport("smithy_http.endpoints", "StaticEndpointParams");
439-
writer.addImport("smithy_core", "URI");
440-
writer.write("""
441-
# Step 7f: Invoke endpoint_resolver.resolve_endpoint
442-
if config.endpoint_uri is None:
443-
raise $1T(
444-
"No endpoint_uri found on the operation config."
445-
)
446-
447-
endpoint = await config.endpoint_resolver.resolve_endpoint(
448-
StaticEndpointParams(uri=config.endpoint_uri)
449-
)
450-
if not endpoint.uri.path:
451-
path = ""
452-
elif endpoint.uri.path.endswith("/"):
453-
path = endpoint.uri.path[:-1]
454-
else:
455-
path = endpoint.uri.path
456-
if context.transport_request.destination.path:
457-
path += context.transport_request.destination.path
458-
context._transport_request.destination = URI(
459-
scheme=endpoint.uri.scheme,
460-
host=context.transport_request.destination.host + endpoint.uri.host,
461-
path=path,
462-
port=endpoint.uri.port,
463-
query=context.transport_request.destination.query,
464-
)
465-
context._transport_request.fields.extend(endpoint.headers)
466-
467-
""", errorSymbol);
435+
context.endpointsGenerator().generateEndpoints(context, writer);
468436
}
469437
writer.popState();
470438

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@
4747
import software.amazon.smithy.python.codegen.generators.ProtocolGenerator;
4848
import software.amazon.smithy.python.codegen.generators.SchemaGenerator;
4949
import software.amazon.smithy.python.codegen.generators.SetupGenerator;
50+
import software.amazon.smithy.python.codegen.generators.StaticEndpointsGenerator;
5051
import software.amazon.smithy.python.codegen.generators.StructureGenerator;
5152
import software.amazon.smithy.python.codegen.generators.UnionGenerator;
53+
import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator;
5254
import software.amazon.smithy.python.codegen.integrations.PythonIntegration;
5355
import software.amazon.smithy.python.codegen.writer.PythonDelegator;
5456
import software.amazon.smithy.python.codegen.writer.PythonWriter;
@@ -81,9 +83,20 @@ public GenerationContext createContext(CreateContextDirective<PythonSettings, Py
8183
directive.integrations(),
8284
directive.model(),
8385
directive.service()))
86+
.endpointsGenerator(resolveEndpointsGenerator(directive))
8487
.build();
8588
}
8689

90+
private EndpointsGenerator resolveEndpointsGenerator(CreateContextDirective<PythonSettings, PythonIntegration> directive) {
91+
for (PythonIntegration integration : directive.integrations()) {
92+
Optional<EndpointsGenerator> generator = integration.getEndpointsGenerator(directive.model(), directive.service());
93+
if (generator.isPresent()) {
94+
return generator.get();
95+
}
96+
}
97+
return new StaticEndpointsGenerator();
98+
}
99+
87100
private ProtocolGenerator resolveProtocolGenerator(
88101
Collection<PythonIntegration> integrations,
89102
Model model,

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import software.amazon.smithy.codegen.core.WriterDelegator;
1212
import software.amazon.smithy.model.Model;
1313
import software.amazon.smithy.python.codegen.generators.ProtocolGenerator;
14+
import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator;
1415
import software.amazon.smithy.python.codegen.integrations.PythonIntegration;
1516
import software.amazon.smithy.python.codegen.writer.PythonDelegator;
1617
import software.amazon.smithy.python.codegen.writer.PythonWriter;
@@ -32,6 +33,7 @@ public final class GenerationContext
3233
private final PythonDelegator delegator;
3334
private final List<PythonIntegration> integrations;
3435
private final ProtocolGenerator protocolGenerator;
36+
private final EndpointsGenerator endpointsGenerator;
3537

3638
private GenerationContext(Builder builder) {
3739
model = builder.model;
@@ -41,6 +43,7 @@ private GenerationContext(Builder builder) {
4143
delegator = builder.delegator;
4244
integrations = builder.integrations;
4345
protocolGenerator = builder.protocolGenerator;
46+
endpointsGenerator = builder.endpointsGenerator;
4447
}
4548

4649
@Override
@@ -80,6 +83,13 @@ public ProtocolGenerator protocolGenerator() {
8083
return protocolGenerator;
8184
}
8285

86+
/**
87+
* @return Returns the endpoints generator to use in code generation.
88+
*/
89+
public EndpointsGenerator endpointsGenerator () {
90+
return endpointsGenerator;
91+
}
92+
8393
/**
8494
* Gets the application protocol for the service protocol.
8595
*
@@ -105,7 +115,8 @@ public SmithyBuilder<GenerationContext> toBuilder() {
105115
.settings(settings)
106116
.symbolProvider(symbolProvider)
107117
.fileManifest(fileManifest)
108-
.writerDelegator(delegator);
118+
.writerDelegator(delegator)
119+
.endpointsGenerator(endpointsGenerator);
109120
}
110121

111122
/**
@@ -119,6 +130,7 @@ public static final class Builder implements SmithyBuilder<GenerationContext> {
119130
private PythonDelegator delegator;
120131
private List<PythonIntegration> integrations;
121132
private ProtocolGenerator protocolGenerator;
133+
private EndpointsGenerator endpointsGenerator;
122134

123135
@Override
124136
public GenerationContext build() {
@@ -187,5 +199,14 @@ public Builder protocolGenerator(ProtocolGenerator protocolGenerator) {
187199
this.protocolGenerator = protocolGenerator;
188200
return this;
189201
}
202+
203+
/**
204+
* @param endpointsGenerator The resolved endpoints generator to use.
205+
* @return Returns the builder.
206+
*/
207+
public Builder endpointsGenerator(EndpointsGenerator endpointsGenerator) {
208+
this.endpointsGenerator = endpointsGenerator;
209+
return this;
210+
}
190211
}
191212
}

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

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public final class ConfigGenerator implements Runnable {
6868

6969
// This list contains any properties that must be added to any http-based
7070
// service client, except for the http client itself.
71-
private static final List<ConfigProperty> HTTP_PROPERTIES = Arrays.asList(
71+
private static final List<ConfigProperty> HTTP_PROPERTIES = List.of(
7272
ConfigProperty.builder()
7373
.name("http_request_config")
7474
.type(Symbol.builder()
@@ -77,42 +77,6 @@ public final class ConfigGenerator implements Runnable {
7777
.addDependency(SmithyPythonDependency.SMITHY_HTTP)
7878
.build())
7979
.documentation("Configuration for individual HTTP requests.")
80-
.build(),
81-
ConfigProperty.builder()
82-
.name("endpoint_resolver")
83-
.type(Symbol.builder()
84-
.name("EndpointResolver[Any]")
85-
.addReference(Symbol.builder()
86-
.name("Any")
87-
.namespace("typing", ".")
88-
.putProperty(SymbolProperties.STDLIB, true)
89-
.build())
90-
.addReference(Symbol.builder()
91-
.name("EndpointResolver")
92-
.namespace("smithy_http.aio.interfaces", ".")
93-
.addDependency(SmithyPythonDependency.SMITHY_HTTP)
94-
.build())
95-
.build())
96-
.documentation("""
97-
The endpoint resolver used to resolve the final endpoint per-operation based on the \
98-
configuration.""")
99-
.nullable(false)
100-
.initialize(writer -> {
101-
writer.addImport("smithy_http.aio.endpoints", "StaticEndpointResolver");
102-
writer.write("self.endpoint_resolver = endpoint_resolver or StaticEndpointResolver()");
103-
})
104-
.build(),
105-
ConfigProperty.builder()
106-
.name("endpoint_uri")
107-
.type(Symbol.builder()
108-
.name("str | URI")
109-
.addReference(Symbol.builder()
110-
.name("URI")
111-
.namespace("smithy_core.interfaces", ".")
112-
.addDependency(SmithyPythonDependency.SMITHY_CORE)
113-
.build())
114-
.build())
115-
.documentation("A static URI to route requests to.")
11680
.build());
11781

11882
private final PythonSettings settings;
@@ -154,6 +118,7 @@ private static List<ConfigProperty> getHttpProperties(GenerationContext context)
154118
properties.add(clientBuilder.build());
155119

156120
properties.addAll(HTTP_PROPERTIES);
121+
properties.addAll(context.endpointsGenerator().endpointsConfig(context));
157122
return List.copyOf(properties);
158123
}
159124

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package software.amazon.smithy.python.codegen.generators;
2+
3+
import java.util.List;
4+
import software.amazon.smithy.codegen.core.Symbol;
5+
import software.amazon.smithy.python.codegen.CodegenUtils;
6+
import software.amazon.smithy.python.codegen.ConfigProperty;
7+
import software.amazon.smithy.python.codegen.GenerationContext;
8+
import software.amazon.smithy.python.codegen.SmithyPythonDependency;
9+
import software.amazon.smithy.python.codegen.SymbolProperties;
10+
import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator;
11+
import software.amazon.smithy.python.codegen.writer.PythonWriter;
12+
13+
public class StaticEndpointsGenerator implements EndpointsGenerator {
14+
@Override
15+
public List<ConfigProperty> endpointsConfig(GenerationContext context) {
16+
return List.of(ConfigProperty.builder()
17+
.name("endpoint_resolver")
18+
.type(Symbol.builder()
19+
.name("EndpointResolver[Any]")
20+
.addReference(Symbol.builder()
21+
.name("Any")
22+
.namespace("typing", ".")
23+
.putProperty(SymbolProperties.STDLIB, true)
24+
.build())
25+
.addReference(Symbol.builder()
26+
.name("EndpointResolver")
27+
.namespace("smithy_http.aio.interfaces", ".")
28+
.addDependency(SmithyPythonDependency.SMITHY_HTTP)
29+
.build())
30+
.build())
31+
.documentation("""
32+
The endpoint resolver used to resolve the final endpoint per-operation based on the \
33+
configuration.""")
34+
.nullable(false)
35+
.initialize(writer -> {
36+
writer.addImport("smithy_http.aio.endpoints", "StaticEndpointResolver");
37+
writer.write("self.endpoint_resolver = endpoint_resolver or StaticEndpointResolver()");
38+
})
39+
.build(),
40+
ConfigProperty.builder()
41+
.name("endpoint_uri")
42+
.type(Symbol.builder()
43+
.name("str | URI")
44+
.addReference(Symbol.builder()
45+
.name("URI")
46+
.namespace("smithy_core.interfaces", ".")
47+
.addDependency(SmithyPythonDependency.SMITHY_CORE)
48+
.build())
49+
.build())
50+
.documentation("A static URI to route requests to.")
51+
.build());
52+
}
53+
54+
@Override
55+
public void generateEndpoints(GenerationContext context, PythonWriter writer) {
56+
var errorSymbol = CodegenUtils.getServiceError(context.settings());
57+
58+
writer.addDependency(SmithyPythonDependency.SMITHY_CORE);
59+
writer.addDependency(SmithyPythonDependency.SMITHY_HTTP);
60+
writer.addImport("smithy_http.endpoints", "StaticEndpointParams");
61+
writer.addImport("smithy_core", "URI");
62+
writer.write("""
63+
# Step 7f: Invoke endpoint_resolver.resolve_endpoint
64+
if config.endpoint_uri is None:
65+
raise $1T(
66+
"No endpoint_uri found on the operation config."
67+
)
68+
69+
endpoint = await config.endpoint_resolver.resolve_endpoint(
70+
StaticEndpointParams(uri=config.endpoint_uri)
71+
)
72+
if not endpoint.uri.path:
73+
path = ""
74+
elif endpoint.uri.path.endswith("/"):
75+
path = endpoint.uri.path[:-1]
76+
else:
77+
path = endpoint.uri.path
78+
if context.transport_request.destination.path:
79+
path += context.transport_request.destination.path
80+
context._transport_request.destination = URI(
81+
scheme=endpoint.uri.scheme,
82+
host=context.transport_request.destination.host + endpoint.uri.host,
83+
path=path,
84+
port=endpoint.uri.port,
85+
query=context.transport_request.destination.query,
86+
)
87+
context._transport_request.fields.extend(endpoint.headers)
88+
89+
""", errorSymbol);
90+
}
91+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package software.amazon.smithy.python.codegen.integrations;
2+
3+
import java.util.List;
4+
import software.amazon.smithy.python.codegen.ConfigProperty;
5+
import software.amazon.smithy.python.codegen.GenerationContext;
6+
import software.amazon.smithy.python.codegen.writer.PythonWriter;
7+
8+
/**
9+
*
10+
*/
11+
public interface EndpointsGenerator {
12+
13+
List<ConfigProperty> endpointsConfig(GenerationContext context);
14+
15+
void generateEndpoints(GenerationContext context, PythonWriter writer);
16+
}

codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66

77
import java.util.Collections;
88
import java.util.List;
9+
import java.util.Optional;
910
import software.amazon.smithy.codegen.core.SmithyIntegration;
11+
import software.amazon.smithy.model.Model;
12+
import software.amazon.smithy.model.shapes.ServiceShape;
1013
import software.amazon.smithy.python.codegen.GenerationContext;
1114
import software.amazon.smithy.python.codegen.PythonSettings;
1215
import software.amazon.smithy.python.codegen.generators.ProtocolGenerator;
@@ -38,4 +41,13 @@ default List<ProtocolGenerator> getProtocolGenerators() {
3841
default List<RuntimeClientPlugin> getClientPlugins() {
3942
return Collections.emptyList();
4043
}
44+
45+
/**
46+
* Get an EndpointsGenerator that will be used to generate endpoints related config and resolution logic.
47+
*
48+
* @return optional EndpointsGenerator.
49+
*/
50+
default Optional<EndpointsGenerator> getEndpointsGenerator(Model model, ServiceShape service) {
51+
return Optional.empty();
52+
}
4153
}

0 commit comments

Comments
 (0)