Skip to content
Open
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ To send us a pull request, please:
1. Fork the repository.
2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
3. Ensure local tests pass (`make test-py` and `make test-protocols`).
4. Run `make lint-py` if you've changed any python sources.
4. Run `make lint-py` and `make check-py` if you've changed any python sources.
4. Commit to your fork using clear commit messages.
5. Send us a pull request, answering any default questions in the pull request interface.
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to mark the class as subject to breaking change: https://smithy.io/javadoc/1.19.0/software/amazon/smithy/utils/SmithyUnstableApi.html

public class AwsPythonDependency {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of self-explanatory, but this is a class that is used to hold logic related to aws-specific dependencies in python. This class is expected to grow with more aws-specific dependencies as they are needed. For now, it just has SMITHY_AWS_CORE.

/**
* The core aws smithy runtime python package.
*
* <p>While in development this will use the develop branch.
*/
public static final PythonDependency SMITHY_AWS_CORE = new PythonDependency(
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SMITHY_AWS_CORE is referenced later - that will end up putting this in the pyproject.toml.

"smithy_aws_core",
// You'll need to locally install this before we publish
"==0.0.1",
PythonDependency.Type.DEPENDENCY,
false);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.python.aws.codegen;

import java.util.Collections;
import java.util.List;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolReference;
import software.amazon.smithy.python.codegen.ConfigProperty;
import software.amazon.smithy.python.codegen.integrations.PythonIntegration;
import software.amazon.smithy.python.codegen.integrations.RuntimeClientPlugin;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
* Adds a runtime plugin to set user agent.
*/
@SmithyInternalApi
public class AwsUserAgentIntegration implements PythonIntegration {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A PythonIntegration is sort of a plugin to the code generator. This uses "service provider interfaces" in Java.

Basically it's referenced later in the META-INF file below and some java magic happens that allows Smithy to pick this up during build time. This is handled by smithy itself, not smithy-python, so we don't have to understand this one on low level just yet.

@Override
public List<RuntimeClientPlugin> getClientPlugins() {
return List.of(
RuntimeClientPlugin.builder()
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A RuntimeClientPlugin is similarly collected to be used later, but this time the code to do so is inside of smithy-python.

I'll need to do a deeper dive here to understand how this works fully, but the gist is outlined in the comment below.

.addConfigProperty(
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addConfigProperty method is adding a configuration to the client. In this case, it's adding the configuration user_agent_extra to be added to the client.

End users will be able to pass in user_agent_extra to the client configuration somehow to be used by the client, similar to how they do in the botocore.config.Config object today.

ConfigProperty.builder()
// TODO: This is the name used in boto, but potentially could be user_agent_prefix. Depends on backwards compat strategy.
.name("user_agent_extra")
.documentation("Additional suffix to be added to the User-Agent header.")
.type(Symbol.builder().name("str").build()) // TODO: Should common types like this be defined as constants somewhere?
.nullable(true)
.build())
.addConfigProperty(
ConfigProperty.builder()
.name("sdk_ua_app_id")
.documentation("A unique and opaque application ID that is appended to the User-Agent header.")
.type(Symbol.builder().name("str").build())
.nullable(true)
.build()
)
.pythonPlugin(
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.pythonPlugin is adding a plugin to the client. This is a smithy interceptor; this is similar to adding an event handler to an event in botocore.

SymbolReference.builder()
.symbol(Symbol.builder()
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A symbol is just a reference to some form of python code. In this case, it's a reference to this new method.

.namespace(AwsPythonDependency.SMITHY_AWS_CORE.packageName() + ".plugins", ".")
.name("user_agent_plugin")
.addDependency(AwsPythonDependency.SMITHY_AWS_CORE)
.build())
.build()
)
.build()
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

software.amazon.smithy.python.aws.codegen.AwsAuthIntegration
software.amazon.smithy.python.aws.codegen.AwsProtocolsIntegration
software.amazon.smithy.python.aws.codegen.AwsUserAgentIntegration
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

from smithy_aws_core.user_agent import UserAgent
from smithy_core.interceptors import Interceptor, InterceptorContext, Request
from smithy_http import Field
from smithy_http.aio import HTTPRequest


class UserAgentInterceptor(Interceptor[Request, None, HTTPRequest, None]):
"""Adds UserAgent header to the Request before signing."""

def __init__(
self,
ua_suffix: str | None = None,
ua_app_id: str | None = None,
sdk_version: str | None = "0.0.1",
) -> None:
"""Initialize the UserAgentInterceptor.

:ua_suffix: Additional suffix to be added to the UserAgent header. :ua_app_id:
User defined and opaque application ID to be added to the UserAgent header.
"""
super().__init__()
self._ua_suffix = ua_suffix
self._ua_app_id = ua_app_id
self._sdk_version = sdk_version

def modify_before_signing(
self, context: InterceptorContext[Request, None, HTTPRequest, None]
) -> HTTPRequest:
user_agent = UserAgent.from_environment().with_config(
ua_suffix=self._ua_suffix,
ua_app_id=self._ua_app_id,
sdk_version=self._sdk_version,
)
request = context.transport_request
request.fields.set_field(
Field(name="User-Agent", values=[user_agent.to_string()])
)
return context.transport_request
16 changes: 16 additions & 0 deletions packages/smithy-aws-core/src/smithy_aws_core/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

from typing import Any

from smithy_aws_core.interceptors.user_agent import UserAgentInterceptor


# TODO: Define a Protocol for Config w/ interceptor method?
def user_agent_plugin(config: Any) -> None:
config.interceptors.append(
UserAgentInterceptor(
ua_suffix=config.user_agent_extra,
ua_app_id=config.sdk_ua_app_id,
)
)
Loading
Loading