pydantic-avro 0.8.1__py3-none-any.whl → 0.9.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.
@@ -61,6 +61,8 @@ AVRO_TYPE_MAPPING = {
61
61
  },
62
62
  }
63
63
 
64
+ PRIMITVE_TYPES = ["int", "long", "float", "double", "boolean", "null"]
65
+
64
66
 
65
67
  def get_definition(ref: str, schema: dict):
66
68
  """Reading definition of base schema for nested structs"""
@@ -133,10 +135,16 @@ class AvroTypeConverter:
133
135
  at = field_props.get("avro_type")
134
136
  if "allOf" in field_props and len(field_props["allOf"]) == 1:
135
137
  r = field_props["allOf"][0]["$ref"]
138
+ if ("prefixItems" in field_props or ("minItems" in field_props and "maxItems" in field_props)) and t == "array":
139
+ t = "tuple"
136
140
  u = field_props.get("anyOf")
141
+ o = field_props.get("oneOf")
142
+ discriminator = field_props.get("discriminator")
137
143
 
138
144
  if u is not None:
139
- 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)
140
148
  elif r is not None:
141
149
  return self._handle_references(r, avro_type_dict)
142
150
  elif t is None:
@@ -162,6 +170,8 @@ class AvroTypeConverter:
162
170
  avro_type_dict["type"] = "boolean"
163
171
  elif t == "null":
164
172
  avro_type_dict["type"] = "null"
173
+ elif t == "tuple":
174
+ return self._tuple_to_avro(field_props, avro_type_dict)
165
175
  else:
166
176
  raise NotImplementedError(
167
177
  f"Type '{t}' not support yet, "
@@ -216,34 +226,98 @@ class AvroTypeConverter:
216
226
  def _object_to_avro(self, field_props: dict) -> dict:
217
227
  """Returns a type of an object field"""
218
228
  a = field_props.get("additionalProperties")
219
- value_type = "string" if a is None else self._get_avro_type_dict(a)["type"]
229
+ if not a or isinstance(a, bool):
230
+ value_type = "string"
231
+ else:
232
+ value_type = self._get_avro_type_dict(a)["type"]
220
233
  return {"type": "map", "values": value_type}
221
234
 
222
- def _union_to_avro(self, field_props: list, avro_type_dict: dict) -> dict:
223
- """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)
224
242
  avro_type_dict["type"] = []
225
243
  for union_element in field_props:
226
244
  t = self._get_avro_type_dict(union_element)
227
245
  avro_type_dict["type"].append(t["type"])
228
246
  return avro_type_dict
229
247
 
248
+ def _tuple_to_avro(self, field_props: dict, avro_type_dict: dict) -> dict:
249
+ """Returns a type of a tuple field"""
250
+ prefix_items = field_props.get("prefixItems")
251
+ if not prefix_items:
252
+ # Pydantic v1 there is no prefixItems, but minItems and maxItems and items is a list.
253
+ prefix_items = field_props.get("items")
254
+ if not prefix_items:
255
+ raise ValueError(f"Tuple Field '{field_props}' does not have any items .")
256
+ possible_types = []
257
+ for prefix_item in prefix_items:
258
+ item_type = self._get_avro_type(prefix_item, avro_type_dict).get("type")
259
+ if not item_type:
260
+ raise ValueError(f"Field '{avro_type_dict}' does not have a defined type.")
261
+ if isinstance(item_type, list):
262
+ possible_types.extend([x for x in item_type if x not in possible_types])
263
+ elif item_type not in possible_types:
264
+ possible_types.append(item_type)
265
+ avro_type_dict["type"] = {"type": "array", "items": possible_types}
266
+ return avro_type_dict
267
+
230
268
  def _array_to_avro(self, field_props: dict, avro_type_dict: dict) -> dict:
231
269
  """Returns a type of an array field"""
232
- items = field_props["items"]
270
+ items = field_props.get("items")
271
+ # In pydantic v1. items is a list, we need to handle this case first
272
+ # E.g. [{'type': 'number'}, {'type': 'number'}]}
273
+ if isinstance(items, list):
274
+ if not len(items):
275
+ raise ValueError(f"Field '{field_props}' does not have valid items.")
276
+ items = items[0]
277
+ if not isinstance(items, dict):
278
+ raise ValueError(f"Field '{field_props}' does not have valid items.")
233
279
  tn = self._get_avro_type_dict(items)
234
280
  # If items in array are an object:
235
281
  if "$ref" in items:
236
282
  tn = tn["type"]
237
283
  # If items in array are a logicalType
238
- if (
239
- isinstance(tn, dict)
240
- and isinstance(tn.get("type", {}), dict)
241
- and tn.get("type", {}).get("logicalType") is not None
242
- ):
284
+ if isinstance(tn, dict) and isinstance(tn.get("type", None), (dict, list)):
243
285
  tn = tn["type"]
244
- # If items in array are an array, the structure must be corrected
245
- if isinstance(tn, dict) and isinstance(tn.get("type", {}), dict) and tn.get("type", {}).get("type") == "array":
246
- items = tn["type"]["items"]
247
- tn = {"type": "array", "items": items}
248
286
  avro_type_dict["type"] = {"type": "array", "items": tn}
249
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pydantic-avro
3
- Version: 0.8.1
3
+ Version: 0.9.1
4
4
  Summary: Converting pydantic classes to avro schemas
5
5
  Home-page: https://github.com/godatadriven/pydantic-avro
6
6
  License: MIT
@@ -9,9 +9,9 @@ pydantic_avro/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  pydantic_avro/to_avro/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  pydantic_avro/to_avro/base.py,sha256=Y8QOGTpXO3BwJ6arrRK-k2JniK5kLTvlDpQ0PyZojmg,1409
11
11
  pydantic_avro/to_avro/config.py,sha256=R9HLkWiXs7YZ02te8CQt5Kf2rbsE8Fx-hjqv3tBSFJU,152
12
- pydantic_avro/to_avro/types.py,sha256=9bGoTDxejaHUsKRvQxwqF3-k7NGHU-vjTnhzR3o8m8o,8980
13
- pydantic_avro-0.8.1.dist-info/entry_points.txt,sha256=gwHiQfbGLO8Np2sa1bZ_bpxU7sEufx6IachViBE_Fnw,66
14
- pydantic_avro-0.8.1.dist-info/LICENSE,sha256=gBlYCG1yxb0vGlsmek0lMPVOK5YDxQope4F54jzeqoY,1069
15
- pydantic_avro-0.8.1.dist-info/WHEEL,sha256=vxFmldFsRN_Hx10GDvsdv1wroKq8r5Lzvjp6GZ4OO8c,88
16
- pydantic_avro-0.8.1.dist-info/METADATA,sha256=PQHBW2nLJ87OPKIpUwicMHU4ph7ibZrD8jAqaZrSzhg,2945
17
- pydantic_avro-0.8.1.dist-info/RECORD,,
12
+ pydantic_avro/to_avro/types.py,sha256=-qemQC_vs-xy7VJDTQ1y1k7K1J6Qv3pTLILqp17MO2A,12731
13
+ pydantic_avro-0.9.1.dist-info/entry_points.txt,sha256=gwHiQfbGLO8Np2sa1bZ_bpxU7sEufx6IachViBE_Fnw,66
14
+ pydantic_avro-0.9.1.dist-info/LICENSE,sha256=gBlYCG1yxb0vGlsmek0lMPVOK5YDxQope4F54jzeqoY,1069
15
+ pydantic_avro-0.9.1.dist-info/WHEEL,sha256=vxFmldFsRN_Hx10GDvsdv1wroKq8r5Lzvjp6GZ4OO8c,88
16
+ pydantic_avro-0.9.1.dist-info/METADATA,sha256=xNTEqdyWeKcmYCG5xabukyW4fFQKY05EZqpR_rx0qEQ,2945
17
+ pydantic_avro-0.9.1.dist-info/RECORD,,