fix issues with fixed type schemas and add a slew of tests of schema promotion/matching
MODIFY
fastavro/_read.pyx
fastavro/_read.pyx
@@ -128,6 +128,10 @@ cpdef match_schemas(w_schema, r_schema):
if match_types(w_schema["items"], r_schema["items"]):
return r_schema
elif w_type in NAMED_TYPES and r_type in NAMED_TYPES:
+ if w_type == r_type == "fixed" and w_schema["size"] != r_schema["size"]:
+ raise SchemaResolutionError(
+ f"Schema mismatch: {w_schema} size is different than {r_schema} size"
+ )
if w_schema["name"] == r_schema["name"] or w_schema["name"] in r_schema.get(
"aliases", []
):

MODIFY
fastavro/_read_py.py
fastavro/_read_py.py
@@ -119,6 +119,10 @@ def match_schemas(w_schema, r_schema):
if match_types(w_schema["items"], r_schema["items"]):
return r_schema
elif w_type in NAMED_TYPES and r_type in NAMED_TYPES:
+ if w_type == r_type == "fixed" and w_schema["size"] != r_schema["size"]:
+ raise SchemaResolutionError(
+ f"Schema mismatch: {w_schema} size is different than {r_schema} size"
+ )
if w_schema["name"] == r_schema["name"] or w_schema["name"] in r_schema.get(
"aliases", []
):

MODIFY
fastavro/_write.pyx
fastavro/_write.pyx
@@ -142,9 +142,13 @@ cdef inline write_crc32(bytearray fo, bytes bytes):
fo += ch_temp[:4]
-cdef inline write_fixed(bytearray fo, object datum, dict named_schemas):
+cdef inline write_fixed(bytearray fo, object datum, dict schema, dict named_schemas):
"""Fixed instances are encoded using the number of bytes declared in the
schema."""
+ if len(datum) != schema["size"]:
+ raise ValueError(
+ f"data of length {len(datum)} does not match schema size: {schema}"
+ )
fo += datum
@@ -390,7 +394,7 @@ cpdef write_data(bytearray fo, datum, schema, dict named_schemas, fname):
elif record_type == "bytes":
return write_bytes(fo, datum)
elif record_type == "fixed":
- return write_fixed(fo, datum, named_schemas)
+ return write_fixed(fo, datum, schema, named_schemas)
elif record_type == "enum":
return write_enum(fo, datum, schema, named_schemas)
elif record_type == "array":

MODIFY
fastavro/_write_py.py
fastavro/_write_py.py
@@ -76,6 +76,10 @@ def write_crc32(encoder, datum):
def write_fixed(encoder, datum, schema, named_schemas, fname):
"""Fixed instances are encoded using the number of bytes declared in the
schema."""
+ if len(datum) != schema["size"]:
+ raise ValueError(
+ f"data of length {len(datum)} does not match schema size: {schema}"
+ )
encoder.write_fixed(datum)

MODIFY
tests/test_fastavro.py
tests/test_fastavro.py
@@ -1636,8 +1636,8 @@ def test_user_specified_sync():
records = [{}]
- fastavro.writer(file1, schema, records, sync_marker=b"sync")
- fastavro.writer(file2, schema, records, sync_marker=b"sync")
+ fastavro.writer(file1, schema, records, sync_marker=b"16bytesyncmarker")
+ fastavro.writer(file2, schema, records, sync_marker=b"16bytesyncmarker")
assert file1.getvalue() == file2.getvalue()
@@ -2668,3 +2668,17 @@ def test_union_of_float_and_no_double():
records = [1.0]
parsed_schema = fastavro.parse_schema(schema)
assert records == roundtrip(parsed_schema, records)
+
+
+def test_error_if_trying_to_write_the_wrong_number_of_bytes():
+ """https://github.com/fastavro/fastavro/issues/522"""
+ schema = {"type": "fixed", "size": 2, "name": "fixed"}
+ parsed_schema = fastavro.parse_schema(schema)
+
+ records = [b"22", b"1", b"22"]
+ with pytest.raises(ValueError):
+ roundtrip(parsed_schema, records)
+
+ records = [b"22", b"333", b"22"]
+ with pytest.raises(ValueError):
+ roundtrip(parsed_schema, records)

fix issues with fixed type schemas and add a slew of tests of schema promotion/matching