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

[PYTHON] generate code based on pydantic v2 #16685

Merged
merged 14 commits into from
Sep 29, 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
Original file line number Diff line number Diff line change
Expand Up @@ -911,13 +911,13 @@ private ModelsMap postProcessModelsMap(ModelsMap objs) {
pydanticImports.add("Field");
pydanticImports.add("StrictStr");
pydanticImports.add("ValidationError");
pydanticImports.add("validator");
pydanticImports.add("field_validator");
} else if (!model.anyOf.isEmpty()) { // anyOF
codegenProperties = model.getComposedSchemas().getAnyOf();
pydanticImports.add("Field");
pydanticImports.add("StrictStr");
pydanticImports.add("ValidationError");
pydanticImports.add("validator");
pydanticImports.add("field_validator");
} else { // typical model
codegenProperties = model.vars;

Expand Down Expand Up @@ -1768,10 +1768,10 @@ public PydanticType(
private PythonType arrayType(IJsonSchemaValidationProperties cp) {
PythonType pt = new PythonType();
if (cp.getMaxItems() != null) {
pt.constrain("max_items", cp.getMaxItems());
pt.constrain("max_length", cp.getMaxItems());
}
if (cp.getMinItems()!= null) {
pt.constrain("min_items", cp.getMinItems());
pt.constrain("min_length", cp.getMinItems());
}
if (cp.getUniqueItems()) {
// A unique "array" is a set
Expand Down Expand Up @@ -1807,7 +1807,7 @@ private PythonType stringType(IJsonSchemaValidationProperties cp) {
}

if (cp.getPattern() != null) {
pydanticImports.add("validator");
pydanticImports.add("field_validator");
// use validator instead as regex doesn't support flags, e.g. IGNORECASE
//fieldCustomization.add(Locale.ROOT, String.format(Locale.ROOT, "regex=r'%s'", cp.getPattern()));
}
Expand Down Expand Up @@ -1938,7 +1938,7 @@ private PythonType binaryType(IJsonSchemaValidationProperties cp) {
strt.constrain("min_length", cp.getMinLength());
}
if (cp.getPattern() != null) {
pydanticImports.add("validator");
pydanticImports.add("field_validator");
// use validator instead as regex doesn't support flags, e.g. IGNORECASE
//fieldCustomization.add(Locale.ROOT, String.format(Locale.ROOT, "regex=r'%s'", cp.getPattern()));
}
Expand Down Expand Up @@ -2042,7 +2042,7 @@ private PythonType fromCommon(IJsonSchemaValidationProperties cp) {
}

if (cp.getIsEnum()) {
pydanticImports.add("validator");
pydanticImports.add("field_validator");
}

if (cp.getIsArray()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import re # noqa: F401
import io
import warnings

from pydantic import validate_arguments, ValidationError
from pydantic import validate_call, ValidationError

{{#imports}}
{{import}}
Expand Down Expand Up @@ -34,7 +34,7 @@ class {{classname}}:
self.api_client = api_client
{{#operation}}

@validate_arguments
@validate_call
{{#asyncio}}
async def {{operationId}}(self, {{#allParams}}{{paramName}} : {{{vendorExtensions.x-py-typing}}}{{^required}} = None{{/required}}, {{/allParams}}**kwargs) -> {{{returnType}}}{{^returnType}}None{{/returnType}}: # noqa: E501
{{/asyncio}}
Expand Down Expand Up @@ -77,7 +77,7 @@ class {{classname}}:
raise ValueError(message)
return {{#asyncio}}await {{/asyncio}}self.{{operationId}}_with_http_info({{#allParams}}{{paramName}}, {{/allParams}}**kwargs) # noqa: E501

@validate_arguments
@validate_call
{{#asyncio}}
async def {{operationId}}_with_http_info(self, {{#allParams}}{{paramName}} : {{{vendorExtensions.x-py-typing}}}{{^required}} = None{{/required}}, {{/allParams}}**kwargs) -> ApiResponse: # noqa: E501
{{/asyncio}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
actual_instance: Any = None
any_of_schemas: List[str] = Literal[{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ANY_OF_SCHEMAS]

class Config:
validate_assignment = True
model_config = {
"validate_assignment": True
}
{{#discriminator}}

discriminator_value_class_map: Dict[str, str] = {
Expand All @@ -54,14 +55,14 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
else:
super().__init__(**kwargs)

@validator('actual_instance')
@field_validator('actual_instance')
def actual_instance_must_validate_anyof(cls, v):
{{#isNullable}}
if v is None:
return v

{{/isNullable}}
instance = {{{classname}}}.construct()
instance = {{{classname}}}.model_construct()
error_messages = []
{{#composedSchemas.anyOf}}
# validate data type: {{{dataType}}}
Expand Down Expand Up @@ -102,7 +103,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
@classmethod
def from_json(cls, json_str: str) -> {{{classname}}}:
"""Returns the object represented by the json string"""
instance = {{{classname}}}.construct()
instance = {{{classname}}}.model_construct()
{{#isNullable}}
if json_str is None:
return instance
Expand Down Expand Up @@ -174,7 +175,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}

def to_str(self) -> str:
"""Returns the string representation of the actual instance"""
return pprint.pformat(self.dict())
return pprint.pformat(self.model_dump())

{{#vendorExtensions.x-py-postponed-model-imports.size}}
{{#vendorExtensions.x-py-postponed-model-imports}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{#vars}}
{{#vendorExtensions.x-regex}}

@validator('{{{name}}}')
@field_validator('{{{name}}}')
def {{{name}}}_validate_regular_expression(cls, value):
"""Validates the regular expression"""
{{^required}}
Expand All @@ -48,7 +48,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{/vendorExtensions.x-regex}}
{{#isEnum}}

@validator('{{{name}}}')
@field_validator('{{{name}}}')
def {{{name}}}_validate_enum(cls, value):
"""Validates the enum"""
{{^required}}
Expand Down Expand Up @@ -76,10 +76,11 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{/isEnum}}
{{/vars}}

class Config:
"""Pydantic configuration"""
allow_population_by_field_name = True
validate_assignment = True
model_config = {
"populate_by_name": True,
"validate_assignment": True
}


{{#hasChildren}}
{{#discriminator}}
Expand Down Expand Up @@ -110,7 +111,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{/hasChildren}}
def to_str(self) -> str:
"""Returns the string representation of the model using alias"""
return pprint.pformat(self.dict(by_alias=True))
return pprint.pformat(self.model_dump(by_alias=True))

def to_json(self) -> str:
"""Returns the JSON representation of the model using alias"""
Expand All @@ -124,7 +125,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}

def to_dict(self):
"""Returns the dictionary representation of the model using alias"""
_dict = self.dict(by_alias=True,
_dict = self.model_dump(by_alias=True,
exclude={
{{#vendorExtensions.x-py-readonly}}
"{{{.}}}",
Expand Down Expand Up @@ -211,8 +212,8 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{#allVars}}
{{#isNullable}}
# set to None if {{{name}}} (nullable) is None
# and __fields_set__ contains the field
if self.{{name}} is None and "{{{name}}}" in self.__fields_set__:
# and model_fields_set contains the field
if self.{{name}} is None and "{{{name}}}" in self.model_fields_set:
_dict['{{{baseName}}}'] = None

{{/isNullable}}
Expand Down Expand Up @@ -240,7 +241,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
return None

if not isinstance(obj, dict):
return {{{classname}}}.parse_obj(obj)
return {{{classname}}}.model_validate(obj)

{{#disallowAdditionalPropertiesIfNotPresent}}
{{^isAdditionalPropertiesTrue}}
Expand All @@ -251,7 +252,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}

{{/isAdditionalPropertiesTrue}}
{{/disallowAdditionalPropertiesIfNotPresent}}
_obj = {{{classname}}}.parse_obj({
_obj = {{{classname}}}.model_validate({
{{#allVars}}
{{#isContainer}}
{{#isArray}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{vendorExtensions.x-py-name}}: {{{vendorExtensions.x-py-typing}}}
{{/composedSchemas.oneOf}}
actual_instance: Optional[Union[{{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}]] = None
one_of_schemas: List[str] = Literal[{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ONE_OF_SCHEMAS]
one_of_schemas: List[str] = Literal[{{#oneOf}}"{{.}}"{{^-last}}, {{/-last}}{{/oneOf}}]

model_config = {
"validate_assignment": True
}

class Config:
validate_assignment = True
{{#discriminator}}

discriminator_value_class_map: Dict[str, str] = {
Expand All @@ -50,14 +52,14 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
else:
super().__init__(**kwargs)

@validator('actual_instance')
@field_validator('actual_instance')
def actual_instance_must_validate_oneof(cls, v):
{{#isNullable}}
if v is None:
return v

{{/isNullable}}
instance = {{{classname}}}.construct()
instance = {{{classname}}}.model_construct()
error_messages = []
match = 0
{{#composedSchemas.oneOf}}
Expand Down Expand Up @@ -101,7 +103,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
@classmethod
def from_json(cls, json_str: str) -> {{{classname}}}:
"""Returns the object represented by the json string"""
instance = {{{classname}}}.construct()
instance = {{{classname}}}.model_construct()
{{#isNullable}}
if json_str is None:
return instance
Expand Down Expand Up @@ -197,7 +199,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}

def to_str(self) -> str:
"""Returns the string representation of the actual instance"""
return pprint.pformat(self.dict())
return pprint.pformat(self.model_dump())

{{#vendorExtensions.x-py-postponed-model-imports.size}}
{{#vendorExtensions.x-py-postponed-model-imports}}
Expand Down
6 changes: 3 additions & 3 deletions samples/client/echo_api/python/openapi_client/api/auth_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import io
import warnings

from pydantic import validate_arguments, ValidationError
from pydantic import validate_call, ValidationError


from openapi_client.api_client import ApiClient
Expand All @@ -40,7 +40,7 @@ def __init__(self, api_client=None) -> None:
api_client = ApiClient.get_default()
self.api_client = api_client

@validate_arguments
@validate_call
def test_auth_http_basic(self, **kwargs) -> str: # noqa: E501
"""To test HTTP basic authentication # noqa: E501

Expand Down Expand Up @@ -68,7 +68,7 @@ def test_auth_http_basic(self, **kwargs) -> str: # noqa: E501
raise ValueError(message)
return self.test_auth_http_basic_with_http_info(**kwargs) # noqa: E501

@validate_arguments
@validate_call
def test_auth_http_basic_with_http_info(self, **kwargs) -> ApiResponse: # noqa: E501
"""To test HTTP basic authentication # noqa: E501

Expand Down
Loading
Loading