pydantic-avro 0.9.0__tar.gz → 0.9.1__tar.gz
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.
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/PKG-INFO +1 -1
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/pyproject.toml +3 -2
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/setup.py +1 -1
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/to_avro/types.py +48 -4
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/LICENSE +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/README.md +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/__init__.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/__main__.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/base.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/from_avro/__init__.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/from_avro/avro_to_pydantic.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/from_avro/class_registery.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/from_avro/types.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/py.typed +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/to_avro/__init__.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/to_avro/base.py +0 -0
- {pydantic_avro-0.9.0 → pydantic_avro-0.9.1}/src/pydantic_avro/to_avro/config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pydantic-avro"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.1"
|
|
4
4
|
description = "Converting pydantic classes to avro schemas"
|
|
5
5
|
authors = ["Peter van 't Hof' <peter.vanthof@godatadriven.com>"]
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ python = ">=3.8.1,<4.0"
|
|
|
18
18
|
pydantic = ">=1.4,<3.0"
|
|
19
19
|
|
|
20
20
|
[tool.poetry.dev-dependencies]
|
|
21
|
-
coverage = { version = "^7.
|
|
21
|
+
coverage = { version = "^7.6.1", extras = ["toml"] }
|
|
22
22
|
pytest = "^8.3.5"
|
|
23
23
|
pytest-mock = "^3.10.0"
|
|
24
24
|
pyproject-flake8 = "^7.0.0"
|
|
@@ -28,6 +28,7 @@ pytest-cov = "^5.0.0"
|
|
|
28
28
|
mypy = "^1.1.1"
|
|
29
29
|
avro = "^1.12.0"
|
|
30
30
|
fastavro = "^1.8.1"
|
|
31
|
+
typing-extensions = "^4.13.2"
|
|
31
32
|
|
|
32
33
|
[tool.poetry.scripts]
|
|
33
34
|
pydantic-avro = "pydantic_avro.__main__:root_main"
|
|
@@ -18,7 +18,7 @@ entry_points = \
|
|
|
18
18
|
|
|
19
19
|
setup_kwargs = {
|
|
20
20
|
'name': 'pydantic-avro',
|
|
21
|
-
'version': '0.9.
|
|
21
|
+
'version': '0.9.1',
|
|
22
22
|
'description': 'Converting pydantic classes to avro schemas',
|
|
23
23
|
'long_description': '[](https://github.com/godatadriven/pydantic-avro/actions/workflows/python-package.yml)\n[](https://codecov.io/gh/godatadriven/pydantic-avro)\n[](https://badge.fury.io/py/pydantic-avro)\n[](https://github.com/godatadriven/pydantic-avro/actions/workflows/codeql-analysis.yml)\n\n# pydantic-avro\n\nThis library can convert a pydantic class to a avro schema or generate python code from a avro schema.\n\n### Install\n\n```bash\npip install pydantic-avro\n```\n\n### Pydantic class to avro schema\n\n```python\nimport json\nfrom typing import Optional\n\nfrom pydantic_avro.base import AvroBase\n\n\nclass TestModel(AvroBase):\n key1: str\n key2: int\n key2: Optional[str]\n\n\nschema_dict: dict = TestModel.avro_schema()\nprint(json.dumps(schema_dict))\n\n```\n\n### Avro schema to pydantic\n\n```shell\n# Print to stdout\npydantic-avro avro_to_pydantic --asvc /path/to/schema.asvc\n\n# Save it to a file\npydantic-avro avro_to_pydantic --asvc /path/to/schema.asvc --output /path/to/output.py\n```\n\n### Specify expected Avro type\n\n```python\nfrom datetime import datetime\nfrom pydantic import Field\nfrom pydantic_avro.base import AvroBase \n\nclass ExampleModel(AvroBase):\n field1: int = Field(..., avro_type="long") # Explicitly set Avro type to "long"\n field2: datetime = Field(..., avro_type="timestamp-millis") # Explicitly set Avro type to "timestamp-millis"\n```\n\n### Install for developers\n\n###### Install package\n\n- Requirement: Poetry 1.*\n\n```shell\npoetry install\n```\n\n###### Run unit tests\n```shell\npytest\ncoverage run -m pytest # with coverage\n# or (depends on your local env) \npoetry run pytest\npoetry run coverage run -m pytest # with coverage\n```\n\n##### Run linting\n\nThe linting is checked in the github workflow. To fix and review issues run this:\n```shell\nblack . # Auto fix all issues\nisort . # Auto fix all issues\npflake . # Only display issues, fixing is manual\n```\n',
|
|
24
24
|
'author': "Peter van 't Hof'",
|
|
@@ -137,11 +137,14 @@ class AvroTypeConverter:
|
|
|
137
137
|
r = field_props["allOf"][0]["$ref"]
|
|
138
138
|
if ("prefixItems" in field_props or ("minItems" in field_props and "maxItems" in field_props)) and t == "array":
|
|
139
139
|
t = "tuple"
|
|
140
|
-
|
|
141
140
|
u = field_props.get("anyOf")
|
|
141
|
+
o = field_props.get("oneOf")
|
|
142
|
+
discriminator = field_props.get("discriminator")
|
|
142
143
|
|
|
143
144
|
if u is not None:
|
|
144
|
-
return self._union_to_avro(u, avro_type_dict)
|
|
145
|
+
return self._union_to_avro(u, avro_type_dict, discriminator)
|
|
146
|
+
elif o is not None:
|
|
147
|
+
return self._union_to_avro(o, avro_type_dict, discriminator)
|
|
145
148
|
elif r is not None:
|
|
146
149
|
return self._handle_references(r, avro_type_dict)
|
|
147
150
|
elif t is None:
|
|
@@ -229,8 +232,13 @@ class AvroTypeConverter:
|
|
|
229
232
|
value_type = self._get_avro_type_dict(a)["type"]
|
|
230
233
|
return {"type": "map", "values": value_type}
|
|
231
234
|
|
|
232
|
-
def _union_to_avro(self, field_props: list, avro_type_dict: dict) -> dict:
|
|
233
|
-
"""Returns a type of a union field"""
|
|
235
|
+
def _union_to_avro(self, field_props: list, avro_type_dict: dict, discriminator: Optional[dict] = None) -> dict:
|
|
236
|
+
"""Returns a type of a union field, including discriminated unions"""
|
|
237
|
+
# Handle discriminated unions
|
|
238
|
+
if discriminator is not None:
|
|
239
|
+
return self._discriminated_union_to_avro(field_props, avro_type_dict, discriminator)
|
|
240
|
+
|
|
241
|
+
# Standard union handling (unchanged)
|
|
234
242
|
avro_type_dict["type"] = []
|
|
235
243
|
for union_element in field_props:
|
|
236
244
|
t = self._get_avro_type_dict(union_element)
|
|
@@ -277,3 +285,39 @@ class AvroTypeConverter:
|
|
|
277
285
|
tn = tn["type"]
|
|
278
286
|
avro_type_dict["type"] = {"type": "array", "items": tn}
|
|
279
287
|
return avro_type_dict
|
|
288
|
+
|
|
289
|
+
def _discriminated_union_to_avro(self, variants: list, avro_type_dict: dict, discriminator: dict) -> dict:
|
|
290
|
+
"""Handles discriminated unions with a discriminator field"""
|
|
291
|
+
discriminator_property = discriminator.get("propertyName", "type")
|
|
292
|
+
variant_types = []
|
|
293
|
+
|
|
294
|
+
# Process each variant in the union
|
|
295
|
+
for variant in variants:
|
|
296
|
+
# Get the discriminator value for this variant
|
|
297
|
+
disc_value = None
|
|
298
|
+
if "properties" in variant and discriminator_property in variant.get("properties", {}):
|
|
299
|
+
prop = variant["properties"][discriminator_property]
|
|
300
|
+
if "const" in prop:
|
|
301
|
+
disc_value = prop["const"]
|
|
302
|
+
elif "enum" in prop and len(prop["enum"]) == 1:
|
|
303
|
+
disc_value = prop["enum"][0]
|
|
304
|
+
|
|
305
|
+
# If we can't determine the discriminator value, generate a regular record
|
|
306
|
+
if disc_value is None:
|
|
307
|
+
variant_type = self._get_avro_type_dict(variant)
|
|
308
|
+
else:
|
|
309
|
+
# Create a named record for this variant
|
|
310
|
+
variant_name = f"{disc_value}Variant"
|
|
311
|
+
if "$ref" in variant:
|
|
312
|
+
ref_schema = get_definition(variant["$ref"], self.root_schema)
|
|
313
|
+
variant_fields = self.fields_to_avro_dicts(ref_schema)
|
|
314
|
+
else:
|
|
315
|
+
variant_fields = self.fields_to_avro_dicts(variant)
|
|
316
|
+
|
|
317
|
+
variant_type = {"type": {"type": "record", "name": variant_name, "fields": variant_fields}}
|
|
318
|
+
|
|
319
|
+
variant_types.append(variant_type["type"])
|
|
320
|
+
|
|
321
|
+
# Set the union of all variant types
|
|
322
|
+
avro_type_dict["type"] = variant_types
|
|
323
|
+
return avro_type_dict
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|