Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7d6de63
Document Python code generator design
jonathan343 Jul 19, 2026
bc7ff3d
Add experimental Python codegen CLI
jonathan343 Jul 19, 2026
cbe477c
Remove redundant exception hierarchy test
jonathan343 Jul 19, 2026
0f09ece
Clarify CLI examples and test module entry point
jonathan343 Jul 19, 2026
ba91974
Address PR feedback
jonathan343 Jul 22, 2026
05ea279
docs(codegen): Clarify service selection and generated shapes
jonathan343 Sep 12, 2026
b020d91
docs(codegen): Generate the service closure by default
jonathan343 Sep 13, 2026
e6b3026
docs(codegen): Document mixin resolution during model loading
jonathan343 Sep 13, 2026
9574e52
feat(codegen): Load models and resolve the service to generate
jonathan343 Sep 12, 2026
95f7590
fix(codegen): Resolve mixins when loading models
jonathan343 Sep 12, 2026
25868bf
fix(codegen): Suggest removeUnusedShapes for name conflicts
jonathan343 Sep 12, 2026
69e6fb5
refactor(codegen): Generate the service closure by default
jonathan343 Sep 13, 2026
b188045
fix(codegen): Merge applies while resolving each mixin
jonathan343 Sep 13, 2026
d309f6e
docs(codegen): State that nested model values are shared
jonathan343 Sep 13, 2026
353f943
fix(codegen): Make nested model values immutable
jonathan343 Sep 13, 2026
560ac4d
refactor(codegen): Simplify the model loader and the CLI
jonathan343 Sep 13, 2026
a1c80eb
fix(codegen): Resolve member IDs to members, not containers
jonathan343 Sep 13, 2026
78084df
fix(codegen): Reject JSON ASTs that are not Smithy 2.x
jonathan343 Sep 13, 2026
85d8151
fix(codegen): Exit 1 when the model file cannot be read
jonathan343 Sep 13, 2026
ffca518
Merge branch 'add-smithy-python' into python-codegen-model
jonathan343 Sep 13, 2026
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
146 changes: 146 additions & 0 deletions designs/codegen/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# 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:

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

`client` generates a service client and the data shapes it uses. `types`
generates a standalone package containing only data shapes. 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. It is required for direct
invocation and MUST NOT be used when the Smithy run plugin supplies the output
directory (`SMITHY_PLUGIN_DIR`).

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

### Service Selection

The CLI does not require a service to be named. It resolves the service to
generate as follows:

* `--service SHAPE_ID` selects a specific service shape. The shape MUST exist in
the model and MUST be a service.
* When `--service` is omitted and the model contains exactly one service shape,
that service is used.
* When `--service` is omitted and the model contains more than one service
shape, the command fails with an invocation error that lists the candidates.

The `client` artifact requires a resolved service. The `types` artifact does
not. The CLI MUST NOT synthesize a placeholder service to satisfy generation.

### Generated Shapes

When a service is resolved, both artifacts generate the data shapes in the
service closure: every shape reachable from the service through its operations,
resources, errors, and members. This matches the surface produced by the other
Smithy code generators. Data shapes in the model that are not connected to the
service are not generated, and the CLI reports how many were left out.

When no service is resolved, the `types` artifact generates every data shape in
the model. Smithy guarantees case-insensitively unique shape names only within a
service closure, so in this mode the command fails when two shapes have
case-insensitively equal names, identifying the conflicting shape IDs.

Trait definitions, prelude shapes, and shapes marked `@mixin` are never
generated. Builds that need a different set of shapes, such as types that are
not bound to any operation, apply smithy-build transforms in the projection.
An option to generate every shape in the model regardless of the service MAY be
added when there is a need for it.

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, such as
options that cannot be combined or a service that cannot be selected, return 2.
Model, I/O, and generation failures, including a model file that cannot be read,
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.
The `run` plugin can also pass settings through its `env` property, so an option
MAY additionally be read from an environment variable. A command-line option
takes precedence over its environment variable.

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.
Only Smithy 2.x JSON ASTs are supported; a document declaring another `smithy`
version is rejected with an error that names the version.

Smithy serializes only what a shape introduces, so shapes that use mixins arrive
without their inherited members, traits, and properties, and traits added to
inherited members arrive as `apply` statements. The CLI resolves mixins while
loading the model, following the rules of the
[Smithy mixins specification](https://smithy.io/2.0/spec/mixins.html), so builds
do not need the `flattenAndRemoveMixins` transform.

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.
70 changes: 70 additions & 0 deletions designs/codegen/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 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 artifact set may grow over time. A `server` artifact is a natural addition,
so the generator should not assume that only `client` and `types` exist.

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.

The generator has no runtime dependencies of its own, including on those
packages. It therefore defines its own shape IDs, shape types, and prelude
rather than reusing `smithy-core`'s. Those are shaped for serializing values at
runtime, whereas the generator needs the JSON AST's own vocabulary: wire-format
type names, member IDs, and lossless shape attributes. The overlap between the
two is intentional.

## 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."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "feature",
"description": "Added JSON AST model loading, service resolution via an optional `--service` option, and generated-shape selection with name-conflict detection."
}
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
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