Adds option to write unions without type hint in json writer output
resolves
MODIFY
fastavro/io/json_encoder.py
fastavro/io/json_encoder.py
@@ -38,15 +38,18 @@ class AvroJSONEncoder:
----------
fo: file-like
Input stream
+ write_union_type: bool (default True)
+ Determine whether to write the union type in the json message.
"""
- def __init__(self, fo):
+ def __init__(self, fo, *, write_union_type=True):
self._fo = fo
self._stack = []
self._current = None
self._key = None
self._records = []
+ self._write_union_type = write_union_type
def write_value(self, value):
if isinstance(self._current, dict):
@@ -191,7 +194,7 @@ class AvroJSONEncoder:
symbol = alternative_symbol.get_symbol(index)
- if symbol != Null():
+ if symbol != Null() and self._write_union_type:
self.write_object_start()
self.write_object_key(alternative_symbol.get_label(index))
# TODO: Do we need this symbol?

MODIFY
fastavro/json_write.py
fastavro/json_write.py
@@ -2,7 +2,7 @@ from ._write_py import writer
from .io.json_encoder import AvroJSONEncoder
-def json_writer(fo, schema, records):
+def json_writer(fo, schema, records, *, write_union_type=True):
"""Write records to fo (stream) according to schema
Parameters
@@ -14,6 +14,10 @@ def json_writer(fo, schema, records):
records: iterable
Records to write. This is commonly a list of the dictionary
representation of the records, but it can be any iterable
+ write_union_type: bool (default True)
+ Determine whether to write the union type in the json message.
+ If this is set to False the output will be clear json.
+ It may however not be decodable back to avro record by `json_read`.
Example::
@@ -43,4 +47,6 @@ def json_writer(fo, schema, records):
with open('some-file', 'w') as out:
json_writer(out, parsed_schema, records)
"""
- return writer(AvroJSONEncoder(fo), schema, records)
+ return writer(
+ AvroJSONEncoder(fo, write_union_type=write_union_type), schema, records
+ )

MODIFY
fastavro/json_write.pyi
fastavro/json_write.pyi
from typing import IO, Dict, Iterable
-def json_writer(fo: IO, schema: Dict, records: Iterable) -> None: ...
+def json_writer(
+ fo: IO, schema: Dict, records: Iterable, *, write_union_type: bool = ...
+) -> None: ...

MODIFY
tests/test_json.py
tests/test_json.py
@@ -204,6 +204,53 @@ def test_encoded_union_output():
assert new_file.getvalue().strip() == expected
+def test_union_output_without_type():
+ """https://github.com/fastavro/fastavro/issues/420"""
+ schema = {
+ "type": "record",
+ "name": "Test",
+ "namespace": "test",
+ "fields": [
+ {
+ "name": "union",
+ "type": [
+ "null",
+ "int",
+ {
+ "type": "record",
+ "name": "union_record",
+ "fields": [
+ {
+ "name": "union_record_field",
+ "type": "string",
+ }
+ ],
+ },
+ ],
+ }
+ ],
+ }
+
+ # A null value is encoded as just null
+ records = [{"union": None}]
+ new_file = StringIO()
+ json_writer(new_file, schema, records, write_union_type=False)
+ assert new_file.getvalue().strip() == json.dumps({"union": None})
+
+ # A non-null, non-named type is encoded as just the value
+ records = [{"union": 321}]
+ new_file = StringIO()
+ json_writer(new_file, schema, records, write_union_type=False)
+ assert new_file.getvalue().strip() == json.dumps({"union": 321})
+
+ # A non-null, named type is encoded as an object
+ records = [{"union": {"union_record_field": "union_field"}}]
+ new_file = StringIO()
+ json_writer(new_file, schema, records, write_union_type=False)
+ expected = json.dumps({"union": {"union_record_field": "union_field"}})
+ assert new_file.getvalue().strip() == expected
+
+
def test_union_string_and_bytes():
schema = {
"type": "record",

Adds option to write unions without type hint in json writer output

resolves #420