-
Notifications
You must be signed in to change notification settings - Fork 24
User agent #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
User agent #387
Changes from 23 commits
cb47f65
91e8208
d3b1d15
2031933
d5473b5
83a0a8f
b7e15d1
8afb134
a7475d7
296811b
f449114
7b7573d
6a49728
b727753
b88dfc2
6c6458b
7aac81c
86e461c
0013139
00ce11f
8ea3bf2
a35f607
5f128d4
20b97ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| public class AwsPythonDependency { | ||
| /** | ||
| * 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( | ||
| "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,114 @@ | ||
| /* | ||
| * 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.List; | ||
| import software.amazon.smithy.aws.traits.ServiceTrait; | ||
| import software.amazon.smithy.codegen.core.Symbol; | ||
| import software.amazon.smithy.codegen.core.SymbolReference; | ||
| 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.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 { | ||
|
|
||
| public static final String USER_AGENT_PLUGIN = """ | ||
| def aws_user_agent_plugin(config: $1T): | ||
| config.interceptors.append( | ||
| $2T( | ||
| ua_suffix=config.user_agent_extra, | ||
| ua_app_id=config.sdk_ua_app_id, | ||
| sdk_version=$3T, | ||
| service_id='$4L' | ||
| ) | ||
| ) | ||
| """; | ||
|
|
||
| @Override | ||
| public List<RuntimeClientPlugin> getClientPlugins(GenerationContext context) { | ||
| if (context.applicationProtocol().isHttpProtocol()) { | ||
| final ConfigProperty userAgentExtra = ConfigProperty.builder() | ||
| .name("user_agent_extra") | ||
| .documentation("Additional suffix to be added to the User-Agent header.") | ||
| .type(Symbol.builder().name("str").build()) | ||
| .nullable(true) | ||
| .build(); | ||
|
|
||
| final ConfigProperty uaAppId = 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(); | ||
|
|
||
| final String user_agent_plugin_file = "user_agent"; | ||
|
|
||
| final String moduleName = context.settings().moduleName(); | ||
| final SymbolReference userAgentPlugin = SymbolReference.builder() | ||
| .symbol(Symbol.builder() | ||
| .namespace(String.format("%s.%s", | ||
| moduleName, | ||
| user_agent_plugin_file.replace('/', '.')), ".") | ||
| .definitionFile(String | ||
| .format("./%s/%s.py", moduleName, user_agent_plugin_file)) | ||
| .name("aws_user_agent_plugin") | ||
| .build()) | ||
| .build(); | ||
| final SymbolReference userAgentInterceptor = SymbolReference.builder() | ||
| .symbol(Symbol.builder() | ||
| .namespace("smithy_aws_core.interceptors.user_agent", ".") | ||
| .name("UserAgentInterceptor") | ||
| .build()) | ||
| .build(); | ||
| final SymbolReference versionSymbol = SymbolReference.builder() | ||
| .symbol(Symbol.builder() | ||
| .namespace(moduleName, ".") | ||
| .name("__version__") | ||
| .build()) | ||
| .build(); | ||
|
|
||
| final String serviceId = context.settings() | ||
| .service(context.model()) | ||
| .getTrait(ServiceTrait.class) | ||
| .map(ServiceTrait::getSdkId) | ||
| .orElse(context.settings().service().getName()) | ||
| .replace(' ', '_'); | ||
|
|
||
| return List.of( | ||
| RuntimeClientPlugin.builder() | ||
| .addConfigProperty(userAgentExtra) | ||
| .addConfigProperty(uaAppId) | ||
| .pythonPlugin(userAgentPlugin) | ||
| .writeAdditionalFiles((c) -> { | ||
| String filename = "%s/%s.py".formatted(moduleName, user_agent_plugin_file); | ||
| c.writerDelegator() | ||
| .useFileWriter( | ||
| filename, | ||
| moduleName + ".", | ||
| writer -> { | ||
| writer.write(USER_AGENT_PLUGIN, | ||
| CodegenUtils.getConfigSymbol(c.settings()), | ||
| userAgentInterceptor, | ||
| versionSymbol, | ||
| serviceId); | ||
|
|
||
| }); | ||
| return List.of(filename); | ||
| }) | ||
| .build()); | ||
| } else { | ||
| return List.of(); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,7 @@ | |
| import software.amazon.smithy.python.codegen.generators.StructureGenerator; | ||
| import software.amazon.smithy.python.codegen.generators.UnionGenerator; | ||
| import software.amazon.smithy.python.codegen.integrations.PythonIntegration; | ||
| import software.amazon.smithy.python.codegen.integrations.RuntimeClientPlugin; | ||
| import software.amazon.smithy.python.codegen.writer.PythonDelegator; | ||
| import software.amazon.smithy.python.codegen.writer.PythonWriter; | ||
| import software.amazon.smithy.utils.SmithyUnstableApi; | ||
|
|
@@ -273,9 +274,39 @@ public void generateIntEnumShape(GenerateIntEnumDirective<GenerationContext, Pyt | |
|
|
||
| @Override | ||
| public void customizeBeforeIntegrations(CustomizeDirective<GenerationContext, PythonSettings> directive) { | ||
| generateServiceModuleInit(directive); | ||
| generatePluginFiles(directive); | ||
| generateInits(directive); | ||
| } | ||
|
|
||
| /** | ||
| * Writes out all extra files required by runtime plugins. | ||
| */ | ||
| private void generatePluginFiles(CustomizeDirective<GenerationContext, PythonSettings> directive) { | ||
| GenerationContext context = directive.context(); | ||
| for (PythonIntegration integration : context.integrations()) { | ||
| for (RuntimeClientPlugin runtimeClientPlugin : integration.getClientPlugins(context)) { | ||
| if (runtimeClientPlugin.matchesService(context.model(), directive.service())) { | ||
| runtimeClientPlugin.writeAdditionalFiles(context); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Creates top level __init__.py file. | ||
| */ | ||
| private void generateServiceModuleInit(CustomizeDirective<GenerationContext, PythonSettings> directive) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be done directly in |
||
| directive.context() | ||
| .writerDelegator() | ||
| .useFileWriter( | ||
| "%s/__init__.py".formatted(directive.context().settings().moduleName()), | ||
| writer -> { | ||
| writer | ||
| .write("__version__: str = '$L'", directive.context().settings().moduleVersion()); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Creates __init__.py files where not already present. | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -219,7 +219,7 @@ private static void writeDefaultHttpAuthSchemes(GenerationContext context, Pytho | |
| var supportedAuthSchemes = new LinkedHashMap<String, Symbol>(); | ||
| var service = context.settings().service(context.model()); | ||
| for (PythonIntegration integration : context.integrations()) { | ||
| for (RuntimeClientPlugin plugin : integration.getClientPlugins()) { | ||
| for (RuntimeClientPlugin plugin : integration.getClientPlugins(context)) { | ||
| if (plugin.matchesService(context.model(), service) | ||
| && plugin.getAuthScheme().isPresent() | ||
| && plugin.getAuthScheme().get().getApplicationProtocol().isHttpProtocol()) { | ||
|
|
@@ -289,7 +289,7 @@ private void writeInterceptorsType(PythonWriter writer) { | |
| } | ||
|
|
||
| private void generateConfig(GenerationContext context, PythonWriter writer) { | ||
| var symbol = CodegenUtils.getConfigSymbol(context.settings()); | ||
| var configSymbol = CodegenUtils.getConfigSymbol(context.settings()); | ||
|
|
||
| // Initialize the list of config properties with our base properties. Here a new | ||
| // list is constructed because that base list is immutable. | ||
|
|
@@ -312,7 +312,7 @@ private void generateConfig(GenerationContext context, PythonWriter writer) { | |
|
|
||
| // Add any relevant config properties from plugins. | ||
| for (PythonIntegration integration : context.integrations()) { | ||
| for (RuntimeClientPlugin plugin : integration.getClientPlugins()) { | ||
| for (RuntimeClientPlugin plugin : integration.getClientPlugins(context)) { | ||
| if (plugin.matchesService(model, service)) { | ||
| properties.addAll(plugin.getConfigProperties()); | ||
| } | ||
|
|
@@ -324,7 +324,7 @@ private void generateConfig(GenerationContext context, PythonWriter writer) { | |
| writer.addStdlibImport("dataclasses", "dataclass"); | ||
| writer.write(""" | ||
| @dataclass(init=False) | ||
| class $L: | ||
| class $T: | ||
|
||
| \"""Configuration for $L.\""" | ||
|
|
||
| ${C|} | ||
|
|
@@ -340,7 +340,7 @@ def __init__( | |
| \""" | ||
| ${C|} | ||
| """, | ||
| symbol.getName(), | ||
| configSymbol, | ||
| context.settings().service().getName(), | ||
| writer.consumer(w -> writePropertyDeclarations(w, finalProperties)), | ||
| writer.consumer(w -> writeInitParams(w, finalProperties)), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.