From 7d85d7457ceaaecfd6dc18c486a647256217198b Mon Sep 17 00:00:00 2001 From: SamRemis Date: Mon, 10 Mar 2025 13:56:16 -0400 Subject: [PATCH 01/11] Initial commit Draft commit - whitespace changes still need to be addressed --- codegen/aws/core/build.gradle.kts | 1 + .../python/aws/codegen/AwsDocConverter.java | 144 ++++++++++++++++++ .../python/codegen/ClientGenerator.java | 4 +- .../generators/StructureGenerator.java | 2 +- .../integrations/PythonIntegration.java | 6 + 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java diff --git a/codegen/aws/core/build.gradle.kts b/codegen/aws/core/build.gradle.kts index 3a81c5190..6f49cc966 100644 --- a/codegen/aws/core/build.gradle.kts +++ b/codegen/aws/core/build.gradle.kts @@ -12,4 +12,5 @@ extra["moduleName"] = "software.amazon.smithy.python.aws.codegen" dependencies { implementation(project(":core")) implementation(libs.smithy.aws.traits) + implementation("org.jsoup:jsoup:1.19.1") } diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java new file mode 100644 index 000000000..821ce633b --- /dev/null +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java @@ -0,0 +1,144 @@ +/* + * 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.model.shapes.Shape; +import software.amazon.smithy.model.traits.DocumentationTrait; +import software.amazon.smithy.python.codegen.PythonSettings; +import software.amazon.smithy.python.codegen.integrations.PythonIntegration; +import software.amazon.smithy.utils.SmithyInternalApi; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.transform.ModelTransformer; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.nodes.TextNode; +import org.jsoup.select.NodeVisitor; + +/** + * Adds a runtime plugin to set user agent. + */ +@SmithyInternalApi +public class AwsDocConverter implements PythonIntegration { + @Override + public Model preprocessModel(Model model, PythonSettings settings) { + return ModelTransformer.create().mapShapes(model, shape -> { + if (shape.hasTrait(DocumentationTrait.class)) { + DocumentationTrait docTrait = shape.getTrait(DocumentationTrait.class).get(); + String html = docTrait.getValue(); + String rst = convertHtmlToRst(html); + DocumentationTrait newDocTrait = new DocumentationTrait(rst); + return Shape.shapeToBuilder(shape) + .addTrait(newDocTrait) + .build(); + } else { + return shape; + } + }); + } + + private String convertHtmlToRst(String html) { + Document document = Jsoup.parse(html); + RstNodeVisitor visitor = new RstNodeVisitor(); + document.body().traverse(visitor); + return visitor.toString(); + } + + private static class RstNodeVisitor implements NodeVisitor { + private final StringBuilder sb = new StringBuilder(); + private boolean inList = false; + + @Override + public void head(Node node, int depth) { + if (node instanceof TextNode) { + //TODO properly handle stripping whitespace + Node parentNode = node.parent(); + if (parentNode != null && parentNode.nodeName().equals("p")) { + //TODO write a test case like the following:

Foo bar + // baz

-> "Foo *bar* baz" + sb.append(((TextNode) node).text().strip()); + } else { + sb.append(((TextNode) node).text()); + } + } else if (node instanceof Element) { + Element element = (Element) node; + switch (element.tagName()) { + case "a": + sb.append("`"); + break; + case "b": + case "strong": + sb.append("**"); + break; + case "i": + case "em": + sb.append("*"); + break; + case "code": + sb.append(" ``"); + break; + case "important": + sb.append(".. important::\n\n "); + break; + case "note": + sb.append(".. note::\n\n "); + break; + //TODO this looks a little weird on modelid for invoke_model input + // do I do something weird based on if it's in a parameter cause + // those are already bullets? + case "ul": + inList = true; + sb.append("\n"); + break; + case "li": + if (inList) { + sb.append("- "); + } + break; + } + } + } + + @Override + public void tail(Node node, int depth) { + if (node instanceof Element) { + Element element = (Element) node; + switch (element.tagName()) { + case "a": + sb.append(" <").append(element.attr("href")).append(">`_ "); + break; + case "b": + case "strong": + sb.append("**"); + break; + case "i": + case "em": + sb.append("*"); + break; + case "code": + sb.append("`` "); + break; + case "important": + case "note": + sb.append("\n\n"); + break; + case "ul": + inList = false; + sb.append("\n"); + break; + case "p": + sb.append("\n\n"); + break; + } + } + } + + @Override + public String toString() { + return sb.toString().trim(); + } + } +} \ No newline at end of file diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index 9f35ea781..2b733fe1b 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -69,10 +69,10 @@ private void generateService(PythonWriter writer) { $L :param config: Optional configuration for the client. Here you can set things like the - endpoint for HTTP services or auth credentials. + endpoint for HTTP services or auth credentials. :param plugins: A list of callables that modify the configuration dynamically. These - can be used to set defaults, for example.""", docs); + can be used to set defaults, for example.""", docs); }); var defaultPlugins = new LinkedHashSet(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java index a91d63000..9f7f66978 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java @@ -309,7 +309,7 @@ private boolean hasDocs() { private void writeMemberDocs(MemberShape member) { member.getMemberTrait(model, DocumentationTrait.class).ifPresent(trait -> { String memberName = symbolProvider.toMemberName(member); - String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())); + String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())).replace("\n", "\n\t"); writer.write(docs); }); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java index cde5869ab..cc661c43d 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; import software.amazon.smithy.codegen.core.SmithyIntegration; +import software.amazon.smithy.model.Model; import software.amazon.smithy.python.codegen.GenerationContext; import software.amazon.smithy.python.codegen.PythonSettings; import software.amazon.smithy.python.codegen.generators.ProtocolGenerator; @@ -39,6 +40,11 @@ default List getClientPlugins(GenerationContext context) { return Collections.emptyList(); } + default Model preprocessModel(Model model, PythonSettings settings) { + return model; + } + + /** * Writes out all extra files required by runtime plugins. */ From 5ad44ff2268fac0bf0ac5c46f99273e17d648ce2 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Mon, 17 Mar 2025 12:57:43 -0400 Subject: [PATCH 02/11] Add RST file generation, RST linewrapping, and whitespace fixes --- .../python/aws/codegen/AwsDocConverter.java | 46 +-- .../aws/codegen/AwsRstDocFileGenerator.java | 197 ++++++++++++ ...hon.codegen.integrations.PythonIntegration | 2 + .../python/codegen/ClientGenerator.java | 22 +- .../codegen/generators/SetupGenerator.java | 198 +++++++++++- .../generators/StructureGenerator.java | 38 ++- .../codegen/generators/UnionGenerator.java | 11 +- .../python/codegen/sections/ErrorSection.java | 16 + .../codegen/sections/OperationSection.java | 17 ++ .../codegen/sections/StructureSection.java | 16 + .../codegen/sections/UnionMemberSection.java | 16 + .../python/codegen/sections/UnionSection.java | 19 ++ .../python/codegen/writer/PythonWriter.java | 106 ++++++- pyproject.toml | 2 + uv.lock | 284 ++++++++++++++++++ 15 files changed, 923 insertions(+), 67 deletions(-) create mode 100644 codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java create mode 100644 codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java index 821ce633b..e6a928de0 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java @@ -44,24 +44,25 @@ private String convertHtmlToRst(String html) { Document document = Jsoup.parse(html); RstNodeVisitor visitor = new RstNodeVisitor(); document.body().traverse(visitor); - return visitor.toString(); + return "\n" + visitor; } private static class RstNodeVisitor implements NodeVisitor { private final StringBuilder sb = new StringBuilder(); private boolean inList = false; + private int listDepth = 0; @Override public void head(Node node, int depth) { if (node instanceof TextNode) { - //TODO properly handle stripping whitespace - Node parentNode = node.parent(); - if (parentNode != null && parentNode.nodeName().equals("p")) { - //TODO write a test case like the following:

Foo bar - // baz

-> "Foo *bar* baz" - sb.append(((TextNode) node).text().strip()); - } else { - sb.append(((TextNode) node).text()); + TextNode textNode = (TextNode) node; + String text = textNode.text(); + if (!text.trim().isEmpty()) { + sb.append(text); + // Account for services making a paragraph tag that's empty except + // for a newline + } else if (node.parent() instanceof Element && ((Element) node.parent()).tagName().equals("p")) { + sb.append(text.replaceAll("[ \\t]+", "")); } } else if (node instanceof Element) { Element element = (Element) node; @@ -78,24 +79,22 @@ public void head(Node node, int depth) { sb.append("*"); break; case "code": - sb.append(" ``"); + sb.append("``"); break; case "important": - sb.append(".. important::\n\n "); + sb.append("\n.. important::\n "); break; case "note": - sb.append(".. note::\n\n "); + sb.append("\n.. note::\n "); break; - //TODO this looks a little weird on modelid for invoke_model input - // do I do something weird based on if it's in a parameter cause - // those are already bullets? case "ul": inList = true; + listDepth++; sb.append("\n"); break; case "li": if (inList) { - sb.append("- "); + sb.append(" ".repeat(listDepth - 1)).append("* "); } break; } @@ -119,18 +118,21 @@ public void tail(Node node, int depth) { sb.append("*"); break; case "code": - sb.append("`` "); + sb.append("``"); break; case "important": case "note": - sb.append("\n\n"); + sb.append("\n"); break; case "ul": - inList = false; - sb.append("\n"); + listDepth--; + if (listDepth == 0) { + inList = false; + } + sb.append("\n\n"); break; case "p": - sb.append("\n\n"); + sb.append("\n"); break; } } @@ -138,7 +140,7 @@ public void tail(Node node, int depth) { @Override public String toString() { - return sb.toString().trim(); + return sb.toString(); } } } \ No newline at end of file diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java new file mode 100644 index 000000000..caf919999 --- /dev/null +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java @@ -0,0 +1,197 @@ +/* + * 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.model.traits.InputTrait; +import software.amazon.smithy.model.traits.OutputTrait; +import software.amazon.smithy.python.codegen.GenerationContext; +import software.amazon.smithy.python.codegen.integrations.PythonIntegration; +import software.amazon.smithy.python.codegen.sections.*; +import software.amazon.smithy.python.codegen.writer.PythonWriter; +import software.amazon.smithy.utils.CodeInterceptor; +import software.amazon.smithy.utils.CodeSection; + +import java.util.ArrayList; +import java.util.List; + +public class AwsRstDocFileGenerator implements PythonIntegration { + + @Override + public List> interceptors( + GenerationContext context + ) { + return List.of( + new OperationGenerationInterceptor(context), + new StructureGenerationInterceptor(context), + new ErrorGenerationInterceptor(context), + new UnionGenerationInterceptor(context), + new UnionMemberGenerationInterceptor(context) + ); + } + + /** + * Utility method to generate a header for documentation files. + * + * @param title The title of the section. + * @return A formatted header string. + */ + private static String generateHeader(String title) { + return String.format("%s\n%s\n\n", title, "=".repeat(title.length())); + } + + private static final class OperationGenerationInterceptor + implements CodeInterceptor.Appender { + + private final GenerationContext context; + + public OperationGenerationInterceptor(GenerationContext context) { + this.context = context; + } + + @Override + public Class sectionType() { + return OperationSection.class; + } + + @Override + public void append(PythonWriter pythonWriter, OperationSection section) { + var operation = section.operation(); + var operationSymbol = context.symbolProvider().toSymbol(operation); + var input = context.model().expectShape(operation.getInputShape()); + var inputSymbol = context.symbolProvider().toSymbol(input); + var output = context.model().expectShape(operation.getOutputShape()); + var outputSymbol = context.symbolProvider().toSymbol(output); + + String operationName = operationSymbol.getName(); + String inputSymbolName = inputSymbol.toString(); + String outputSymbolName = outputSymbol.toString(); + String serviceName = context.symbolProvider().toSymbol(section.service()).getName(); + String docsFileName = String.format("docs/client/%s.rst", operationName); + String fullOperationReference = String.format("%s.client.%s.%s", + context.settings().moduleName(), + serviceName, + operationName); + + context.writerDelegator().useFileWriter(docsFileName, "", fileWriter -> { + fileWriter.write(generateHeader(operationName)); + fileWriter.write(".. automethod:: " + fullOperationReference + "\n\n"); + fileWriter.write(".. toctree::\n :hidden:\n :maxdepth: 2\n\n"); + fileWriter.write("=================\nInput:\n=================\n\n"); + fileWriter.write(".. autoclass:: " + inputSymbolName + "\n :members:\n"); + fileWriter.write("=================\nOutput:\n=================\n\n"); + fileWriter.write(".. autoclass:: " + outputSymbolName + "\n :members:\n"); + }); + } + } + + private static final class StructureGenerationInterceptor + implements CodeInterceptor.Appender { + + private final GenerationContext context; + + public StructureGenerationInterceptor(GenerationContext context) { + this.context = context; + } + + @Override + public Class sectionType() { + return StructureSection.class; + } + + @Override + public void append(PythonWriter pythonWriter, StructureSection section) { + var shape = section.structure(); + var symbol = context.symbolProvider().toSymbol(shape); + String docsFileName = String.format("docs/models/%s.rst", + symbol.getName()); + if (!shape.hasTrait(InputTrait.class) && !shape.hasTrait(OutputTrait.class)) { + context.writerDelegator().useFileWriter(docsFileName, "", writer -> { + writer.write(generateHeader(symbol.getName())); + writer.write(".. autoclass:: " + symbol.toString() + "\n :members:\n"); + }); + } + } + } + + private static final class ErrorGenerationInterceptor + implements CodeInterceptor.Appender { + + private final GenerationContext context; + + public ErrorGenerationInterceptor(GenerationContext context) { + this.context = context; + } + + @Override + public Class sectionType() { + return ErrorSection.class; + } + + @Override + public void append(PythonWriter pythonWriter, ErrorSection section) { + var symbol = section.errorSymbol(); + String docsFileName = String.format("docs/models/%s.rst", + symbol.getName()); + context.writerDelegator().useFileWriter(docsFileName, "", writer -> { + writer.write(generateHeader(symbol.getName())); + writer.write(".. autoexception:: " + symbol.toString() + "\n :members:\n :show-inheritance:\n"); + }); + } + } + + private static final class UnionGenerationInterceptor + implements CodeInterceptor.Appender { + + private final GenerationContext context; + + public UnionGenerationInterceptor(GenerationContext context) { + this.context = context; + } + + @Override + public Class sectionType() { + return UnionSection.class; + } + + @Override + public void append(PythonWriter pythonWriter, UnionSection section) { + String parentName = section.parentName(); + ArrayList memberNames = section.memberNames(); + String docsFileName = String.format("docs/models/%s.rst", parentName); + context.writerDelegator().useFileWriter(docsFileName, "", writer -> { + writer.write(".. _" + parentName + ":\n\n"); + writer.write(generateHeader(parentName)); + writer.write(".. autodata:: " + context.symbolProvider().toSymbol(section.unionShape()).toString() + " \n"); + }); + } + } + + private static final class UnionMemberGenerationInterceptor + implements CodeInterceptor.Appender { + + private final GenerationContext context; + + public UnionMemberGenerationInterceptor(GenerationContext context) { + this.context = context; + } + + @Override + public Class sectionType() { + return UnionMemberSection.class; + } + + @Override + public void append(PythonWriter pythonWriter, UnionMemberSection section) { + var memberSymbol = section.memberSymbol(); + String symbolName = memberSymbol.getName(); + String docsFileName = String.format("docs/models/%s.rst", symbolName); + context.writerDelegator().useFileWriter(docsFileName, "", writer -> { + writer.write(".. _" + symbolName + ":\n\n"); + writer.write(generateHeader(symbolName)); + writer.write(".. autoclass:: " + memberSymbol.toString() + " \n"); + }); + } + } +} \ No newline at end of file diff --git a/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration b/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration index a338df30c..b7025b1a6 100644 --- a/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration +++ b/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration @@ -8,3 +8,5 @@ software.amazon.smithy.python.aws.codegen.AwsProtocolsIntegration software.amazon.smithy.python.aws.codegen.AwsServiceIdIntegration software.amazon.smithy.python.aws.codegen.AwsUserAgentIntegration software.amazon.smithy.python.aws.codegen.AwsStandardRegionalEndpointsIntegration +software.amazon.smithy.python.aws.codegen.AwsDocConverter +software.amazon.smithy.python.aws.codegen.AwsRstDocFileGenerator diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index 2b733fe1b..ad78c7181 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -23,11 +23,7 @@ import software.amazon.smithy.model.traits.StringTrait; import software.amazon.smithy.python.codegen.integrations.PythonIntegration; import software.amazon.smithy.python.codegen.integrations.RuntimeClientPlugin; -import software.amazon.smithy.python.codegen.sections.InitializeHttpAuthParametersSection; -import software.amazon.smithy.python.codegen.sections.ResolveEndpointSection; -import software.amazon.smithy.python.codegen.sections.ResolveIdentitySection; -import software.amazon.smithy.python.codegen.sections.SendRequestSection; -import software.amazon.smithy.python.codegen.sections.SignRequestSection; +import software.amazon.smithy.python.codegen.sections.*; import software.amazon.smithy.python.codegen.writer.PythonWriter; import software.amazon.smithy.utils.SmithyInternalApi; @@ -763,6 +759,7 @@ private void generateOperation(PythonWriter writer, OperationShape operation) { var output = model.expectShape(operation.getOutputShape()); var outputSymbol = symbolProvider.toSymbol(output); + writer.pushState(new OperationSection(service, operation)); writer.openBlock("async def $L(self, input: $T, plugins: list[$T] | None = None) -> $T:", "", operationMethodSymbol.getName(), @@ -790,26 +787,29 @@ private void generateOperation(PythonWriter writer, OperationShape operation) { """, serSymbol, deserSymbol, operation.getId().getName()); } }); + writer.popState(); } private void writeSharedOperationInit(PythonWriter writer, OperationShape operation, Shape input) { writer.writeDocs(() -> { - var docs = operation.getTrait(DocumentationTrait.class) + var docs = writer.formatDocs(operation.getTrait(DocumentationTrait.class) .map(StringTrait::getValue) - .orElse(String.format("Invokes the %s operation.", operation.getId().getName())); + .orElse(String.format("Invokes the %s operation.", + operation.getId().getName()))); var inputDocs = input.getTrait(DocumentationTrait.class) .map(StringTrait::getValue) .orElse("The operation's input."); writer.write(""" - $L - :param input: $L :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.""", docs, inputDocs); + Changes made by these plugins only apply for the duration of the operation + execution and will not affect any other operation invocations. + + $L + """,inputDocs, docs); }); var defaultPlugins = new LinkedHashSet(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 74fbffadc..9019c0c18 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -45,6 +45,7 @@ public static void generateSetup( var dependencies = gatherDependencies(context.writerDelegator().getDependencies().stream()); writePyproject(settings, context.writerDelegator(), dependencies); writeReadme(settings, context); + writeDocsSkeleton(settings, context); } /** @@ -240,12 +241,6 @@ private static void writeReadme( """, title, description); service.getTrait(DocumentationTrait.class).map(StringTrait::getValue).ifPresent(documentation -> { - // TODO: make sure this documentation is well-formed - // Existing services in AWS, for example, have a lot of HTML docs. - // HTML nodes *are* valid commonmark technically, so it should be - // fine here. If we were to make this file RST formatted though, - // we'd have a problem. We have to solve that at some point anyway - // since the python code docs are RST format. writer.write(""" ### Documentation @@ -255,4 +250,195 @@ private static void writeReadme( writer.popState(); }); } + + /** + * Write the files required for sphinx doc generation + */ + private static void writeDocsSkeleton(PythonSettings settings, GenerationContext context) { + writeConf(settings, context); + writeMakeBat(context); + writeMakeFile(context); + writeIndexes(context); + } + + /** + * Write a conf.py file. + * A conf.py file is a configuration file used by Sphinx, a documentation + * generation tool for Python projects. This file contains settings and + * configurations that control the behavior and appearance of the generated + * documentation. + */ + private static void writeConf( + PythonSettings settings, + GenerationContext context + ) { + String version = settings.moduleVersion(); + context.writerDelegator().useFileWriter("docs/conf.py", "", writer -> { + writer.write(""" +import os +import sys +sys.path.insert(0, os.path.abspath('..')) + +project = 'AWS SDK for Python' +author = 'Boto' +release = '$L' + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', +] + +templates_path = ['_templates'] +exclude_patterns = [] + +autodoc_default_options = { + 'exclude-members': 'deserialize,deserialize_kwargs,serialize,serialize_members' +} + +html_theme = 'pydata_sphinx_theme' +html_theme_options = { + "navbar_center": [], + "logo": { + "text": "AWS SDK for Python", + } +} + +autodoc_typehints = 'both' + """, version); + }); + } + + + /** + * Write a make.bat file. + * A make.bat file is a batch script used on Windows to build Sphinx documentation. + * This script sets up the environment and runs the Sphinx build commands. + * + * @param context The generation context containing the writer delegator. + */ + private static void writeMakeBat( + GenerationContext context + ) { + context.writerDelegator().useFileWriter("docs/make.bat", "", writer -> { + writer.write(""" +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set SERVICESDIR=source/reference/services +set SPHINXOPTS=-j auto +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . + +if "%1" == "" goto help + +if "%1" == "clean" ( + rmdir /S /Q %BUILDDIR% + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + echo. + echo "Build finished. The HTML pages are in %BUILDDIR%/html." + goto end +) + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd + """); + }); + } + + /** + * Write a Makefile. + * A Makefile is used on Unix-based systems to build Sphinx documentation. + * This file contains rules for cleaning the build directory and generating HTML documentation. + * + * @param context The generation context containing the writer delegator. + */ + private static void writeMakeFile( + GenerationContext context + ) { + context.writerDelegator().useFileWriter("docs/Makefile", "", writer -> { + writer.write(""" +SPHINXBUILD = sphinx-build +BUILDDIR = build +SERVICESDIR = source/reference/services +SPHINXOPTS = -j auto +ALLSPHINXOPTS = -d $$(BUILDDIR)/doctrees $$(SPHINXOPTS) . + +clean: +\t-rm -rf $$(BUILDDIR)/* + +html: +\t$$(SPHINXBUILD) -b html $$(ALLSPHINXOPTS) $$(BUILDDIR)/html +\t@echo +\t@echo "Build finished. The HTML pages are in $$(BUILDDIR)/html." + """); + }); + } + + + /** + * Write the main index files for the documentation. + * This method creates the main index.rst file and additional index files for + * the client and models sections. + * + * @param context The generation context containing the writer delegator. + */ + private static void writeIndexes(GenerationContext context) { + // Write the main index file for the documentation + context.writerDelegator().useFileWriter("docs/index.rst", "", writer -> { + writer.write(""" +AWS SDK For Python +==================================================== + +.. toctree:: + :maxdepth: 2 + :titlesonly: + :glob: + + */index + """); + }); + + // Write the index file for the client section + writeIndexFile(context, "docs/client/index.rst", "Client"); + + // Write the index file for the models section + writeIndexFile(context, "docs/models/index.rst", "Models"); + } + + /** + * Helper method to write an index file with the given title. + * This method creates an index file at the specified file path with the provided title. + * + * @param context The generation context. + * @param filePath The file path of the index file. + * @param title The title of the index file. + */ + private static void writeIndexFile(GenerationContext context, String filePath, String title) { + context.writerDelegator().useFileWriter(filePath, "", writer -> { + writer.write(""" +$L +======= +.. toctree:: + :maxdepth: 1 + :titlesonly: + :glob: + + * + """, title); + }); + } + } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java index 9f7f66978..cf711f0ac 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java @@ -35,6 +35,8 @@ import software.amazon.smithy.python.codegen.GenerationContext; import software.amazon.smithy.python.codegen.PythonSettings; import software.amazon.smithy.python.codegen.SymbolProperties; +import software.amazon.smithy.python.codegen.sections.ErrorSection; +import software.amazon.smithy.python.codegen.sections.StructureSection; import software.amazon.smithy.python.codegen.writer.PythonWriter; import software.amazon.smithy.utils.SmithyInternalApi; @@ -98,24 +100,27 @@ public void run() { private void renderStructure() { writer.addStdlibImport("dataclasses", "dataclass"); var symbol = symbolProvider.toSymbol(shape); + writer.pushState(new StructureSection(shape)); writer.write(""" - @dataclass(kw_only=True) - class $L: - ${C|} - - ${C|} - - ${C|} - - ${C|} - - """, + @dataclass(kw_only=True) + class $L: + ${C|} + + ${C|} + + ${C|} + + ${C|} + + """, symbol.getName(), writer.consumer(w -> writeClassDocs(false)), writer.consumer(w -> writeProperties()), writer.consumer(w -> generateSerializeMethod()), writer.consumer(w -> generateDeserializeMethod())); + + writer.popState(); } private void renderError() { @@ -128,7 +133,7 @@ private void renderError() { var code = shape.getId().getName(); var symbol = symbolProvider.toSymbol(shape); var apiError = CodegenUtils.getApiError(settings); - + writer.pushState(new ErrorSection(symbol)); writer.write(""" @dataclass(kw_only=True) class $1L($2T): @@ -153,7 +158,9 @@ class $1L($2T): writer.consumer(w -> writeProperties()), writer.consumer(w -> generateSerializeMethod()), writer.consumer(w -> generateDeserializeMethod())); - } + writer.popState(); + + } private void writeProperties() { for (MemberShape member : requiredMembers) { @@ -231,7 +238,8 @@ private void writeClassDocs(boolean isError) { }); if (isError) { - writer.write(":param message: A message associated with the specific error."); + writer.write("\n:param message: A message associated with the " + + "specific error."); } if (!shape.members().isEmpty()) { @@ -309,7 +317,7 @@ private boolean hasDocs() { private void writeMemberDocs(MemberShape member) { member.getMemberTrait(model, DocumentationTrait.class).ifPresent(trait -> { String memberName = symbolProvider.toMemberName(member); - String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())).replace("\n", "\n\t"); + String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())).replace("\n", "\n "); writer.write(docs); }); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java index e592460d9..a3d41bb91 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Set; + import software.amazon.smithy.codegen.core.SymbolProvider; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.MemberShape; @@ -15,6 +16,8 @@ import software.amazon.smithy.model.traits.StringTrait; import software.amazon.smithy.python.codegen.GenerationContext; import software.amazon.smithy.python.codegen.SymbolProperties; +import software.amazon.smithy.python.codegen.sections.UnionMemberSection; +import software.amazon.smithy.python.codegen.sections.UnionSection; import software.amazon.smithy.python.codegen.writer.PythonWriter; import software.amazon.smithy.utils.SmithyInternalApi; @@ -47,6 +50,7 @@ public UnionGenerator( @Override public void run() { + writer.addStdlibImports("typing", Set.of("Union")); writer.pushState(); var parentName = symbolProvider.toSymbol(shape).getName(); writer.addStdlibImport("dataclasses", "dataclass"); @@ -61,7 +65,7 @@ public void run() { var target = model.expectShape(member.getTarget()); var targetSymbol = symbolProvider.toSymbol(target); - + writer.pushState(new UnionMemberSection(memberSymbol)); writer.write(""" @dataclass class $1L: @@ -92,6 +96,7 @@ def deserialize(cls, deserializer: ShapeDeserializer) -> Self: new MemberDeserializerGenerator(context, w, member, "deserializer"))) ); + writer.popState(); } // Note that the unknown variant doesn't implement __eq__. This is because @@ -99,6 +104,7 @@ def deserialize(cls, deserializer: ShapeDeserializer) -> Self: // Since the underlying value is unknown and un-comparable, that is the only // realistic implementation. var unknownSymbol = symbolProvider.toSymbol(shape).expectProperty(SymbolProperties.UNION_UNKNOWN); + writer.pushState(new UnionMemberSection(unknownSymbol)); writer.addImport("smithy_core.exceptions", "SmithyException"); writer.write(""" @dataclass @@ -125,9 +131,12 @@ raise NotImplementedError() """, unknownSymbol.getName()); memberNames.add(unknownSymbol.getName()); + writer.popState(); writer.write("type $L = $L\n", parentName, String.join(" | ", memberNames)); + writer.pushState(new UnionSection(shape, parentName, memberNames)); shape.getTrait(DocumentationTrait.class).ifPresent(trait -> writer.writeDocs(trait.getValue())); + writer.popState(); generateDeserializer(); writer.popState(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java new file mode 100644 index 000000000..2fd589699 --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java @@ -0,0 +1,16 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.codegen.sections; + +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.utils.CodeSection; +import software.amazon.smithy.utils.SmithyInternalApi; + +/** + * A section that controls writing an error. + */ +@SmithyInternalApi +public record ErrorSection(Symbol errorSymbol) implements CodeSection { +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java new file mode 100644 index 000000000..f64dad265 --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java @@ -0,0 +1,17 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.codegen.sections; + +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.utils.CodeSection; +import software.amazon.smithy.utils.SmithyInternalApi; + +/** + * A section that controls writing an operation. + */ +@SmithyInternalApi +public record OperationSection(Shape service, OperationShape operation) implements CodeSection { +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java new file mode 100644 index 000000000..da33ed285 --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java @@ -0,0 +1,16 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.codegen.sections; + +import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.utils.CodeSection; +import software.amazon.smithy.utils.SmithyInternalApi; + +/** + * A section that controls writing a structure. + */ +@SmithyInternalApi +public record StructureSection(StructureShape structure) implements CodeSection { +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java new file mode 100644 index 000000000..dd785ea07 --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java @@ -0,0 +1,16 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.codegen.sections; + +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.utils.CodeSection; +import software.amazon.smithy.utils.SmithyInternalApi; + +/** + * A section that controls writing a union member. + */ +@SmithyInternalApi +public record UnionMemberSection(Symbol memberSymbol) implements CodeSection { +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java new file mode 100644 index 000000000..a5bb1c7a6 --- /dev/null +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java @@ -0,0 +1,19 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.codegen.sections; + +import software.amazon.smithy.model.shapes.UnionShape; +import software.amazon.smithy.utils.CodeSection; +import software.amazon.smithy.utils.SmithyInternalApi; + +import java.util.ArrayList; + +/** + * A section that controls writing a union. + */ +@SmithyInternalApi +public record UnionSection(UnionShape unionShape, String parentName, + ArrayList memberNames) implements CodeSection { +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java index 20c00f885..e43707494 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java @@ -41,7 +41,7 @@ public final class PythonWriter extends SymbolWriter MAX_LINE_LENGTH) { + int wrapAt = findWrapPosition(line, MAX_LINE_LENGTH); + wrappedText.append(indentStr).append(line, 0, wrapAt).append("\n"); + line = line.substring(wrapAt).trim(); + if (line.isEmpty()) { + return; + } + } + wrappedText.append(indentStr).append(line).append("\n"); + } + + private static int findWrapPosition(String line, int maxLineLength) { + // Find the last space before maxLineLength + int wrapAt = line.lastIndexOf(' ', maxLineLength); + if (wrapAt == -1) { + // If no space found, force wrap at maxLineLength + wrapAt = maxLineLength; + } else { + // Ensure we don't break a link + int linkStart = line.lastIndexOf("`", wrapAt); + int linkEnd = line.indexOf("`_", wrapAt); + if (linkStart != -1 && (linkEnd == -1 || linkEnd < linkStart)) { + linkEnd = line.indexOf("`_", linkStart); + if (linkEnd != -1 && linkEnd <= maxLineLength) { + wrapAt = linkEnd + 2; + } else { + // No matching `_` found, keep the original wrap position + wrapAt = line.lastIndexOf(' ', maxLineLength); + if (wrapAt == -1) { + wrapAt = maxLineLength; + } + } + } + } + // Include trailing punctuation before a space in the previous line + int nextSpace = line.indexOf(' ', wrapAt); + if (nextSpace != -1) { + int i = wrapAt; + while (i < nextSpace && !Character.isLetterOrDigit(line.charAt(i))) { + i++; + } + if (i == nextSpace) { + wrapAt = nextSpace; + } + } + return wrapAt; + } + + + private static int getIndentationLevel(String line) { + int indent = 0; + while (indent < line.length() && Character.isWhitespace(line.charAt(indent))) { + indent++; + } + return indent; + } + + /** * Opens a block to write comments. * @@ -288,8 +370,8 @@ public String toString() { } contents += super.toString(); - if (addCodegenWarningHeader) { - String header = "# Code generated by smithy-python-codegen DO NOT EDIT.\n\n"; + if (!commentStart.equals("")) { + String header = String.format("%s Code generated by smithy-python-codegen DO NOT EDIT.\n\n", commentStart); contents = header + contents; } return contents; diff --git a/pyproject.toml b/pyproject.toml index b10ae5f41..eb54f5edd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,11 +10,13 @@ dependencies = [] dev = [ "black>=25.1.0", "docformatter>=1.7.5", + "pydata-sphinx-theme>=0.16.1", "pyright>=1.1.396", "pytest>=8.3.4", "pytest-asyncio>=0.25.3", "pytest-cov>=6.0.0", "ruff>=0.9.7", + "sphinx>=8.2.3", ] [tool.uv] diff --git a/uv.lock b/uv.lock index 788a60bc5..54bdba2af 100644 --- a/uv.lock +++ b/uv.lock @@ -14,6 +14,18 @@ members = [ "smithy-python", ] +[[package]] +name = "accessible-pygments" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903 }, +] + [[package]] name = "aiohappyeyeballs" version = "2.4.6" @@ -84,6 +96,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, ] +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 }, +] + [[package]] name = "attrs" version = "25.1.0" @@ -154,6 +175,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/e3/f524d3211fe4491887767da03f58de4b431790ed120b0e446565caaad027/awscrt-0.23.10-cp313-abi3-win_amd64.whl", hash = "sha256:23d2dfeaa0b62bb3bad569cec03a959bdbf62e9123ad1f235bfacb61d420f8d0", size = 2635008 }, ] +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/3c/adaf39ce1fb4afdd21b611e3d530b183bb7759c9b673d60db0e347fd4439/beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", size = 619516 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015 }, +] + [[package]] name = "black" version = "25.1.0" @@ -178,6 +221,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] +[[package]] +name = "certifi" +version = "2025.1.31" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, +] + [[package]] name = "charset-normalizer" version = "3.4.1" @@ -286,6 +338,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/95/568a2fca29df365b82012b09b64964a05f4f20ac83c2137b262f3fa3188f/docformatter-1.7.5-py3-none-any.whl", hash = "sha256:a24f5545ed1f30af00d106f5d85dc2fce4959295687c24c8f39f5263afaf9186", size = 32798 }, ] +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, +] + [[package]] name = "freezegun" version = "1.5.1" @@ -365,6 +426,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/25/a2/e187beee237808b2c417109ae0f4f7ee7c81ecbe9706305d6ac2a509cc45/ijson-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f890d04ad33262d0c77ead53c85f13abfb82f2c8f078dfbf24b78f59534dfdd", size = 51272 }, ] +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, +] + [[package]] name = "iniconfig" version = "2.0.0" @@ -374,6 +444,56 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +] + [[package]] name = "multidict" version = "6.1.0" @@ -549,6 +669,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/35/6c4c6fc8774a9e3629cd750dc24a7a4fb090a25ccd5c3246d127b70f9e22/propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", size = 12101 }, ] +[[package]] +name = "pydata-sphinx-theme" +version = "0.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "accessible-pygments" }, + { name = "babel" }, + { name = "beautifulsoup4" }, + { name = "docutils" }, + { name = "pygments" }, + { name = "sphinx" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/0d/8ba33fa83a7dcde13eb3c1c2a0c1cc29950a048bfed6d9b0d8b6bd710b4c/pydata_sphinx_theme-0.16.1-py3-none-any.whl", hash = "sha256:225331e8ac4b32682c18fcac5a57a6f717c4e632cea5dd0e247b55155faeccde", size = 6723264 }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, +] + [[package]] name = "pyright" version = "1.1.396" @@ -614,6 +761,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, ] +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "roman-numerals-py" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 }, +] + [[package]] name = "ruff" version = "0.9.7" @@ -739,11 +910,13 @@ source = { virtual = "." } dev = [ { name = "black" }, { name = "docformatter" }, + { name = "pydata-sphinx-theme" }, { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "ruff" }, + { name = "sphinx" }, ] [package.metadata] @@ -752,11 +925,113 @@ dev = [ dev = [ { name = "black", specifier = ">=25.1.0" }, { name = "docformatter", specifier = ">=1.7.5" }, + { name = "pydata-sphinx-theme", specifier = ">=0.16.1" }, { name = "pyright", specifier = ">=1.1.396" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "pytest-asyncio", specifier = ">=0.25.3" }, { name = "pytest-cov", specifier = ">=6.0.0" }, { name = "ruff", specifier = ">=0.9.7" }, + { name = "sphinx", specifier = ">=8.2.3" }, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, +] + +[[package]] +name = "soupsieve" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals-py" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741 }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, ] [[package]] @@ -774,6 +1049,15 @@ version = "0.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2", size = 3099 } +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, +] + [[package]] name = "yarl" version = "1.18.3" From 3c637c6b4c356e19c4b785d95164c7f7cec282c5 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Mon, 17 Mar 2025 16:19:15 -0400 Subject: [PATCH 03/11] Run linter, minor fixes --- .../python/aws/codegen/AwsDocConverter.java | 8 +- .../python/codegen/ClientGenerator.java | 4 +- .../codegen/generators/SetupGenerator.java | 164 +++++++++--------- .../generators/StructureGenerator.java | 27 +-- .../codegen/generators/UnionGenerator.java | 3 +- .../integrations/PythonIntegration.java | 1 - .../python/codegen/sections/ErrorSection.java | 3 +- .../codegen/sections/OperationSection.java | 3 +- .../codegen/sections/StructureSection.java | 3 +- .../codegen/sections/UnionMemberSection.java | 3 +- .../python/codegen/sections/UnionSection.java | 10 +- .../python/codegen/writer/PythonWriter.java | 4 +- 12 files changed, 111 insertions(+), 122 deletions(-) diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java index e6a928de0..d33279068 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java @@ -19,7 +19,8 @@ import org.jsoup.select.NodeVisitor; /** - * Adds a runtime plugin to set user agent. + * Add a runtime plugin to convert the HTML docs that are provided by services into + * RST */ @SmithyInternalApi public class AwsDocConverter implements PythonIntegration { @@ -121,7 +122,7 @@ public void tail(Node node, int depth) { sb.append("``"); break; case "important": - case "note": + case "note", "p", "li": sb.append("\n"); break; case "ul": @@ -131,9 +132,6 @@ public void tail(Node node, int depth) { } sb.append("\n\n"); break; - case "p": - sb.append("\n"); - break; } } } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java index ad78c7181..6e954f32c 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/ClientGenerator.java @@ -807,9 +807,9 @@ private void writeSharedOperationInit(PythonWriter writer, OperationShape operat :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. - + $L - """,inputDocs, docs); + """, inputDocs, docs); }); var defaultPlugins = new LinkedHashSet(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 9019c0c18..0f57678ff 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -275,40 +275,39 @@ private static void writeConf( String version = settings.moduleVersion(); context.writerDelegator().useFileWriter("docs/conf.py", "", writer -> { writer.write(""" -import os -import sys -sys.path.insert(0, os.path.abspath('..')) + import os + import sys + sys.path.insert(0, os.path.abspath('..')) -project = 'AWS SDK for Python' -author = 'Boto' -release = '$L' + project = 'AWS SDK for Python' + author = 'Boto' + release = '$L' -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.viewcode', -] + extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', + ] -templates_path = ['_templates'] -exclude_patterns = [] + templates_path = ['_templates'] + exclude_patterns = [] -autodoc_default_options = { - 'exclude-members': 'deserialize,deserialize_kwargs,serialize,serialize_members' -} + autodoc_default_options = { + 'exclude-members': 'deserialize,deserialize_kwargs,serialize,serialize_members' + } -html_theme = 'pydata_sphinx_theme' -html_theme_options = { - "navbar_center": [], - "logo": { - "text": "AWS SDK for Python", - } -} + html_theme = 'pydata_sphinx_theme' + html_theme_options = { + "navbar_center": [], + "logo": { + "text": "AWS SDK for Python", + } + } -autodoc_typehints = 'both' - """, version); + autodoc_typehints = 'both' + """, version); }); } - /** * Write a make.bat file. * A make.bat file is a batch script used on Windows to build Sphinx documentation. @@ -321,40 +320,40 @@ private static void writeMakeBat( ) { context.writerDelegator().useFileWriter("docs/make.bat", "", writer -> { writer.write(""" -@ECHO OFF + @ECHO OFF -pushd %~dp0 + pushd %~dp0 -REM Command file for Sphinx documentation + REM Command file for Sphinx documentation -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set SERVICESDIR=source/reference/services -set SPHINXOPTS=-j auto -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . + if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build + ) + set BUILDDIR=build + set SERVICESDIR=source/reference/services + set SPHINXOPTS=-j auto + set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -if "%1" == "" goto help + if "%1" == "" goto help -if "%1" == "clean" ( - rmdir /S /Q %BUILDDIR% - goto end -) + if "%1" == "clean" ( + rmdir /S /Q %BUILDDIR% + goto end + ) -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - echo. - echo "Build finished. The HTML pages are in %BUILDDIR%/html." - goto end -) + if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + echo. + echo "Build finished. The HTML pages are in %BUILDDIR%/html." + goto end + ) -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + :help + %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -:end -popd - """); + :end + popd + """); }); } @@ -370,24 +369,23 @@ private static void writeMakeFile( ) { context.writerDelegator().useFileWriter("docs/Makefile", "", writer -> { writer.write(""" -SPHINXBUILD = sphinx-build -BUILDDIR = build -SERVICESDIR = source/reference/services -SPHINXOPTS = -j auto -ALLSPHINXOPTS = -d $$(BUILDDIR)/doctrees $$(SPHINXOPTS) . - -clean: -\t-rm -rf $$(BUILDDIR)/* - -html: -\t$$(SPHINXBUILD) -b html $$(ALLSPHINXOPTS) $$(BUILDDIR)/html -\t@echo -\t@echo "Build finished. The HTML pages are in $$(BUILDDIR)/html." - """); + SPHINXBUILD = sphinx-build + BUILDDIR = build + SERVICESDIR = source/reference/services + SPHINXOPTS = -j auto + ALLSPHINXOPTS = -d $$(BUILDDIR)/doctrees $$(SPHINXOPTS) . + + clean: + \t-rm -rf $$(BUILDDIR)/* + + html: + \t$$(SPHINXBUILD) -b html $$(ALLSPHINXOPTS) $$(BUILDDIR)/html + \t@echo + \t@echo "Build finished. The HTML pages are in $$(BUILDDIR)/html." + """); }); } - /** * Write the main index files for the documentation. * This method creates the main index.rst file and additional index files for @@ -399,16 +397,16 @@ private static void writeIndexes(GenerationContext context) { // Write the main index file for the documentation context.writerDelegator().useFileWriter("docs/index.rst", "", writer -> { writer.write(""" -AWS SDK For Python -==================================================== + AWS SDK For Python + ==================================================== -.. toctree:: - :maxdepth: 2 - :titlesonly: - :glob: + .. toctree:: + :maxdepth: 2 + :titlesonly: + :glob: - */index - """); + */index + """); }); // Write the index file for the client section @@ -429,15 +427,15 @@ private static void writeIndexes(GenerationContext context) { private static void writeIndexFile(GenerationContext context, String filePath, String title) { context.writerDelegator().useFileWriter(filePath, "", writer -> { writer.write(""" -$L -======= -.. toctree:: - :maxdepth: 1 - :titlesonly: - :glob: - - * - """, title); + $L + ======= + .. toctree:: + :maxdepth: 1 + :titlesonly: + :glob: + + * + """, title); }); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java index cf711f0ac..f4f9c3d6a 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java @@ -103,17 +103,17 @@ private void renderStructure() { writer.pushState(new StructureSection(shape)); writer.write(""" - @dataclass(kw_only=True) - class $L: - ${C|} - - ${C|} - - ${C|} - - ${C|} - - """, + @dataclass(kw_only=True) + class $L: + ${C|} + + ${C|} + + ${C|} + + ${C|} + + """, symbol.getName(), writer.consumer(w -> writeClassDocs(false)), writer.consumer(w -> writeProperties()), @@ -160,7 +160,7 @@ class $1L($2T): writer.consumer(w -> generateDeserializeMethod())); writer.popState(); - } + } private void writeProperties() { for (MemberShape member : requiredMembers) { @@ -317,7 +317,8 @@ private boolean hasDocs() { private void writeMemberDocs(MemberShape member) { member.getMemberTrait(model, DocumentationTrait.class).ifPresent(trait -> { String memberName = symbolProvider.toMemberName(member); - String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())).replace("\n", "\n "); + String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())) + .replace("\n", "\n "); writer.write(docs); }); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java index a3d41bb91..ac8d52978 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.Set; - import software.amazon.smithy.codegen.core.SymbolProvider; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.MemberShape; @@ -133,8 +132,8 @@ raise NotImplementedError() memberNames.add(unknownSymbol.getName()); writer.popState(); - writer.write("type $L = $L\n", parentName, String.join(" | ", memberNames)); writer.pushState(new UnionSection(shape, parentName, memberNames)); + writer.write("$L = Union[$L]\n", parentName, String.join(" | ", memberNames)); shape.getTrait(DocumentationTrait.class).ifPresent(trait -> writer.writeDocs(trait.getValue())); writer.popState(); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java index cc661c43d..8fe18b2e7 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/integrations/PythonIntegration.java @@ -44,7 +44,6 @@ default Model preprocessModel(Model model, PythonSettings settings) { return model; } - /** * Writes out all extra files required by runtime plugins. */ diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java index 2fd589699..4b8831f0f 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/ErrorSection.java @@ -12,5 +12,4 @@ * A section that controls writing an error. */ @SmithyInternalApi -public record ErrorSection(Symbol errorSymbol) implements CodeSection { -} +public record ErrorSection(Symbol errorSymbol) implements CodeSection {} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java index f64dad265..ceab19545 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/OperationSection.java @@ -13,5 +13,4 @@ * A section that controls writing an operation. */ @SmithyInternalApi -public record OperationSection(Shape service, OperationShape operation) implements CodeSection { -} +public record OperationSection(Shape service, OperationShape operation) implements CodeSection {} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java index da33ed285..23713e651 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/StructureSection.java @@ -12,5 +12,4 @@ * A section that controls writing a structure. */ @SmithyInternalApi -public record StructureSection(StructureShape structure) implements CodeSection { -} +public record StructureSection(StructureShape structure) implements CodeSection {} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java index dd785ea07..bd6d999e6 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionMemberSection.java @@ -12,5 +12,4 @@ * A section that controls writing a union member. */ @SmithyInternalApi -public record UnionMemberSection(Symbol memberSymbol) implements CodeSection { -} +public record UnionMemberSection(Symbol memberSymbol) implements CodeSection {} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java index a5bb1c7a6..55138f2f6 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/sections/UnionSection.java @@ -4,16 +4,16 @@ */ package software.amazon.smithy.python.codegen.sections; +import java.util.ArrayList; import software.amazon.smithy.model.shapes.UnionShape; import software.amazon.smithy.utils.CodeSection; import software.amazon.smithy.utils.SmithyInternalApi; -import java.util.ArrayList; - /** * A section that controls writing a union. */ @SmithyInternalApi -public record UnionSection(UnionShape unionShape, String parentName, - ArrayList memberNames) implements CodeSection { -} +public record UnionSection( + UnionShape unionShape, + String parentName, + ArrayList memberNames) implements CodeSection {} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java index e43707494..86c77d770 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java @@ -218,7 +218,6 @@ private static int findWrapPosition(String line, int maxLineLength) { return wrapAt; } - private static int getIndentationLevel(String line) { int indent = 0; while (indent < line.length() && Character.isWhitespace(line.charAt(indent))) { @@ -227,7 +226,6 @@ private static int getIndentationLevel(String line) { return indent; } - /** * Opens a block to write comments. * @@ -371,7 +369,7 @@ public String toString() { contents += super.toString(); if (!commentStart.equals("")) { - String header = String.format("%s Code generated by smithy-python-codegen DO NOT EDIT.\n\n", commentStart); + String header = String.format("%s Code generated by smithy-python-codegen DO NOT EDIT.%n%n", commentStart); contents = header + contents; } return contents; From 1a3655269fbb35fbca2468a5e025ed8a35cdc1fe Mon Sep 17 00:00:00 2001 From: SamRemis Date: Tue, 18 Mar 2025 14:18:54 -0400 Subject: [PATCH 04/11] Fix linewrapping, add tests --- .../python/aws/codegen/AwsDocConverter.java | 46 +++++--- .../aws/codegen/AwsRstDocFileGenerator.java | 17 ++- .../aws/codegen/AwsDocConverterTest.java | 108 ++++++++++++++++++ .../python/codegen/PythonDependency.java | 5 +- .../codegen/SmithyPythonDependency.java | 18 +++ .../codegen/generators/SetupGenerator.java | 35 ++++-- .../python/codegen/writer/PythonWriter.java | 4 +- 7 files changed, 199 insertions(+), 34 deletions(-) create mode 100644 codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java index d33279068..d6d3cfa08 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java @@ -4,19 +4,19 @@ */ package software.amazon.smithy.python.aws.codegen; -import software.amazon.smithy.model.shapes.Shape; -import software.amazon.smithy.model.traits.DocumentationTrait; -import software.amazon.smithy.python.codegen.PythonSettings; -import software.amazon.smithy.python.codegen.integrations.PythonIntegration; -import software.amazon.smithy.utils.SmithyInternalApi; -import software.amazon.smithy.model.Model; -import software.amazon.smithy.model.transform.ModelTransformer; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; import org.jsoup.select.NodeVisitor; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.traits.DocumentationTrait; +import software.amazon.smithy.model.transform.ModelTransformer; +import software.amazon.smithy.python.codegen.PythonSettings; +import software.amazon.smithy.python.codegen.integrations.PythonIntegration; +import software.amazon.smithy.utils.SmithyInternalApi; /** * Add a runtime plugin to convert the HTML docs that are provided by services into @@ -41,7 +41,7 @@ public Model preprocessModel(Model model, PythonSettings settings) { }); } - private String convertHtmlToRst(String html) { + String convertHtmlToRst(String html) { Document document = Jsoup.parse(html); RstNodeVisitor visitor = new RstNodeVisitor(); document.body().traverse(visitor); @@ -60,8 +60,8 @@ public void head(Node node, int depth) { String text = textNode.text(); if (!text.trim().isEmpty()) { sb.append(text); - // Account for services making a paragraph tag that's empty except - // for a newline + // Account for services making a paragraph tag that's empty except + // for a newline } else if (node.parent() instanceof Element && ((Element) node.parent()).tagName().equals("p")) { sb.append(text.replaceAll("[ \\t]+", "")); } @@ -98,6 +98,11 @@ public void head(Node node, int depth) { sb.append(" ".repeat(listDepth - 1)).append("* "); } break; + case "h1": + sb.append("\n"); + break; + default: + break; } } } @@ -108,7 +113,7 @@ public void tail(Node node, int depth) { Element element = (Element) node; switch (element.tagName()) { case "a": - sb.append(" <").append(element.attr("href")).append(">`_ "); + sb.append(" <").append(element.attr("href")).append(">`_"); break; case "b": case "strong": @@ -122,7 +127,7 @@ public void tail(Node node, int depth) { sb.append("``"); break; case "important": - case "note", "p", "li": + case "note", "p": sb.append("\n"); break; case "ul": @@ -130,7 +135,20 @@ public void tail(Node node, int depth) { if (listDepth == 0) { inList = false; } - sb.append("\n\n"); + if (sb.charAt(sb.length() - 1) != '\n') { + sb.append("\n\n"); + } + break; + case "li": + if (sb.charAt(sb.length() - 1) != '\n') { + sb.append("\n\n"); + } + break; + case "h1": + String title = element.text(); + sb.append("\n").append("=".repeat(title.length())).append("\n"); + break; + default: break; } } @@ -141,4 +159,4 @@ public String toString() { return sb.toString(); } } -} \ No newline at end of file +} diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java index caf919999..6cddfcf90 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java @@ -4,6 +4,9 @@ */ package software.amazon.smithy.python.aws.codegen; +import static software.amazon.smithy.python.codegen.SymbolProperties.OPERATION_METHOD; + +import java.util.List; import software.amazon.smithy.model.traits.InputTrait; import software.amazon.smithy.model.traits.OutputTrait; import software.amazon.smithy.python.codegen.GenerationContext; @@ -13,9 +16,6 @@ import software.amazon.smithy.utils.CodeInterceptor; import software.amazon.smithy.utils.CodeSection; -import java.util.ArrayList; -import java.util.List; - public class AwsRstDocFileGenerator implements PythonIntegration { @Override @@ -27,8 +27,7 @@ public List> inte new StructureGenerationInterceptor(context), new ErrorGenerationInterceptor(context), new UnionGenerationInterceptor(context), - new UnionMemberGenerationInterceptor(context) - ); + new UnionMemberGenerationInterceptor(context)); } /** @@ -38,7 +37,7 @@ public List> inte * @return A formatted header string. */ private static String generateHeader(String title) { - return String.format("%s\n%s\n\n", title, "=".repeat(title.length())); + return String.format("%s%n%s%n%n", title, "=".repeat(title.length())); } private static final class OperationGenerationInterceptor @@ -58,7 +57,7 @@ public Class sectionType() { @Override public void append(PythonWriter pythonWriter, OperationSection section) { var operation = section.operation(); - var operationSymbol = context.symbolProvider().toSymbol(operation); + var operationSymbol = context.symbolProvider().toSymbol(operation).expectProperty(OPERATION_METHOD); var input = context.model().expectShape(operation.getInputShape()); var inputSymbol = context.symbolProvider().toSymbol(input); var output = context.model().expectShape(operation.getOutputShape()); @@ -158,12 +157,12 @@ public Class sectionType() { @Override public void append(PythonWriter pythonWriter, UnionSection section) { String parentName = section.parentName(); - ArrayList memberNames = section.memberNames(); String docsFileName = String.format("docs/models/%s.rst", parentName); context.writerDelegator().useFileWriter(docsFileName, "", writer -> { writer.write(".. _" + parentName + ":\n\n"); writer.write(generateHeader(parentName)); - writer.write(".. autodata:: " + context.symbolProvider().toSymbol(section.unionShape()).toString() + " \n"); + writer.write( + ".. autodata:: " + context.symbolProvider().toSymbol(section.unionShape()).toString() + " \n"); }); } } diff --git a/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java b/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java new file mode 100644 index 000000000..7ba500077 --- /dev/null +++ b/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java @@ -0,0 +1,108 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.python.aws.codegen; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class AwsDocConverterTest { + + private AwsDocConverter awsDocConverter; + + @BeforeEach + public void setUp() { + awsDocConverter = new AwsDocConverter(); + } + + @Test + public void testConvertHtmlToRstWithTitleAndParagraph() { + String html = "

Title

Paragraph

"; + String expected = "\n\nTitle\n=====\nParagraph\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithImportantNote() { + String html = "Important note"; + String expected = "\n\n.. important::\n Important note\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithList() { + String html = "
  • Item 1
  • Item 2
"; + String expected = "\n\n* Item 1\n\n* Item 2\n\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithMixedElements() { + String html = "

Title

Paragraph

  • Item 1
  • Item 2
"; + String expected = "\n\nTitle\n=====\nParagraph\n\n* Item 1\n\n* Item 2\n\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithNestedElements() { + String html = "

Title

Paragraph with bold text

"; + String expected = "\n\nTitle\n=====\nParagraph with **bold** text\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithAnchorTag() { + String html = "Link"; + String expected = "\n`Link `_"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithBoldTag() { + String html = "Bold text"; + String expected = "\n**Bold text**"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithItalicTag() { + String html = "Italic text"; + String expected = "\n*Italic text*"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithCodeTag() { + String html = "code snippet"; + String expected = "\n``code snippet``"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithNoteTag() { + String html = "Note text"; + String expected = "\n\n.. note::\n Note text\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } + + @Test + public void testConvertHtmlToRstWithNestedList() { + String html = "
  • Item 1
    • Subitem 1
  • Item 2
"; + String expected = "\n\n* Item 1\n * Subitem 1\n\n* Item 2\n\n"; + String result = awsDocConverter.convertHtmlToRst(html); + assertEquals(expected, result); + } +} diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/PythonDependency.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/PythonDependency.java index 89f016b9e..908541b3f 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/PythonDependency.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/PythonDependency.java @@ -60,7 +60,10 @@ public enum Type { DEPENDENCY("dependency"), /** A dependency only used for testing purposes. */ - TEST_DEPENDENCY("testDependency"); + TEST_DEPENDENCY("testDependency"), + + /** A dependency only used for docs generation. */ + DOCS_DEPENDENCY("docsDependency"); private final String type; diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java index 0e1a456e1..c43e47d61 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java @@ -102,6 +102,24 @@ public final class SmithyPythonDependency { Type.TEST_DEPENDENCY, false); + /** + * library used for documentation generation + */ + public static final PythonDependency SPHINX = new PythonDependency( + "sphinx", + ">=8.2.3", + Type.DOCS_DEPENDENCY, + false); + + /** + * sphinx theme + */ + public static final PythonDependency SPHINX_PYDATA_THEME = new PythonDependency( + "pydata-sphinx-theme", + ">=0.16.1", + Type.DOCS_DEPENDENCY, + false); + private SmithyPythonDependency() {} /** diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 0f57678ff..22dd305bf 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -20,10 +20,7 @@ import software.amazon.smithy.model.traits.DocumentationTrait; import software.amazon.smithy.model.traits.StringTrait; import software.amazon.smithy.model.traits.TitleTrait; -import software.amazon.smithy.python.codegen.GenerationContext; -import software.amazon.smithy.python.codegen.PythonDependency; -import software.amazon.smithy.python.codegen.PythonSettings; -import software.amazon.smithy.python.codegen.SymbolProperties; +import software.amazon.smithy.python.codegen.*; import software.amazon.smithy.python.codegen.sections.PyprojectSection; import software.amazon.smithy.python.codegen.sections.ReadmeSection; import software.amazon.smithy.python.codegen.writer.PythonWriter; @@ -42,10 +39,10 @@ public static void generateSetup( PythonSettings settings, GenerationContext context ) { + writeDocsSkeleton(settings, context); var dependencies = gatherDependencies(context.writerDelegator().getDependencies().stream()); writePyproject(settings, context.writerDelegator(), dependencies); writeReadme(settings, context); - writeDocsSkeleton(settings, context); } /** @@ -150,9 +147,24 @@ private static void writePyproject( writer.openBlock("dependencies = [", "]", () -> writeDependencyList(writer, deps.values())); }); - Optional.ofNullable(dependencies.get(PythonDependency.Type.TEST_DEPENDENCY.getType())).ifPresent(deps -> { + Optional> testDeps = + Optional.ofNullable(dependencies.get(PythonDependency.Type.TEST_DEPENDENCY.getType())) + .map(Map::values); + + Optional> docsDeps = + Optional.ofNullable(dependencies.get(PythonDependency.Type.DOCS_DEPENDENCY.getType())) + .map(Map::values); + + if (testDeps.isPresent() || docsDeps.isPresent()) { writer.write("[project.optional-dependencies]"); - writer.openBlock("tests = [", "]", () -> writeDependencyList(writer, deps.values())); + } + + testDeps.ifPresent(deps -> { + writer.openBlock("tests = [", "]", () -> writeDependencyList(writer, deps)); + }); + + docsDeps.ifPresent(deps -> { + writer.openBlock("docs = [", "]", () -> writeDependencyList(writer, deps)); }); // TODO: remove the pyright global suppressions after the serde redo is done @@ -254,7 +266,14 @@ private static void writeReadme( /** * Write the files required for sphinx doc generation */ - private static void writeDocsSkeleton(PythonSettings settings, GenerationContext context) { + private static void writeDocsSkeleton( + PythonSettings settings, + GenerationContext context + ) { + context.writerDelegator().useFileWriter("pyproject.toml", "", writer -> { + writer.addDependency(SmithyPythonDependency.SPHINX); + writer.addDependency(SmithyPythonDependency.SPHINX_PYDATA_THEME); + }); writeConf(settings, context); writeMakeBat(context); writeMakeFile(context); diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java index 86c77d770..56c7f8e14 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java @@ -191,9 +191,9 @@ private static int findWrapPosition(String line, int maxLineLength) { // Ensure we don't break a link int linkStart = line.lastIndexOf("`", wrapAt); int linkEnd = line.indexOf("`_", wrapAt); - if (linkStart != -1 && (linkEnd == -1 || linkEnd < linkStart)) { + if (linkStart != -1 && (linkEnd != -1 && linkEnd > linkStart)) { linkEnd = line.indexOf("`_", linkStart); - if (linkEnd != -1 && linkEnd <= maxLineLength) { + if (linkEnd != -1) { wrapAt = linkEnd + 2; } else { // No matching `_` found, keep the original wrap position From 2eab1a8b7bec04b4fa09c8702c718ca9211656c2 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Tue, 18 Mar 2025 14:24:20 -0400 Subject: [PATCH 05/11] remove global dependencies on sphinx and pydata --- pyproject.toml | 2 - uv.lock | 284 ------------------------------------------------- 2 files changed, 286 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eb54f5edd..b10ae5f41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,13 +10,11 @@ dependencies = [] dev = [ "black>=25.1.0", "docformatter>=1.7.5", - "pydata-sphinx-theme>=0.16.1", "pyright>=1.1.396", "pytest>=8.3.4", "pytest-asyncio>=0.25.3", "pytest-cov>=6.0.0", "ruff>=0.9.7", - "sphinx>=8.2.3", ] [tool.uv] diff --git a/uv.lock b/uv.lock index 54bdba2af..788a60bc5 100644 --- a/uv.lock +++ b/uv.lock @@ -14,18 +14,6 @@ members = [ "smithy-python", ] -[[package]] -name = "accessible-pygments" -version = "0.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903 }, -] - [[package]] name = "aiohappyeyeballs" version = "2.4.6" @@ -96,15 +84,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, ] -[[package]] -name = "alabaster" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 }, -] - [[package]] name = "attrs" version = "25.1.0" @@ -175,28 +154,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/e3/f524d3211fe4491887767da03f58de4b431790ed120b0e446565caaad027/awscrt-0.23.10-cp313-abi3-win_amd64.whl", hash = "sha256:23d2dfeaa0b62bb3bad569cec03a959bdbf62e9123ad1f235bfacb61d420f8d0", size = 2635008 }, ] -[[package]] -name = "babel" -version = "2.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, -] - -[[package]] -name = "beautifulsoup4" -version = "4.13.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f0/3c/adaf39ce1fb4afdd21b611e3d530b183bb7759c9b673d60db0e347fd4439/beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", size = 619516 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015 }, -] - [[package]] name = "black" version = "25.1.0" @@ -221,15 +178,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] -[[package]] -name = "certifi" -version = "2025.1.31" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, -] - [[package]] name = "charset-normalizer" version = "3.4.1" @@ -338,15 +286,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/95/568a2fca29df365b82012b09b64964a05f4f20ac83c2137b262f3fa3188f/docformatter-1.7.5-py3-none-any.whl", hash = "sha256:a24f5545ed1f30af00d106f5d85dc2fce4959295687c24c8f39f5263afaf9186", size = 32798 }, ] -[[package]] -name = "docutils" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, -] - [[package]] name = "freezegun" version = "1.5.1" @@ -426,15 +365,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/25/a2/e187beee237808b2c417109ae0f4f7ee7c81ecbe9706305d6ac2a509cc45/ijson-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f890d04ad33262d0c77ead53c85f13abfb82f2c8f078dfbf24b78f59534dfdd", size = 51272 }, ] -[[package]] -name = "imagesize" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, -] - [[package]] name = "iniconfig" version = "2.0.0" @@ -444,56 +374,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, -] - [[package]] name = "multidict" version = "6.1.0" @@ -669,33 +549,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/35/6c4c6fc8774a9e3629cd750dc24a7a4fb090a25ccd5c3246d127b70f9e22/propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", size = 12101 }, ] -[[package]] -name = "pydata-sphinx-theme" -version = "0.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "accessible-pygments" }, - { name = "babel" }, - { name = "beautifulsoup4" }, - { name = "docutils" }, - { name = "pygments" }, - { name = "sphinx" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/0d/8ba33fa83a7dcde13eb3c1c2a0c1cc29950a048bfed6d9b0d8b6bd710b4c/pydata_sphinx_theme-0.16.1-py3-none-any.whl", hash = "sha256:225331e8ac4b32682c18fcac5a57a6f717c4e632cea5dd0e247b55155faeccde", size = 6723264 }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, -] - [[package]] name = "pyright" version = "1.1.396" @@ -761,30 +614,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, ] -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - -[[package]] -name = "roman-numerals-py" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 }, -] - [[package]] name = "ruff" version = "0.9.7" @@ -910,13 +739,11 @@ source = { virtual = "." } dev = [ { name = "black" }, { name = "docformatter" }, - { name = "pydata-sphinx-theme" }, { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "ruff" }, - { name = "sphinx" }, ] [package.metadata] @@ -925,113 +752,11 @@ dev = [ dev = [ { name = "black", specifier = ">=25.1.0" }, { name = "docformatter", specifier = ">=1.7.5" }, - { name = "pydata-sphinx-theme", specifier = ">=0.16.1" }, { name = "pyright", specifier = ">=1.1.396" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "pytest-asyncio", specifier = ">=0.25.3" }, { name = "pytest-cov", specifier = ">=6.0.0" }, { name = "ruff", specifier = ">=0.9.7" }, - { name = "sphinx", specifier = ">=8.2.3" }, -] - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, -] - -[[package]] -name = "soupsieve" -version = "2.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, -] - -[[package]] -name = "sphinx" -version = "8.2.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "roman-numerals-py" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741 }, -] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, -] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, -] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, -] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, -] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, -] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, ] [[package]] @@ -1049,15 +774,6 @@ version = "0.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2", size = 3099 } -[[package]] -name = "urllib3" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, -] - [[package]] name = "yarl" version = "1.18.3" From eb0f27b12e48c7c4f929730b3ce155fb0cff03d8 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Tue, 18 Mar 2025 15:32:25 -0400 Subject: [PATCH 06/11] Fix linewrapping issue --- .../smithy/python/codegen/generators/SetupGenerator.java | 1 - .../amazon/smithy/python/codegen/writer/PythonWriter.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 22dd305bf..6543cb440 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -316,7 +316,6 @@ private static void writeConf( html_theme = 'pydata_sphinx_theme' html_theme_options = { - "navbar_center": [], "logo": { "text": "AWS SDK for Python", } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java index 56c7f8e14..6a95ca664 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java @@ -185,8 +185,8 @@ private static int findWrapPosition(String line, int maxLineLength) { // Find the last space before maxLineLength int wrapAt = line.lastIndexOf(' ', maxLineLength); if (wrapAt == -1) { - // If no space found, force wrap at maxLineLength - wrapAt = maxLineLength; + // If no space found, don't wrap + wrapAt = line.length(); } else { // Ensure we don't break a link int linkStart = line.lastIndexOf("`", wrapAt); From cf9e9ec2382a4ad4b5de18b992f3f6959c652c02 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Wed, 19 Mar 2025 18:08:23 -0400 Subject: [PATCH 07/11] Updates based on PR feedback --- codegen/aws/core/build.gradle.kts | 1 - .../aws/codegen/AwsRstDocFileGenerator.java | 4 ++ ...hon.codegen.integrations.PythonIntegration | 1 - ...ava => MarkdownToRstDocConverterTest.java} | 51 +++++++------- codegen/core/build.gradle.kts | 2 + .../codegen/generators/SetupGenerator.java | 12 +++- .../generators/StructureGenerator.java | 3 +- .../codegen/generators/UnionGenerator.java | 2 + .../writer/MarkdownToRstDocConverter.java} | 68 +++++++++++-------- .../python/codegen/writer/PythonWriter.java | 5 +- codegen/gradle/libs.versions.toml | 6 ++ 11 files changed, 93 insertions(+), 62 deletions(-) rename codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/{AwsDocConverterTest.java => MarkdownToRstDocConverterTest.java} (59%) rename codegen/{aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java => core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java} (74%) diff --git a/codegen/aws/core/build.gradle.kts b/codegen/aws/core/build.gradle.kts index 6f49cc966..3a81c5190 100644 --- a/codegen/aws/core/build.gradle.kts +++ b/codegen/aws/core/build.gradle.kts @@ -12,5 +12,4 @@ extra["moduleName"] = "software.amazon.smithy.python.aws.codegen" dependencies { implementation(project(":core")) implementation(libs.smithy.aws.traits) - implementation("org.jsoup:jsoup:1.19.1") } diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java index 6cddfcf90..ec81cbdc7 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java +++ b/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java @@ -23,6 +23,10 @@ public List> inte GenerationContext context ) { return List.of( + // We generate custom RST files for each member that we want to have + // its own page. This gives us much more fine-grained control of + // what gets generated than just using automodule or autoclass on + // the client would alone. new OperationGenerationInterceptor(context), new StructureGenerationInterceptor(context), new ErrorGenerationInterceptor(context), diff --git a/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration b/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration index b7025b1a6..2a8cfe6d6 100644 --- a/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration +++ b/codegen/aws/core/src/main/resources/META-INF/services/software.amazon.smithy.python.codegen.integrations.PythonIntegration @@ -8,5 +8,4 @@ software.amazon.smithy.python.aws.codegen.AwsProtocolsIntegration software.amazon.smithy.python.aws.codegen.AwsServiceIdIntegration software.amazon.smithy.python.aws.codegen.AwsUserAgentIntegration software.amazon.smithy.python.aws.codegen.AwsStandardRegionalEndpointsIntegration -software.amazon.smithy.python.aws.codegen.AwsDocConverter software.amazon.smithy.python.aws.codegen.AwsRstDocFileGenerator diff --git a/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java b/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java similarity index 59% rename from codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java rename to codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java index 7ba500077..8c81dac65 100644 --- a/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/AwsDocConverterTest.java +++ b/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java @@ -8,101 +8,102 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import software.amazon.smithy.python.codegen.writer.MarkdownToRstDocConverter; -public class AwsDocConverterTest { +public class MarkdownToRstDocConverterTest { - private AwsDocConverter awsDocConverter; + private MarkdownToRstDocConverter markdownToRstDocConverter; @BeforeEach public void setUp() { - awsDocConverter = new AwsDocConverter(); + markdownToRstDocConverter = new MarkdownToRstDocConverter(); } @Test - public void testConvertHtmlToRstWithTitleAndParagraph() { + public void testConvertCommonmarkToRstWithTitleAndParagraph() { String html = "

Title

Paragraph

"; String expected = "\n\nTitle\n=====\nParagraph\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithImportantNote() { + public void testConvertCommonmarkToRstWithImportantNote() { String html = "Important note"; String expected = "\n\n.. important::\n Important note\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithList() { + public void testConvertCommonmarkToRstWithList() { String html = "
  • Item 1
  • Item 2
"; String expected = "\n\n* Item 1\n\n* Item 2\n\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithMixedElements() { + public void testConvertCommonmarkToRstWithMixedElements() { String html = "

Title

Paragraph

  • Item 1
  • Item 2
"; String expected = "\n\nTitle\n=====\nParagraph\n\n* Item 1\n\n* Item 2\n\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithNestedElements() { + public void testConvertCommonmarkToRstWithNestedElements() { String html = "

Title

Paragraph with bold text

"; String expected = "\n\nTitle\n=====\nParagraph with **bold** text\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithAnchorTag() { + public void testConvertCommonmarkToRstWithAnchorTag() { String html = "Link"; String expected = "\n`Link `_"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithBoldTag() { + public void testConvertCommonmarkToRstWithBoldTag() { String html = "Bold text"; String expected = "\n**Bold text**"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithItalicTag() { + public void testConvertCommonmarkToRstWithItalicTag() { String html = "Italic text"; String expected = "\n*Italic text*"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithCodeTag() { + public void testConvertCommonmarkToRstWithCodeTag() { String html = "code snippet"; String expected = "\n``code snippet``"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithNoteTag() { + public void testConvertCommonmarkToRstWithNoteTag() { String html = "Note text"; String expected = "\n\n.. note::\n Note text\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } @Test - public void testConvertHtmlToRstWithNestedList() { + public void testConvertCommonmarkToRstWithNestedList() { String html = "
  • Item 1
    • Subitem 1
  • Item 2
"; String expected = "\n\n* Item 1\n * Subitem 1\n\n* Item 2\n\n"; - String result = awsDocConverter.convertHtmlToRst(html); + String result = markdownToRstDocConverter.convertCommonmarkToRst(html); assertEquals(expected, result); } } diff --git a/codegen/core/build.gradle.kts b/codegen/core/build.gradle.kts index bc8da8191..04f9064dd 100644 --- a/codegen/core/build.gradle.kts +++ b/codegen/core/build.gradle.kts @@ -15,4 +15,6 @@ dependencies { implementation(libs.smithy.protocol.test.traits) // We have this because we're using RestJson1 as a 'generic' protocol. implementation(libs.smithy.aws.traits) + implementation(libs.jsoup) + implementation(libs.commonmark) } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 6543cb440..09f115a92 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -14,6 +14,8 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; + +import software.amazon.smithy.aws.traits.ServiceTrait; import software.amazon.smithy.codegen.core.CodegenException; import software.amazon.smithy.codegen.core.SymbolDependency; import software.amazon.smithy.codegen.core.WriterDelegator; @@ -270,6 +272,8 @@ private static void writeDocsSkeleton( PythonSettings settings, GenerationContext context ) { + //TODO Add a configurable flag to disable the generation of the sphinx files + //TODO Add a configuration that will allow users to select a sphinx theme context.writerDelegator().useFileWriter("pyproject.toml", "", writer -> { writer.addDependency(SmithyPythonDependency.SPHINX); writer.addDependency(SmithyPythonDependency.SPHINX_PYDATA_THEME); @@ -291,14 +295,18 @@ private static void writeConf( PythonSettings settings, GenerationContext context ) { + var service = context.model().expectShape(settings.service()); String version = settings.moduleVersion(); + String project = service.getTrait(TitleTrait.class) + .map(StringTrait::getValue) + .orElse(service.getTrait(ServiceTrait.class).get().getSdkId()); context.writerDelegator().useFileWriter("docs/conf.py", "", writer -> { writer.write(""" import os import sys sys.path.insert(0, os.path.abspath('..')) - project = 'AWS SDK for Python' + project = '$L' author = 'Boto' release = '$L' @@ -322,7 +330,7 @@ private static void writeConf( } autodoc_typehints = 'both' - """, version); + """, project, version); }); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java index f4f9c3d6a..d7cc4dd1b 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/StructureGenerator.java @@ -317,8 +317,7 @@ private boolean hasDocs() { private void writeMemberDocs(MemberShape member) { member.getMemberTrait(model, DocumentationTrait.class).ifPresent(trait -> { String memberName = symbolProvider.toMemberName(member); - String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())) - .replace("\n", "\n "); + String docs = writer.formatDocs(String.format(":param %s: %s", memberName, trait.getValue())); writer.write(docs); }); } diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java index ac8d52978..b05c56fbb 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/UnionGenerator.java @@ -133,6 +133,8 @@ raise NotImplementedError() writer.popState(); writer.pushState(new UnionSection(shape, parentName, memberNames)); + // We need to use the old union syntax until we either migrate away from + // Sphinx or Sphinx fixes the issue upstream: https://github.com/sphinx-doc/sphinx/issues/10785 writer.write("$L = Union[$L]\n", parentName, String.join(" | ", memberNames)); shape.getTrait(DocumentationTrait.class).ifPresent(trait -> writer.writeDocs(trait.getValue())); writer.popState(); diff --git a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java similarity index 74% rename from codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java rename to codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java index d6d3cfa08..2d3eed526 100644 --- a/codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.python.aws.codegen; +package software.amazon.smithy.python.codegen.writer; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -10,45 +10,54 @@ import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; import org.jsoup.select.NodeVisitor; -import software.amazon.smithy.model.Model; -import software.amazon.smithy.model.shapes.Shape; -import software.amazon.smithy.model.traits.DocumentationTrait; -import software.amazon.smithy.model.transform.ModelTransformer; -import software.amazon.smithy.python.codegen.PythonSettings; -import software.amazon.smithy.python.codegen.integrations.PythonIntegration; +import software.amazon.smithy.utils.SetUtils; import software.amazon.smithy.utils.SmithyInternalApi; +import org.commonmark.node.BlockQuote; +import org.commonmark.node.FencedCodeBlock; +import org.commonmark.node.Heading; +import org.commonmark.node.HtmlBlock; +import org.commonmark.node.ListBlock; +import org.commonmark.node.ThematicBreak; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; + +import static org.jsoup.nodes.Document.OutputSettings.Syntax.html; /** - * Add a runtime plugin to convert the HTML docs that are provided by services into - * RST + * Add a runtime plugin to convert the HTML docs that are provided by services into RST */ @SmithyInternalApi -public class AwsDocConverter implements PythonIntegration { - @Override - public Model preprocessModel(Model model, PythonSettings settings) { - return ModelTransformer.create().mapShapes(model, shape -> { - if (shape.hasTrait(DocumentationTrait.class)) { - DocumentationTrait docTrait = shape.getTrait(DocumentationTrait.class).get(); - String html = docTrait.getValue(); - String rst = convertHtmlToRst(html); - DocumentationTrait newDocTrait = new DocumentationTrait(rst); - return Shape.shapeToBuilder(shape) - .addTrait(newDocTrait) - .build(); - } else { - return shape; - } - }); +public class MarkdownToRstDocConverter { + private static final Parser MARKDOWN_PARSER = Parser.builder() + .enabledBlockTypes(SetUtils.of( + Heading.class, HtmlBlock.class, ThematicBreak.class, FencedCodeBlock.class, + BlockQuote.class, ListBlock.class)) + .build(); + + // Singleton instance + private static final MarkdownToRstDocConverter DOC_CONVERTER = new MarkdownToRstDocConverter(); + + // Private constructor to prevent instantiation + private MarkdownToRstDocConverter() { + // Constructor } - String convertHtmlToRst(String html) { - Document document = Jsoup.parse(html); + public static MarkdownToRstDocConverter getInstance() { + return DOC_CONVERTER; + } + + + public String convertCommonmarkToRst(String commonmark) { + String html = + HtmlRenderer.builder().escapeHtml(false).build().render(MARKDOWN_PARSER.parse(commonmark)); + Document document = Jsoup.parse(commonmark); RstNodeVisitor visitor = new RstNodeVisitor(); document.body().traverse(visitor); return "\n" + visitor; } private static class RstNodeVisitor implements NodeVisitor { + //TODO migrate away from StringBuilder to use a SimpleCodeWriter private final StringBuilder sb = new StringBuilder(); private boolean inList = false; private int listDepth = 0; @@ -127,7 +136,8 @@ public void tail(Node node, int depth) { sb.append("``"); break; case "important": - case "note", "p": + case "note": + case "p": sb.append("\n"); break; case "ul": @@ -159,4 +169,4 @@ public String toString() { return sb.toString(); } } -} +} \ No newline at end of file diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java index 6a95ca664..0e5901139 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java @@ -39,6 +39,7 @@ public final class PythonWriter extends SymbolWriter { private static final Logger LOGGER = Logger.getLogger(PythonWriter.class.getName()); + private static final MarkdownToRstDocConverter DOC_CONVERTER = MarkdownToRstDocConverter.getInstance(); private final String fullPackageName; private final String commentStart; @@ -152,8 +153,8 @@ public PythonWriter writeDocs(String docs) { * @return Formatted documentation. */ public String formatDocs(String docs) { - String rstDocs = wrapRST(docs).toString(); - return rstDocs.replace("$", "$$"); + String rstDocs = DOC_CONVERTER.convertCommonmarkToRst(docs); + return wrapRST(rstDocs).toString().replace("$", "$$"); } public static String wrapRST(String text) { diff --git a/codegen/gradle/libs.versions.toml b/codegen/gradle/libs.versions.toml index 8a1bc5ce1..09ed17efd 100644 --- a/codegen/gradle/libs.versions.toml +++ b/codegen/gradle/libs.versions.toml @@ -6,11 +6,14 @@ spotbugs = "6.0.22" spotless = "7.0.2" smithy-gradle-plugins = "1.2.0" dep-analysis = "2.11.0" +jsoup = "1.19.1" +commonmark = "0.15.2" [libraries] smithy-model = { module = "software.amazon.smithy:smithy-model", version.ref = "smithy" } smithy-codegen = { module = "software.amazon.smithy:smithy-codegen-core", version.ref = "smithy" } smithy-aws-traits = { module = "software.amazon.smithy:smithy-aws-traits", version.ref = "smithy" } +smithy-aws-endpoints = { module = "software.amazon.smithy:smithy-aws-endpoints", version.ref = "smithy" } smithy-aws-protocol-tests = { module = "software.amazon.smithy:smithy-aws-protocol-tests", version.ref = "smithy" } smithy-protocol-test-traits = { module = "software.amazon.smithy:smithy-protocol-test-traits", version.ref = "smithy"} smithy-waiters = { module = "software.amazon.smithy:smithy-waiters", version.ref = "smithy" } @@ -28,6 +31,9 @@ spotbugs = { module = "com.github.spotbugs.snom:spotbugs-gradle-plugin", version spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" } dependency-analysis = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dep-analysis" } +jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } +commonmark = { module = "com.atlassian.commonmark:commonmark", version.ref ="commonmark" } + [plugins] smithy-gradle-base = { id = "software.amazon.smithy.gradle.smithy-base", version.ref = "smithy-gradle-plugins" } smithy-gradle-jar = { id = "software.amazon.smithy.gradle.smithy-jar", version.ref = "smithy-gradle-plugins" } From fb551e26f2b6b544b4cb2bc7cefb92222150673b Mon Sep 17 00:00:00 2001 From: SamRemis Date: Wed, 19 Mar 2025 18:10:37 -0400 Subject: [PATCH 08/11] Update codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java Co-authored-by: Nate Prewitt --- .../amazon/smithy/python/codegen/generators/SetupGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 09f115a92..6fb82374a 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -307,7 +307,7 @@ private static void writeConf( sys.path.insert(0, os.path.abspath('..')) project = '$L' - author = 'Boto' + author = 'Amazon Web Services' release = '$L' extensions = [ From 169c9884fc97eb982279335ac4868bc5198c132b Mon Sep 17 00:00:00 2001 From: SamRemis Date: Thu, 20 Mar 2025 09:31:27 -0400 Subject: [PATCH 09/11] Update libs.versions.toml --- codegen/gradle/libs.versions.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/codegen/gradle/libs.versions.toml b/codegen/gradle/libs.versions.toml index 58eef9c8b..94f940712 100644 --- a/codegen/gradle/libs.versions.toml +++ b/codegen/gradle/libs.versions.toml @@ -13,7 +13,6 @@ commonmark = "0.15.2" smithy-model = { module = "software.amazon.smithy:smithy-model", version.ref = "smithy" } smithy-codegen = { module = "software.amazon.smithy:smithy-codegen-core", version.ref = "smithy" } smithy-aws-traits = { module = "software.amazon.smithy:smithy-aws-traits", version.ref = "smithy" } -smithy-aws-endpoints = { module = "software.amazon.smithy:smithy-aws-endpoints", version.ref = "smithy" } smithy-aws-protocol-tests = { module = "software.amazon.smithy:smithy-aws-protocol-tests", version.ref = "smithy" } smithy-protocol-test-traits = { module = "software.amazon.smithy:smithy-protocol-test-traits", version.ref = "smithy"} smithy-waiters = { module = "software.amazon.smithy:smithy-waiters", version.ref = "smithy" } From 12f66d8713bf5ce1c22850857f5ad35ddc9be424 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Thu, 20 Mar 2025 11:56:24 -0400 Subject: [PATCH 10/11] variable fix --- .../codegen/generators/SetupGenerator.java | 30 +++++++++-------- .../writer/MarkdownToRstDocConverter.java | 33 ++++++++++--------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java index 6fb82374a..cd17c6e5e 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java @@ -14,7 +14,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; - import software.amazon.smithy.aws.traits.ServiceTrait; import software.amazon.smithy.codegen.core.CodegenException; import software.amazon.smithy.codegen.core.SymbolDependency; @@ -278,10 +277,16 @@ private static void writeDocsSkeleton( writer.addDependency(SmithyPythonDependency.SPHINX); writer.addDependency(SmithyPythonDependency.SPHINX_PYDATA_THEME); }); - writeConf(settings, context); + var service = context.model().expectShape(settings.service()); + String projectName = service.getTrait(TitleTrait.class) + .map(StringTrait::getValue) + .orElseGet(() -> service.getTrait(ServiceTrait.class) + .map(ServiceTrait::getSdkId) + .orElse(context.settings().service().getName())); + writeConf(settings, context, projectName); + writeIndexes(context, projectName); writeMakeBat(context); writeMakeFile(context); - writeIndexes(context); } /** @@ -293,13 +298,10 @@ private static void writeDocsSkeleton( */ private static void writeConf( PythonSettings settings, - GenerationContext context + GenerationContext context, + String projectName ) { - var service = context.model().expectShape(settings.service()); String version = settings.moduleVersion(); - String project = service.getTrait(TitleTrait.class) - .map(StringTrait::getValue) - .orElse(service.getTrait(ServiceTrait.class).get().getSdkId()); context.writerDelegator().useFileWriter("docs/conf.py", "", writer -> { writer.write(""" import os @@ -325,12 +327,12 @@ private static void writeConf( html_theme = 'pydata_sphinx_theme' html_theme_options = { "logo": { - "text": "AWS SDK for Python", + "text": "$L", } } autodoc_typehints = 'both' - """, project, version); + """, projectName, version, projectName); }); } @@ -419,12 +421,12 @@ private static void writeMakeFile( * * @param context The generation context containing the writer delegator. */ - private static void writeIndexes(GenerationContext context) { + private static void writeIndexes(GenerationContext context, String projectName) { // Write the main index file for the documentation context.writerDelegator().useFileWriter("docs/index.rst", "", writer -> { writer.write(""" - AWS SDK For Python - ==================================================== + $L + $L .. toctree:: :maxdepth: 2 @@ -432,7 +434,7 @@ private static void writeIndexes(GenerationContext context) { :glob: */index - """); + """, projectName, "=".repeat(projectName.length())); }); // Write the index file for the client section diff --git a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java index 2d3eed526..811d938c0 100644 --- a/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java +++ b/codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/MarkdownToRstDocConverter.java @@ -4,14 +4,8 @@ */ package software.amazon.smithy.python.codegen.writer; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; -import org.jsoup.nodes.TextNode; -import org.jsoup.select.NodeVisitor; -import software.amazon.smithy.utils.SetUtils; -import software.amazon.smithy.utils.SmithyInternalApi; +import static org.jsoup.nodes.Document.OutputSettings.Syntax.html; + import org.commonmark.node.BlockQuote; import org.commonmark.node.FencedCodeBlock; import org.commonmark.node.Heading; @@ -20,8 +14,14 @@ import org.commonmark.node.ThematicBreak; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; - -import static org.jsoup.nodes.Document.OutputSettings.Syntax.html; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.nodes.TextNode; +import org.jsoup.select.NodeVisitor; +import software.amazon.smithy.utils.SetUtils; +import software.amazon.smithy.utils.SmithyInternalApi; /** * Add a runtime plugin to convert the HTML docs that are provided by services into RST @@ -30,8 +30,12 @@ public class MarkdownToRstDocConverter { private static final Parser MARKDOWN_PARSER = Parser.builder() .enabledBlockTypes(SetUtils.of( - Heading.class, HtmlBlock.class, ThematicBreak.class, FencedCodeBlock.class, - BlockQuote.class, ListBlock.class)) + Heading.class, + HtmlBlock.class, + ThematicBreak.class, + FencedCodeBlock.class, + BlockQuote.class, + ListBlock.class)) .build(); // Singleton instance @@ -46,11 +50,10 @@ public static MarkdownToRstDocConverter getInstance() { return DOC_CONVERTER; } - public String convertCommonmarkToRst(String commonmark) { String html = HtmlRenderer.builder().escapeHtml(false).build().render(MARKDOWN_PARSER.parse(commonmark)); - Document document = Jsoup.parse(commonmark); + Document document = Jsoup.parse(html); RstNodeVisitor visitor = new RstNodeVisitor(); document.body().traverse(visitor); return "\n" + visitor; @@ -169,4 +172,4 @@ public String toString() { return sb.toString(); } } -} \ No newline at end of file +} From 25f2bd4db3da6cf85953e13493aec5132c901968 Mon Sep 17 00:00:00 2001 From: SamRemis Date: Thu, 20 Mar 2025 12:30:08 -0400 Subject: [PATCH 11/11] Update MarkdownToRstDocConverterTest.java --- .../python/aws/codegen/MarkdownToRstDocConverterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java b/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java index 8c81dac65..0f51a6433 100644 --- a/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java +++ b/codegen/aws/core/src/test/java/software/amazon/smithy/python/aws/codegen/MarkdownToRstDocConverterTest.java @@ -16,7 +16,7 @@ public class MarkdownToRstDocConverterTest { @BeforeEach public void setUp() { - markdownToRstDocConverter = new MarkdownToRstDocConverter(); + markdownToRstDocConverter = MarkdownToRstDocConverter.getInstance(); } @Test