Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 016bd0d

Browse files
authored
v2 readme adds usage notes (#144)
* Adds usage section * Adds Json Schema Type Object section * Adds todos * Adds another invalid variable * Adds details sections to readme * Small readme improvements * Samples updated * Adds Schema default feature
1 parent fa5b24c commit 016bd0d

File tree

19 files changed

+687
-56
lines changed

19 files changed

+687
-56
lines changed

docs/generators/java.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
308308
|AdditionalProperties|✗|OAS2,OAS3
309309
|AllOf|✗|OAS2,OAS3
310310
|AnyOf|✗|OAS3
311+
|Default|✗|OAS2,OAS3
311312
|Discriminator|✓|OAS2,OAS3
312313
|Enum|✓|OAS2,OAS3
313314
|ExclusiveMinimum|✓|OAS2,OAS3

docs/generators/jaxrs-jersey.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
291291
|AdditionalProperties|✗|OAS2,OAS3
292292
|AllOf|✗|OAS2,OAS3
293293
|AnyOf|✗|OAS3
294+
|Default|✗|OAS2,OAS3
294295
|Discriminator|✓|OAS2,OAS3
295296
|Enum|✓|OAS2,OAS3
296297
|ExclusiveMinimum|✓|OAS2,OAS3

docs/generators/jmeter.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
150150
|AdditionalProperties|✗|OAS2,OAS3
151151
|AllOf|✗|OAS2,OAS3
152152
|AnyOf|✗|OAS3
153+
|Default|✗|OAS2,OAS3
153154
|Discriminator|✓|OAS2,OAS3
154155
|Enum|✓|OAS2,OAS3
155156
|ExclusiveMinimum|✓|OAS2,OAS3

docs/generators/kotlin.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
260260
|AdditionalProperties|✗|OAS2,OAS3
261261
|AllOf|✗|OAS2,OAS3
262262
|AnyOf|✗|OAS3
263+
|Default|✗|OAS2,OAS3
263264
|Discriminator|✓|OAS2,OAS3
264265
|Enum|✓|OAS2,OAS3
265266
|ExclusiveMinimum|✓|OAS2,OAS3

docs/generators/python.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
219219
|AdditionalProperties|✓|OAS2,OAS3
220220
|AllOf|✓|OAS2,OAS3
221221
|AnyOf|✓|OAS3
222+
|Default|✓|OAS2,OAS3
222223
|Discriminator|✓|OAS2,OAS3
223224
|Enum|✓|OAS2,OAS3
224225
|ExclusiveMinimum|✓|OAS2,OAS3

modules/openapi-json-schema-generator-core/src/main/java/org/openapijsonschematools/codegen/meta/FeatureSet.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ public Builder excludeDocumentationFeatures(DocumentationFeature... documentatio
524524
* @param schemaFeatures the {@code schemaSupportFeature} to set
525525
* @return a reference to this Builder
526526
*/
527-
public Builder schemaSupportFeatures(EnumSet<SchemaFeature> schemaFeatures) {
527+
public Builder schemaFeatures(EnumSet<SchemaFeature> schemaFeatures) {
528528
if (schemaFeatures != null) {
529529
this.schemaFeatures = schemaFeatures;
530530
} else {
@@ -540,7 +540,7 @@ public Builder schemaSupportFeatures(EnumSet<SchemaFeature> schemaFeatures) {
540540
*
541541
* @return a reference to this Builder
542542
*/
543-
public Builder includeSchemaSupportFeatures(SchemaFeature... schemaFeature) {
543+
public Builder includeSchemaFeatures(SchemaFeature... schemaFeature) {
544544
this.schemaFeatures.addAll(Arrays.stream(schemaFeature).collect(Collectors.toList()));
545545
return this;
546546
}
@@ -552,7 +552,7 @@ public Builder includeSchemaSupportFeatures(SchemaFeature... schemaFeature) {
552552
*
553553
* @return a reference to this Builder
554554
*/
555-
public Builder excludeSchemaSupportFeatures(SchemaFeature... schemaFeature) {
555+
public Builder excludeSchemaFeatures(SchemaFeature... schemaFeature) {
556556
this.schemaFeatures.removeAll(Arrays.stream(schemaFeature).collect(Collectors.toList()));
557557
return this;
558558
}

modules/openapi-json-schema-generator-core/src/main/java/org/openapijsonschematools/codegen/meta/features/SchemaFeature.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public enum SchemaFeature {
4040
@OAS3
4141
AnyOf,
4242

43+
@OAS2 @OAS3
44+
Default,
45+
4346
@OAS2 @OAS3
4447
Discriminator,
4548

modules/openapi-json-schema-generator-core/src/test/java/org/openapijsonschematools/codegen/meta/FeatureSetTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void flattenOnMultipleFeatures() {
4444
.includeParameterFeatures(ParameterFeature.In_Header, ParameterFeature.In_Query)
4545
.includeSecurityFeatures(SecurityFeature.HTTP_Bearer, SecurityFeature.HTTP_Basic, SecurityFeature.OAuth2_Implicit)
4646
.includeDocumentationFeatures(DocumentationFeature.ComponentSchemas)
47-
.includeSchemaSupportFeatures(SchemaFeature.OneOf)
47+
.includeSchemaFeatures(SchemaFeature.OneOf)
4848
.build();
4949

5050
List<FeatureSet.FeatureSetFlattened> flattened = featureSet.flatten();

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/DefaultCodegen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public class DefaultCodegen implements CodegenConfig {
142142
GlobalFeature.Info,
143143
GlobalFeature.Components
144144
)
145-
.includeSchemaSupportFeatures(
145+
.includeSchemaFeatures(
146146
SchemaFeature.Discriminator, SchemaFeature.Enum,
147147
SchemaFeature.ExclusiveMaximum, SchemaFeature.ExclusiveMinimum,
148148
SchemaFeature.Format, SchemaFeature.Items,

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/AbstractJavaCodegen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public AbstractJavaCodegen() {
135135
.securityFeatures(EnumSet.noneOf(
136136
SecurityFeature.class
137137
))
138-
.excludeSchemaSupportFeatures(
138+
.excludeSchemaFeatures(
139139
SchemaFeature.Not
140140
)
141141
.includeClientModificationFeatures(

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/JMeterClientCodegen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public JMeterClientCodegen() {
8484
SecurityFeature.ApiKey,
8585
SecurityFeature.OAuth2_Implicit
8686
))
87-
.excludeSchemaSupportFeatures(
87+
.excludeSchemaFeatures(
8888
SchemaFeature.Not
8989
)
9090
.includeParameterFeatures(

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/KotlinClientCodegen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public KotlinClientCodegen() {
147147
SecurityFeature.OAuth2_ClientCredentials,
148148
SecurityFeature.OAuth2_Implicit
149149
)
150-
.excludeSchemaSupportFeatures(
150+
.excludeSchemaFeatures(
151151
SchemaFeature.Not
152152
)
153153
.excludeParameterFeatures(

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/PythonClientCodegen.java

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,20 +143,33 @@ public PythonClientCodegen() {
143143
DataTypeFeature.Byte,
144144
DataTypeFeature.Password
145145
)
146-
.includeSchemaSupportFeatures(
146+
.includeSchemaFeatures(
147147
SchemaFeature.AdditionalProperties,
148-
SchemaFeature.AllOf, SchemaFeature.AnyOf,
149-
SchemaFeature.Discriminator, SchemaFeature.Enum,
150-
SchemaFeature.ExclusiveMaximum, SchemaFeature.ExclusiveMinimum,
151-
SchemaFeature.Format, SchemaFeature.Items,
152-
SchemaFeature.MaxItems, SchemaFeature.MaxLength,
153-
SchemaFeature.MaxProperties, SchemaFeature.Maximum,
154-
SchemaFeature.MinItems, SchemaFeature.MinLength,
155-
SchemaFeature.MinProperties, SchemaFeature.Minimum,
156-
SchemaFeature.MultipleOf, SchemaFeature.Not,
157-
SchemaFeature.Nullable, SchemaFeature.OneOf,
158-
SchemaFeature.Pattern, SchemaFeature.Properties,
159-
SchemaFeature.Required, SchemaFeature.Type,
148+
SchemaFeature.AllOf,
149+
SchemaFeature.AnyOf,
150+
SchemaFeature.Default,
151+
SchemaFeature.Discriminator,
152+
SchemaFeature.Enum,
153+
SchemaFeature.ExclusiveMaximum,
154+
SchemaFeature.ExclusiveMinimum,
155+
SchemaFeature.Format,
156+
SchemaFeature.Items,
157+
SchemaFeature.MaxItems,
158+
SchemaFeature.MaxLength,
159+
SchemaFeature.MaxProperties,
160+
SchemaFeature.Maximum,
161+
SchemaFeature.MinItems,
162+
SchemaFeature.MinLength,
163+
SchemaFeature.MinProperties,
164+
SchemaFeature.Minimum,
165+
SchemaFeature.MultipleOf,
166+
SchemaFeature.Not,
167+
SchemaFeature.Nullable,
168+
SchemaFeature.OneOf,
169+
SchemaFeature.Pattern,
170+
SchemaFeature.Properties,
171+
SchemaFeature.Required,
172+
SchemaFeature.Type,
160173
SchemaFeature.UniqueItems
161174
)
162175
.includeDocumentationFeatures(

modules/openapi-json-schema-generator/src/main/resources/python/README.hbs

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This Python package is automatically generated by the [OpenAPI JSON Schema Gener
1515
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
1616
{{/if}}
1717

18-
## Requirements.
18+
## Requirements
1919

2020
Python {{generatorLanguageVersion}}
2121

@@ -24,7 +24,7 @@ Python {{generatorLanguageVersion}}
2424
- [Migration from Other Python Generators](migration_other_python_generators.md)
2525

2626

27-
## Installation & Usage
27+
## Installation
2828
### pip install
2929

3030
If the python package is hosted on a repository, you can install directly using:
@@ -53,8 +53,130 @@ Then import the package:
5353
import {{{packageName}}}
5454
```
5555

56+
## Usage Notes
57+
### Validation, Immutability, and Data Type
58+
This python code validates data to schema classes and return back an immutable instance containing the data
59+
which subclasses all validated schema classes. This ensure that
60+
- valid data cannot be mutated and become invalid to a set of schemas
61+
- the one exception is that files are not immutable, so schema instances storing/sending/receiving files are not immutable
62+
- one can use isinstance to check if a instance or property is valid to a schema class
63+
- this means that expensive validation does not need to be run twice
64+
65+
<details>
66+
<summary>Reason</summary>
67+
68+
To do that, some changes had to be made. Python bool and NoneType cannot be subclassed,
69+
so to be able to meet the above design goals, I implemented BoolClass and NoneClass classes
70+
to allow schemas to subclass them.
71+
72+
In python 0 == False and 1 == True. This is a problem for json schema which is language independent.
73+
The [json schema test suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite) has
74+
[explicit tests that require that 0 != False and 1 != True](https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/main/tests/draft2020-12/type.json#L260-L267)
75+
Using the above described BoolClass and NoneClasses allows those tests to pass.
76+
- Another example of a package using it's own boolean class is [numpy's bool_](https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.bool_)
77+
</details>
78+
79+
If you need to check is True/False/None, instead use instance.is_true_()/.is_false_()/.is_none_()
80+
81+
Here is the mapping from json schema types to python subclassed types:
82+
| Json Schema Type | Python Base Class |
83+
| ---------------- | ----------------- |
84+
| object | frozendict.frozendict |
85+
| array | tuple |
86+
| string | str |
87+
| number | decimal.Decimal |
88+
| integer | decimal.Decimal |
89+
| boolean | BoolClass |
90+
| null | NoneClass |
91+
| AnyType (unset) | typing.Union[frozendict.frozendict, tuple, str, decimal.Decimal, BoolClass, NoneClass] |
92+
93+
### Storage of Json Schema Definition in Python Classes
94+
In openapi v3.0.3 there are ~ 28 json schema keywords. Almost all of them can apply if
95+
type is unset. This data could be stored as
96+
1. class properties
97+
2. in a container in the class like in a dict or in a nested class
98+
99+
This data is stored in a nested class named Schema_.
100+
Storing this data as a nested class ensures that the data is encapsulated, does not collide with
101+
class properties, and allows for deeper complex inline definitions.
102+
103+
<details>
104+
<summary>Reason</summary>
105+
106+
If the data were stored at the class property level, then the keywords could collide with
107+
type object property names. To avoid that, one could make the properties semi or fully private with
108+
a single or double underscore prefix, but that it a lot of data to put there.
109+
Better to separate out json schema data from type object properties at the class property level.
110+
111+
If the data were stored in a container that would segregate the different data which is good.
112+
But json schemas can be inlined to any depth. Those complex deeper schemas would need to be included.
113+
One could define them higher in the class file and then refer to them in the dict. That would required
114+
iterating over schemas and adding all of the inner into a collection, and then generate that collection.
115+
116+
The schema definitions are already nested from the json schema definition. The easiest solution is
117+
to use a nested json schema definition class which holds that data. That way:
118+
- the data is separated from class properties
119+
- deeper complicated schemas can still be stored
120+
121+
So a nested class was chosen to store json schema data, this class is named Schema_.
122+
- The [django project uses this same pattern to store model class metadata in a Meta class](https://docs.djangoproject.com/en/4.1/topics/db/models/#meta-options)
123+
</details>
124+
125+
### Json Schema Type Object
126+
Most component schemas (models) are probably of type object. Which is a map data structure.
127+
Json schema allows string keys in this map, which means schema properties can have key names that are
128+
invalid python variable names. Names like:
129+
- "hi-there"
130+
- "1variable"
131+
- "@now"
132+
- " "
133+
- "from"
134+
135+
To allow these use cases to work, frozendict.frozendict is used as the base class of type object schemas.
136+
This means that one can use normal dict methods on instances of these classes.
137+
138+
<details>
139+
<summary>Other Details</summary>
140+
141+
- optional properties which were not set will not exist in the instance
142+
- None is only allowed in as a value if type: "null" was included or nullable: true was set
143+
- type hints are written for accessing values by key literals like instance["hi-there"]
144+
- and there is a method instance.get_item_["hi-there"] which returns an schemas.Unset value if the key was not set
145+
- required properties with valid python names are accessible with instance.SomeRequiredProp
146+
which uses the exact key from the openapi document
147+
- preserving the original key names is required to properly validate a payload to multiple json schemas
148+
</details>
149+
150+
### Json Schema Type + Format, Validated Data Storage
151+
N schemas can be validated on the same payload.
152+
To allow multiple schemas to validate, the data must be stored using one base class whether or not
153+
a json schema format constraint exists in the schema.
154+
See te below accessors for string data:
155+
- type string + format: See .as_date_, .as_datetime_, .as_decimal_, .as_uuid_
156+
157+
In json schema, type: number with no format validates both integers and floats, so decimal.Decimal is used to store them.
158+
See te below accessors for number data:
159+
- type number + format: See .as_float_, .as_int_
160+
161+
<details>
162+
<summary>String + Date Example</summary>
163+
164+
For example the string payload '2023-12-20' is validates to both of these schemas:
165+
1. string only
166+
```
167+
- type: string
168+
```
169+
2. string and date format
170+
```
171+
- type: string
172+
format: date
173+
```
174+
Because of use cases like this, a datetime.date is allowed as an input to this schema, but the data
175+
is stored as a string, with a date accessor, instance.as_date_
176+
</details>
177+
56178
## Getting Started
57179

58-
Please follow the [installation procedure](#installation--usage) and then run the following:
180+
Please follow the [installation procedure](#installation) and then run the following:
59181

60182
{{> _helper_readme_common }}

modules/openapi-json-schema-generator/src/main/resources/python/_helper_readme_common.hbs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ RecursionError indicating the maximum recursion limit has been exceeded. In that
133133
134134
Solution 1:
135135
Use specific imports for apis and models like:
136-
- `from {{{packageName}}}.{{apiPackage}}.default_api import DefaultApi`
137-
- `from {{{packageName}}}.{{apiPackage}}.paths.some_path import SomePath`
138-
- `from {{{packageName}}}.paths.some_path.get import ApiForget`
139-
- `from {{{packageName}}}.{{modelPackage}}.pet import Pet`
136+
- tagged api: `from {{{packageName}}}.{{apiPackage}}.tags.default_api import DefaultApi`
137+
- api for one path: `from {{{packageName}}}.{{apiPackage}}.paths.some_path import SomePath`
138+
- api for one operation (path + verb): `from {{{packageName}}}.paths.some_path.get import ApiForget`
139+
- single model import: `from {{{packageName}}}.{{modelPackage}}.pet import Pet`
140140
141141
Solution 2:
142142
Before importing the package, adjust the maximum recursion limit as shown below:

0 commit comments

Comments
 (0)