Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion codegen-output/aws-json-1-0/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ classifiers = [
dependencies = [
"smithy_aws_core[json]~=0.12.0",
"smithy_core~=0.9.0",
"smithy_http[aiohttp]~=0.6.0"
"smithy_http[aiohttp]~=0.6.0",
"smithy_json~=0.3.0"
]

[project.optional-dependencies]
Expand Down
7 changes: 6 additions & 1 deletion codegen-output/aws-json-1-0/src/awsjson10/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from smithy_core.serializers import SerializeableShape
from smithy_http.aio.interfaces import HTTPClient
from smithy_http.plugins import user_agent_plugin
from smithy_json.plugins import json_deserialization_plugin

from .config import AsyncJSONRPC10Config, Plugin
from .models import (
Expand Down Expand Up @@ -94,7 +95,11 @@ def __init__(
super().__init__()
self._config = config
self._plugins = plugins
self._client_plugins: list[Plugin] = [aws_user_agent_plugin, user_agent_plugin]
self._client_plugins: list[Plugin] = [
aws_user_agent_plugin,
json_deserialization_plugin,
user_agent_plugin,
]

async def _ensure_setup(self) -> AsyncJSONRPC10Config:
if not self._setup_done:
Expand Down
9 changes: 9 additions & 0 deletions codegen-output/aws-json-1-0/src/awsjson10/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from smithy_core.interfaces.auth import AuthSchemeResolver
from smithy_core.shapes import ShapeID
from smithy_http.aio.aiohttp import AIOHTTPClient
from smithy_json import JSONDeserializationMode

from .auth import HTTPAuthSchemeResolver
from .models import (
Expand Down Expand Up @@ -111,6 +112,7 @@ class _AsyncJSONRPC10ConfigOverrides(AwsConfigOverrides, total=False):
)
auth_schemes: dict[ShapeID, AuthScheme[Any, Any, Any, Any]] | None
auth_scheme_resolver: AuthSchemeResolver | None
json_deserialization_mode: JSONDeserializationMode | None


@dataclass(kw_only=True, repr=False, init=False)
Expand Down Expand Up @@ -174,6 +176,12 @@ class AsyncJSONRPC10Config(AsyncAwsConfig):
header.
"""

json_deserialization_mode: JSONDeserializationMode | None = None
"""
Controls whether JSON response payloads are deserialized eagerly or
incrementally.
"""

_FIELDS: ClassVar[dict[str, FieldSpec]] = {
"aws_credentials_identity_resolver": FieldSpec(default=None),
"region": FieldSpec(default=None),
Expand All @@ -182,6 +190,7 @@ class AsyncJSONRPC10Config(AsyncAwsConfig):
"aws_session_token": FieldSpec(default=None),
"user_agent_extra": FieldSpec(default=None),
"sdk_ua_app_id": FieldSpec(default=None),
"json_deserialization_mode": FieldSpec(default=None),
**AsyncAwsConfig._FIELDS,
"endpoint_uri": FieldSpec(
default=None, resolver=EndpointUriResolver("json_rpc_10")
Expand Down
3 changes: 2 additions & 1 deletion codegen-output/aws-json-1-1/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ classifiers = [
dependencies = [
"smithy_aws_core[json]~=0.12.0",
"smithy_core~=0.9.0",
"smithy_http[aiohttp]~=0.6.0"
"smithy_http[aiohttp]~=0.6.0",
"smithy_json~=0.3.0"
]

[project.optional-dependencies]
Expand Down
7 changes: 6 additions & 1 deletion codegen-output/aws-json-1-1/src/awsjson11/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from smithy_core.serializers import SerializeableShape
from smithy_http.aio.interfaces import HTTPClient
from smithy_http.plugins import user_agent_plugin
from smithy_json.plugins import json_deserialization_plugin

from .config import AsyncJsonProtocolConfig, Plugin
from .models import (
Expand Down Expand Up @@ -100,7 +101,11 @@ def __init__(
super().__init__()
self._config = config
self._plugins = plugins
self._client_plugins: list[Plugin] = [aws_user_agent_plugin, user_agent_plugin]
self._client_plugins: list[Plugin] = [
aws_user_agent_plugin,
json_deserialization_plugin,
user_agent_plugin,
]

async def _ensure_setup(self) -> AsyncJsonProtocolConfig:
if not self._setup_done:
Expand Down
9 changes: 9 additions & 0 deletions codegen-output/aws-json-1-1/src/awsjson11/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from smithy_core.interfaces.auth import AuthSchemeResolver
from smithy_core.shapes import ShapeID
from smithy_http.aio.aiohttp import AIOHTTPClient
from smithy_json import JSONDeserializationMode

from .auth import HTTPAuthSchemeResolver
from .models import (
Expand Down Expand Up @@ -111,6 +112,7 @@ class _AsyncJsonProtocolConfigOverrides(AwsConfigOverrides, total=False):
)
auth_schemes: dict[ShapeID, AuthScheme[Any, Any, Any, Any]] | None
auth_scheme_resolver: AuthSchemeResolver | None
json_deserialization_mode: JSONDeserializationMode | None


@dataclass(kw_only=True, repr=False, init=False)
Expand Down Expand Up @@ -174,6 +176,12 @@ class AsyncJsonProtocolConfig(AsyncAwsConfig):
header.
"""

json_deserialization_mode: JSONDeserializationMode | None = None
"""
Controls whether JSON response payloads are deserialized eagerly or
incrementally.
"""

_FIELDS: ClassVar[dict[str, FieldSpec]] = {
"aws_credentials_identity_resolver": FieldSpec(default=None),
"region": FieldSpec(default=None),
Expand All @@ -182,6 +190,7 @@ class AsyncJsonProtocolConfig(AsyncAwsConfig):
"aws_session_token": FieldSpec(default=None),
"user_agent_extra": FieldSpec(default=None),
"sdk_ua_app_id": FieldSpec(default=None),
"json_deserialization_mode": FieldSpec(default=None),
**AsyncAwsConfig._FIELDS,
"endpoint_uri": FieldSpec(
default=None, resolver=EndpointUriResolver("json_protocol")
Expand Down
3 changes: 2 additions & 1 deletion codegen-output/rest-json-1/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ classifiers = [
dependencies = [
"smithy_aws_core[eventstream, json]~=0.12.0",
"smithy_core~=0.9.0",
"smithy_http[aiohttp]~=0.6.0"
"smithy_http[aiohttp]~=0.6.0",
"smithy_json~=0.3.0"
]

[project.optional-dependencies]
Expand Down
7 changes: 6 additions & 1 deletion codegen-output/rest-json-1/src/restjson/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from smithy_core.serializers import SerializeableShape
from smithy_http.aio.interfaces import HTTPClient
from smithy_http.plugins import user_agent_plugin
from smithy_json.plugins import json_deserialization_plugin

from .config import AsyncRestJsonProtocolConfig, Plugin
from .models import (
Expand Down Expand Up @@ -392,7 +393,11 @@ def __init__(
super().__init__()
self._config = config
self._plugins = plugins
self._client_plugins: list[Plugin] = [aws_user_agent_plugin, user_agent_plugin]
self._client_plugins: list[Plugin] = [
aws_user_agent_plugin,
json_deserialization_plugin,
user_agent_plugin,
]

async def _ensure_setup(self) -> AsyncRestJsonProtocolConfig:
if not self._setup_done:
Expand Down
9 changes: 9 additions & 0 deletions codegen-output/rest-json-1/src/restjson/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from smithy_core.interfaces.auth import AuthSchemeResolver
from smithy_core.shapes import ShapeID
from smithy_http.aio.aiohttp import AIOHTTPClient
from smithy_json import JSONDeserializationMode

from .auth import HTTPAuthSchemeResolver
from .models import (
Expand Down Expand Up @@ -556,6 +557,7 @@ class _AsyncRestJsonProtocolConfigOverrides(AwsConfigOverrides, total=False):
)
auth_schemes: dict[ShapeID, AuthScheme[Any, Any, Any, Any]] | None
auth_scheme_resolver: AuthSchemeResolver | None
json_deserialization_mode: JSONDeserializationMode | None


@dataclass(kw_only=True, repr=False, init=False)
Expand Down Expand Up @@ -619,6 +621,12 @@ class AsyncRestJsonProtocolConfig(AsyncAwsConfig):
header.
"""

json_deserialization_mode: JSONDeserializationMode | None = None
"""
Controls whether JSON response payloads are deserialized eagerly or
incrementally.
"""

_FIELDS: ClassVar[dict[str, FieldSpec]] = {
"aws_credentials_identity_resolver": FieldSpec(default=None),
"region": FieldSpec(default=None),
Expand All @@ -627,6 +635,7 @@ class AsyncRestJsonProtocolConfig(AsyncAwsConfig):
"aws_session_token": FieldSpec(default=None),
"user_agent_extra": FieldSpec(default=None),
"sdk_ua_app_id": FieldSpec(default=None),
"json_deserialization_mode": FieldSpec(default=None),
**AsyncAwsConfig._FIELDS,
"endpoint_uri": FieldSpec(
default=None, resolver=EndpointUriResolver("rest_json_protocol")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public void testCodegen(@TempDir Path tempDir) throws IOException {
assertTrue(config.contains("self.auth_schemes = auth_schemes"));
assertTrue(config.contains("default_factory=lambda: AIOHTTPClient()"));
assertFalse(config.contains("from smithy_http.aio.crt import AWSCRTHTTPClient"));
assertTrue(config.contains(
"json_deserialization_mode: JSONDeserializationMode | None"));
assertTrue(config.contains(
"\"json_deserialization_mode\": FieldSpec(default=None)"));

var client = Files.readString(tempDir.resolve("src/restjson/client.py"));
assertInOrder(
Expand All @@ -73,6 +77,9 @@ public void testCodegen(@TempDir Path tempDir) throws IOException {
assertFalse(client.contains("plugin(self._config)"));
assertTrue(client.contains("retry_mode=config.retry_mode"));
assertTrue(client.contains("max_attempts=config.max_attempts"));
assertTrue(client.contains(
"from smithy_json.plugins import json_deserialization_plugin"));
assertTrue(client.contains("json_deserialization_plugin,"));

var schemas = Files.readString(tempDir.resolve("src/restjson/_private/schemas.py"));
assertTrue(schemas.contains("aws.protocols#restJson1"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ public void testCodegen(@TempDir Path tempDir) throws IOException {
var config = Files.readString(tempDir.resolve("src/weather/config.py"));
assertTrue(config.contains("self.transport = transport or AIOHTTPClient()"));
assertFalse(config.contains("self.transport = transport or AWSCRTHTTPClient()"));
assertTrue(config.contains(
"json_deserialization_mode: JSONDeserializationMode | None"));
assertTrue(config.contains(
"self.json_deserialization_mode = json_deserialization_mode"));

assertTrue(client.contains(
"from smithy_json.plugins import json_deserialization_plugin"));
assertTrue(client.contains("json_deserialization_plugin,"));

// An output that models a "responseMetadata" member gets both the SDK-reserved
// response_metadata attribute and the escaped modeled member, so neither shadows
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.python.codegen.integrations;

import java.util.List;
import java.util.Set;
import software.amazon.smithy.aws.traits.protocols.AwsJson1_0Trait;
import software.amazon.smithy.aws.traits.protocols.AwsJson1_1Trait;
import software.amazon.smithy.aws.traits.protocols.RestJson1Trait;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolReference;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.ShapeId;
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.utils.SmithyInternalApi;

/**
* Adds configurable JSON deserialization to clients that support a JSON protocol.
*/
@SmithyInternalApi
public final class JsonDeserializationIntegration implements PythonIntegration {
private static final Set<ShapeId> JSON_PROTOCOLS = Set.of(
RestJson1Trait.ID,
AwsJson1_0Trait.ID,
AwsJson1_1Trait.ID);

@Override
public List<RuntimeClientPlugin> getClientPlugins(GenerationContext context) {
var mode = Symbol.builder()
.name("JSONDeserializationMode")
.namespace("smithy_json", ".")
.addDependency(SmithyPythonDependency.SMITHY_JSON)
.build();
var plugin = SymbolReference.builder()
.symbol(Symbol.builder()
.name("json_deserialization_plugin")
.namespace("smithy_json.plugins", ".")
.addDependency(SmithyPythonDependency.SMITHY_JSON)
.build())
.build();
var property = ConfigProperty.builder()
.name("json_deserialization_mode")
.type(mode)
.documentation(
"Controls whether JSON response payloads are deserialized eagerly or incrementally.")
.nullable(true)
.build();

return List.of(RuntimeClientPlugin.builder()
.servicePredicate(JsonDeserializationIntegration::usesJsonProtocol)
.addConfigProperty(property)
.pythonPlugin(plugin)
.build());
}

static boolean usesJsonProtocol(Model model, ServiceShape service) {
return ServiceIndex.of(model)
.getProtocols(service)
.keySet()
.stream()
.anyMatch(JSON_PROTOCOLS::contains);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#

software.amazon.smithy.python.codegen.integrations.RestJsonIntegration
software.amazon.smithy.python.codegen.integrations.JsonDeserializationIntegration
software.amazon.smithy.python.codegen.integrations.Rpcv2CborIntegration
software.amazon.smithy.python.codegen.integrations.HttpApiKeyAuth
software.amazon.smithy.python.codegen.integrations.UserAgentIntegration
Expand Down
Loading
Loading