Skip to content

Commit 0dc2616

Browse files
committed
Add python changes for regional_endpoints
1 parent f4b87b9 commit 0dc2616

File tree

5 files changed

+146
-3
lines changed

5 files changed

+146
-3
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
from dataclasses import dataclass
4+
from urllib.parse import urlparse
5+
6+
import smithy_core
7+
from smithy_core import URI
8+
from smithy_http.aio.interfaces import EndpointResolver
9+
from smithy_http.endpoints import Endpoint, EndpointResolutionError
10+
11+
12+
@dataclass(kw_only=True)
13+
class RegionalEndpointParameters:
14+
"""Endpoint parameters for services with standard regional endpoints."""
15+
16+
sdk_endpoint: str | smithy_core.interfaces.URI | None
17+
region: str | None
18+
19+
20+
class StandardRegionalEndpointsResolver(EndpointResolver[RegionalEndpointParameters]):
21+
"""Resolves endpoints for services with standard regional endpoints."""
22+
23+
def __init__(self, endpoint_prefix: str):
24+
self._endpoint_prefix = endpoint_prefix
25+
26+
async def resolve_endpoint(self, params: RegionalEndpointParameters) -> Endpoint:
27+
if params.sdk_endpoint is not None:
28+
# If it's not a string, it's already a parsed URI so just pass it along.
29+
if not isinstance(params.sdk_endpoint, str):
30+
return Endpoint(uri=params.sdk_endpoint)
31+
32+
parsed = urlparse(params.sdk_endpoint)
33+
34+
# This will end up getting wrapped in the client.
35+
if parsed.hostname is None:
36+
raise EndpointResolutionError(
37+
f"Unable to parse hostname from provided URI: {params.sdk_endpoint}"
38+
)
39+
40+
return Endpoint(
41+
uri=URI(
42+
host=parsed.hostname,
43+
path=parsed.path,
44+
scheme=parsed.scheme,
45+
query=parsed.query,
46+
port=parsed.port,
47+
)
48+
)
49+
50+
if params.region is not None:
51+
# TODO: use dns suffix determined from partition metadata
52+
dns_suffix = "amazonaws.com"
53+
hostname = f"{self._endpoint_prefix}.{params.region}.{dns_suffix}"
54+
55+
return Endpoint(uri=URI(host=hostname))
56+
57+
raise EndpointResolutionError(
58+
"Unable to resolve endpoint - either endpoint_url or region are required."
59+
)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
from smithy_aws_core.endpoints.standard_regional import (
4+
StandardRegionalEndpointsResolver,
5+
RegionalEndpointParameters,
6+
)
7+
8+
from smithy_core import URI
9+
from smithy_http.endpoints import EndpointResolutionError
10+
11+
import pytest
12+
13+
14+
async def test_resolve_endpoint_with_valid_sdk_endpoint_string():
15+
resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service")
16+
params = RegionalEndpointParameters(
17+
sdk_endpoint="https://example.com/path?query=123", region=None
18+
)
19+
20+
endpoint = await resolver.resolve_endpoint(params)
21+
22+
assert endpoint.uri.host == "example.com"
23+
assert endpoint.uri.path == "/path"
24+
assert endpoint.uri.scheme == "https"
25+
assert endpoint.uri.query == "query=123"
26+
27+
28+
async def test_resolve_endpoint_with_sdk_endpoint_uri():
29+
resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service")
30+
parsed_uri = URI(
31+
host="example.com", path="/path", scheme="https", query="query=123", port=443
32+
)
33+
params = RegionalEndpointParameters(sdk_endpoint=parsed_uri, region=None)
34+
35+
endpoint = await resolver.resolve_endpoint(params)
36+
37+
assert endpoint.uri == parsed_uri
38+
39+
40+
async def test_resolve_endpoint_with_invalid_sdk_endpoint():
41+
resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service")
42+
params = RegionalEndpointParameters(sdk_endpoint="invalid-uri", region=None)
43+
44+
with pytest.raises(EndpointResolutionError):
45+
await resolver.resolve_endpoint(params)
46+
47+
48+
async def test_resolve_endpoint_with_region():
49+
resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service")
50+
params = RegionalEndpointParameters(sdk_endpoint=None, region="us-west-2")
51+
52+
endpoint = await resolver.resolve_endpoint(params)
53+
54+
assert endpoint.uri.host == "service.us-west-2.amazonaws.com"
55+
56+
57+
async def test_resolve_endpoint_with_no_sdk_endpoint_or_region():
58+
resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service")
59+
params = RegionalEndpointParameters(sdk_endpoint=None, region=None)
60+
61+
with pytest.raises(EndpointResolutionError):
62+
await resolver.resolve_endpoint(params)
63+
64+
65+
async def test_resolve_endpoint_with_sdk_endpoint_and_region():
66+
resolver = StandardRegionalEndpointsResolver(endpoint_prefix="service")
67+
params = RegionalEndpointParameters(
68+
sdk_endpoint="https://example.com", region="us-west-2"
69+
)
70+
71+
endpoint = await resolver.resolve_endpoint(params)
72+
73+
assert endpoint.uri.host == "example.com"

packages/smithy-http/src/smithy_http/aio/endpoints.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from smithy_core import URI
66

77
from .. import interfaces as http_interfaces
8-
from ..endpoints import Endpoint, StaticEndpointParams
8+
from ..endpoints import Endpoint, StaticEndpointParams, EndpointResolutionError
99
from . import interfaces as http_aio_interfaces
1010

1111

@@ -17,6 +17,11 @@ class StaticEndpointResolver(
1717
async def resolve_endpoint(
1818
self, params: StaticEndpointParams
1919
) -> http_interfaces.Endpoint:
20+
if params.uri is None:
21+
raise EndpointResolutionError(
22+
"Unable to resolve endpoint: endpoint_uri is required"
23+
)
24+
2025
# If it's not a string, it's already a parsed URI so just pass it along.
2126
if not isinstance(params.uri, str):
2227
return Endpoint(uri=params.uri)
@@ -27,7 +32,7 @@ async def resolve_endpoint(
2732

2833
# This will end up getting wrapped in the client.
2934
if parsed.hostname is None:
30-
raise ValueError(
35+
raise EndpointResolutionError(
3136
f"Unable to parse hostname from provided URI: {params.uri}"
3237
)
3338

packages/smithy-http/src/smithy_http/endpoints.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33
from dataclasses import dataclass, field
44

5+
from smithy_core import SmithyException
56
from smithy_core.interfaces import URI
67

78
from . import Fields, interfaces
@@ -13,11 +14,14 @@ class Endpoint(interfaces.Endpoint):
1314
headers: interfaces.Fields = field(default_factory=Fields)
1415

1516

17+
class EndpointResolutionError(SmithyException):
18+
"""Exception type for all exceptions raised by endpoint resolution."""
19+
1620
@dataclass
1721
class StaticEndpointParams:
1822
"""Static endpoint params.
1923
2024
:param uri: A static URI to route requests to.
2125
"""
2226

23-
uri: str | URI
27+
uri: str | URI | None

0 commit comments

Comments
 (0)