Skip to content

Commit

Permalink
feat!: python pydantic follows v2 (#1851)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethaasan committed Mar 4, 2024
1 parent 5f6ea52 commit 2e2c0c2
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 16 deletions.
6 changes: 5 additions & 1 deletion docs/languages/Python.md
Expand Up @@ -8,19 +8,23 @@ There are special use-cases that each language supports; this document pertains

- [Generate Pydantic models](#generate-pydantic-models)
- [Generate models with JSON Serializer and Deserializer methods](#generate-models-with-json-serializer-and-deserializer-methods)
* [Limitations](#limitations)
- [Limitations](#limitations)

<!-- tocstop -->

## Generate Pydantic models

In some cases you might want to use [pydantic](https://pypi.org/project/pydantic/) data validation and settings management using Python type hints for the models.
Modelina follows Pydantic v2.

You can find an example of its use [here](../../examples/generate-python-pydantic-models/index.ts)

## Generate models with JSON Serializer and Deserializer methods

Using the preset `PYTON_JSON_SERIALIZER`, you can generate `serializeToJson` method to convert model instance to JSON and `deserializeFromJson` method to convert JSON to model instance.

### Limitations

1. Above preset doesn't unwrap properties of type `ConstrainedDictionaryModel` with `serialilzationType = unwrap`
2. The serialized JSON object will have the same property names as defined in the model object.

Expand Down
31 changes: 25 additions & 6 deletions docs/migrations/version-3-to-4.md
@@ -1,9 +1,10 @@
# Migration from v3 to v4

This document contain all the breaking changes and migrations guidelines for adapting your code to the new version.

## Fixed edge cases for camel case names

Naming such as object properties using camel case formatting had an edge case where if they contained a number followed by an underscore and a letter it would be incorrectly formatted. This has been fixed in this version, which might mean properties, model names, etc that use camel case might be renamed.
Naming such as object properties using camel case formatting had an edge case where if they contained a number followed by an underscore and a letter it would be incorrectly formatted. This has been fixed in this version, which might mean properties, model names, etc that use camel case might be renamed.

This example contains such a string:

Expand Down Expand Up @@ -34,7 +35,7 @@ interface AnonymousSchema_1 {

### Constant values are now properly rendered as const properties

This example used to generate a `string` with a getter and setter, but will now generate a const string that is initialized to the const value provided.
This example used to generate a `string` with a getter and setter, but will now generate a const string that is initialized to the const value provided.

```yaml
type: object
Expand All @@ -48,9 +49,9 @@ will generate

```csharp
public class TestClass {
private const string property = "test";
public string Property
private const string property = "test";

public string Property
{
get { return property; }
}
Expand All @@ -62,7 +63,7 @@ Notice that `Property` no longer has a `set` method. This might break existing m

### DateTime and DateTimeOffset are now properly rendered based on specification format

In the previous version, `date-time` and `date` formats were rendered as `DateTime` and `DateTimeOffset` respectively.
In the previous version, `date-time` and `date` formats were rendered as `DateTime` and `DateTimeOffset` respectively.
This has been changed to render `DateTimeOffset` for `date-time` and `DateTime` for `date` formats.

This might break existing implementation and require manual changes.
Expand All @@ -84,4 +85,22 @@ DateTime dateTime2 = modelinaModel.DateTime.LocalDateTime;
Console.WriteLine(dateTime2);
```

## Python

### Pydantic now follows v2 instead of v1

Reference: https://docs.pydantic.dev/2.6/migration/

The schema description is now a description and not an alias:

```python
class Message(BaseModel):
identifier: str = Field(description='''The Identifier for the Message''')
```

In Modelina 3 this used is rendered as:

```python
class Message(BaseModel):
identifier: str = Field(alias='''The Identifier for the Message''')
```
Expand Up @@ -3,8 +3,8 @@
exports[`Should be able to render python models and should log expected output to console: class-model 1`] = `
Array [
"class Root(BaseModel):
optionalField: Optional[str] = Field(alias='''this field is optional''', default=None)
requiredField: str = Field(alias='''this field is required''')
optionalField: Optional[str] = Field(description='''this field is optional''', default=None)
requiredField: str = Field(description='''this field is required''')
noDescription: Optional[str] = Field(default=None)
options: Optional[Options] = Field(default=None)
",
Expand Down
12 changes: 6 additions & 6 deletions src/generators/python/presets/Pydantic.ts
Expand Up @@ -33,15 +33,15 @@ const PYTHON_PYDANTIC_CLASS_PRESET: ClassPresetType<PythonOptions> = {
type = `Optional[${type}]`;
}

const alias = params.property.property.originalInput['description']
? `alias='''${params.property.property.originalInput['description']}'''`
const description = params.property.property.originalInput['description']
? `description='''${params.property.property.originalInput['description']}'''`
: '';
const defaultValue = params.property.required ? '' : 'default=None';

if (alias && defaultValue) {
return `${propertyName}: ${type} = Field(${alias}, ${defaultValue})`;
} else if (alias) {
return `${propertyName}: ${type} = Field(${alias})`;
if (description && defaultValue) {
return `${propertyName}: ${type} = Field(${description}, ${defaultValue})`;
} else if (description) {
return `${propertyName}: ${type} = Field(${description})`;
}
return `${propertyName}: ${type} = Field(${defaultValue})`;
},
Expand Down
Expand Up @@ -2,7 +2,7 @@

exports[`PYTHON_PYDANTIC_PRESET should render pydantic for class 1`] = `
"class Test(BaseModel):
prop: Optional[str] = Field(alias='''test
prop: Optional[str] = Field(description='''test
multi
line
description''', default=None)
Expand Down

0 comments on commit 2e2c0c2

Please sign in to comment.