Skip to content

Commit 5b2ec33

Browse files
Enable shapes-only codegen
This adds an alternative generation mode that only generates "data shapes".
1 parent 08bf50d commit 5b2ec33

File tree

7 files changed

+179
-10
lines changed

7 files changed

+179
-10
lines changed

README.md

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ This repository does *not* contain any generated clients, such as for S3 or othe
2828
AWS services. Rather, these are the tools that facilitate the generation of those
2929
clients and non-AWS Smithy clients.
3030

31-
### How do I use this?
31+
### How do I use this to create a client?
3232

3333
The first step is to create a Smithy pacakge. If this is your first time working
3434
with Smithy, follow [this quickstart guide](https://smithy.io/2.0/quickstart.html)
@@ -82,8 +82,8 @@ this file, see the
8282
"sources": ["model"],
8383
"maven": {
8484
"dependencies": [
85-
"software.amazon.smithy:smithy-model:[1.34.0,2.0)",
86-
"software.amazon.smithy:smithy-aws-traits:[1.34.0,2.0)",
85+
"software.amazon.smithy:smithy-model:[1.54.0,2.0)",
86+
"software.amazon.smithy:smithy-aws-traits:[1.54.0,2.0)",
8787
"software.amazon.smithy.python:smithy-python-codegen:0.1.0"
8888
]
8989
},
@@ -145,6 +145,107 @@ Only for now. Once the generator has been published, the Smithy CLI will be able
145145
to run it without a separate Java installation. Similarly, once the python
146146
helper libraries have been published you won't need to install them manually.
147147

148+
### How do I generate types for shapes without a client?
149+
150+
If all you want are concrete Python classes for the shapes in your Smithy model,
151+
all you need to do is replace `python-client-codegen` with
152+
`python-shape-codegen` when following the steps above. Your `smithy-build.json`
153+
would now look like:
154+
155+
```json
156+
{
157+
"version": "1.0",
158+
"sources": ["model"],
159+
"maven": {
160+
"dependencies": [
161+
"software.amazon.smithy:smithy-model:[1.54.0,2.0)",
162+
"software.amazon.smithy.python:smithy-python-codegen:0.1.0"
163+
]
164+
},
165+
"projections": {
166+
"shapes": {
167+
"plugins": {
168+
"python-shape-codegen": {
169+
"service": "com.example#EchoService",
170+
"module": "echo",
171+
"moduleVersion": "0.0.1"
172+
}
173+
}
174+
}
175+
}
176+
}
177+
```
178+
179+
The module with the generated shape classes can be found in
180+
`build/smithy/client/python-shape-codegen` after you run `smithy-build`.
181+
182+
Note that a service shape is still required. In this case, it's used for the
183+
purposes of namespacing since all shapes within a service's closure must have a
184+
unique name. The service shape also has the `rename` property to resolve any
185+
conflicts you might encounter.
186+
187+
The one downside to this is that at time of writing there is no way to add
188+
shapes to a service that aren't connected to it via an operation or error. In
189+
the future, the service shape will have a `shapes` property or some other way of
190+
doing this. For now, it is recommended to just create a dummy operation to add
191+
any shapes needed, like below:
192+
193+
```smithy
194+
$version: "2.0"
195+
196+
namespace com.example
197+
198+
service ShapeNamespaceService {
199+
version: "2006-03-01"
200+
operations: [ShapeContainer]
201+
}
202+
203+
operation ShapeContainer {
204+
input := {
205+
example: ExampleShape
206+
}
207+
}
208+
209+
structure ExampleShape {
210+
intMember: Integer
211+
}
212+
```
213+
214+
You can also generate both a client package and a shape package in one build,
215+
but they won't depend on each other. To do this, just add both plugins in the
216+
projection, or create a projection for each plugin. Below is an example showing
217+
both plugins in one projection:
218+
219+
```json
220+
{
221+
"version": "1.0",
222+
"sources": ["model"],
223+
"maven": {
224+
"dependencies": [
225+
"software.amazon.smithy:smithy-model:[1.54.0,2.0)",
226+
"software.amazon.smithy:smithy-aws-traits:[1.54.0,2.0)",
227+
"software.amazon.smithy.python:smithy-python-codegen:0.1.0"
228+
]
229+
},
230+
"projections": {
231+
"client": {
232+
"plugins": {
233+
"python-client-codegen": {
234+
"service": "com.example#EchoService",
235+
"module": "echo",
236+
"moduleVersion": "0.0.1"
237+
},
238+
"python-shape-codegen": {
239+
"service": "com.example#EchoService",
240+
"module": "echo",
241+
"moduleVersion": "0.0.1"
242+
}
243+
}
244+
}
245+
}
246+
}
247+
```
248+
148249
### Core Modules and Interfaces
149250

150251
* `smithy-core` provides transport-agnostic core modules and interfaces

codegen/smithy-python-codegen-test/smithy-build.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
"service": "example.weather#Weather",
66
"module": "weather",
77
"moduleVersion": "0.0.1"
8+
},
9+
"python-shape-codegen": {
10+
"service": "example.weather#Weather",
11+
"module": "weather",
12+
"moduleVersion": "0.0.1"
813
}
914
}
1015
}

codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/DirectedPythonCodegen.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ final class DirectedPythonCodegen implements DirectedCodegen<GenerationContext,
6262
private static final Logger LOGGER = Logger.getLogger(DirectedPythonCodegen.class.getName());
6363
private static final int PYTHON_MINOR_VERSION = 12; // 3.12
6464

65+
private final boolean shapesOnly;
66+
67+
DirectedPythonCodegen(boolean shapesOnly) {
68+
this.shapesOnly = shapesOnly;
69+
}
70+
71+
DirectedPythonCodegen() {
72+
this(false);
73+
}
74+
6575
@Override
6676
public SymbolProvider createSymbolProvider(CreateSymbolProviderDirective<PythonSettings> directive) {
6777
return new SymbolVisitor(directive.model(), directive.settings());
@@ -112,10 +122,13 @@ private ProtocolGenerator resolveProtocolGenerator(
112122
@Override
113123
public void customizeBeforeShapeGeneration(CustomizeDirective<GenerationContext, PythonSettings> directive) {
114124
generateServiceErrors(directive.settings(), directive.context().writerDelegator());
115-
new ConfigGenerator(directive.settings(), directive.context()).run();
116-
117125
generateSchemas(directive.context(), directive.connectedShapes().values());
118126

127+
if (shapesOnly) {
128+
return;
129+
}
130+
131+
new ConfigGenerator(directive.settings(), directive.context()).run();
119132
var serviceIndex = ServiceIndex.of(directive.model());
120133
if (directive.context().applicationProtocol().isHttpProtocol()
121134
&& !serviceIndex.getAuthSchemes(directive.service()).isEmpty()) {
@@ -136,6 +149,10 @@ private void generateSchemas(GenerationContext context, Collection<Shape> shapes
136149

137150
@Override
138151
public void generateService(GenerateServiceDirective<GenerationContext, PythonSettings> directive) {
152+
if (shapesOnly) {
153+
return;
154+
}
155+
139156
new ClientGenerator(directive.context(), directive.service()).run();
140157

141158
var protocolGenerator = directive.context().protocolGenerator();

codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/PythonSettings.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public record PythonSettings(
4141
ShapeId service,
4242
String moduleName,
4343
String moduleVersion,
44-
String moduleDescription
44+
String moduleDescription,
45+
boolean shapesOnly
4546
) implements ToSmithyBuilder<PythonSettings> {
4647

4748
private static final String SERVICE = "service";
@@ -67,7 +68,8 @@ public PythonSettings(Builder builder) {
6768
builder.moduleVersion,
6869
StringUtils.isBlank(builder.moduleDescription)
6970
? builder.moduleName + " client"
70-
: builder.moduleDescription
71+
: builder.moduleDescription,
72+
builder.shapesOnly
7173
);
7274
}
7375

@@ -106,12 +108,13 @@ public static PythonSettings fromNode(ObjectNode config) {
106108
}
107109

108110
@Override
109-
public SmithyBuilder<PythonSettings> toBuilder() {
111+
public Builder toBuilder() {
110112
return builder()
111113
.service(service)
112114
.moduleName(moduleName)
113115
.moduleVersion(moduleVersion)
114-
.moduleDescription(moduleDescription);
116+
.moduleDescription(moduleDescription)
117+
.shapesOnly(shapesOnly);
115118
}
116119

117120
public static Builder builder() {
@@ -124,6 +127,7 @@ public static class Builder implements SmithyBuilder<PythonSettings> {
124127
private String moduleName;
125128
private String moduleVersion;
126129
private String moduleDescription;
130+
private boolean shapesOnly = false;
127131

128132
@Override
129133
public PythonSettings build() {
@@ -152,5 +156,10 @@ public Builder moduleDescription(String moduleDescription) {
152156
this.moduleDescription = moduleDescription;
153157
return this;
154158
}
159+
160+
public Builder shapesOnly(boolean shapesOnly) {
161+
this.shapesOnly = shapesOnly;
162+
return this;
163+
}
155164
}
156165
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.python.codegen;
7+
8+
import software.amazon.smithy.build.PluginContext;
9+
import software.amazon.smithy.build.SmithyBuildPlugin;
10+
import software.amazon.smithy.codegen.core.directed.CodegenDirector;
11+
import software.amazon.smithy.python.codegen.integration.PythonIntegration;
12+
13+
public final class PythonShapeCodegenPlugin implements SmithyBuildPlugin {
14+
@Override
15+
public String getName() {
16+
return "python-shape-codegen";
17+
}
18+
19+
@Override
20+
public void execute(PluginContext context) {
21+
CodegenDirector<PythonWriter, PythonIntegration, GenerationContext, PythonSettings> runner
22+
= new CodegenDirector<>();
23+
24+
PythonSettings settings = PythonSettings.fromNode(context.getSettings()).toBuilder()
25+
.shapesOnly(true)
26+
.build();
27+
runner.settings(settings);
28+
runner.directedCodegen(new DirectedPythonCodegen(true));
29+
runner.fileManifest(context.getFileManifest());
30+
runner.service(settings.service());
31+
runner.model(context.getModel());
32+
runner.integrationClass(PythonIntegration.class);
33+
runner.performDefaultCodegenTransforms();
34+
runner.run();
35+
}
36+
}

codegen/smithy-python-codegen/src/main/java/software/amazon/smithy/python/codegen/integration/HttpApiKeyAuth.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
5757

5858
@Override
5959
public void customize(GenerationContext context) {
60-
if (!hasApiKeyAuth(context)) {
60+
if (!hasApiKeyAuth(context) || context.settings().shapesOnly()) {
6161
return;
6262
}
6363
var trait = context.settings().service(context.model()).expectTrait(HttpApiKeyAuthTrait.class);

codegen/smithy-python-codegen/src/main/resources/META-INF/services/software.amazon.smithy.build.SmithyBuildPlugin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
#
55

66
software.amazon.smithy.python.codegen.PythonClientCodegenPlugin
7+
software.amazon.smithy.python.codegen.PythonShapeCodegenPlugin

0 commit comments

Comments
 (0)