Skip to content

Commit fed1e58

Browse files
authored
Release November 21st, 2025
2 parents 2a646ce + f5da49f commit fed1e58

File tree

46 files changed

+1030
-93
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1030
-93
lines changed

codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsPythonDependency.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ private AwsPythonDependency() {}
2222
*/
2323
public static final PythonDependency SMITHY_AWS_CORE = new PythonDependency(
2424
"smithy_aws_core",
25-
"~=0.1.0",
25+
"~=0.2.0",
2626
PythonDependency.Type.DEPENDENCY,
2727
false);
2828
}

codegen/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515

1616
allprojects {
1717
group = "software.amazon.smithy.python"
18-
version = "0.0.1"
18+
version = "0.1.0"
1919
}

codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ private void generateService(PythonWriter writer) {
8383
}
8484
}
8585

86+
writer.addDependency(SmithyPythonDependency.SMITHY_CORE);
87+
writer.addImport("smithy_core.retries", "RetryStrategyResolver");
8688
writer.write("""
8789
def __init__(self, config: $1T | None = None, plugins: list[$2T] | None = None):
8890
self._config = config or $1T()
@@ -95,6 +97,8 @@ def __init__(self, config: $1T | None = None, plugins: list[$2T] | None = None):
9597
9698
for plugin in client_plugins:
9799
plugin(self._config)
100+
101+
self._retry_strategy_resolver = RetryStrategyResolver()
98102
""", configSymbol, pluginSymbol, writer.consumer(w -> writeDefaultPlugins(w, defaultPlugins)));
99103

100104
var topDownIndex = TopDownIndex.of(model);
@@ -168,8 +172,7 @@ private void writeSharedOperationInit(PythonWriter writer, OperationShape operat
168172
writer.write("""
169173
:param plugins: A list of callables that modify the configuration dynamically.
170174
Changes made by these plugins only apply for the duration of the operation
171-
execution and will not affect any other operation invocations.
172-
""");
175+
execution and will not affect any other operation invocations.""");
173176

174177
});
175178

@@ -188,6 +191,8 @@ private void writeSharedOperationInit(PythonWriter writer, OperationShape operat
188191
writer.addImport("smithy_core.types", "TypedProperties");
189192
writer.addImport("smithy_core.aio.client", "RequestPipeline");
190193
writer.addImport("smithy_core.exceptions", "ExpectationNotMetError");
194+
writer.addImport("smithy_core.retries", "RetryStrategyOptions");
195+
writer.addImport("smithy_core.interfaces.retries", "RetryStrategy");
191196
writer.addStdlibImport("copy", "deepcopy");
192197

193198
writer.write("""
@@ -201,6 +206,24 @@ private void writeSharedOperationInit(PythonWriter writer, OperationShape operat
201206
plugin(config)
202207
if config.protocol is None or config.transport is None:
203208
raise ExpectationNotMetError("protocol and transport MUST be set on the config to make calls.")
209+
210+
# Resolve retry strategy from config
211+
if isinstance(config.retry_strategy, RetryStrategy):
212+
retry_strategy = config.retry_strategy
213+
elif isinstance(config.retry_strategy, RetryStrategyOptions):
214+
retry_strategy = await self._retry_strategy_resolver.resolve_retry_strategy(
215+
options=config.retry_strategy
216+
)
217+
elif config.retry_strategy is None:
218+
retry_strategy = await self._retry_strategy_resolver.resolve_retry_strategy(
219+
options=RetryStrategyOptions()
220+
)
221+
else:
222+
raise TypeError(
223+
f"retry_strategy must be RetryStrategy, RetryStrategyOptions, or None, "
224+
f"got {type(config.retry_strategy).__name__}"
225+
)
226+
204227
pipeline = RequestPipeline(
205228
protocol=config.protocol,
206229
transport=config.transport
@@ -213,7 +236,7 @@ raise ExpectationNotMetError("protocol and transport MUST be set on the config t
213236
auth_scheme_resolver=config.auth_scheme_resolver,
214237
supported_auth_schemes=config.auth_schemes,
215238
endpoint_resolver=config.endpoint_resolver,
216-
retry_strategy=config.retry_strategy,
239+
retry_strategy=retry_strategy,
217240
)
218241
""", writer.consumer(w -> writeDefaultPlugins(w, defaultPlugins)));
219242

codegen/core/src/main/java/software/amazon/smithy/python/codegen/HttpProtocolTestGenerator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ def __init__(self, request: HTTPRequest):
631631
class $3L:
632632
""\"An asynchronous HTTP client solely for testing purposes.""\"
633633
634+
TIMEOUT_EXCEPTIONS = ()
635+
634636
def __init__(self, *, client_config: HTTPClientConfiguration | None = None):
635637
self._client_config = client_config
636638
@@ -644,6 +646,8 @@ async def send(
644646
class $4L:
645647
""\"An asynchronous HTTP client solely for testing purposes.""\"
646648
649+
TIMEOUT_EXCEPTIONS = ()
650+
647651
def __init__(
648652
self,
649653
*,

codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public final class SmithyPythonDependency {
2222
*/
2323
public static final PythonDependency SMITHY_CORE = new PythonDependency(
2424
"smithy_core",
25-
"~=0.1.0",
25+
"~=0.2.0",
2626
Type.DEPENDENCY,
2727
false);
2828

@@ -33,7 +33,7 @@ public final class SmithyPythonDependency {
3333
*/
3434
public static final PythonDependency SMITHY_HTTP = new PythonDependency(
3535
"smithy_http",
36-
"~=0.2.0",
36+
"~=0.3.0",
3737
Type.DEPENDENCY,
3838
false);
3939

@@ -60,7 +60,7 @@ public final class SmithyPythonDependency {
6060
*/
6161
public static final PythonDependency SMITHY_JSON = new PythonDependency(
6262
"smithy_json",
63-
"~=0.1.0",
63+
"~=0.2.0",
6464
Type.DEPENDENCY,
6565
false);
6666

@@ -69,7 +69,7 @@ public final class SmithyPythonDependency {
6969
*/
7070
public static final PythonDependency SMITHY_AWS_EVENT_STREAM = new PythonDependency(
7171
"smithy_aws_event_stream",
72-
"~=0.1.0",
72+
"~=0.2.0",
7373
Type.DEPENDENCY,
7474
false);
7575

@@ -78,7 +78,7 @@ public final class SmithyPythonDependency {
7878
*/
7979
public static final PythonDependency SMITHY_AWS_CORE = new PythonDependency(
8080
"smithy_aws_core",
81-
"~=0.1.0",
81+
"~=0.2.0",
8282
Type.DEPENDENCY,
8383
false);
8484

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/ConfigGenerator.java

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.List;
1111
import java.util.Locale;
1212
import java.util.TreeSet;
13+
import software.amazon.smithy.aws.traits.ServiceTrait;
1314
import software.amazon.smithy.codegen.core.Symbol;
1415
import software.amazon.smithy.model.knowledge.EventStreamIndex;
1516
import software.amazon.smithy.model.knowledge.ServiceIndex;
@@ -54,17 +55,20 @@ public final class ConfigGenerator implements Runnable {
5455
ConfigProperty.builder()
5556
.name("retry_strategy")
5657
.type(Symbol.builder()
57-
.name("RetryStrategy")
58-
.namespace("smithy_core.interfaces.retries", ".")
59-
.addDependency(SmithyPythonDependency.SMITHY_CORE)
58+
.name("RetryStrategy | RetryStrategyOptions")
59+
.addReference(Symbol.builder()
60+
.name("RetryStrategy")
61+
.namespace("smithy_core.interfaces.retries", ".")
62+
.addDependency(SmithyPythonDependency.SMITHY_CORE)
63+
.build())
64+
.addReference(Symbol.builder()
65+
.name("RetryStrategyOptions")
66+
.namespace("smithy_core.retries", ".")
67+
.addDependency(SmithyPythonDependency.SMITHY_CORE)
68+
.build())
6069
.build())
61-
.documentation("The retry strategy for issuing retry tokens and computing retry delays.")
62-
.nullable(false)
63-
.initialize(writer -> {
64-
writer.addDependency(SmithyPythonDependency.SMITHY_CORE);
65-
writer.addImport("smithy_core.retries", "SimpleRetryStrategy");
66-
writer.write("self.retry_strategy = retry_strategy or SimpleRetryStrategy()");
67-
})
70+
.documentation(
71+
"The retry strategy or options for configuring retry behavior. Can be either a configured RetryStrategy or RetryStrategyOptions to create one.")
6872
.build(),
6973
ConfigProperty.builder()
7074
.name("endpoint_uri")
@@ -331,6 +335,11 @@ private void generateConfig(GenerationContext context, PythonWriter writer) {
331335
}
332336

333337
var finalProperties = List.copyOf(properties);
338+
final String serviceId = context.settings()
339+
.service(context.model())
340+
.getTrait(ServiceTrait.class)
341+
.map(ServiceTrait::getSdkId)
342+
.orElse(context.settings().service().getName());
334343
writer.pushState(new ConfigSection(finalProperties));
335344
writer.addStdlibImport("dataclasses", "dataclass");
336345
writer.write("""
@@ -345,14 +354,11 @@ def __init__(
345354
*,
346355
${C|}
347356
):
348-
\"""Constructor.
349-
350357
${C|}
351-
\"""
352358
${C|}
353359
""",
354360
configSymbol.getName(),
355-
context.settings().service().getName(),
361+
serviceId,
356362
writer.consumer(w -> writePropertyDeclarations(w, finalProperties)),
357363
writer.consumer(w -> writeInitParams(w, finalProperties)),
358364
writer.consumer(w -> documentProperties(w, finalProperties)),
@@ -376,17 +382,20 @@ private void writeInitParams(PythonWriter writer, Collection<ConfigProperty> pro
376382
}
377383

378384
private void documentProperties(PythonWriter writer, Collection<ConfigProperty> properties) {
379-
var iter = properties.iterator();
380-
while (iter.hasNext()) {
381-
var property = iter.next();
382-
var docs = writer.formatDocs(String.format(":param %s: %s", property.name(), property.documentation()));
385+
writer.writeDocs(() -> {
386+
var iter = properties.iterator();
387+
writer.write("\nConstructor.\n");
388+
while (iter.hasNext()) {
389+
var property = iter.next();
390+
var docs = writer.formatDocs(String.format(":param %s: %s", property.name(), property.documentation()));
391+
392+
if (iter.hasNext()) {
393+
docs += "\n";
394+
}
383395

384-
if (iter.hasNext()) {
385-
docs += "\n";
396+
writer.write(docs);
386397
}
387-
388-
writer.write(docs);
389-
}
398+
});
390399
}
391400

392401
private void initializeProperties(PythonWriter writer, Collection<ConfigProperty> properties) {

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/InitGenerator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.nio.file.Path;
88
import java.nio.file.Paths;
9+
import java.util.Set;
910
import java.util.stream.Collectors;
1011
import software.amazon.smithy.python.codegen.GenerationContext;
1112
import software.amazon.smithy.utils.SmithyInternalApi;
@@ -15,6 +16,8 @@
1516
*/
1617
@SmithyInternalApi
1718
public final class InitGenerator implements Runnable {
19+
// Set of directories that need __init__.py files
20+
private static final Set<String> PACKAGE_DIRECTORIES = Set.of("src", "tests");
1821

1922
private final GenerationContext context;
2023

@@ -31,6 +34,7 @@ public void run() {
3134
.stream()
3235
.map(Paths::get)
3336
.filter(path -> !path.getParent().equals(context.fileManifest().getBaseDir()))
37+
.filter(path -> PACKAGE_DIRECTORIES.contains(path.getName(0).toString()))
3438
.collect(Collectors.groupingBy(Path::getParent, Collectors.toSet()));
3539
for (var entry : directories.entrySet()) {
3640
var initPath = entry.getKey().resolve("__init__.py");

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ private void writeProperties() {
242242
${?useField}\
243243
field(${?sensitive}repr=False, ${/sensitive}${defaultKey:L}=${defaultValue:L})\
244244
${/useField}
245-
${?docs}""\"${docs:L}""\"${/docs}""", memberName, symbolProvider.toSymbol(member));
245+
${?docs}""\"${docs:L}""\"${/docs}
246+
""", memberName, symbolProvider.toSymbol(member));
246247
writer.popState();
247248
}
248249
}

codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ public PythonWriter writeDocs(Runnable runnable) {
127127
pushState();
128128
writeInline("\"\"\"");
129129
runnable.run();
130+
trimTrailingWhitespaces();
131+
ensureNewline();
130132
write("\"\"\"");
131133
popState();
132134
return this;
@@ -143,6 +145,35 @@ public PythonWriter writeDocs(String docs) {
143145
return this;
144146
}
145147

148+
/**
149+
* Trims all trailing whitespace from the writer buffer.
150+
*
151+
* @return Returns the writer.
152+
*/
153+
public PythonWriter trimTrailingWhitespaces() {
154+
// Disable the writer formatting config to ensure toString()
155+
// returns the unmodified state of the underlying StringBuilder
156+
trimBlankLines(-1);
157+
trimTrailingSpaces(false);
158+
159+
String current = super.toString();
160+
int end = current.length() - 1;
161+
while (end >= 0 && Character.isWhitespace(current.charAt(end))) {
162+
end--;
163+
}
164+
165+
String trailing = current.substring(end + 1);
166+
if (!trailing.isEmpty()) {
167+
unwrite(trailing);
168+
}
169+
170+
// Re-enable the formatting config
171+
trimBlankLines();
172+
trimTrailingSpaces(true);
173+
174+
return this;
175+
}
176+
146177
private static final int MAX_LINE_LENGTH = CodegenUtils.MAX_PREFERRED_LINE_LENGTH - 8;
147178

148179
/**

codegen/gradle/libs.versions.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[versions]
2-
junit5 = "6.0.0"
3-
smithy = "1.63.0"
2+
junit5 = "6.0.1"
3+
smithy = "1.64.0"
44
test-logger-plugin = "4.0.0"
55
spotbugs = "6.0.22"
6-
spotless = "8.0.0"
6+
spotless = "8.1.0"
77
smithy-gradle-plugins = "1.3.0"
8-
dep-analysis = "3.4.0"
8+
dep-analysis = "3.4.1"
99
jsoup = "1.21.2"
1010
commonmark = "0.17.0"
1111

0 commit comments

Comments
 (0)