Skip to content

Add experimental Python codegen CLI scaffold#744

Open
jonathan343 wants to merge 4 commits into
developfrom
add-smithy-python
Open

Add experimental Python codegen CLI scaffold#744
jonathan343 wants to merge 4 commits into
developfrom
add-smithy-python

Conversation

@jonathan343

@jonathan343 jonathan343 commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Overview

This PR lays the foundation for a Python-native Smithy code generator. It adds an experimental smithy-python package with the command-line interface that will eventually generate Python clients and standalone types packages.

The CLI currently validates its inputs and then exits with an explicit “generation is not implemented yet” error. The existing Java generator remains the primary one while the Python implementation is developed incrementally.

Background

The Python generator will consume Smithy JSON AST models and produce packages compatible with the existing Smithy Python runtime. It is distributed separately from those runtime packages and is only needed during code generation.

Smithy’s run plugin invokes the generator as an external process, allowing it to integrate with standard Smithy builds without being loaded into the Smithy CLI or implemented in Java. Read Smithy run plugin docs for more info.

Changes Summary

  • Created a new smithy-python package.
  • Add generate client and generate types commands.
  • Support direct invocation using --model and --output.
    • Note: This list of params will grow as in subsequent PRs
  • Support Smithy run plugin invocation through standard input and the provided plugin environment.
  • Validate invocation inputs and distinguish argument errors from I/O and generation failures.
  • Add unit tests covering CLI behavior, environment parsing, and the error hierarchy.
  • Document the generator architecture, CLI contract, and migration strategy.

CLI smoke tests

$ smithy-python --version
smithy-python 0.0.0
$ smithy-python generate --help
usage: smithy-python generate [-h] {client,types} ...

positional arguments:
  {client,types}
    client        Generate a client package
    types         Generate a standalone types package

options:
  -h, --help      show this help message and exit

Both generation commands accept a model and reach the expected placeholder behavior:

$ echo '{}' | smithy-python generate client --output /tmp/smithy-python-client
smithy-python: error: client generation is not implemented yet
$ echo '{}' | smithy-python generate types --output /tmp/smithy-python-types
smithy-python: error: types generation is not implemented yet

Both generation commands exit with status 1, as expected for the current implementation.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@jonathan343
jonathan343 requested a review from a team as a code owner July 19, 2026 03:18
Mark generation command examples as schematic and clarify option validation behavior. Exercise python -m smithy_python in a subprocess.
@@ -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.

Comment thread 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.

Comment thread designs/codegen/cli.md

## 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.

artifact.add_argument(
"--model",
type=Path,
help="Read the JSON AST from a file instead of standard input",

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.

Something like "The Smithy JSON AST model file to use for code generation. If not set, the model is read from standard input."

Comment on lines +77 to +82
for name, help_text in (
("client", "Generate a client package"),
("types", "Generate a standalone types package"),
):
artifact = artifacts.add_parser(name, help=help_text)
artifact.add_argument(

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 seems like a use-case for parent parsers.

artifact.add_argument(
"--output",
type=Path,
help="Output directory for direct invocation",

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.

Best to mention here where the default value comes from.

@dataclass(frozen=True, slots=True)
class _Invocation:
artifact: str
model_source: bytes

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.

A readable would be better here I think. You don't want to have to buffer all of that only to pass it into json.reads or whatever else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants