Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: render python union in pydantic in the pre 3.10 way #1626

Merged
merged 2 commits into from
Nov 21, 2023
Merged
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
38 changes: 37 additions & 1 deletion docs/migrations/version-2-to-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,43 @@ Is not affected by this change.

### Python

Is not affected by this change.
#### Union type for the Pydantic preset supports Python pre 3.10

Modelina used to use the newer way of representing unions in Python by using the `|` operator. In the Pydantic preset, this is now adjusted to support Python pre 3.10 by using `Union[Model1, Model2]` instead:

```yaml
title: UnionTest
type: object
properties:
unionTest:
oneOf:
- title: Union1
type: object
properties:
testProp1:
type: string
- title: Union2
type: object
properties:
testProp2:
type: string
```

will generate

```python
class UnionTest(BaseModel):
unionTest: Optional[Union[Union1, Union2]] = Field()
additionalProperties: Optional[dict[Any, Any]] = Field()

class Union1(BaseModel):
testProp1: Optional[str] = Field()
additionalProperties: Optional[dict[Any, Any]] = Field()

class Union2(BaseModel):
testProp2: Optional[str] = Field()
additionalProperties: Optional[dict[Any, Any]] = Field()
```

### Go

Expand Down
19 changes: 15 additions & 4 deletions src/generators/python/presets/Pydantic.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ConstrainedUnionModel } from '../../../models';
import { PythonOptions } from '../PythonGenerator';
import { ClassPresetType, PythonPreset } from '../PythonPreset';

const PYTHON_PYDANTIC_CLASS_PRESET: ClassPresetType<PythonOptions> = {
async self({ renderer, model }) {
renderer.dependencyManager.addDependency(
'from typing import Optional, Any'
'from typing import Optional, Any, Union'
);
renderer.dependencyManager.addDependency(
'from pydantic import BaseModel, Field'
Expand All @@ -18,9 +19,19 @@ const PYTHON_PYDANTIC_CLASS_PRESET: ClassPresetType<PythonOptions> = {
);
},
property(params) {
const type = params.property.required
? params.property.property.type
: `Optional[${params.property.property.type}]`;
let type = params.property.property.type;

if (params.property.property instanceof ConstrainedUnionModel) {
const unionTypes = params.property.property.union.map(
(unionModel) => unionModel.type
);
type = `Union[${unionTypes.join(', ')}]`;
}

if (!params.property.required) {
type = `Optional[${type}]`;
}

const alias = params.property.property.originalInput['description']
? `alias='''${params.property.property.originalInput['description']}'''`
: '';
Expand Down
34 changes: 34 additions & 0 deletions test/generators/python/presets/Pydantic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,38 @@ describe('PYTHON_PYDANTIC_PRESET', () => {
expect(models).toHaveLength(1);
expect(models[0].result).toMatchSnapshot();
});

test('should render union to support Python < 3.10', async () => {
const doc = {
title: 'UnionTest',
type: 'object',
properties: {
unionTest: {
oneOf: [
{
title: 'Union1',
type: 'object',
properties: {
testProp1: {
type: 'string'
}
}
},
{
title: 'Union2',
type: 'object',
properties: {
testProp2: {
type: 'string'
}
}
}
]
}
}
};

const models = await generator.generate(doc);
expect(models.map((model) => model.result)).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,20 @@ exports[`PYTHON_PYDANTIC_PRESET should render pydantic for class 1`] = `
additionalProperties: Optional[dict[Any, Any]] = Field()
"
`;

exports[`PYTHON_PYDANTIC_PRESET should render union to support Python < 3.10 1`] = `
Array [
"class UnionTest(BaseModel):
unionTest: Optional[Union[Union1, Union2]] = Field()
additionalProperties: Optional[dict[Any, Any]] = Field()
",
"class Union1(BaseModel):
testProp1: Optional[str] = Field()
additionalProperties: Optional[dict[Any, Any]] = Field()
",
"class Union2(BaseModel):
testProp2: Optional[str] = Field()
additionalProperties: Optional[dict[Any, Any]] = Field()
",
]
`;