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
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ private void writeSharedOperationInit(PythonWriter writer, OperationShape operat
writer.write("""
:param plugins: A list of callables that modify the configuration dynamically.
Changes made by these plugins only apply for the duration of the operation
execution and will not affect any other operation invocations.
""");
execution and will not affect any other operation invocations.""");
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems a little strange for the fix. Is it because this adds the newline we need but our actual writer is also always appending a newline so we get two? I think this issue was affecting multiple places. I wonder if we should be doing something more like trimming extra newlines from the end of the final docstring (or not appending them to the end).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes there are a couple places where we add two newlines on accident by using write instead of writeInline and then passing in a text block which adds its own newline.

I pushed up a commit that adds a helper method to PythonWriter that removes all trailing whitespaces. We'll call it and then add a single newline before writing the closing """ in writeDocs(). This normalizes all docstrings and prevents a trailing blank line.

This fixed all of the issues I've seen in models.py and client.py. I also made the ConfigGenerator use writeDocs() (it didn't previously) and it resolved the blank line issue for its constructor as well.

I still fixed the source of the double newlines but the helper method will help prevent this issue from reoccurring in the future.

This is the diff for the Transcribe client with these codegen changes.


});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,7 @@ def __init__(
*,
${C|}
):
\"""Constructor.

${C|}
\"""
${C|}
""",
configSymbol.getName(),
Expand Down Expand Up @@ -376,17 +373,20 @@ private void writeInitParams(PythonWriter writer, Collection<ConfigProperty> pro
}

private void documentProperties(PythonWriter writer, Collection<ConfigProperty> properties) {
var iter = properties.iterator();
while (iter.hasNext()) {
var property = iter.next();
var docs = writer.formatDocs(String.format(":param %s: %s", property.name(), property.documentation()));
writer.writeDocs(() ->{
var iter = properties.iterator();
writer.write("\nConstructor.\n");
while (iter.hasNext()) {
var property = iter.next();
var docs = writer.formatDocs(String.format(":param %s: %s", property.name(), property.documentation()));

if (iter.hasNext()) {
docs += "\n";
}

if (iter.hasNext()) {
docs += "\n";
writer.write(docs);
}

writer.write(docs);
}
});
}

private void initializeProperties(PythonWriter writer, Collection<ConfigProperty> properties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

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

private final GenerationContext context;

Expand All @@ -31,6 +34,7 @@ public void run() {
.stream()
.map(Paths::get)
.filter(path -> !path.getParent().equals(context.fileManifest().getBaseDir()))
.filter(path -> PACKAGE_DIRECTORIES.contains(path.getName(0).toString()))
Copy link
Contributor

@nateprewitt nateprewitt Nov 4, 2025

Choose a reason for hiding this comment

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

path.getName(0) in this case is always the first path part rather than a qualified path? e.g. src and not /src or aws-sdk-bedrock-runtime/src?

Copy link
Contributor Author

@arandito arandito Nov 5, 2025

Choose a reason for hiding this comment

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

This only iterates through the file paths we provide when creating file writers. According to Smithy's FileManifest, the file writer path has to be relative to the base directory so this can never be aws-sdk-bedrock-runtime/src or /src. If it was, this would fail duing smithy build.

However, I did notice that we use either ./src/ or docs/ to create file writers which are both valid options. But the paths always get normalized to src/, docs/, etc.

path.getName(0) will always be the first part in this case.

.collect(Collectors.groupingBy(Path::getParent, Collectors.toSet()));
for (var entry : directories.entrySet()) {
var initPath = entry.getKey().resolve("__init__.py");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ private void writeProperties() {
${?useField}\
field(${?sensitive}repr=False, ${/sensitive}${defaultKey:L}=${defaultValue:L})\
${/useField}
${?docs}""\"${docs:L}""\"${/docs}""", memberName, symbolProvider.toSymbol(member));
${?docs}""\"${docs:L}""\"${/docs}
""", memberName, symbolProvider.toSymbol(member));
writer.popState();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public PythonWriter writeDocs(Runnable runnable) {
pushState();
writeInline("\"\"\"");
runnable.run();
trimTrailingWhitespaces();
ensureNewline();
write("\"\"\"");
popState();
return this;
Expand All @@ -143,6 +145,35 @@ public PythonWriter writeDocs(String docs) {
return this;
}

/**
* Trims all trailing whitespace from the writer buffer.
*
* @return Returns the writer.
*/
public PythonWriter trimTrailingWhitespaces() {
// Disable the writer formatting config to ensure toString()
// returns the unmodified state of the underlying StringBuilder
trimBlankLines(-1);
trimTrailingSpaces(false);

String current = super.toString();
int end = current.length() - 1;
while (end >= 0 && Character.isWhitespace(current.charAt(end))) {
end--;
}

String trailing = current.substring(end + 1);
if (!trailing.isEmpty()) {
unwrite(trailing);
}

// Re-enable the formatting config
trimBlankLines();
trimTrailingSpaces(true);

return this;
}

private static final int MAX_LINE_LENGTH = CodegenUtils.MAX_PREFERRED_LINE_LENGTH - 8;

/**
Expand Down
Loading