From 3e8fb3344e6ed5429acea02c1e643454be6081c4 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 27 Feb 2025 13:47:58 -0800 Subject: [PATCH 1/8] Generic hook for EndpointsGenerator w/ default StaticEndpointsGenerator. --- .../python/codegen/ClientGenerator.java | 34 +------ .../python/codegen/DirectedPythonCodegen.java | 13 +++ .../python/codegen/GenerationContext.java | 23 ++++- .../codegen/generators/ConfigGenerator.java | 39 +------- .../generators/StaticEndpointsGenerator.java | 91 +++++++++++++++++++ .../integrations/EndpointsGenerator.java | 16 ++++ .../integrations/PythonIntegration.java | 12 +++ 7 files changed, 157 insertions(+), 71 deletions(-) create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index e24305226..c2a4b154c 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -432,39 +432,7 @@ async def _handle_attempt( writer.pushState(new ResolveEndpointSection()); if (context.applicationProtocol().isHttpProtocol()) { - writer.addDependency(SmithyPythonDependency.SMITHY_CORE); - writer.addDependency(SmithyPythonDependency.SMITHY_HTTP); - // TODO: implement the endpoints 2.0 spec and remove the hard-coded handling of static params. - writer.addImport("smithy_http.endpoints", "StaticEndpointParams"); - writer.addImport("smithy_core", "URI"); - writer.write(""" - # Step 7f: Invoke endpoint_resolver.resolve_endpoint - if config.endpoint_uri is None: - raise $1T( - "No endpoint_uri found on the operation config." - ) - - endpoint = await config.endpoint_resolver.resolve_endpoint( - StaticEndpointParams(uri=config.endpoint_uri) - ) - if not endpoint.uri.path: - path = "" - elif endpoint.uri.path.endswith("/"): - path = endpoint.uri.path[:-1] - else: - path = endpoint.uri.path - if context.transport_request.destination.path: - path += context.transport_request.destination.path - context._transport_request.destination = URI( - scheme=endpoint.uri.scheme, - host=context.transport_request.destination.host + endpoint.uri.host, - path=path, - port=endpoint.uri.port, - query=context.transport_request.destination.query, - ) - context._transport_request.fields.extend(endpoint.headers) - - """, errorSymbol); + context.endpointsGenerator().generateEndpoints(context, writer); } writer.popState(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/DirectedPythonCodegen.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/DirectedPythonCodegen.java index a52cb082e..98270804e 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/DirectedPythonCodegen.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/DirectedPythonCodegen.java @@ -47,8 +47,10 @@ import software.amazon.smithy.python.codegen.generators.ProtocolGenerator; import software.amazon.smithy.python.codegen.generators.SchemaGenerator; import software.amazon.smithy.python.codegen.generators.SetupGenerator; +import software.amazon.smithy.python.codegen.generators.StaticEndpointsGenerator; import software.amazon.smithy.python.codegen.generators.StructureGenerator; import software.amazon.smithy.python.codegen.generators.UnionGenerator; +import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator; import software.amazon.smithy.python.codegen.integrations.PythonIntegration; import software.amazon.smithy.python.codegen.writer.PythonDelegator; import software.amazon.smithy.python.codegen.writer.PythonWriter; @@ -81,9 +83,20 @@ public GenerationContext createContext(CreateContextDirective directive) { + for (PythonIntegration integration : directive.integrations()) { + Optional generator = integration.getEndpointsGenerator(directive.model(), directive.service()); + if (generator.isPresent()) { + return generator.get(); + } + } + return new StaticEndpointsGenerator(); + } + private ProtocolGenerator resolveProtocolGenerator( Collection integrations, Model model, diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/GenerationContext.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/GenerationContext.java index 2f112e388..18fd2cd5e 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/GenerationContext.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/GenerationContext.java @@ -11,6 +11,7 @@ import software.amazon.smithy.codegen.core.WriterDelegator; import software.amazon.smithy.model.Model; import software.amazon.smithy.python.codegen.generators.ProtocolGenerator; +import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator; import software.amazon.smithy.python.codegen.integrations.PythonIntegration; import software.amazon.smithy.python.codegen.writer.PythonDelegator; import software.amazon.smithy.python.codegen.writer.PythonWriter; @@ -32,6 +33,7 @@ public final class GenerationContext private final PythonDelegator delegator; private final List integrations; private final ProtocolGenerator protocolGenerator; + private final EndpointsGenerator endpointsGenerator; private GenerationContext(Builder builder) { model = builder.model; @@ -41,6 +43,7 @@ private GenerationContext(Builder builder) { delegator = builder.delegator; integrations = builder.integrations; protocolGenerator = builder.protocolGenerator; + endpointsGenerator = builder.endpointsGenerator; } @Override @@ -80,6 +83,13 @@ public ProtocolGenerator protocolGenerator() { return protocolGenerator; } + /** + * @return Returns the endpoints generator to use in code generation. + */ + public EndpointsGenerator endpointsGenerator () { + return endpointsGenerator; + } + /** * Gets the application protocol for the service protocol. * @@ -105,7 +115,8 @@ public SmithyBuilder toBuilder() { .settings(settings) .symbolProvider(symbolProvider) .fileManifest(fileManifest) - .writerDelegator(delegator); + .writerDelegator(delegator) + .endpointsGenerator(endpointsGenerator); } /** @@ -119,6 +130,7 @@ public static final class Builder implements SmithyBuilder { private PythonDelegator delegator; private List integrations; private ProtocolGenerator protocolGenerator; + private EndpointsGenerator endpointsGenerator; @Override public GenerationContext build() { @@ -187,5 +199,14 @@ public Builder protocolGenerator(ProtocolGenerator protocolGenerator) { this.protocolGenerator = protocolGenerator; return this; } + + /** + * @param endpointsGenerator The resolved endpoints generator to use. + * @return Returns the builder. + */ + public Builder endpointsGenerator(EndpointsGenerator endpointsGenerator) { + this.endpointsGenerator = endpointsGenerator; + return this; + } } } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ConfigGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ConfigGenerator.java index fb01926d8..0a435bcd1 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ConfigGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ConfigGenerator.java @@ -68,7 +68,7 @@ public final class ConfigGenerator implements Runnable { // This list contains any properties that must be added to any http-based // service client, except for the http client itself. - private static final List HTTP_PROPERTIES = Arrays.asList( + private static final List HTTP_PROPERTIES = List.of( ConfigProperty.builder() .name("http_request_config") .type(Symbol.builder() @@ -77,42 +77,6 @@ public final class ConfigGenerator implements Runnable { .addDependency(SmithyPythonDependency.SMITHY_HTTP) .build()) .documentation("Configuration for individual HTTP requests.") - .build(), - ConfigProperty.builder() - .name("endpoint_resolver") - .type(Symbol.builder() - .name("EndpointResolver[Any]") - .addReference(Symbol.builder() - .name("Any") - .namespace("typing", ".") - .putProperty(SymbolProperties.STDLIB, true) - .build()) - .addReference(Symbol.builder() - .name("EndpointResolver") - .namespace("smithy_http.aio.interfaces", ".") - .addDependency(SmithyPythonDependency.SMITHY_HTTP) - .build()) - .build()) - .documentation(""" - The endpoint resolver used to resolve the final endpoint per-operation based on the \ - configuration.""") - .nullable(false) - .initialize(writer -> { - writer.addImport("smithy_http.aio.endpoints", "StaticEndpointResolver"); - writer.write("self.endpoint_resolver = endpoint_resolver or StaticEndpointResolver()"); - }) - .build(), - ConfigProperty.builder() - .name("endpoint_uri") - .type(Symbol.builder() - .name("str | URI") - .addReference(Symbol.builder() - .name("URI") - .namespace("smithy_core.interfaces", ".") - .addDependency(SmithyPythonDependency.SMITHY_CORE) - .build()) - .build()) - .documentation("A static URI to route requests to.") .build()); private final PythonSettings settings; @@ -154,6 +118,7 @@ private static List getHttpProperties(GenerationContext context) properties.add(clientBuilder.build()); properties.addAll(HTTP_PROPERTIES); + properties.addAll(context.endpointsGenerator().endpointsConfig(context)); return List.copyOf(properties); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java new file mode 100644 index 000000000..0161992ab --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java @@ -0,0 +1,91 @@ +package software.amazon.smithy.python.codegen.generators; + +import java.util.List; +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.python.codegen.CodegenUtils; +import software.amazon.smithy.python.codegen.ConfigProperty; +import software.amazon.smithy.python.codegen.GenerationContext; +import software.amazon.smithy.python.codegen.SmithyPythonDependency; +import software.amazon.smithy.python.codegen.SymbolProperties; +import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator; +import software.amazon.smithy.python.codegen.writer.PythonWriter; + +public class StaticEndpointsGenerator implements EndpointsGenerator { + @Override + public List endpointsConfig(GenerationContext context) { + return List.of(ConfigProperty.builder() + .name("endpoint_resolver") + .type(Symbol.builder() + .name("EndpointResolver[Any]") + .addReference(Symbol.builder() + .name("Any") + .namespace("typing", ".") + .putProperty(SymbolProperties.STDLIB, true) + .build()) + .addReference(Symbol.builder() + .name("EndpointResolver") + .namespace("smithy_http.aio.interfaces", ".") + .addDependency(SmithyPythonDependency.SMITHY_HTTP) + .build()) + .build()) + .documentation(""" + The endpoint resolver used to resolve the final endpoint per-operation based on the \ + configuration.""") + .nullable(false) + .initialize(writer -> { + writer.addImport("smithy_http.aio.endpoints", "StaticEndpointResolver"); + writer.write("self.endpoint_resolver = endpoint_resolver or StaticEndpointResolver()"); + }) + .build(), + ConfigProperty.builder() + .name("endpoint_uri") + .type(Symbol.builder() + .name("str | URI") + .addReference(Symbol.builder() + .name("URI") + .namespace("smithy_core.interfaces", ".") + .addDependency(SmithyPythonDependency.SMITHY_CORE) + .build()) + .build()) + .documentation("A static URI to route requests to.") + .build()); + } + + @Override + public void generateEndpoints(GenerationContext context, PythonWriter writer) { + var errorSymbol = CodegenUtils.getServiceError(context.settings()); + + writer.addDependency(SmithyPythonDependency.SMITHY_CORE); + writer.addDependency(SmithyPythonDependency.SMITHY_HTTP); + writer.addImport("smithy_http.endpoints", "StaticEndpointParams"); + writer.addImport("smithy_core", "URI"); + writer.write(""" + # Step 7f: Invoke endpoint_resolver.resolve_endpoint + if config.endpoint_uri is None: + raise $1T( + "No endpoint_uri found on the operation config." + ) + + endpoint = await config.endpoint_resolver.resolve_endpoint( + StaticEndpointParams(uri=config.endpoint_uri) + ) + if not endpoint.uri.path: + path = "" + elif endpoint.uri.path.endswith("/"): + path = endpoint.uri.path[:-1] + else: + path = endpoint.uri.path + if context.transport_request.destination.path: + path += context.transport_request.destination.path + context._transport_request.destination = URI( + scheme=endpoint.uri.scheme, + host=context.transport_request.destination.host + endpoint.uri.host, + path=path, + port=endpoint.uri.port, + query=context.transport_request.destination.query, + ) + context._transport_request.fields.extend(endpoint.headers) + + """, errorSymbol); + } +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java new file mode 100644 index 000000000..9207d862b --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java @@ -0,0 +1,16 @@ +package software.amazon.smithy.python.codegen.integrations; + +import java.util.List; +import software.amazon.smithy.python.codegen.ConfigProperty; +import software.amazon.smithy.python.codegen.GenerationContext; +import software.amazon.smithy.python.codegen.writer.PythonWriter; + +/** + * + */ +public interface EndpointsGenerator { + + List endpointsConfig(GenerationContext context); + + void generateEndpoints(GenerationContext context, PythonWriter writer); +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java index a23cf237a..40b33e252 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java @@ -6,7 +6,10 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; import software.amazon.smithy.codegen.core.SmithyIntegration; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.ServiceShape; import software.amazon.smithy.python.codegen.GenerationContext; import software.amazon.smithy.python.codegen.PythonSettings; import software.amazon.smithy.python.codegen.generators.ProtocolGenerator; @@ -38,4 +41,13 @@ default List getProtocolGenerators() { default List getClientPlugins() { return Collections.emptyList(); } + + /** + * Get an EndpointsGenerator that will be used to generate endpoints related config and resolution logic. + * + * @return optional EndpointsGenerator. + */ + default Optional getEndpointsGenerator(Model model, ServiceShape service) { + return Optional.empty(); + } } From dc3a7ccede19125cc1aef5c3f4d822d12236d2ee Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Thu, 27 Feb 2025 15:30:34 -0800 Subject: [PATCH 2/8] Add implementation of AWS StandardRegionalEndpoints --- .../aws/codegen/AwsPythonDependency.java | 26 +++++ .../AwsRegionalEndpointsGenerator.java | 100 ++++++++++++++++++ .../AwsRegionalEndpointsIntegration.java | 14 +++ ...hon.codegen.integrations.PythonIntegration | 1 + .../python/codegen/ClientGenerator.java | 1 + .../generators/StaticEndpointsGenerator.java | 1 - .../integrations/EndpointsGenerator.java | 23 +++- .../src/smithy_aws_core/endpoints/__init__.py | 2 + .../endpoints/standard_regional.py | 61 +++++++++++ 9 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsPythonDependency.java create mode 100644 codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java create mode 100644 codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsIntegration.java create mode 100644 packages/smithy-aws-core/src/smithy_aws_core/endpoints/__init__.py create mode 100644 packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsPythonDependency.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsPythonDependency.java new file mode 100644 index 000000000..d6d3563db --- /dev/null +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsPythonDependency.java @@ -0,0 +1,26 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.aws.codegen; + +import software.amazon.smithy.python.codegen.PythonDependency; +import software.amazon.smithy.utils.SmithyUnstableApi; + +/** + * AWS Dependencies used in the smithy python generator. + */ +@SmithyUnstableApi +public class AwsPythonDependency { + /** + * The core aws smithy runtime python package. + * + *

While in development this will use the develop branch. + */ + public static final PythonDependency SMITHY_AWS_CORE = new PythonDependency( + "smithy_aws_core", + // You'll need to locally install this before we publish + "==0.0.1", + PythonDependency.Type.DEPENDENCY, + false); +} \ No newline at end of file diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java new file mode 100644 index 000000000..b7f853c93 --- /dev/null +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java @@ -0,0 +1,100 @@ +package software.amazon.smithy.python.aws.codegen; + +import java.util.List; +import software.amazon.smithy.aws.traits.ServiceTrait; +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.python.codegen.CodegenUtils; +import software.amazon.smithy.python.codegen.ConfigProperty; +import software.amazon.smithy.python.codegen.GenerationContext; +import software.amazon.smithy.python.codegen.SmithyPythonDependency; +import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator; +import software.amazon.smithy.python.codegen.writer.PythonWriter; + +/** + * Generates endpoint config and resolution logic for standard regional endpoints. + */ +public class AwsRegionalEndpointsGenerator implements EndpointsGenerator { + @Override + public List endpointsConfig(GenerationContext context) { + return List.of(ConfigProperty.builder() + .name("endpoint_resolver") + .type(Symbol.builder() + .name("EndpointResolver[RegionalEndpointParameters]") + .addReference(Symbol.builder() + .name("RegionalEndpointParameters") + .namespace(AwsPythonDependency.SMITHY_AWS_CORE.packageName() + ".endpoints.standard_regional", ".") + .addDependency(AwsPythonDependency.SMITHY_AWS_CORE) + .build()) + .addReference(Symbol.builder() + .name("EndpointResolver") + .namespace("smithy_http.aio.interfaces", ".") + .addDependency(SmithyPythonDependency.SMITHY_HTTP) + .build()) + .build()) + .documentation(""" + The endpoint resolver used to resolve the final endpoint per-operation based on the \ + configuration.""") + .nullable(false) + .initialize(writer -> { + writer.addImport("smithy_aws_core.endpoints.standard_regional", "StandardRegionalEndpointsResolver"); + String endpointPrefix = context.settings().service(context.model()) + .getTrait(ServiceTrait.class) + .map(ServiceTrait::getEndpointPrefix) + .orElse(context.settings().service().getName()); + + writer.write( + "self.endpoint_resolver = endpoint_resolver or StandardRegionalEndpointsResolver(endpoint_prefix='$L')", + endpointPrefix); + }) + .build(), + ConfigProperty.builder() + .name("endpoint_uri") + .type(Symbol.builder() + .name("str | URI") + .addReference(Symbol.builder() + .name("URI") + .namespace("smithy_core.interfaces", ".") + .addDependency(SmithyPythonDependency.SMITHY_CORE) + .build()) + .build()) + .documentation("A static URI to route requests to.") + .build(), + ConfigProperty.builder() + .name("region") + .type(Symbol.builder().name("str").build()) + .documentation(" The AWS region to connect to. The configured region is used to " + + "determine the service endpoint.") + .build()); + } + + @Override + public void generateEndpoints(GenerationContext context, PythonWriter writer) { + var errorSymbol = CodegenUtils.getServiceError(context.settings()); + + writer.addDependency(AwsPythonDependency.SMITHY_AWS_CORE); + writer.addImport("smithy_aws_core.endpoints.standard_regional", "RegionalEndpointParameters"); + writer.addImport("smithy_core", "URI"); + writer.write(""" + endpoint = await config.endpoint_resolver.resolve_endpoint( + RegionalEndpointParameters(sdk_endpoint=config.endpoint_uri,region=config.region) + ) + if not endpoint.uri.path: + path = "" + elif endpoint.uri.path.endswith("/"): + path = endpoint.uri.path[:-1] + else: + path = endpoint.uri.path + if context.transport_request.destination.path: + path += context.transport_request.destination.path + context._transport_request.destination = URI( + scheme=endpoint.uri.scheme, + host=context.transport_request.destination.host + endpoint.uri.host, + path=path, + port=endpoint.uri.port, + query=context.transport_request.destination.query, + ) + context._transport_request.fields.extend(endpoint.headers) + + """); + } +} diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsIntegration.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsIntegration.java new file mode 100644 index 000000000..298f88acc --- /dev/null +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsIntegration.java @@ -0,0 +1,14 @@ +package software.amazon.smithy.python.aws.codegen; + +import java.util.Optional; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.ServiceShape; +import software.amazon.smithy.python.codegen.integrations.EndpointsGenerator; +import software.amazon.smithy.python.codegen.integrations.PythonIntegration; + +public class AwsRegionalEndpointsIntegration implements PythonIntegration { + @Override + public Optional getEndpointsGenerator(Model model, ServiceShape service) { + return Optional.of(new AwsRegionalEndpointsGenerator()); + } +} diff --git a/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration b/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration index 5155ed74a..b4ae333c5 100644 --- a/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration +++ b/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration @@ -5,3 +5,4 @@ software.amazon.smithy.python.aws.codegen.AwsAuthIntegration software.amazon.smithy.python.aws.codegen.AwsProtocolsIntegration +software.amazon.smithy.python.aws.codegen.AwsRegionalEndpointsIntegration diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index c2a4b154c..303da5844 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -432,6 +432,7 @@ async def _handle_attempt( writer.pushState(new ResolveEndpointSection()); if (context.applicationProtocol().isHttpProtocol()) { + writer.write("# Step 7f: Invoke endpoint_resolver.resolve_endpoint"); context.endpointsGenerator().generateEndpoints(context, writer); } writer.popState(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java index 0161992ab..80f9a990e 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java @@ -60,7 +60,6 @@ public void generateEndpoints(GenerationContext context, PythonWriter writer) { writer.addImport("smithy_http.endpoints", "StaticEndpointParams"); writer.addImport("smithy_core", "URI"); writer.write(""" - # Step 7f: Invoke endpoint_resolver.resolve_endpoint if config.endpoint_uri is None: raise $1T( "No endpoint_uri found on the operation config." diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java index 9207d862b..0db50e5ce 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java @@ -6,11 +6,32 @@ import software.amazon.smithy.python.codegen.writer.PythonWriter; /** - * + * Interface for Endpoints Generators. + * Endpoints Generators are responsible for defining the client configuration + * required for resolving endpoints, this includes an appropriately typed + * `endpoint_resolver` and any other configuration properties such as `endpoint_uri`. + * Endpoint generators are also responsible for rendering the logic in the client's + * request execution stack that sets the destination on the transport request. + * Endpoints Generators are only applied to services that use an HTTP transport. */ public interface EndpointsGenerator { + /** + * Endpoints Generators are responsible for defining the client configuration + * required for resolving endpoints, this includes an appropriately typed + * `endpoint_resolver` and any other configuration properties such as `endpoint_uri` + * + * @param context generation context. + * @return list of client config required to resolve endpoints. + */ List endpointsConfig(GenerationContext context); + /** + * Render the logic in the client's request execution stack that sets the + * destination on the transport request using the provided writer. + * + * @param context generation context + * @param writer writer to generate endpoint resolution/setting logic with + */ void generateEndpoints(GenerationContext context, PythonWriter writer); } diff --git a/packages/smithy-aws-core/src/smithy_aws_core/endpoints/__init__.py b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/__init__.py new file mode 100644 index 000000000..33cbe867a --- /dev/null +++ b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py new file mode 100644 index 000000000..f242bf96b --- /dev/null +++ b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py @@ -0,0 +1,61 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from dataclasses import dataclass +from urllib.parse import urlparse + +import smithy_core +from smithy_core import URI +from smithy_http.aio.interfaces import EndpointResolver +from smithy_http.endpoints import Endpoint + + +@dataclass(kw_only=True) +class RegionalEndpointParameters: + """Endpoint parameters for services with standard regional endpoints.""" + + sdk_endpoint: str | smithy_core.interfaces.URI | None + region: str | None + + +class StandardRegionalEndpointsResolver(EndpointResolver[RegionalEndpointParameters]): + """Resolves endpoints for services with standard regional endpoints.""" + + def __init__(self, endpoint_prefix: str): + self._endpoint_prefix = endpoint_prefix + + async def resolve_endpoint(self, params: RegionalEndpointParameters) -> Endpoint: + if params.sdk_endpoint is not None: + # If it's not a string, it's already a parsed URI so just pass it along. + if not isinstance(params.sdk_endpoint, str): + return Endpoint(uri=params.sdk_endpoint) + + # Does crt have implementations of these parsing methods? Using the standard + # library is probably fine. + parsed = urlparse(params.sdk_endpoint) + + # This will end up getting wrapped in the client. + if parsed.hostname is None: + raise ValueError( + f"Unable to parse hostname from provided URI: {params.sdk_endpoint}" + ) + + return Endpoint( + uri=URI( + host=parsed.hostname, + path=parsed.path, + scheme=parsed.scheme, + query=parsed.query, + port=parsed.port, + ) + ) + + if params.region is not None: + # TODO: use dns suffix determined from partition metadata + dns_suffix = "amazonaws.com" + hostname = f"{self._endpoint_prefix}.{params.region}.{dns_suffix}" + + return Endpoint(uri=URI(host=hostname)) + + raise ValueError( + "Unable to resolve endpoint - either endpoint_url or region are required." + ) From 2a4e6f09218b852372074369a374a758b05fbe4a Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 28 Feb 2025 10:21:14 -0800 Subject: [PATCH 3/8] Refactor endpoints generator to reduce duplicate code - generator now just renders endpoint_parameter construction --- .../AwsRegionalEndpointsGenerator.java | 26 ++----------- .../python/codegen/ClientGenerator.java | 26 ++++++++++++- .../generators/StaticEndpointsGenerator.java | 39 ++----------------- .../integrations/EndpointsGenerator.java | 11 +++--- .../src/smithy_http/aio/endpoints.py | 3 ++ .../smithy-http/src/smithy_http/endpoints.py | 2 +- 6 files changed, 43 insertions(+), 64 deletions(-) diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java index b7f853c93..47a49fa09 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRegionalEndpointsGenerator.java @@ -68,33 +68,15 @@ public List endpointsConfig(GenerationContext context) { } @Override - public void generateEndpoints(GenerationContext context, PythonWriter writer) { - var errorSymbol = CodegenUtils.getServiceError(context.settings()); + public void renderEndpointParameterConstruction(GenerationContext context, PythonWriter writer) { writer.addDependency(AwsPythonDependency.SMITHY_AWS_CORE); writer.addImport("smithy_aws_core.endpoints.standard_regional", "RegionalEndpointParameters"); - writer.addImport("smithy_core", "URI"); writer.write(""" - endpoint = await config.endpoint_resolver.resolve_endpoint( - RegionalEndpointParameters(sdk_endpoint=config.endpoint_uri,region=config.region) + endpoint_parameters = RegionalEndpointParameters( + sdk_endpoint=config.endpoint_uri, + region=config.region ) - if not endpoint.uri.path: - path = "" - elif endpoint.uri.path.endswith("/"): - path = endpoint.uri.path[:-1] - else: - path = endpoint.uri.path - if context.transport_request.destination.path: - path += context.transport_request.destination.path - context._transport_request.destination = URI( - scheme=endpoint.uri.scheme, - host=context.transport_request.destination.host + endpoint.uri.host, - path=path, - port=endpoint.uri.port, - query=context.transport_request.destination.query, - ) - context._transport_request.fields.extend(endpoint.headers) - """); } } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index 303da5844..e4fc1ff58 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -432,8 +432,32 @@ async def _handle_attempt( writer.pushState(new ResolveEndpointSection()); if (context.applicationProtocol().isHttpProtocol()) { + writer.addDependency(SmithyPythonDependency.SMITHY_CORE); + writer.addImport("smithy_core", "URI"); writer.write("# Step 7f: Invoke endpoint_resolver.resolve_endpoint"); - context.endpointsGenerator().generateEndpoints(context, writer); + + context.endpointsGenerator().renderEndpointParameterConstruction(context, writer); + + writer.write(""" + endpoint = await config.endpoint_resolver.resolve_endpoint(endpoint_parameters) + if not endpoint.uri.path: + path = "" + elif endpoint.uri.path.endswith("/"): + path = endpoint.uri.path[:-1] + else: + path = endpoint.uri.path + if context.transport_request.destination.path: + path += context.transport_request.destination.path + context._transport_request.destination = URI( + scheme=endpoint.uri.scheme, + host=context.transport_request.destination.host + endpoint.uri.host, + path=path, + port=endpoint.uri.port, + query=context.transport_request.destination.query, + ) + context._transport_request.fields.extend(endpoint.headers) + + """); } writer.popState(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java index 80f9a990e..2b2891c5a 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java @@ -2,7 +2,6 @@ import java.util.List; import software.amazon.smithy.codegen.core.Symbol; -import software.amazon.smithy.python.codegen.CodegenUtils; import software.amazon.smithy.python.codegen.ConfigProperty; import software.amazon.smithy.python.codegen.GenerationContext; import software.amazon.smithy.python.codegen.SmithyPythonDependency; @@ -29,8 +28,8 @@ public List endpointsConfig(GenerationContext context) { .build()) .build()) .documentation(""" - The endpoint resolver used to resolve the final endpoint per-operation based on the \ - configuration.""") + The endpoint resolver used to resolve the final endpoint per-operation based on the \ + configuration.""") .nullable(false) .initialize(writer -> { writer.addImport("smithy_http.aio.endpoints", "StaticEndpointResolver"); @@ -52,39 +51,9 @@ public List endpointsConfig(GenerationContext context) { } @Override - public void generateEndpoints(GenerationContext context, PythonWriter writer) { - var errorSymbol = CodegenUtils.getServiceError(context.settings()); - - writer.addDependency(SmithyPythonDependency.SMITHY_CORE); + public void renderEndpointParameterConstruction(GenerationContext context, PythonWriter writer) { writer.addDependency(SmithyPythonDependency.SMITHY_HTTP); writer.addImport("smithy_http.endpoints", "StaticEndpointParams"); - writer.addImport("smithy_core", "URI"); - writer.write(""" - if config.endpoint_uri is None: - raise $1T( - "No endpoint_uri found on the operation config." - ) - - endpoint = await config.endpoint_resolver.resolve_endpoint( - StaticEndpointParams(uri=config.endpoint_uri) - ) - if not endpoint.uri.path: - path = "" - elif endpoint.uri.path.endswith("/"): - path = endpoint.uri.path[:-1] - else: - path = endpoint.uri.path - if context.transport_request.destination.path: - path += context.transport_request.destination.path - context._transport_request.destination = URI( - scheme=endpoint.uri.scheme, - host=context.transport_request.destination.host + endpoint.uri.host, - path=path, - port=endpoint.uri.port, - query=context.transport_request.destination.query, - ) - context._transport_request.fields.extend(endpoint.headers) - - """, errorSymbol); + writer.write("endpoint_parameters = StaticEndpointParams(uri=config.endpoint_uri)"); } } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java index 0db50e5ce..dfb349bd9 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/EndpointsGenerator.java @@ -18,7 +18,7 @@ public interface EndpointsGenerator { /** * Endpoints Generators are responsible for defining the client configuration - * required for resolving endpoints, this includes an appropriately typed + * required for resolving endpoints, this must include an appropriately typed * `endpoint_resolver` and any other configuration properties such as `endpoint_uri` * * @param context generation context. @@ -27,11 +27,12 @@ public interface EndpointsGenerator { List endpointsConfig(GenerationContext context); /** - * Render the logic in the client's request execution stack that sets the - * destination on the transport request using the provided writer. + * Render the logic in the client's request execution stack that constructs + * `endpoint_parameters`. Implementations must add required dependencies and import statements + * and must ensure the `endpoint_parameters` variable is set. * * @param context generation context - * @param writer writer to generate endpoint resolution/setting logic with + * @param writer writer to write out logic to construct `endpoint_parameters`. */ - void generateEndpoints(GenerationContext context, PythonWriter writer); + void renderEndpointParameterConstruction(GenerationContext context, PythonWriter writer); } diff --git a/packages/smithy-http/src/smithy_http/aio/endpoints.py b/packages/smithy-http/src/smithy_http/aio/endpoints.py index f0c703240..f9fcb7610 100644 --- a/packages/smithy-http/src/smithy_http/aio/endpoints.py +++ b/packages/smithy-http/src/smithy_http/aio/endpoints.py @@ -17,6 +17,9 @@ class StaticEndpointResolver( async def resolve_endpoint( self, params: StaticEndpointParams ) -> http_interfaces.Endpoint: + if params.uri is None: + raise ValueError("Unable to resolve endpoint: endpoint_uri is required") + # If it's not a string, it's already a parsed URI so just pass it along. if not isinstance(params.uri, str): return Endpoint(uri=params.uri) diff --git a/packages/smithy-http/src/smithy_http/endpoints.py b/packages/smithy-http/src/smithy_http/endpoints.py index 3e3f99dc8..3160ebc4b 100644 --- a/packages/smithy-http/src/smithy_http/endpoints.py +++ b/packages/smithy-http/src/smithy_http/endpoints.py @@ -20,4 +20,4 @@ class StaticEndpointParams: :param uri: A static URI to route requests to. """ - uri: str | URI + uri: str | URI | None From 526740e89f73b9786eaa80cd97178466b9a0c347 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 28 Feb 2025 10:42:46 -0800 Subject: [PATCH 4/8] Add EndpointResolutionError --- .../src/smithy_aws_core/endpoints/standard_regional.py | 6 +++--- packages/smithy-http/src/smithy_http/aio/endpoints.py | 8 +++++--- packages/smithy-http/src/smithy_http/endpoints.py | 5 +++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py index f242bf96b..203755737 100644 --- a/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py +++ b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py @@ -6,7 +6,7 @@ import smithy_core from smithy_core import URI from smithy_http.aio.interfaces import EndpointResolver -from smithy_http.endpoints import Endpoint +from smithy_http.endpoints import Endpoint, EndpointResolutionError @dataclass(kw_only=True) @@ -35,7 +35,7 @@ async def resolve_endpoint(self, params: RegionalEndpointParameters) -> Endpoint # This will end up getting wrapped in the client. if parsed.hostname is None: - raise ValueError( + raise EndpointResolutionError( f"Unable to parse hostname from provided URI: {params.sdk_endpoint}" ) @@ -56,6 +56,6 @@ async def resolve_endpoint(self, params: RegionalEndpointParameters) -> Endpoint return Endpoint(uri=URI(host=hostname)) - raise ValueError( + raise EndpointResolutionError( "Unable to resolve endpoint - either endpoint_url or region are required." ) diff --git a/packages/smithy-http/src/smithy_http/aio/endpoints.py b/packages/smithy-http/src/smithy_http/aio/endpoints.py index f9fcb7610..9ce4ae34d 100644 --- a/packages/smithy-http/src/smithy_http/aio/endpoints.py +++ b/packages/smithy-http/src/smithy_http/aio/endpoints.py @@ -5,7 +5,7 @@ from smithy_core import URI from .. import interfaces as http_interfaces -from ..endpoints import Endpoint, StaticEndpointParams +from ..endpoints import Endpoint, StaticEndpointParams, EndpointResolutionError from . import interfaces as http_aio_interfaces @@ -18,7 +18,9 @@ async def resolve_endpoint( self, params: StaticEndpointParams ) -> http_interfaces.Endpoint: if params.uri is None: - raise ValueError("Unable to resolve endpoint: endpoint_uri is required") + raise EndpointResolutionError( + "Unable to resolve endpoint: endpoint_uri is required" + ) # If it's not a string, it's already a parsed URI so just pass it along. if not isinstance(params.uri, str): @@ -30,7 +32,7 @@ async def resolve_endpoint( # This will end up getting wrapped in the client. if parsed.hostname is None: - raise ValueError( + raise EndpointResolutionError( f"Unable to parse hostname from provided URI: {params.uri}" ) diff --git a/packages/smithy-http/src/smithy_http/endpoints.py b/packages/smithy-http/src/smithy_http/endpoints.py index 3160ebc4b..a1337734b 100644 --- a/packages/smithy-http/src/smithy_http/endpoints.py +++ b/packages/smithy-http/src/smithy_http/endpoints.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 from dataclasses import dataclass, field +from smithy_core import SmithyException from smithy_core.interfaces import URI from . import Fields, interfaces @@ -13,6 +14,10 @@ class Endpoint(interfaces.Endpoint): headers: interfaces.Fields = field(default_factory=Fields) +class EndpointResolutionError(SmithyException): + """Exception type for all exceptions raised by endpoint resolution.""" + + @dataclass class StaticEndpointParams: """Static endpoint params. From a3118d7f0b70125c5d032d510e764b97bf06c23d Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Fri, 28 Feb 2025 10:55:53 -0800 Subject: [PATCH 5/8] Fix static endpoint parameter generation --- .../python/codegen/generators/StaticEndpointsGenerator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java index 2b2891c5a..a4ef6c757 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StaticEndpointsGenerator.java @@ -54,6 +54,10 @@ public List endpointsConfig(GenerationContext context) { public void renderEndpointParameterConstruction(GenerationContext context, PythonWriter writer) { writer.addDependency(SmithyPythonDependency.SMITHY_HTTP); writer.addImport("smithy_http.endpoints", "StaticEndpointParams"); - writer.write("endpoint_parameters = StaticEndpointParams(uri=config.endpoint_uri)"); + writer.write(""" + endpoint_parameters = StaticEndpointParams( + uri=config.endpoint_uri + ) + """); } } From 7ad023fe934b450d3e9172dd05d1f598266f08cd Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 4 Mar 2025 09:00:31 -0800 Subject: [PATCH 6/8] Add tests for StandardRegionalEndpointsResolver --- .../unit/endpoints/test_standard_regional.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py diff --git a/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py b/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py new file mode 100644 index 000000000..080781a0d --- /dev/null +++ b/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py @@ -0,0 +1,62 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from smithy_aws_core.endpoints.standard_regional import ( + StandardRegionalEndpointsResolver, + RegionalEndpointParameters, +) + +from smithy_core import URI +from smithy_http.endpoints import EndpointResolutionError + +import pytest + + +async def test_resolve_endpoint_with_valid_sdk_endpoint_string(): + resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service") + params = RegionalEndpointParameters( + sdk_endpoint="https://example.com/path?query=123", region=None + ) + + endpoint = await resolver.resolve_endpoint(params) + + assert endpoint.uri.host == "example.com" + assert endpoint.uri.path == "/path" + assert endpoint.uri.scheme == "https" + assert endpoint.uri.query == "query=123" + + +async def test_resolve_endpoint_with_sdk_endpoint_uri(): + resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service") + parsed_uri = URI( + host="example.com", path="/path", scheme="https", query="query=123", port=443 + ) + params = RegionalEndpointParameters(sdk_endpoint=parsed_uri, region=None) + + endpoint = await resolver.resolve_endpoint(params) + + assert endpoint.uri == parsed_uri + + +async def test_resolve_endpoint_with_invalid_sdk_endpoint(): + resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service") + params = RegionalEndpointParameters(sdk_endpoint="invalid-uri", region=None) + + with pytest.raises(EndpointResolutionError): + await resolver.resolve_endpoint(params) + + +async def test_resolve_endpoint_with_region(): + resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service") + params = RegionalEndpointParameters(sdk_endpoint=None, region="us-west-2") + + endpoint = await resolver.resolve_endpoint(params) + + assert endpoint.uri.host == "service.us-west-2.amazonaws.com" + + +async def test_resolve_endpoint_with_no_sdk_endpoint_or_region(): + resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service") + params = RegionalEndpointParameters(sdk_endpoint=None, region=None) + + with pytest.raises(EndpointResolutionError): + await resolver.resolve_endpoint(params) From d101b9a99135f611336e37a95937ed18838e2431 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 4 Mar 2025 15:36:18 -0800 Subject: [PATCH 7/8] Add test for sdk endpoint + region set --- .../tests/unit/endpoints/test_standard_regional.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py b/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py index 080781a0d..332d8969d 100644 --- a/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py +++ b/packages/smithy-aws-core/tests/unit/endpoints/test_standard_regional.py @@ -60,3 +60,14 @@ async def test_resolve_endpoint_with_no_sdk_endpoint_or_region(): with pytest.raises(EndpointResolutionError): await resolver.resolve_endpoint(params) + + +async def test_resolve_endpoint_with_sdk_endpoint_and_region(): + resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service") + params = RegionalEndpointParameters( + sdk_endpoint="https://example.com", region="us-west-2" + ) + + endpoint = await resolver.resolve_endpoint(params) + + assert endpoint.uri.host == "example.com" From 9d4dc1541e25e28520017d2d7f9541598875681a Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Wed, 5 Mar 2025 10:14:34 -0800 Subject: [PATCH 8/8] Minor cleanups --- .../software/amazon/smithy/python/codegen/ClientGenerator.java | 2 +- .../src/smithy_aws_core/endpoints/standard_regional.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index 1b7fe468b..b2df848c5 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -448,7 +448,7 @@ async def _handle_attempt( context.endpointsGenerator().renderEndpointParameterConstruction(context, writer); writer.write(""" - logger.debug("Calling endpoint resolver with parameters: %s", endpoint_resolver_parameters) + logger.debug("Calling endpoint resolver with parameters: %s", endpoint_parameters) endpoint = await config.endpoint_resolver.resolve_endpoint(endpoint_parameters) logger.debug("Endpoint resolver result: %s", endpoint) if not endpoint.uri.path: diff --git a/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py index 203755737..6064d6315 100644 --- a/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py +++ b/packages/smithy-aws-core/src/smithy_aws_core/endpoints/standard_regional.py @@ -29,8 +29,6 @@ async def resolve_endpoint(self, params: RegionalEndpointParameters) -> Endpoint if not isinstance(params.sdk_endpoint, str): return Endpoint(uri=params.sdk_endpoint) - # Does crt have implementations of these parsing methods? Using the standard - # library is probably fine. parsed = urlparse(params.sdk_endpoint) # This will end up getting wrapped in the client.