Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ This code generator, and the clients it generates, are unstable and should not
be used in production systems yet. Several features, such as detailed logging,
have not been implemented yet.

> [!NOTE]
> The Java generator in `codegen` remains the authoritative implementation.
> `packages/smithy-python` contains an experimental Python-native CLI scaffold
> that does not generate code yet.

### What is this repository?

This repository contains two major components:
Expand All @@ -20,9 +25,9 @@ This repository contains two major components:
2) Core modules and interfaces for building service clients in Python

These components facilitate generating clients for any [Smithy](https://smithy.io/)
service. The `codegen` directory contains the source code for generating clients.
The `python-packages` directory contains the source code for the handwritten python
components.
service. The `codegen` directory contains the current Java generator,
`packages/smithy-python` contains the Python-native generator scaffold, and the
other directories under `packages` contain the handwritten Python components.

This repository does *not* contain any generated clients, such as for S3 or other
AWS services. Rather, these are the tools that facilitate the generation of those
Expand Down
95 changes: 95 additions & 0 deletions designs/codegen/cli.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I haven't talked much about this publicly since I'm still working on implementations and a blog post, but check a look at shape closures. This is a way to drive generation that doesn't root everything in a service.

What it means for you is relatively little, other than that you should tolerate generating without a set service. Current type codegen generates a synthetic one, but you shouldn't operate that way.

Computing a closure is beyond your scope as a non-java plugin. I would suggest rather that you generate what's given to you and put the onus on customers to use smithy-build transforms to narrow it down to what they want. Maybe later you could implement everything needed to compute it and relax that restriction.

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Code Generator CLI

The `smithy-python` command is the process interface described in the
[Python Code Generation](index.md) overview. It supports direct use and
invocation from Smithy's
[`run` plugin](https://smithy.io/2.0/guides/smithy-build-json.html#run-plugin).

## Commands

Generation is organized by artifact type:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But what if you could mix artifacts. You don't now - but you could. Types+client or types+server is an obvious combo that's easy to do without much difficulty.

smithy-python generate --modes client,types

You could default that to just be client since most will want that.


```console
smithy-python generate client [OPTIONS]
smithy-python generate types [OPTIONS]
```

`client` generates a service client and its required types. `types` generates a
standalone types package. Both commands accept the following process options:

* `--model PATH` reads a JSON AST from a file instead of standard input.
* `--output PATH` selects the output directory for direct invocation.

Settings specific to each artifact will be added with the functionality that
consumes them.

The command MUST return zero after successful generation and non-zero when
arguments, settings, the model, or generation are invalid. Diagnostics are
written to standard error. Invalid command syntax and invocation inputs return
2, while I/O and generation failures return 1.

## Smithy `run` Plugin

The Smithy `run` plugin executes an external program during a build. It sends the
projection's Smithy model as a JSON AST to the process's standard input and runs
the process in the plugin's output directory.

A plugin ID MUST use `run::` followed by a custom artifact name. The configured
command identifies the artifact to generate:

```json
{
"version": "1.0",
"projections": {
"client": {
"plugins": {
"run::python-client": {
"command": ["smithy-python", "generate", "client"]
}
}
}
}
}
```

Artifact-specific options will be appended to `command` after they are defined.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is more for my own understanding: the existing Java generator receives service, module, and moduleVersion as plugin settings for each generated client. So in the future are we going to add options like the following?

{
  "run::python-client": {
    "command": [
      "smithy-python",
      "generate",
      "client",
      "--service",
      "com.amazonaws.bedrockruntime#AmazonBedrockFrontendService",
      "--module",
      "aws_sdk_bedrock_runtime",
      "--module-version",
      "0.8.0"
    ]
  }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yup. I need to look into Jordon's comment to see if --service will still be needed. I'll also consider using --package-name which we derive the module name from w/ an optional override (.e.g a aws-sdk-s3 package name generates a aws_sdk_s3 module name). I also think --module-version should become --package-version.

We may also grow this overtime to add new options like --http-client aiohttp | httpx | awscrt


The `smithy-python` executable MUST be installed or otherwise available on the
Smithy process's `PATH`. Smithy passes no arguments other than those in
`command`.

### Input and Output

When invoked by Smithy, the CLI reads one JSON AST document from standard input.
The document represents the model after projection transforms have been applied.

The presence of `SMITHY_PLUGIN_DIR` identifies an invocation by the `run` plugin.
Generated files are written beneath this directory, which Smithy also uses as the
process's working directory. The CLI MUST NOT write generated files outside it,
and `--model` and `--output` MUST NOT be used in this mode.

The `run` plugin provides the following environment variables:

| Name | Purpose |
|------|---------|
| `SMITHY_ROOT_DIR` | Root directory of the Smithy build. |
| `SMITHY_PLUGIN_DIR` | Output and working directory for the plugin. |
| `SMITHY_PROJECTION_NAME` | Name of the active projection. |
| `SMITHY_ARTIFACT_NAME` | Custom artifact name from the plugin ID. |
| `SMITHY_INCLUDES_PRELUDE` | Whether the JSON AST includes prelude shapes. |

The CLI uses this context to interpret the model. Protocol and platform
integrations MAY also use it while generating files.

Smithy omits prelude shapes by default. A build MAY set `sendPrelude` to `true`
in the `run` plugin configuration when those shapes are needed.

## Direct Invocation

When `SMITHY_PLUGIN_DIR` is absent, the CLI treats the command as a direct
invocation and requires `--output`. It follows the same
generation path as Smithy invocation and can read a JSON AST from a file instead
of standard input by using `--model`. When standard input is an interactive
terminal, `--model` is required so that an omitted input does not wait indefinitely
for input. This mode is intended for development, testing, and integration with
tools other than the Smithy CLI.
60 changes: 60 additions & 0 deletions designs/codegen/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Python Code Generation

Smithy Python currently generates clients with the Java implementation in
`codegen`. This document describes the Python code generator that will replace
that implementation over time.

The Python generator is distributed as `smithy-python`. It is separate from the
runtime packages used by generated code, and is only needed while generating a
package.

## Goals

* Generate Python clients and standalone types packages from Smithy models.
* Integrate with standard Smithy builds without requiring a Java code generator.
* Provide extension points for protocol and platform-specific behavior.
* Produce code compatible with the existing Smithy Python runtime packages.
* Allow the Python and Java generators to coexist during migration.

## Architecture

The generator consumes a Smithy JSON AST and settings for an artifact. It loads
the model, applies artifact and protocol-specific behavior, and writes a Python
package.

```text
Smithy JSON AST + settings
|
v
smithy-python generator
|
v
client or types package
```

Two artifact types are initially planned:

* `client` will generate a service client and its required types.
* `types` will generate a standalone package of types selected from a model.

The command-line interface is the generator's first entry point. Smithy's `run`
plugin invokes it as an external process, so the generator does not need to be
loaded into the Smithy CLI or implemented in Java.

Generated packages MUST NOT depend on `smithy-python` at runtime. They MAY
depend on the handwritten runtime packages in this repository.

## Migration

The Java generator remains authoritative while the Python generator is under
development. Features may be implemented and reviewed incrementally without
changing the Java path. A generated artifact SHOULD move to the Python generator
only after the required behavior is supported and tested.

The Python generator does not need to reproduce Java implementation details or
byte-for-byte output. It MUST preserve the supported Smithy semantics and public
behavior of generated packages.

## Designs

* [Code Generator CLI](cli.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "feature",
"description": "Added the experimental smithy-python package and CLI scaffold."
}
1 change: 1 addition & 0 deletions packages/smithy-python/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Note for reviewers: Our release infra will automatically handle version bumping and changelog management.

1 change: 1 addition & 0 deletions packages/smithy-python/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
19 changes: 19 additions & 0 deletions packages/smithy-python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# smithy-python

> [!WARNING]
> This package is an experimental scaffold. It does not generate code yet. The
> Java generator in the repository's `codegen` directory remains authoritative.

`smithy-python` will provide Python-native code generation for Smithy models.
The initial command-line interface exposes the planned client and types generation
commands so that their top-level shape can be developed independently from the
generator implementation.

```console
smithy-python generate client [OPTIONS]
smithy-python generate types [OPTIONS]
```

After validating their invocation options, both generation commands currently exit
with an error explaining that generation has not been implemented. The package is
included in workspace builds to validate its packaging and entry points.
51 changes: 51 additions & 0 deletions packages/smithy-python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[project]
name = "smithy-python"
dynamic = ["version"]
requires-python = ">=3.12"
authors = [
{name = "Amazon Web Services"},
]
description = "A Smithy code generator for Python clients and types."
readme = "README.md"
license = {text = "Apache License 2.0"}
keywords = ["smithy", "codegen", "sdk"]
classifiers = [
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"Natural Language :: English",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Free Threading :: 2 - Beta",
"Topic :: Software Development :: Code Generators",
]
dependencies = []

[project.scripts]
smithy-python = "smithy_python.cli:main"

[project.urls]
"Changelog" = "https://github.com/smithy-lang/smithy-python/blob/develop/packages/smithy-python/CHANGELOG.md"
"Code" = "https://github.com/smithy-lang/smithy-python/tree/develop/packages/smithy-python/"
"Issue tracker" = "https://github.com/smithy-lang/smithy-python/issues"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.version]
path = "src/smithy_python/__init__.py"

[tool.hatch.build]
exclude = [
"tests",
]

[tool.ruff]
src = ["src"]
5 changes: 5 additions & 0 deletions packages/smithy-python/src/smithy_python/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""A Smithy code generator for Python clients and types."""

__version__ = "0.0.0"
7 changes: 7 additions & 0 deletions packages/smithy-python/src/smithy_python/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

from .cli import main

if __name__ == "__main__":
raise SystemExit(main())
Loading
Loading