Skip to content

Commit 2a737c8

Browse files
committed
chore: Replace dataclasses and dataclasses_json with pydantic
1 parent fc49079 commit 2a737c8

File tree

4 files changed

+130
-206
lines changed

4 files changed

+130
-206
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,46 @@
1-
from dataclasses import dataclass, field
2-
from dataclasses_json import dataclass_json, config
3-
from typing import Optional, Iterable
41
import sys
5-
import json
2+
from typing import Literal, Union, Tuple
3+
from pydantic import BaseModel, RootModel
64

75

8-
# TODO tkulik: try to get rid of the `dataclasses_json` dependency
6+
class SomeEnum(RootModel):
7+
class Field1(RootModel[Literal['Field1']]):
8+
pass
99

10+
class Field2(BaseModel):
11+
Field2: Tuple[int, int]
1012

11-
enum_field = lambda: field(default=None, metadata=config(exclude=lambda x: x is None))
13+
class Field3(BaseModel):
14+
class __InnerStruct(BaseModel):
15+
a: str
16+
b: int
17+
Field3: __InnerStruct
1218

13-
@dataclass_json
14-
@dataclass
15-
class SomeEnum:
16-
class VariantIndicator:
17-
pass
19+
class Field4(BaseModel):
20+
Field4: 'SomeEnum'
1821

19-
class Field3Type:
20-
a: str
21-
b: int
22-
23-
class Field5Type:
24-
a: Iterable['SomeEnum']
25-
26-
Field1: Optional[VariantIndicator] = enum_field()
27-
Field2: Optional[tuple[int, int]] = enum_field()
28-
Field3: Optional[Field3Type] = enum_field()
29-
Field4: Optional[Iterable['SomeEnum']] = enum_field()
30-
Field5: Optional[Field5Type] = enum_field()
31-
32-
def deserialize(json):
33-
if not ":" in json:
34-
if json == '"Field1"':
35-
return SomeEnum(Field1=SomeEnum.VariantIndicator())
36-
else:
37-
raise Exception(f"Deserialization error, undefined variant: {json}")
38-
else:
39-
return SomeEnum.from_json(json)
40-
41-
def serialize(self):
42-
if self.Field1 is not None:
43-
return '"Field1"'
44-
else:
45-
return SomeEnum.to_json(self)
46-
47-
@dataclass_json
48-
@dataclass
49-
class UnitStructure:
50-
def deserialize(json):
51-
if json == "null":
52-
return UnitStructure()
53-
else:
54-
Exception(f"Deserialization error, undefined value: {json}")
55-
56-
def serialize(self):
57-
return 'null'
58-
59-
@dataclass_json
60-
@dataclass
61-
class TupleStructure:
62-
Tuple: tuple[int, str, int]
63-
64-
def deserialize(json):
65-
return TupleStructure.from_json(f'{{ "Tuple": {json} }}')
66-
67-
def serialize(self):
68-
return json.dumps(self.Tuple)
69-
70-
@dataclass_json
71-
@dataclass
72-
class NamedStructure:
22+
class Field5(BaseModel):
23+
class __InnerStruct(BaseModel):
24+
a: 'SomeEnum'
25+
Field5: __InnerStruct
26+
27+
root: Union[Field1, Field2, Field3, Field4, Field5]
28+
29+
30+
class UnitStructure(RootModel):
31+
root: None
32+
33+
34+
class TupleStructure(RootModel):
35+
root: Tuple[int, str, int]
36+
37+
38+
class NamedStructure(BaseModel):
7339
a: str
7440
b: int
75-
c: Iterable['SomeEnum']
41+
c: SomeEnum
42+
7643

77-
def deserialize(json):
78-
return NamedStructure.from_json(json)
79-
80-
def serialize(self):
81-
return self.to_json()
8244

8345
###
8446
### TESTS:
@@ -88,32 +50,36 @@ def serialize(self):
8850
input = input.rstrip()
8951
try:
9052
if index < 5:
91-
deserialized = SomeEnum.deserialize(input)
53+
deserialized = SomeEnum.model_validate_json(input)
9254
elif index == 5:
93-
deserialized = UnitStructure.deserialize(input)
55+
deserialized = UnitStructure.model_validate_json(input)
9456
elif index == 6:
95-
deserialized = TupleStructure.deserialize(input)
57+
deserialized = TupleStructure.model_validate_json(input)
9658
else:
97-
deserialized = NamedStructure.deserialize(input)
59+
deserialized = NamedStructure.model_validate_json(input)
9860
except:
9961
raise(Exception(f"This json can't be deserialized: {input}"))
100-
serialized = deserialized.serialize()
62+
serialized = deserialized.model_dump_json()
10163
print(serialized)
10264

10365

10466
# def handle_msg(json):
105-
# a = SomeEnum.deserialize(json)
106-
# if a.Field1 is not None:
67+
# a = SomeEnum.model_validate_json(json)
68+
# if isinstance(a.root, SomeEnum.Field1):
10769
# print("SomeEnum::Field1")
108-
# elif a.Field2 is not None:
109-
# print(a.Field2[0])
110-
# print(a.Field2[1])
111-
# elif a.Field3 is not None:
112-
# print(a.Field3)
113-
# elif a.Field4 is not None:
114-
# print(a.Field4)
115-
# elif a.Field5 is not None:
116-
# print(a.Field5)
70+
# elif isinstance(a.root, SomeEnum.Field2):
71+
# print(a.root.Field2[0])
72+
# print(a.root.Field2[1])
73+
# elif isinstance(a.root, SomeEnum.Field3):
74+
# print(a.root.Field3)
75+
# elif isinstance(a.root, SomeEnum.Field4):
76+
# print(a.root.Field4)
77+
# elif isinstance(a.root, SomeEnum.Field5):
78+
# print(a.root.Field5)
11779

11880
# handle_msg('"Field1"')
119-
# handle_msg('{"Field2": [10, 12]}')
81+
# handle_msg('{"Field2": [10, 12]}')
82+
# handle_msg('{"Field3": { "a": "10", "b": 12 } }')
83+
# handle_msg('{"Field4": { "Field4": "Field1" } }')
84+
# handle_msg('{"Field5": { "a": "Field1" } }')
85+
# handle_msg('{"Field5": { "a": { "Field5": { "a": "Field1" } } } }')
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,38 @@
11
# This code is @generated by cw-schema-codegen. Do not modify this manually.
2-
from dataclasses import dataclass, field
3-
from dataclasses_json import dataclass_json, config
4-
from typing import Optional, Iterable
52

6-
enum_field = lambda: field(default=None, metadata=config(exclude=lambda x: x is None))
3+
import typing
4+
from pydantic import BaseModel, RootModel
75

8-
@dataclass_json
9-
@dataclass
10-
class {{ name }}:
11-
'''{% for doc in docs %}
6+
class {{ name }}(RootModel):
7+
"""{% for doc in docs %}
128
{{ doc }}
13-
{% endfor %}'''
14-
15-
class VariantIndicator:
16-
'''
17-
This structure is an indicator of the simple enum variant that is currently contained
18-
in this enum structure. It's used only for the enum variants that does not contain
19-
any inner structure. It's constructed automatically and it's not intend to be manually
20-
used by the user.
21-
'''
22-
pass
23-
9+
{% endfor %}"""
2410

2511
{% for variant in variants %}
26-
'''{% for doc in variant.docs %}
27-
{{ doc }}
28-
{% endfor %}'''
29-
{% match variant.ty %}
30-
{% when TypeTemplate::Unit %}
31-
{{ variant.name }}: Optional[VariantIndicator] = enum_field()
32-
{% when TypeTemplate::Tuple with (types) %}
33-
{{ variant.name }}: Optional[tuple[{{ types|join(", ") }}]] = enum_field()
34-
{% when TypeTemplate::Named with { fields } %}
35-
class {{ variant.name }}Type:
36-
{% for field in fields %}
37-
'''{% for doc in field.docs %}
38-
# {{ doc }}
39-
{% endfor %}'''
40-
{{ field.name }}: {{ field.ty }}
41-
{% endfor %}
42-
{{ variant.name }}: Optional[{{ variant.name }}Type] = enum_field()
43-
{% endmatch %}
12+
{% match variant.ty %}
13+
{% when TypeTemplate::Unit %}
14+
class {{ variant.name }}(RootModel):
15+
"""{% for doc in variant.docs %}
16+
{{ doc }}
17+
{% endfor %}"""
18+
root: None
19+
{% when TypeTemplate::Tuple with (types) %}
20+
class {{ variant.name }}(BaseModel):
21+
"""{% for doc in variant.docs %}
22+
{{ doc }}
23+
{% endfor %}"""
24+
{{ variant.name }}: typing.Tuple[{{ types|join(", ") }}]
25+
{% when TypeTemplate::Named with { fields } %}
26+
class __Inner:
27+
"""{% for doc in variant.docs %}
28+
{{ doc }}
29+
{% endfor %}"""
30+
{% for field in fields %}
31+
{{ field.name }}: {{ field.ty }}
32+
"""{% for doc in field.docs %}
33+
# {{ doc }}
34+
{% endfor %}"""
35+
{% endfor %}
36+
{{ variant.name }}: __Inner
37+
{% endmatch %}
4438
{% endfor %}
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,31 @@
11
# This code is @generated by cw-schema-codegen. Do not modify this manually.
22

3-
/**
4-
{% for doc in docs %}
5-
* {{ doc }}
6-
{% endfor %}
7-
*/
8-
9-
type {{ name }} =
10-
{% match ty %}
11-
{% when TypeTemplate::Unit %}
12-
void
13-
{% when TypeTemplate::Tuple with (types) %}
14-
[{{ types|join(", ") }}]
15-
{% when TypeTemplate::Named with { fields } %}
16-
{
17-
{% for field in fields %}
18-
/**
19-
{% for doc in field.docs %}
20-
* {{ doc }}
21-
{% endfor %}
22-
*/
23-
24-
{{ field.name }}: {{ field.ty }};
25-
{% endfor %}
26-
}
27-
{% endmatch %}
28-
3+
import typing
4+
from pydantic import BaseModel, RootModel
295

306

31-
# This code is @generated by cw-schema-codegen. Do not modify this manually.
32-
from dataclasses import dataclass, field
33-
from dataclasses_json import dataclass_json, config
34-
from typing import Optional, Iterable
35-
36-
@dataclass_json
37-
@dataclass
38-
class {{ name }}:
7+
{% match ty %}
8+
{% when TypeTemplate::Unit %}
9+
class {{ name }}(RootModel):
3910
'''{% for doc in docs %}
4011
{{ doc }}
4112
{% endfor %}'''
42-
43-
{% match ty %}
44-
{% when TypeTemplate::Unit %}
45-
pass
46-
{% when TypeTemplate::Tuple with (types) %}
47-
{{ variant.name }}: tuple[{{ types|join(", ") }}]
48-
{% when TypeTemplate::Named with { fields } %}
49-
{% for field in fields %}
50-
'''{% for doc in field.docs %}
51-
# {{ doc }}
52-
{% endfor %}'''
53-
{{ field.name }}: {{ field.ty }}
54-
{% endfor %}
55-
{% endmatch %}
13+
root: None
14+
{% when TypeTemplate::Tuple with (types) %}
15+
class {{ name }}(RootModel):
16+
'''{% for doc in docs %}
17+
{{ doc }}
18+
{% endfor %}'''
19+
root: typing.Tuple[{{ types|join(", ") }}]
20+
{% when TypeTemplate::Named with { fields } %}
21+
class {{ name }}(BaseModel):
22+
'''{% for doc in docs %}
23+
{{ doc }}
24+
{% endfor %}'''
25+
{% for field in fields %}
26+
{{ field.name }}: {{ field.ty }}
27+
'''{% for doc in field.docs %}
28+
# {{ doc }}
29+
{% endfor %}'''
30+
{% endfor %}
31+
{% endmatch %}

packages/cw-schema-codegen/tests/snapshots/python_tpl__simple_enum.snap

+21-33
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,27 @@ expression: rendered
44
snapshot_kind: text
55
---
66
# This code is @generated by cw-schema-codegen. Do not modify this manually.
7-
from dataclasses import dataclass, field
8-
from dataclasses_json import dataclass_json, config
9-
from typing import Optional, Iterable
107

11-
enum_field = lambda: field(default=None, metadata=config(exclude=lambda x: x is None))
8+
import typing
9+
from pydantic import BaseModel, RootModel
1210

13-
@dataclass_json
14-
@dataclass
15-
class Simple:
16-
'''
11+
class Simple(RootModel):
12+
"""
1713
Simple enum
18-
'''
19-
20-
class VariantIndicator:
21-
'''
22-
This structure is an indicator of the simple enum variant that is currently contained
23-
in this enum structure. It's used only for the enum variants that does not contain
24-
any inner structure. It's constructed automatically and it's not intend to be manually
25-
used by the user.
26-
'''
27-
pass
28-
29-
30-
31-
'''
32-
One variant
33-
'''
34-
35-
One: Optional[VariantIndicator] = enum_field()
36-
37-
38-
'''
39-
Two variant
40-
'''
41-
42-
Two: Optional[VariantIndicator] = enum_field()
14+
"""
15+
16+
17+
18+
class One(RootModel):
19+
"""
20+
One variant
21+
"""
22+
root: None
23+
24+
25+
26+
class Two(RootModel):
27+
"""
28+
Two variant
29+
"""
30+
root: None

0 commit comments

Comments
 (0)