avrotize 2.21.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. avrotize/__init__.py +66 -0
  2. avrotize/__main__.py +6 -0
  3. avrotize/_version.py +34 -0
  4. avrotize/asn1toavro.py +160 -0
  5. avrotize/avrotize.py +152 -0
  6. avrotize/avrotocpp/CMakeLists.txt.jinja +77 -0
  7. avrotize/avrotocpp/build.bat.jinja +7 -0
  8. avrotize/avrotocpp/build.sh.jinja +7 -0
  9. avrotize/avrotocpp/dataclass_body.jinja +108 -0
  10. avrotize/avrotocpp/vcpkg.json.jinja +21 -0
  11. avrotize/avrotocpp.py +483 -0
  12. avrotize/avrotocsharp/README.md.jinja +166 -0
  13. avrotize/avrotocsharp/class_test.cs.jinja +266 -0
  14. avrotize/avrotocsharp/dataclass_core.jinja +293 -0
  15. avrotize/avrotocsharp/enum_test.cs.jinja +20 -0
  16. avrotize/avrotocsharp/project.csproj.jinja +30 -0
  17. avrotize/avrotocsharp/project.sln.jinja +34 -0
  18. avrotize/avrotocsharp/run_coverage.ps1.jinja +98 -0
  19. avrotize/avrotocsharp/run_coverage.sh.jinja +149 -0
  20. avrotize/avrotocsharp/testproject.csproj.jinja +19 -0
  21. avrotize/avrotocsharp.py +1180 -0
  22. avrotize/avrotocsv.py +121 -0
  23. avrotize/avrotodatapackage.py +173 -0
  24. avrotize/avrotodb.py +1383 -0
  25. avrotize/avrotogo/go_enum.jinja +12 -0
  26. avrotize/avrotogo/go_helpers.jinja +31 -0
  27. avrotize/avrotogo/go_struct.jinja +151 -0
  28. avrotize/avrotogo/go_test.jinja +47 -0
  29. avrotize/avrotogo/go_union.jinja +38 -0
  30. avrotize/avrotogo.py +476 -0
  31. avrotize/avrotographql.py +197 -0
  32. avrotize/avrotoiceberg.py +210 -0
  33. avrotize/avrotojava/class_test.java.jinja +212 -0
  34. avrotize/avrotojava/enum_test.java.jinja +21 -0
  35. avrotize/avrotojava/testproject.pom.jinja +54 -0
  36. avrotize/avrotojava.py +2156 -0
  37. avrotize/avrotojs.py +250 -0
  38. avrotize/avrotojsons.py +481 -0
  39. avrotize/avrotojstruct.py +345 -0
  40. avrotize/avrotokusto.py +364 -0
  41. avrotize/avrotomd/README.md.jinja +49 -0
  42. avrotize/avrotomd.py +137 -0
  43. avrotize/avrotools.py +168 -0
  44. avrotize/avrotoparquet.py +208 -0
  45. avrotize/avrotoproto.py +359 -0
  46. avrotize/avrotopython/dataclass_core.jinja +241 -0
  47. avrotize/avrotopython/enum_core.jinja +87 -0
  48. avrotize/avrotopython/pyproject_toml.jinja +18 -0
  49. avrotize/avrotopython/test_class.jinja +97 -0
  50. avrotize/avrotopython/test_enum.jinja +23 -0
  51. avrotize/avrotopython.py +626 -0
  52. avrotize/avrotorust/dataclass_enum.rs.jinja +74 -0
  53. avrotize/avrotorust/dataclass_struct.rs.jinja +204 -0
  54. avrotize/avrotorust/dataclass_union.rs.jinja +105 -0
  55. avrotize/avrotorust.py +435 -0
  56. avrotize/avrotots/class_core.ts.jinja +140 -0
  57. avrotize/avrotots/class_test.ts.jinja +77 -0
  58. avrotize/avrotots/enum_core.ts.jinja +46 -0
  59. avrotize/avrotots/gitignore.jinja +34 -0
  60. avrotize/avrotots/index.ts.jinja +0 -0
  61. avrotize/avrotots/package.json.jinja +23 -0
  62. avrotize/avrotots/tsconfig.json.jinja +21 -0
  63. avrotize/avrotots.py +687 -0
  64. avrotize/avrotoxsd.py +344 -0
  65. avrotize/cddltostructure.py +1841 -0
  66. avrotize/commands.json +3496 -0
  67. avrotize/common.py +834 -0
  68. avrotize/constants.py +87 -0
  69. avrotize/csvtoavro.py +132 -0
  70. avrotize/datapackagetoavro.py +76 -0
  71. avrotize/dependencies/cpp/vcpkg/vcpkg.json +19 -0
  72. avrotize/dependencies/cs/net90/dependencies.csproj +29 -0
  73. avrotize/dependencies/go/go121/go.mod +6 -0
  74. avrotize/dependencies/java/jdk21/pom.xml +91 -0
  75. avrotize/dependencies/python/py312/requirements.txt +13 -0
  76. avrotize/dependencies/rust/stable/Cargo.toml +17 -0
  77. avrotize/dependencies/typescript/node22/package.json +16 -0
  78. avrotize/dependency_resolver.py +348 -0
  79. avrotize/dependency_version.py +432 -0
  80. avrotize/generic/generic.avsc +57 -0
  81. avrotize/jsonstoavro.py +2167 -0
  82. avrotize/jsonstostructure.py +2864 -0
  83. avrotize/jstructtoavro.py +878 -0
  84. avrotize/kstructtoavro.py +93 -0
  85. avrotize/kustotoavro.py +455 -0
  86. avrotize/openapitostructure.py +717 -0
  87. avrotize/parquettoavro.py +157 -0
  88. avrotize/proto2parser.py +498 -0
  89. avrotize/proto3parser.py +403 -0
  90. avrotize/prototoavro.py +382 -0
  91. avrotize/prototypes/any.avsc +19 -0
  92. avrotize/prototypes/api.avsc +106 -0
  93. avrotize/prototypes/duration.avsc +20 -0
  94. avrotize/prototypes/field_mask.avsc +18 -0
  95. avrotize/prototypes/struct.avsc +60 -0
  96. avrotize/prototypes/timestamp.avsc +20 -0
  97. avrotize/prototypes/type.avsc +253 -0
  98. avrotize/prototypes/wrappers.avsc +117 -0
  99. avrotize/structuretocddl.py +597 -0
  100. avrotize/structuretocpp/CMakeLists.txt.jinja +76 -0
  101. avrotize/structuretocpp/build.bat.jinja +3 -0
  102. avrotize/structuretocpp/build.sh.jinja +3 -0
  103. avrotize/structuretocpp/dataclass_body.jinja +50 -0
  104. avrotize/structuretocpp/vcpkg.json.jinja +11 -0
  105. avrotize/structuretocpp.py +697 -0
  106. avrotize/structuretocsharp/class_test.cs.jinja +180 -0
  107. avrotize/structuretocsharp/dataclass_core.jinja +156 -0
  108. avrotize/structuretocsharp/enum_test.cs.jinja +36 -0
  109. avrotize/structuretocsharp/json_structure_converters.cs.jinja +399 -0
  110. avrotize/structuretocsharp/program.cs.jinja +49 -0
  111. avrotize/structuretocsharp/project.csproj.jinja +17 -0
  112. avrotize/structuretocsharp/project.sln.jinja +34 -0
  113. avrotize/structuretocsharp/testproject.csproj.jinja +18 -0
  114. avrotize/structuretocsharp/tuple_converter.cs.jinja +121 -0
  115. avrotize/structuretocsharp.py +2295 -0
  116. avrotize/structuretocsv.py +365 -0
  117. avrotize/structuretodatapackage.py +659 -0
  118. avrotize/structuretodb.py +1125 -0
  119. avrotize/structuretogo/go_enum.jinja +12 -0
  120. avrotize/structuretogo/go_helpers.jinja +26 -0
  121. avrotize/structuretogo/go_interface.jinja +18 -0
  122. avrotize/structuretogo/go_struct.jinja +187 -0
  123. avrotize/structuretogo/go_test.jinja +70 -0
  124. avrotize/structuretogo.py +729 -0
  125. avrotize/structuretographql.py +502 -0
  126. avrotize/structuretoiceberg.py +355 -0
  127. avrotize/structuretojava/choice_core.jinja +34 -0
  128. avrotize/structuretojava/class_core.jinja +23 -0
  129. avrotize/structuretojava/enum_core.jinja +18 -0
  130. avrotize/structuretojava/equals_hashcode.jinja +30 -0
  131. avrotize/structuretojava/pom.xml.jinja +26 -0
  132. avrotize/structuretojava/tuple_core.jinja +49 -0
  133. avrotize/structuretojava.py +938 -0
  134. avrotize/structuretojs/class_core.js.jinja +33 -0
  135. avrotize/structuretojs/enum_core.js.jinja +10 -0
  136. avrotize/structuretojs/package.json.jinja +12 -0
  137. avrotize/structuretojs/test_class.js.jinja +84 -0
  138. avrotize/structuretojs/test_enum.js.jinja +58 -0
  139. avrotize/structuretojs/test_runner.js.jinja +45 -0
  140. avrotize/structuretojs.py +657 -0
  141. avrotize/structuretojsons.py +498 -0
  142. avrotize/structuretokusto.py +639 -0
  143. avrotize/structuretomd/README.md.jinja +204 -0
  144. avrotize/structuretomd.py +322 -0
  145. avrotize/structuretoproto.py +764 -0
  146. avrotize/structuretopython/dataclass_core.jinja +363 -0
  147. avrotize/structuretopython/enum_core.jinja +45 -0
  148. avrotize/structuretopython/map_alias.jinja +21 -0
  149. avrotize/structuretopython/pyproject_toml.jinja +23 -0
  150. avrotize/structuretopython/test_class.jinja +103 -0
  151. avrotize/structuretopython/test_enum.jinja +34 -0
  152. avrotize/structuretopython.py +799 -0
  153. avrotize/structuretorust/dataclass_enum.rs.jinja +63 -0
  154. avrotize/structuretorust/dataclass_struct.rs.jinja +121 -0
  155. avrotize/structuretorust/dataclass_union.rs.jinja +81 -0
  156. avrotize/structuretorust.py +714 -0
  157. avrotize/structuretots/class_core.ts.jinja +78 -0
  158. avrotize/structuretots/enum_core.ts.jinja +6 -0
  159. avrotize/structuretots/gitignore.jinja +8 -0
  160. avrotize/structuretots/index.ts.jinja +1 -0
  161. avrotize/structuretots/package.json.jinja +39 -0
  162. avrotize/structuretots/test_class.ts.jinja +35 -0
  163. avrotize/structuretots/tsconfig.json.jinja +21 -0
  164. avrotize/structuretots.py +740 -0
  165. avrotize/structuretoxsd.py +679 -0
  166. avrotize/xsdtoavro.py +413 -0
  167. avrotize-2.21.1.dist-info/METADATA +1319 -0
  168. avrotize-2.21.1.dist-info/RECORD +171 -0
  169. avrotize-2.21.1.dist-info/WHEEL +4 -0
  170. avrotize-2.21.1.dist-info/entry_points.txt +3 -0
  171. avrotize-2.21.1.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,363 @@
1
+ """ {{ class_name }} dataclass. """
2
+
3
+ # pylint: disable=too-many-lines, too-many-locals, too-many-branches, too-many-statements, too-many-arguments, line-too-long, wildcard-import
4
+
5
+ {%- if avro_annotation or dataclasses_json_annotation %}
6
+ import io
7
+ import gzip
8
+ {%- endif %}
9
+ import enum
10
+ import typing
11
+ import dataclasses
12
+ from dataclasses import dataclass
13
+ {%- if is_abstract %}
14
+ from abc import ABC
15
+ {%- endif %}
16
+ {%- if dataclasses_json_annotation %}
17
+ import dataclasses_json
18
+ from dataclasses_json import Undefined, dataclass_json
19
+ {%- for field in fields if field.type == "datetime.datetime" or field.type == "typing.Optional[datetime.datetime]" %}
20
+ {%- if loop.first %}
21
+ from marshmallow import fields
22
+ {%- endif %}
23
+ {%- endfor %}
24
+ {%- endif %}
25
+ {%- if avro_annotation or dataclasses_json_annotation %}
26
+ import json
27
+ {%- endif %}
28
+ {%- if avro_annotation %}
29
+ import avro.schema
30
+ import avro.io
31
+ {%- endif %}
32
+ {%- for import_type in import_types if import_type not in ['datetime.datetime', 'datetime.date', 'datetime.time', 'datetime.timedelta', 'decimal.Decimal', 'uuid.UUID'] %}
33
+ from {{ '.'.join(import_type.split('.')[:-1]) | lower }} import {{ import_type.split('.')[-1] }}
34
+ {%- endfor %}
35
+ {%- for import_type in import_types if import_type in ['datetime.datetime', 'datetime.date', 'datetime.time', 'datetime.timedelta'] %}
36
+ {%- if loop.first %}
37
+ import datetime
38
+ {%- endif %}
39
+ {%- endfor %}
40
+ {%- for import_type in import_types if import_type == 'decimal.Decimal' %}
41
+ {%- if loop.first %}
42
+ import decimal
43
+ {%- endif %}
44
+ {%- endfor %}
45
+ {%- for import_type in import_types if import_type == 'uuid.UUID' %}
46
+ {%- if loop.first %}
47
+ import uuid
48
+ {%- endif %}
49
+ {%- endfor %}
50
+
51
+ {% if dataclasses_json_annotation %}
52
+ @dataclass_json(undefined=Undefined.EXCLUDE)
53
+ {%- endif %}
54
+ @dataclass
55
+ class {{ class_name }}{% if base_class or is_abstract %}({% if base_class %}{{ base_class.split('.')[-1] }}{% if is_abstract %}, {% endif %}{% endif %}{% if is_abstract %}ABC{% endif %}){% endif %}:
56
+ """
57
+ {{ docstring }}
58
+ {% if fields %}
59
+ Attributes:
60
+ {%- for field in fields %}
61
+ {{ field.docstring }}
62
+ {%- endfor -%}
63
+ {% endif %}
64
+ """
65
+ {% if avro_annotation %}
66
+ AvroType: typing.ClassVar[avro.schema.Schema] = avro.schema.parse(
67
+ "{{ avro_schema_json }}"
68
+ )
69
+ {% endif %}
70
+ {% for field in fields %}
71
+ {%- set isdate = field.type == "datetime.datetime" or field.type == "typing.Optional[datetime.datetime]" %}
72
+ {{ field.name }}: {{ field.type }}=dataclasses.field(kw_only=True{% if dataclasses_json_annotation %}, metadata=dataclasses_json.config(field_name="{{ field.original_name }}"{%- if isdate -%}, encoder=lambda d: d.isoformat() if isinstance(d, datetime.datetime) else d if d else None, decoder=lambda d: datetime.datetime.fromisoformat(d) if isinstance(d, str) else d if d else None, mm_field=fields.DateTime(format='iso'){%- endif -%}){%- endif %})
73
+ {%- endfor %}
74
+
75
+ @classmethod
76
+ def from_serializer_dict(cls, data: dict) -> '{{ class_name }}':
77
+ """
78
+ Converts a dictionary to a dataclass instance.
79
+
80
+ Args:
81
+ data: The dictionary to convert to a dataclass.
82
+
83
+ Returns:
84
+ The dataclass representation of the dataclass.
85
+ """
86
+ {%- for field in fields %}
87
+ {%- if field.name != field.original_name %}
88
+ if '{{ field.original_name }}' in data:
89
+ data['{{ field.name }}'] = data.pop('{{ field.original_name }}')
90
+ {%- endif %}
91
+ {%- endfor %}
92
+ return cls(**data)
93
+
94
+ {%- if avro_annotation %}
95
+ @classmethod
96
+ def from_avro_dict(cls, data: dict) -> '{{ class_name }}':
97
+ """
98
+ Converts a dictionary from Avro deserialization to a dataclass instance.
99
+ Handles conversion of string representations back to Python types for
100
+ extended logical types.
101
+
102
+ Args:
103
+ data: The dictionary from Avro deserialization.
104
+
105
+ Returns:
106
+ The dataclass representation.
107
+ """
108
+ # Convert string values back to Python types for Avro string-based logical types
109
+ converted = data.copy()
110
+
111
+ {%- for field in fields %}
112
+ {%- set field_key = field.original_name if field.name != field.original_name else field.name %}
113
+ if '{{ field_key }}' in converted and converted['{{ field_key }}'] is not None:
114
+ value = converted['{{ field_key }}']
115
+ {%- if field.source_type in ['date', 'datetime', 'timestamp', 'time', 'duration', 'decimal', 'uuid', 'int128', 'uint128'] %}
116
+ {%- if field.source_type == 'date' %}
117
+ if isinstance(value, str):
118
+ converted['{{ field_key }}'] = datetime.date.fromisoformat(value)
119
+ {%- elif field.source_type in ['datetime', 'timestamp'] %}
120
+ if isinstance(value, str):
121
+ converted['{{ field_key }}'] = datetime.datetime.fromisoformat(value)
122
+ {%- elif field.source_type == 'time' %}
123
+ if isinstance(value, str):
124
+ converted['{{ field_key }}'] = datetime.time.fromisoformat(value)
125
+ {%- elif field.source_type == 'duration' %}
126
+ if isinstance(value, str):
127
+ converted['{{ field_key }}'] = datetime.timedelta(seconds=float(value))
128
+ {%- elif field.source_type == 'decimal' %}
129
+ if isinstance(value, str):
130
+ converted['{{ field_key }}'] = decimal.Decimal(value)
131
+ {%- elif field.source_type == 'uuid' %}
132
+ if isinstance(value, str):
133
+ converted['{{ field_key }}'] = uuid.UUID(value)
134
+ {%- elif field.source_type in ['int128', 'uint128'] %}
135
+ if isinstance(value, str):
136
+ converted['{{ field_key }}'] = int(value)
137
+ {%- endif %}
138
+ {%- endif %}
139
+ {%- if field.name != field.original_name %}
140
+ if '{{ field.original_name }}' in converted:
141
+ converted['{{ field.name }}'] = converted.pop('{{ field.original_name }}')
142
+ {%- endif %}
143
+ {%- endfor %}
144
+
145
+ return cls(**converted)
146
+ {%- endif %}
147
+
148
+ def to_serializer_dict(self) -> dict:
149
+ """
150
+ Converts the dataclass to a dictionary.
151
+
152
+ Returns:
153
+ The dictionary representation of the dataclass.
154
+ """
155
+ asdict_result = dataclasses.asdict(self, dict_factory=self._dict_resolver)
156
+ {%- for field in fields %}
157
+ {%- if field.name != field.original_name and field.original_name+'_' != field.name %}
158
+ if '{{ field.name }}' in asdict_result:
159
+ asdict_result['{{ field.original_name }}'] = asdict_result.pop('{{ field.name }}')
160
+ {%- endif %}
161
+ {%- endfor %}
162
+ return asdict_result
163
+
164
+ def _dict_resolver(self, data):
165
+ """
166
+ Helps resolving the Enum values to their actual values and fixes the key names.
167
+ """
168
+ def _resolve_enum(v):
169
+ if isinstance(v, enum.Enum):
170
+ return v.value
171
+ return v
172
+ def _fix_key(k):
173
+ return k[:-1] if k.endswith('_') else k
174
+ return {_fix_key(k): _resolve_enum(v) for k, v in iter(data)}
175
+ {%- if avro_annotation %}
176
+
177
+ def to_avro_dict(self) -> dict:
178
+ """
179
+ Converts the dataclass to a dictionary suitable for Avro serialization.
180
+ Handles conversion of Python types to Avro-compatible string representations
181
+ for extended logical types.
182
+
183
+ Returns:
184
+ The dictionary representation suitable for Avro serialization.
185
+ """
186
+ result = self.to_serializer_dict()
187
+ converted = result.copy()
188
+
189
+ # Convert specific fields based on their source types
190
+ {%- for field in fields %}
191
+ {%- set field_key = field.original_name if field.name != field.original_name else field.name %}
192
+ {%- if field.source_type in ['date', 'datetime', 'timestamp', 'time', 'duration', 'decimal', 'uuid', 'int128', 'uint128'] %}
193
+ if '{{ field_key }}' in converted and converted['{{ field_key }}'] is not None:
194
+ value = converted['{{ field_key }}']
195
+ {%- if field.source_type == 'date' %}
196
+ if isinstance(value, datetime.date):
197
+ converted['{{ field_key }}'] = value.isoformat()
198
+ {%- elif field.source_type in ['datetime', 'timestamp'] %}
199
+ if isinstance(value, datetime.datetime):
200
+ converted['{{ field_key }}'] = value.isoformat()
201
+ {%- elif field.source_type == 'time' %}
202
+ if isinstance(value, datetime.time):
203
+ converted['{{ field_key }}'] = value.isoformat()
204
+ {%- elif field.source_type == 'duration' %}
205
+ if isinstance(value, datetime.timedelta):
206
+ converted['{{ field_key }}'] = str(value.total_seconds())
207
+ {%- elif field.source_type == 'decimal' %}
208
+ if isinstance(value, decimal.Decimal):
209
+ converted['{{ field_key }}'] = str(value)
210
+ {%- elif field.source_type == 'uuid' %}
211
+ if isinstance(value, uuid.UUID):
212
+ converted['{{ field_key }}'] = str(value)
213
+ {%- elif field.source_type in ['int128', 'uint128'] %}
214
+ if isinstance(value, int):
215
+ converted['{{ field_key }}'] = str(value)
216
+ {%- endif %}
217
+ {%- endif %}
218
+ {%- endfor %}
219
+
220
+ return converted
221
+ {%- endif %}
222
+ {%- if avro_annotation or dataclasses_json_annotation %}
223
+
224
+ def to_byte_array(self, content_type_string: str) -> bytes:
225
+ """
226
+ Converts the dataclass to a byte array based on the content type string.
227
+
228
+ Args:
229
+ content_type_string: The content type string to convert the dataclass to.
230
+ Supported content types:
231
+ {%- if dataclasses_json_annotation %}
232
+ 'application/json': Encodes the data to JSON format.
233
+ {%- endif %}
234
+ {%- if avro_annotation %}
235
+ 'avro/binary': Encodes the data to Avro binary format.
236
+ 'application/vnd.apache.avro+avro': Encodes the data to Avro binary format.
237
+ {%- endif %}
238
+ Supported content type extensions:
239
+ '+gzip': Compresses the byte array using gzip, e.g. 'application/json+gzip'.
240
+
241
+ Returns:
242
+ The byte array representation of the dataclass.
243
+ """
244
+ content_type = content_type_string.split(';')[0].strip()
245
+ result = None
246
+
247
+ # Strip compression suffix for base type matching
248
+ base_content_type = content_type.replace('+gzip', '')
249
+
250
+ {%- if avro_annotation %}
251
+ if base_content_type in ['avro/binary', 'application/vnd.apache.avro+avro']:
252
+ # Convert to Avro binary format using the embedded schema
253
+ writer = avro.io.DatumWriter(self.AvroType)
254
+ with io.BytesIO() as stream:
255
+ encoder = avro.io.BinaryEncoder(stream)
256
+ writer.write(self.to_avro_dict(), encoder)
257
+ result = stream.getvalue()
258
+ {%- endif %}
259
+ {%- if dataclasses_json_annotation %}
260
+ if base_content_type == 'application/json':
261
+ #pylint: disable=no-member
262
+ result = self.to_json()
263
+ #pylint: enable=no-member
264
+ {%- endif %}
265
+
266
+ if result is not None and content_type.endswith('+gzip'):
267
+ # Handle string result from to_json()
268
+ if isinstance(result, str):
269
+ result = result.encode('utf-8')
270
+ with io.BytesIO() as stream:
271
+ with gzip.GzipFile(fileobj=stream, mode='wb') as gzip_file:
272
+ gzip_file.write(result)
273
+ result = stream.getvalue()
274
+
275
+ if result is None:
276
+ raise NotImplementedError(f"Unsupported media type {content_type}")
277
+
278
+ return result
279
+
280
+ @classmethod
281
+ def from_data(cls, data: typing.Any, content_type_string: typing.Optional[str] = None) -> typing.Optional['{{ class_name }}']:
282
+ """
283
+ Converts the data to a dataclass based on the content type string.
284
+
285
+ Args:
286
+ data: The data to convert to a dataclass.
287
+ content_type_string: The content type string to convert the data to.
288
+ Supported content types:
289
+ {%- if dataclasses_json_annotation %}
290
+ 'application/json': Attempts to decode the data from JSON encoded format.
291
+ {%- endif %}
292
+ {%- if avro_annotation %}
293
+ 'avro/binary': Attempts to decode the data from Avro binary format.
294
+ 'application/vnd.apache.avro+avro': Attempts to decode the data from Avro binary format.
295
+ {%- endif %}
296
+ Supported content type extensions:
297
+ '+gzip': First decompresses the data using gzip, e.g. 'application/json+gzip'.
298
+ Returns:
299
+ The dataclass representation of the data.
300
+ """
301
+ if data is None:
302
+ return None
303
+ if isinstance(data, cls):
304
+ return data
305
+ if isinstance(data, dict):
306
+ return cls.from_serializer_dict(data)
307
+
308
+ content_type = (content_type_string or 'application/octet-stream').split(';')[0].strip()
309
+
310
+ if content_type.endswith('+gzip'):
311
+ if isinstance(data, (bytes, io.BytesIO)):
312
+ stream = io.BytesIO(data) if isinstance(data, bytes) else data
313
+ else:
314
+ raise NotImplementedError('Data is not of a supported type for gzip decompression')
315
+ with gzip.GzipFile(fileobj=stream, mode='rb') as gzip_file:
316
+ data = gzip_file.read()
317
+
318
+ # Strip compression suffix for base type matching
319
+ base_content_type = content_type.replace('+gzip', '')
320
+
321
+ {%- if avro_annotation %}
322
+ if base_content_type in ['avro/binary', 'application/vnd.apache.avro+avro']:
323
+ if isinstance(data, bytes):
324
+ # Decode from Avro binary format using the embedded schema
325
+ reader = avro.io.DatumReader(cls.AvroType)
326
+ with io.BytesIO(data) as stream:
327
+ decoder = avro.io.BinaryDecoder(stream)
328
+ _record = reader.read(decoder)
329
+ return {{ class_name }}.from_avro_dict(_record)
330
+ else:
331
+ raise NotImplementedError('Data is not of a supported type for Avro deserialization')
332
+ {%- endif %}
333
+ {%- if dataclasses_json_annotation %}
334
+ if base_content_type == 'application/json':
335
+ if isinstance(data, (bytes, str)):
336
+ data_str = data.decode('utf-8') if isinstance(data, bytes) else data
337
+ _record = json.loads(data_str)
338
+ {%- for field in fields %}
339
+ {%- if field.name != field.original_name %}
340
+ if '{{ field.original_name }}' in _record:
341
+ _record['{{ field.name }}'] = _record.pop('{{ field.original_name }}')
342
+ {%- endif %}
343
+ {%- endfor %}
344
+ return {{ class_name }}.from_serializer_dict(_record)
345
+ else:
346
+ raise NotImplementedError('Data is not of a supported type for JSON deserialization')
347
+ {%- endif %}
348
+ raise NotImplementedError(f'Unsupported media type {content_type}')
349
+ {%- endif %}
350
+
351
+ @classmethod
352
+ def create_instance(cls) -> '{{ class_name }}':
353
+ """
354
+ Creates an instance of the dataclass with test values.
355
+
356
+ Returns:
357
+ An instance of the dataclass.
358
+ """
359
+ return cls(
360
+ {%- for field in fields %}
361
+ {{ field.name }}={{ field.test_value }}{{ "," if not loop.last else "" }}
362
+ {%- endfor %}
363
+ )
@@ -0,0 +1,45 @@
1
+ from enum import Enum
2
+
3
+
4
+ class {{ class_name }}(Enum):
5
+ """
6
+ {{ docstring }}
7
+ """
8
+ {%- for symbol in symbols %}
9
+ {{ symbol }} = '{{ symbol }}'
10
+ {%- endfor %}
11
+
12
+ @classmethod
13
+ def from_ordinal(cls, ordinal: int | str) -> '{{ class_name }}':
14
+ """
15
+ Get enum member by ordinal
16
+
17
+ Args:
18
+ ordinal (int | str): The ordinal of the enum member. This can be an integer or a string representation of an integer.
19
+
20
+ Returns:
21
+ The enum member corresponding to the ordinal.
22
+ """
23
+ if ordinal is None:
24
+ raise ValueError("ordinal must not be None")
25
+ if isinstance(ordinal, str) and ordinal.isdigit():
26
+ ordinal = int(ordinal)
27
+ members = list(cls)
28
+ if 0 <= int(ordinal) < len(members):
29
+ return members[ordinal]
30
+ else:
31
+ raise IndexError("Ordinal out of range for enum")
32
+
33
+ @classmethod
34
+ def to_ordinal(cls, member: '{{ class_name }}') -> int:
35
+ """
36
+ Get enum ordinal
37
+
38
+ Args:
39
+ member ({{ class_name }}): The enum member to get the ordinal of.
40
+
41
+ Returns:
42
+ The ordinal of the enum member.
43
+ """
44
+ members = list(cls)
45
+ return members.index(member)
@@ -0,0 +1,21 @@
1
+ """ {{ class_name }} type alias. """
2
+
3
+ # pylint: disable=line-too-long
4
+ from typing import TypeAlias
5
+ {%- for import_type in import_types %}
6
+ {%- if import_type.startswith('datetime.') %}
7
+ import datetime
8
+ {%- elif import_type == 'decimal.Decimal' %}
9
+ import decimal
10
+ {%- elif import_type == 'uuid.UUID' %}
11
+ import uuid
12
+ {%- elif import_type.startswith(base_package + '.') %}
13
+ from {{ '.'.join(import_type.split('.')[:-1]) }} import {{ import_type.split('.')[-1] }}
14
+ {%- endif %}
15
+ {%- endfor %}
16
+
17
+
18
+ {{ class_name }}: TypeAlias = dict[str, {{ values_type }}]
19
+ """
20
+ {{ docstring }}
21
+ """
@@ -0,0 +1,23 @@
1
+ [tool.poetry]
2
+ name = "{{ package_name }}"
3
+ version = "0.1.0"
4
+ description = "A package for handling JSON Structure schema data"
5
+ authors = ["Your Name"]
6
+ license = "MIT"
7
+ packages = [ { include = "{{ package_name|replace('-','_')|lower }}", from="src" } ]
8
+
9
+ [tool.poetry.dependencies]
10
+ python = "<4.0,>=3.10"
11
+ {%- if dataclasses_json_annotation %}
12
+ dataclasses-json = "^0.6.7"
13
+ {%- endif %}
14
+ {%- if avro_annotation %}
15
+ avro-python3 = "^1.10.2"
16
+ {%- endif %}
17
+
18
+ [tool.poetry.dev-dependencies]
19
+ pylint = "^3.2.3"
20
+
21
+ [build-system]
22
+ requires = ["poetry-core>=1.0.0"]
23
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,103 @@
1
+ """
2
+ Test case for {{ class_name }}
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import unittest
8
+
9
+ sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '../src'.replace('/', os.sep))))
10
+
11
+ from {{ package_name | lower }} import {{ class_name }}
12
+
13
+ {%- for import_type in import_types if import_type not in ['decimal.Decimal', 'datetime.datetime', 'datetime.date', 'datetime.time', 'datetime.timedelta', 'uuid.UUID'] %}
14
+ {%- set import_type_name = import_type.split('.')[-1] %}
15
+ {%- set import_package_name = '.'.join(import_type.split('.')[:-1]) | lower %}
16
+ {%- if import_package_name %}
17
+ from {{ import_package_name }} import {{ import_type_name }}
18
+ {%- endif -%}
19
+ {%- endfor %}
20
+ {%- for import_type in import_types if import_type in ['datetime.datetime', 'datetime.date', 'datetime.time', 'datetime.timedelta'] %}
21
+ {%- if loop.first %}
22
+ import datetime
23
+ {%- endif %}
24
+ {%- endfor %}
25
+ {%- for import_type in import_types if import_type == 'decimal.Decimal' %}
26
+ {%- if loop.first %}
27
+ import decimal
28
+ {%- endif %}
29
+ {%- endfor %}
30
+ {%- for import_type in import_types if import_type == 'uuid.UUID' %}
31
+ {%- if loop.first %}
32
+ import uuid
33
+ {%- endif %}
34
+ {%- endfor %}
35
+
36
+
37
+ class {{ test_class_name }}(unittest.TestCase):
38
+ """
39
+ Test case for {{ class_name }}
40
+ """
41
+
42
+ def setUp(self):
43
+ """
44
+ Set up test case
45
+ """
46
+ self.instance = {{ test_class_name }}.create_instance()
47
+
48
+ @staticmethod
49
+ def create_instance():
50
+ """
51
+ Create instance of {{ class_name }} for testing
52
+ """
53
+ instance = {{ class_name }}(
54
+ {%- for field in fields %}
55
+ {{ field.name }}={{ field.test_value }}{%- if not loop.last %},{%- endif %}
56
+ {%- endfor %}
57
+ )
58
+ return instance
59
+
60
+ {% for field in fields %}
61
+ def test_{{ field.name }}_property(self):
62
+ """
63
+ Test {{ field.name }} property
64
+ """
65
+ test_value = {{ field.test_value }}
66
+ self.instance.{{ field.name }} = test_value
67
+ self.assertEqual(self.instance.{{ field.name }}, test_value)
68
+ {% endfor %}
69
+
70
+ {%- if avro_annotation %}
71
+ def test_to_byte_array_avro(self):
72
+ """
73
+ Test to_byte_array method with avro media type
74
+ """
75
+ media_type = "application/vnd.apache.avro+avro"
76
+ bytes_data = self.instance.to_byte_array(media_type)
77
+ new_instance = {{ class_name }}.from_data(bytes_data, media_type)
78
+ bytes_data2 = new_instance.to_byte_array(media_type)
79
+ self.assertEqual(bytes_data, bytes_data2)
80
+ {%- endif %}
81
+
82
+ {%- if dataclasses_json_annotation %}
83
+ def test_to_byte_array_json(self):
84
+ """
85
+ Test to_byte_array method with json media type
86
+ """
87
+ media_type = "application/json"
88
+ bytes_data = self.instance.to_byte_array(media_type)
89
+ new_instance = {{ class_name }}.from_data(bytes_data, media_type)
90
+ bytes_data2 = new_instance.to_byte_array(media_type)
91
+ self.assertEqual(bytes_data, bytes_data2)
92
+
93
+ def test_to_json(self):
94
+ """
95
+ Test to_json method
96
+ """
97
+ json_data = self.instance.to_json()
98
+ new_instance = {{ class_name }}.from_json(json_data)
99
+ json_data2 = new_instance.to_json()
100
+ self.assertEqual(json_data, json_data2)
101
+ {%- endif %}
102
+
103
+
@@ -0,0 +1,34 @@
1
+ import os
2
+ import sys
3
+ import unittest
4
+
5
+ sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '../src'.replace('/', os.sep))))
6
+
7
+ from {{ package_name | lower }} import {{ class_name }}
8
+
9
+
10
+ class {{ test_class_name }}(unittest.TestCase):
11
+ """
12
+ Test case for {{ class_name }}
13
+ """
14
+
15
+ def setUp(self):
16
+ """
17
+ Setup test
18
+ """
19
+ self.instance = {{ test_class_name }}.create_instance()
20
+
21
+ @staticmethod
22
+ def create_instance():
23
+ """
24
+ Create instance of {{ class_name }}
25
+ """
26
+ return {{ class_name }}.{{ symbols[0] }}
27
+
28
+ def test_enum_values(self):
29
+ """
30
+ Test that all enum values are defined
31
+ """
32
+ {%- for symbol in symbols %}
33
+ self.assertEqual({{ class_name }}.{{ symbol }}.value, "{{ symbol }}")
34
+ {%- endfor %}