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

Fix msgspec template to add field #1942

Merged
4 changes: 3 additions & 1 deletion datamodel_code_generator/model/msgspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@


def _has_field_assignment(field: DataModelFieldBase) -> bool:
return bool(field.field) or not (
return not (
field.required
or (field.represented_default == 'None' and field.strip_default_none)
)
Expand Down Expand Up @@ -177,6 +177,8 @@ def __str__(self) -> str:

if self.default != UNDEFINED and self.default is not None:
data['default'] = self.default
elif not self.required:
data['default'] = None

if self.required:
data = {
Expand Down
6 changes: 4 additions & 2 deletions datamodel_code_generator/model/template/msgspec.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ class {{ class_name }}:
{%- if not field.annotated and field.field %}
{{ field.name }}: {{ field.type_hint }} = {{ field.field }}
{%- else %}
{%- if field.annotated %}
{%- if field.annotated and not field.field %}
{{ field.name }}: {{ field.annotated }}
{%- elif field.annotated and field.field %}
{{ field.name }}: {{ field.annotated }} = {{ field.field }}
{%- else %}
{{ field.name }}: {{ field.type_hint }}
{%- endif %}
{%- if not field.required or field.data_type.is_optional or field.nullable
{%- if not field.field and (not field.required or field.data_type.is_optional or field.nullable)
%} = {{ field.represented_default }}
{%- endif -%}
{%- endif %}
Expand Down
2 changes: 1 addition & 1 deletion tests/data/expected/main/main_msgspec_struct/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from typing import List, Optional

from msgspec import Meta, Struct
from msgspec import Meta, Struct, field
Fixed Show fixed Hide fixed
from typing_extensions import Annotated


Expand Down
66 changes: 66 additions & 0 deletions tests/data/expected/main/main_msgspec_struct_snake_case/output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# generated by datamodel-codegen:
# filename: api_ordered_required_fields.yaml
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from typing import List, Optional

from msgspec import Meta, Struct, field
from typing_extensions import Annotated


class Pet(Struct):
id: int
name: str
before_tag: str = field(name='beforeTag')
tag: Optional[str] = None


Pets = List[Pet]


class User(Struct):
id: int
name: str
tag: Optional[str] = None


Users = List[User]


Id = str


Rules = List[str]


class Error(Struct):
code: int
message: str


class Api(Struct):
api_key: Optional[
Annotated[str, Meta(description='To be used as a dataset parameter value')]
] = field(name='apiKey', default=None)
api_version_number: Optional[
Annotated[str, Meta(description='To be used as a version parameter value')]
] = field(name='apiVersionNumber', default=None)
api_url: Optional[
Annotated[str, Meta(description="The URL describing the dataset's fields")]
] = field(name='apiUrl', default=None)
api_documentation_url: Optional[
Annotated[str, Meta(description='A URL to the API console for each API')]
] = field(name='apiDocumentationUrl', default=None)


Apis = List[Api]


class Event(Struct):
name: Optional[str] = None


class Result(Struct):
event: Optional[Event] = None
2 changes: 1 addition & 1 deletion tests/data/expected/main/main_pattern_msgspec/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from typing import Annotated, Optional

from msgspec import Meta, Struct
from msgspec import Meta, Struct, field
Fixed Show fixed Hide fixed


class Info(Struct):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from typing import Annotated, List, Optional, Union

from msgspec import Meta, Struct
from msgspec import Meta, Struct, field
Fixed Show fixed Hide fixed


class Pet(Struct):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Api(Struct):


class Event(Struct):
name_: Optional[str] = field(name='name')
name_: Optional[str] = field(name='name', default=None)


class Result(Struct):
Expand Down
182 changes: 182 additions & 0 deletions tests/data/openapi/api_ordered_required_fields.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: POST
type: aws_proxy
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: POST
type: aws_proxy
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: POST
type: aws_proxy
components:
schemas:
Pet:
required:
- id
- name
- beforeTag
properties:
id:
type: integer
format: int64
default: 1
name:
type: string
beforeTag:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Users:
type: array
items:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Id:
type: string
Rules:
type: array
items:
type: string
Error:
description: error result
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
apis:
type: array
items:
type: object
properties:
apiKey:
type: string
description: To be used as a dataset parameter value
apiVersionNumber:
type: string
description: To be used as a version parameter value
apiUrl:
type: string
format: uri
description: "The URL describing the dataset's fields"
apiDocumentationUrl:
type: string
format: uri
description: A URL to the API console for each API
Event:
type: object
description: Event object
properties:
name:
type: string
Result:
type: object
properties:
event:
$ref: '#/components/schemas/Event'
27 changes: 27 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6139,6 +6139,33 @@ def test_main_msgspec_struct():
)


@freeze_time('2019-07-26')
def test_main_msgspec_struct_snake_case():
with TemporaryDirectory() as output_dir:
output_file: Path = Path(output_dir) / 'output.py'
return_code: Exit = main(
[
'--input',
str(OPEN_API_DATA_PATH / 'api_ordered_required_fields.yaml'),
'--output',
str(output_file),
# min msgspec python version is 3.8
'--target-python-version',
'3.8',
'--snake-case-field',
'--output-model-type',
'msgspec.Struct',
]
)
assert return_code == Exit.OK
assert (
output_file.read_text()
== (
EXPECTED_MAIN_PATH / 'main_msgspec_struct_snake_case' / 'output.py'
).read_text()
)


@freeze_time('2019-07-26')
@pytest.mark.skipif(
black.__version__.split('.')[0] == '19',
Expand Down