add option to disable tuple notation
MODIFY
fastavro/_validation.pyx
fastavro/_validation.pyx
@@ -79,9 +79,9 @@ cdef inline bint validate_array(
datum,
dict schema,
dict named_schemas,
- str parent_ns="",
- bint raise_errors=True,
- bint strict=False,
+ str parent_ns,
+ bint raise_errors,
+ dict options,
) except -1:
if not isinstance(datum, (Sequence, array.array)) or isinstance(datum, str):
return False
@@ -93,7 +93,7 @@ cdef inline bint validate_array(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
):
return False
return True
@@ -103,9 +103,9 @@ cdef inline bint validate_map(
object datum,
dict schema,
dict named_schemas,
- str parent_ns="",
- bint raise_errors=True,
- bint strict=False,
+ str parent_ns,
+ bint raise_errors,
+ dict options,
) except -1:
# initial checks for map type
if not isinstance(datum, Mapping):
@@ -121,7 +121,7 @@ cdef inline bint validate_map(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
):
return False
return True
@@ -131,9 +131,9 @@ cdef inline bint validate_record(
object datum,
dict schema,
dict named_schemas,
- str parent_ns="",
- bint raise_errors=True,
- bint strict=False,
+ str parent_ns,
+ bint raise_errors,
+ dict options,
) except -1:
if not isinstance(datum, Mapping):
return False
@@ -143,7 +143,7 @@ cdef inline bint validate_record(
for f in schema["fields"]:
datum_value = datum.get(f["name"], f.get("default", NoValue))
- if datum_value is NoValue and strict:
+ if datum_value is NoValue and options.get("strict"):
return False
elif datum_value is NoValue:
datum_value = None
@@ -154,7 +154,7 @@ cdef inline bint validate_record(
named_schemas=named_schemas,
field=f"{fullname}.{f['name']}",
raise_errors=raise_errors,
- strict=strict,
+ options=options,
):
return False
return True
@@ -164,11 +164,11 @@ cdef inline bint validate_union(
object datum,
list schema,
dict named_schemas,
- str parent_ns=None,
- bint raise_errors=True,
- bint strict=False,
+ str parent_ns,
+ bint raise_errors,
+ dict options,
) except -1:
- if isinstance(datum, tuple):
+ if isinstance(datum, tuple) and not options.get("disable_tuple_notation"):
(name, datum) = datum
for candidate in schema:
if extract_record_type(candidate) == "record":
@@ -182,7 +182,7 @@ cdef inline bint validate_union(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
else:
return False
@@ -196,7 +196,7 @@ cdef inline bint validate_union(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
if ret:
# We exit on the first passing type in Unions
@@ -212,9 +212,9 @@ cpdef _validate(
object datum,
object schema,
dict named_schemas,
- str field="",
- bint raise_errors=True,
- bint strict=False,
+ str field,
+ bint raise_errors,
+ dict options,
):
record_type = extract_record_type(schema)
result = None
@@ -251,7 +251,7 @@ cpdef _validate(
named_schemas=named_schemas,
parent_ns=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
elif record_type == "map":
result = validate_map(
@@ -260,7 +260,7 @@ cpdef _validate(
named_schemas=named_schemas,
parent_ns=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
elif record_type in ("union", "error_union"):
result = validate_union(
@@ -269,7 +269,7 @@ cpdef _validate(
named_schemas=named_schemas,
parent_ns=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
elif record_type in ("record", "error", "request"):
result = validate_record(
@@ -278,7 +278,7 @@ cpdef _validate(
named_schemas=named_schemas,
parent_ns=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
elif record_type in named_schemas:
result = _validate(
@@ -287,7 +287,7 @@ cpdef _validate(
named_schemas=named_schemas,
field=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
else:
raise UnknownType(record_type)
@@ -299,14 +299,32 @@ cpdef _validate(
cpdef validate(
- object datum, object schema, str field="", bint raise_errors=True, bint strict=False
+ object datum,
+ object schema,
+ str field="",
+ bint raise_errors=True,
+ bint strict=False,
+ bint disable_tuple_notation=False,
):
named_schemas = {}
parsed_schema = parse_schema(schema, named_schemas)
- return _validate(datum, parsed_schema, named_schemas, field, raise_errors, strict)
+ return _validate(
+ datum,
+ parsed_schema,
+ named_schemas,
+ field,
+ raise_errors,
+ options={"strict": strict, "disable_tuple_notation": disable_tuple_notation},
+ )
-cpdef validate_many(records, schema, bint raise_errors=True, bint strict=False):
+cpdef validate_many(
+ object records,
+ object schema,
+ bint raise_errors=True,
+ bint strict=False,
+ bint disable_tuple_notation=False,
+):
cdef bint result
cdef list errors = []
cdef list results = []
@@ -318,8 +336,12 @@ cpdef validate_many(records, schema, bint raise_errors=True, bint strict=False):
record,
parsed_schema,
named_schemas,
+ field="",
raise_errors=raise_errors,
- strict=strict,
+ options={
+ "strict": strict,
+ "disable_tuple_notation": disable_tuple_notation,
+ }
)
results.append(result)
except ValidationError as e:

MODIFY
fastavro/_validation_py.py
fastavro/_validation_py.py
@@ -13,63 +13,27 @@ from .types import Schema, NamedSchemas
NoValue = object()
-def validate_null(datum, **kwargs):
- """
- Checks that the data value is None.
-
- Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
- """
+def _validate_null(datum, **kwargs):
+ """Checks that the data value is None."""
return datum is None
-def validate_boolean(datum, **kwargs):
- """
- Check that the data value is bool instance
-
- Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
- """
+def _validate_boolean(datum, **kwargs):
+ """Check that the data value is bool instance"""
return isinstance(datum, bool)
-def validate_string(datum, **kwargs):
- """
- Check that the data value is string
-
- Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
- """
+def _validate_string(datum, **kwargs):
+ """Check that the data value is string"""
return isinstance(datum, str)
-def validate_bytes(datum, **kwargs):
- """
- Check that the data value is python bytes type
-
- Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
- """
+def _validate_bytes(datum, **kwargs):
+ """Check that the data value is python bytes type"""
return isinstance(datum, (bytes, bytearray))
-def validate_int(datum, **kwargs):
+def _validate_int(datum, **kwargs):
"""
Check that the data value is a non floating
point number with size less that Int32.
@@ -77,13 +41,6 @@ def validate_int(datum, **kwargs):
Int32 = -2147483648<=datum<=2147483647
conditional python types: int, numbers.Integral
-
- Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
"""
return (
isinstance(datum, (int, numbers.Integral))
@@ -92,7 +49,7 @@ def validate_int(datum, **kwargs):
)
-def validate_long(datum, **kwargs):
+def _validate_long(datum, **kwargs):
"""
Check that the data value is a non floating
point number with size less that long64.
@@ -100,13 +57,6 @@ def validate_long(datum, **kwargs):
Int64 = -9223372036854775808 <= datum <= 9223372036854775807
conditional python types: int, numbers.Integral
-
- :Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
"""
return (
isinstance(datum, (int, numbers.Integral))
@@ -115,76 +65,32 @@ def validate_long(datum, **kwargs):
)
-def validate_float(datum, **kwargs):
+def _validate_float(datum, **kwargs):
"""
Check that the data value is a floating
point number or double precision.
conditional python types
(int, float, numbers.Real)
-
- Parameters
- ----------
- datum: Any
- Data being validated
- kwargs: Any
- Unused kwargs
"""
return isinstance(datum, (int, float, numbers.Real)) and not isinstance(datum, bool)
-def validate_fixed(datum, schema, **kwargs):
+def _validate_fixed(datum, schema, **kwargs):
"""
Check that the data value is fixed width bytes,
matching the schema['size'] exactly!
-
- Parameters
- ----------
- datum: Any
- Data being validated
- schema: dict
- Schema
- kwargs: Any
- Unused kwargs
"""
return isinstance(datum, bytes) and len(datum) == schema["size"]
-def validate_enum(datum, schema, **kwargs):
- """
- Check that the data value matches one of the enum symbols.
-
- i.e "blue" in ["red", green", "blue"]
-
- Parameters
- ----------
- datum: Any
- Data being validated
- schema: dict
- Schema
- kwargs: Any
- Unused kwargs
- """
+def _validate_enum(datum, schema, **kwargs):
+ """Check that the data value matches one of the enum symbols."""
return datum in schema["symbols"]
-def validate_array(
- datum, schema, named_schemas, parent_ns=None, raise_errors=True, strict=False
-):
- """
- Check that the data list values all match schema['items'].
-
- Parameters
- ----------
- datum: Any
- Data being validated
- schema: dict
- Schema
- parent_ns: str
- parent namespace
- raise_errors: bool
- If true, raises ValidationError on invalid data
- """
+def _validate_array(datum, schema, named_schemas, parent_ns, raise_errors, options):
+ """Check that the data list values all match schema['items']."""
return (
isinstance(datum, (Sequence, array.array))
and not isinstance(datum, str)
@@ -195,30 +101,17 @@ def validate_array(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
for d in datum
)
)
-def validate_map(
- datum, schema, named_schemas, parent_ns=None, raise_errors=True, strict=False
-):
+def _validate_map(datum, schema, named_schemas, parent_ns, raise_errors, options):
"""
Check that the data is a Map(k,v)
matching values to schema['values'] type.
-
- Parameters
- ----------
- datum: Any
- Data being validated
- schema: dict
- Schema
- parent_ns: str
- parent namespace
- raise_errors: bool
- If true, raises ValidationError on invalid data
"""
return (
isinstance(datum, Mapping)
@@ -230,30 +123,17 @@ def validate_map(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
for v in datum.values()
)
)
-def validate_record(
- datum, schema, named_schemas, parent_ns=None, raise_errors=True, strict=False
-):
+def _validate_record(datum, schema, named_schemas, parent_ns, raise_errors, options):
"""
Check that the data is a Mapping type with all schema defined fields
validated as True.
-
- Parameters
- ----------
- datum: Any
- Data being validated
- schema: dict
- Schema
- parent_ns: str
- parent namespace
- raise_errors: bool
- If true, raises ValidationError on invalid data
"""
_, fullname = schema_name(schema, parent_ns)
return (
@@ -266,32 +146,19 @@ def validate_record(
named_schemas=named_schemas,
field=f"{fullname}.{f['name']}",
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
for f in schema["fields"]
)
)
-def validate_union(
- datum, schema, named_schemas, parent_ns=None, raise_errors=True, strict=False
-):
+def _validate_union(datum, schema, named_schemas, parent_ns, raise_errors, options):
"""
Check that the data is a list type with possible options to
validate as True.
-
- Parameters
- ----------
- datum: Any
- Data being validated
- schema: dict
- Schema
- parent_ns: str
- parent namespace
- raise_errors: bool
- If true, raises ValidationError on invalid data
"""
- if isinstance(datum, tuple):
+ if isinstance(datum, tuple) and not options.get("disable_tuple_notation"):
(name, datum) = datum
for candidate in schema:
if extract_record_type(candidate) == "record":
@@ -305,7 +172,7 @@ def validate_union(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
else:
return False
@@ -319,7 +186,7 @@ def validate_union(
named_schemas=named_schemas,
field=parent_ns,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
if ret:
# We exit on the first passing type in Unions
@@ -332,32 +199,32 @@ def validate_union(
VALIDATORS = {
- "null": validate_null,
- "boolean": validate_boolean,
- "string": validate_string,
- "int": validate_int,
- "long": validate_long,
- "float": validate_float,
- "double": validate_float,
- "bytes": validate_bytes,
- "fixed": validate_fixed,
- "enum": validate_enum,
- "array": validate_array,
- "map": validate_map,
- "union": validate_union,
- "error_union": validate_union,
- "record": validate_record,
- "error": validate_record,
- "request": validate_record,
+ "null": _validate_null,
+ "boolean": _validate_boolean,
+ "string": _validate_string,
+ "int": _validate_int,
+ "long": _validate_long,
+ "float": _validate_float,
+ "double": _validate_float,
+ "bytes": _validate_bytes,
+ "fixed": _validate_fixed,
+ "enum": _validate_enum,
+ "array": _validate_array,
+ "map": _validate_map,
+ "union": _validate_union,
+ "error_union": _validate_union,
+ "record": _validate_record,
+ "error": _validate_record,
+ "request": _validate_record,
}
-def _validate(datum, schema, named_schemas, field="", raise_errors=True, strict=False):
+def _validate(datum, schema, named_schemas, field, raise_errors, options):
# This function expects the schema to already be parsed
record_type = extract_record_type(schema)
result = None
- if datum is NoValue and strict:
+ if datum is NoValue and options.get("strict"):
result = False
else:
if datum is NoValue:
@@ -377,7 +244,7 @@ def _validate(datum, schema, named_schemas, field="", raise_errors=True, strict=
named_schemas=named_schemas,
parent_ns=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
elif record_type in named_schemas:
result = _validate(
@@ -386,7 +253,7 @@ def _validate(datum, schema, named_schemas, field="", raise_errors=True, strict=
named_schemas=named_schemas,
field=field,
raise_errors=raise_errors,
- strict=strict,
+ options=options,
)
else:
raise UnknownType(record_type)
@@ -403,6 +270,7 @@ def validate(
field: str = "",
raise_errors: bool = True,
strict: bool = False,
+ disable_tuple_notation: bool = False,
) -> bool:
"""
Determine if a python datum is an instance of a schema.
@@ -421,6 +289,9 @@ def validate(
strict
If true, fields without values will raise errors rather than implicitly
defaulting to None
+ disable_tuple_notation
+ If set to True, tuples will not be treated as a special case. Therefore,
+ using a tuple to indicate the type of a record will not work
Example::
@@ -432,7 +303,14 @@ def validate(
"""
named_schemas: NamedSchemas = {}
parsed_schema = parse_schema(schema, named_schemas)
- return _validate(datum, parsed_schema, named_schemas, field, raise_errors, strict)
+ return _validate(
+ datum,
+ parsed_schema,
+ named_schemas,
+ field,
+ raise_errors,
+ options={"strict": strict, "disable_tuple_notation": disable_tuple_notation},
+ )
def validate_many(
@@ -440,6 +318,7 @@ def validate_many(
schema: Schema,
raise_errors: bool = True,
strict: bool = False,
+ disable_tuple_notation: bool = False,
) -> bool:
"""
Validate a list of data!
@@ -456,6 +335,9 @@ def validate_many(
strict
If true, fields without values will raise errors rather than implicitly
defaulting to None
+ disable_tuple_notation
+ If set to True, tuples will not be treated as a special case. Therefore,
+ using a tuple to indicate the type of a record will not work
Example::
@@ -476,8 +358,12 @@ def validate_many(
record,
parsed_schema,
named_schemas,
+ field="",
raise_errors=raise_errors,
- strict=strict,
+ options={
+ "strict": strict,
+ "disable_tuple_notation": disable_tuple_notation,
+ },
)
)
except ValidationError as e:

MODIFY
fastavro/_write.pyi
fastavro/_write.pyi
@@ -13,8 +13,10 @@ def writer(
validator: bool = ...,
sync_marker: bytes = ...,
codec_compression_level: Optional[int] = ...,
+ *,
strict: bool = ...,
strict_allow_default: bool = ...,
+ disable_tuple_notation: bool = ...,
) -> None: ...
class GenericWriter:
@@ -39,6 +41,7 @@ class Writer(GenericWriter):
validator: bool = ...,
sync_marker: bytes = ...,
compression_level: Optional[int] = ...,
+ options: Dict[str, bool] = ...,
): ...
def dump(self) -> None: ...
def write(self, record: AvroMessage) -> None: ...
@@ -49,6 +52,8 @@ def schemaless_writer(
fo: IO,
schema: Schema,
record: Any,
+ *,
strict: bool = ...,
strict_allow_default: bool = ...,
+ disable_tuple_notation: bool = ...,
) -> None: ...

MODIFY
fastavro/_write.pyx
fastavro/_write.pyx
@@ -253,7 +253,7 @@ cdef write_union(bytearray fo, datum, schema, dict named_schemas, fname, dict op
cdef str extracted_type
cdef str schema_name
best_match_index = -1
- if isinstance(datum, tuple):
+ if isinstance(datum, tuple) and not options.get("disable_tuple_notation"):
(name, datum) = datum
for index, candidate in enumerate(schema):
extracted_type = extract_record_type(candidate)
@@ -298,7 +298,14 @@ cdef write_union(bytearray fo, datum, schema, dict named_schemas, fname, dict op
# Nothing except "double" is even worth considering.
continue
- if _validate(datum, candidate, named_schemas, raise_errors=False):
+ if _validate(
+ datum,
+ candidate,
+ named_schemas,
+ field="",
+ raise_errors=False,
+ options=options,
+ ):
record_type = extract_record_type(candidate)
if record_type == "record":
logical_type = extract_logical_type(candidate)
@@ -711,7 +718,7 @@ cdef class Writer:
def write(self, record):
if self.validate_fn:
- self.validate_fn(record, self.schema, self._named_schemas)
+ self.validate_fn(record, self.schema, self._named_schemas, "", True, self.options)
write_data(self.io.value, record, self.schema, self._named_schemas, "", self.options)
self.block_count += 1
if self.io.tell() >= self.sync_interval:
@@ -743,8 +750,10 @@ def writer(
validator=None,
sync_marker=None,
codec_compression_level=None,
+ *,
strict=False,
strict_allow_default=False,
+ disable_tuple_notation=False,
):
# Sanity check that records is not a single dictionary (as that is a common
# mistake and the exception that gets raised is not helpful)
@@ -760,7 +769,11 @@ def writer(
validator,
sync_marker,
codec_compression_level,
- options={"strict": strict, "strict_allow_default": strict_allow_default}
+ options={
+ "strict": strict,
+ "strict_allow_default": strict_allow_default,
+ "disable_tuple_notation": disable_tuple_notation,
+ }
)
for record in records:
@@ -768,7 +781,14 @@ def writer(
output.flush()
-def schemaless_writer(fo, schema, record, strict=False, strict_allow_default=False):
+def schemaless_writer(
+ fo,
+ schema,
+ record,
+ strict=False,
+ strict_allow_default=False,
+ disable_tuple_notation=False,
+):
cdef bytearray tmp = bytearray()
named_schemas = {}
schema = parse_schema(schema, named_schemas)
@@ -778,6 +798,10 @@ def schemaless_writer(fo, schema, record, strict=False, strict_allow_default=Fal
schema,
named_schemas,
"",
- {"strict": strict, "strict_allow_default": strict_allow_default},
+ {
+ "strict": strict,
+ "strict_allow_default": strict_allow_default,
+ "disable_tuple_notation": disable_tuple_notation,
+ },
)
fo.write(tmp)

MODIFY
fastavro/_write_py.py
fastavro/_write_py.py
@@ -140,7 +140,7 @@ def write_union(encoder, datum, schema, named_schemas, fname, options):
is then encoded per the indicated schema within the union."""
best_match_index = -1
- if isinstance(datum, tuple):
+ if isinstance(datum, tuple) and not options.get("disable_tuple_notation"):
(name, datum) = datum
for index, candidate in enumerate(schema):
extracted_type = extract_record_type(candidate)
@@ -186,7 +186,14 @@ def write_union(encoder, datum, schema, named_schemas, fname, options):
# Nothing except "double" is even worth considering.
continue
- if _validate(datum, candidate, named_schemas, raise_errors=False):
+ if _validate(
+ datum,
+ candidate,
+ named_schemas,
+ raise_errors=False,
+ field="",
+ options=options,
+ ):
record_type = extract_record_type(candidate)
if record_type == "record":
logical_type = extract_logical_type(candidate)
@@ -529,7 +536,9 @@ class Writer(GenericWriter):
def write(self, record):
if self.validate_fn:
- self.validate_fn(record, self.schema, self._named_schemas)
+ self.validate_fn(
+ record, self.schema, self._named_schemas, "", True, self.options
+ )
write_data(self.io, record, self.schema, self._named_schemas, "", self.options)
self.block_count += 1
if self.io._fo.tell() >= self.sync_interval:
@@ -569,7 +578,9 @@ class JSONWriter(GenericWriter):
def write(self, record):
if self.validate_fn:
- self.validate_fn(record, self.schema, self._named_schemas)
+ self.validate_fn(
+ record, self.schema, self._named_schemas, "", True, self.options
+ )
write_data(
self.encoder, record, self.schema, self._named_schemas, "", self.options
)
@@ -588,8 +599,10 @@ def writer(
validator: bool = False,
sync_marker: bytes = b"",
codec_compression_level: Optional[int] = None,
+ *,
strict: bool = False,
strict_allow_default: bool = False,
+ disable_tuple_notation: bool = False,
):
"""Write records to fo (stream) according to schema
@@ -623,6 +636,9 @@ def writer(
If set to True, an error will be raised if records do not contain
exactly the same fields that the schema states unless it is a missing
field that has a default value in the schema
+ disable_tuple_notation
+ If set to True, tuples will not be treated as a special case. Therefore,
+ using a tuple to indicate the type of a record will not work
Example::
@@ -694,7 +710,11 @@ def writer(
validator,
sync_marker,
codec_compression_level,
- options={"strict": strict, "strict_allow_default": strict_allow_default},
+ options={
+ "strict": strict,
+ "strict_allow_default": strict_allow_default,
+ "disable_tuple_notation": disable_tuple_notation,
+ },
)
else:
output = Writer(
@@ -706,7 +726,11 @@ def writer(
validator,
sync_marker,
codec_compression_level,
- options={"strict": strict, "strict_allow_default": strict_allow_default},
+ options={
+ "strict": strict,
+ "strict_allow_default": strict_allow_default,
+ "disable_tuple_notation": disable_tuple_notation,
+ },
)
for record in records:
@@ -718,8 +742,10 @@ def schemaless_writer(
fo: IO,
schema: Schema,
record: Any,
+ *,
strict: bool = False,
strict_allow_default: bool = False,
+ disable_tuple_notation: bool = False,
):
"""Write a single record without the schema or header information
@@ -738,6 +764,9 @@ def schemaless_writer(
If set to True, an error will be raised if records do not contain
exactly the same fields that the schema states unless it is a missing
field that has a default value in the schema
+ disable_tuple_notation
+ If set to True, tuples will not be treated as a special case. Therefore,
+ using a tuple to indicate the type of a record will not work
Example::
@@ -758,6 +787,10 @@ def schemaless_writer(
schema,
named_schemas,
"",
- {"strict": strict, "strict_allow_default": strict_allow_default},
+ {
+ "strict": strict,
+ "strict_allow_default": strict_allow_default,
+ "disable_tuple_notation": disable_tuple_notation,
+ },
)
encoder.flush()

MODIFY
fastavro/json_write.py
fastavro/json_write.py
@@ -15,6 +15,7 @@ def json_writer(
encoder=AvroJSONEncoder,
strict: bool = False,
strict_allow_default: bool = False,
+ disable_tuple_notation: bool = False,
) -> None:
"""Write records to fo (stream) according to schema
@@ -43,6 +44,9 @@ def json_writer(
If set to True, an error will be raised if records do not contain
exactly the same fields that the schema states unless it is a missing
field that has a default value in the schema
+ disable_tuple_notation
+ If set to True, tuples will not be treated as a special case. Therefore,
+ using a tuple to indicate the type of a record will not work
Example::
@@ -79,4 +83,5 @@ def json_writer(
validator=validator,
strict=strict,
strict_allow_default=strict_allow_default,
+ disable_tuple_notation=disable_tuple_notation,
)

MODIFY
tests/test_fastavro.py
tests/test_fastavro.py
@@ -3242,3 +3242,22 @@ def test_strict_allow_default_option():
with pytest.raises(ValueError, match="field_1 is specified .*? but missing"):
roundtrip(schema, [test_record3], writer_kwargs={"strict_allow_default": True})
+
+
+def test_disable_tuple_notation_option():
+ """https://github.com/fastavro/fastavro/issues/548"""
+ schema = {
+ "namespace": "namespace",
+ "name": "name",
+ "type": "record",
+ "fields": [
+ {"name": "foo", "type": ["string", {"type": "array", "items": "string"}]}
+ ],
+ }
+
+ new_records = roundtrip(
+ schema,
+ [{"foo": ("string", "0")}],
+ writer_kwargs={"disable_tuple_notation": True},
+ )
+ assert new_records == [{"foo": ["string", "0"]}]

MODIFY
tests/test_json.py
tests/test_json.py
@@ -840,3 +840,22 @@ def test_json_with_map():
}
roundtrip(schema, [payload])
+
+
+def test_disable_tuple_notation_option():
+ """https://github.com/fastavro/fastavro/issues/548"""
+ schema = {
+ "namespace": "namespace",
+ "name": "name",
+ "type": "record",
+ "fields": [
+ {"name": "foo", "type": ["string", {"type": "array", "items": "string"}]}
+ ],
+ }
+
+ new_records = roundtrip(
+ schema,
+ [{"foo": ("string", "0")}],
+ writer_kwargs={"disable_tuple_notation": True},
+ )
+ assert new_records == [{"foo": ["string", "0"]}]

MODIFY
tests/test_schemaless.py
tests/test_schemaless.py
@@ -234,3 +234,20 @@ def test_strict_allow_default_option():
with pytest.raises(ValueError, match="field_1 is specified .*? but missing"):
roundtrip(schema, test_record3, writer_kwargs={"strict_allow_default": True})
+
+
+def test_disable_tuple_notation_option():
+ """https://github.com/fastavro/fastavro/issues/548"""
+ schema = {
+ "namespace": "namespace",
+ "name": "name",
+ "type": "record",
+ "fields": [
+ {"name": "foo", "type": ["string", {"type": "array", "items": "string"}]}
+ ],
+ }
+
+ new_record = roundtrip(
+ schema, {"foo": ("string", "0")}, writer_kwargs={"disable_tuple_notation": True}
+ )
+ assert new_record == {"foo": ["string", "0"]}

add option to disable tuple notation