differentiate between codec not supported and codec library not installed
MODIFY
appveyor.yml
appveyor.yml
@@ -19,7 +19,8 @@ test_script:
- "set PYTHONPATH=%cd%"
- "set FASTAVRO_USE_CYTHON=1"
- "%PYTHON%\\python.exe setup.py build_ext --inplace"
- - "%PYTHON%\\python.exe -m pytest -v tests"
+ - "%PYTHON%\\python.exe -m pytest --cov=fastavro -v tests"
+ - "%PYTHON%\\Scripts\\codecov.exe"
after_test:
# If tests are successful, create binary packages for the project.

MODIFY
azure-pipelines.yml
azure-pipelines.yml
@@ -43,6 +43,7 @@ jobs:
- script: |
./run-tests.sh
+ codecov
displayName: 'pytest'
- script: |

MODIFY
fastavro/_read.pyx
fastavro/_read.pyx
@@ -619,10 +619,14 @@ cpdef snappy_read_block(fo):
try:
import snappy
-
- BLOCK_READERS['snappy'] = snappy_read_block
except ImportError:
- pass
+ def no_snappy(decoder):
+ raise ValueError(
+ "snappy codec is supported but you need to install python-snappy"
+ )
+ BLOCK_READERS['snappy'] = no_snappy
+else:
+ BLOCK_READERS['snappy'] = snappy_read_block
def _iter_avro_records(fo, header, codec, writer_schema, reader_schema):

MODIFY
fastavro/_read_py.py
fastavro/_read_py.py
@@ -480,10 +480,14 @@ def snappy_read_block(decoder):
try:
import snappy
-
- BLOCK_READERS['snappy'] = snappy_read_block
except ImportError:
- pass
+ def no_snappy(decoder):
+ raise ValueError(
+ "snappy codec is supported but you need to install python-snappy"
+ )
+ BLOCK_READERS['snappy'] = no_snappy
+else:
+ BLOCK_READERS['snappy'] = snappy_read_block
def _iter_avro_records(decoder, header, codec, writer_schema, reader_schema):

MODIFY
fastavro/_write.pyx
fastavro/_write.pyx
@@ -373,16 +373,19 @@ BLOCK_WRITERS = {
try:
import snappy
-
- BLOCK_WRITERS['snappy'] = snappy_write_block
except ImportError:
- snappy = None
+ def no_snappy(encoder, block_bytes):
+ raise ValueError(
+ "snappy codec is supported but you need to install python-snappy"
+ )
+ BLOCK_WRITERS['snappy'] = no_snappy
+else:
+ BLOCK_WRITERS['snappy'] = snappy_write_block
cpdef snappy_write_block(object fo, bytes block_bytes):
"""Write block in "snappy" codec."""
cdef bytearray tmp = bytearray()
- assert snappy is not None
data = snappy.compress(block_bytes)
write_long(tmp, len(data) + 4) # for CRC

MODIFY
fastavro/_write_py.py
fastavro/_write_py.py
@@ -264,8 +264,6 @@ BLOCK_WRITERS = {
'deflate': deflate_write_block
}
-try:
- import snappy
def snappy_write_block(encoder, block_bytes):
"""Write block in "snappy" codec."""
@@ -275,9 +273,17 @@ try:
encoder._fo.write(data)
encoder.write_crc32(block_bytes)
- BLOCK_WRITERS['snappy'] = snappy_write_block
+
+try:
+ import snappy
except ImportError:
- pass
+ def no_snappy(encoder, block_bytes):
+ raise ValueError(
+ "snappy codec is supported but you need to install python-snappy"
+ )
+ BLOCK_WRITERS['snappy'] = no_snappy
+else:
+ BLOCK_WRITERS['snappy'] = snappy_write_block
class GenericWriter(object):

MODIFY
tests/test_compression.py
tests/test_compression.py
@@ -33,3 +33,68 @@ def test_snappy():
file.seek(0)
out_records = list(fastavro.reader(file))
assert records == out_records
+
+
+@pytest.mark.skipif(os.name != "nt", reason="snappy is present")
+def test_snappy_not_installed():
+ schema = {
+ "doc": "A weather reading.",
+ "name": "Weather",
+ "namespace": "test",
+ "type": "record",
+ "fields": [
+ {"name": "station", "type": "string"},
+ {"name": "time", "type": "long"},
+ {"name": "temp", "type": "int"},
+ ],
+ }
+
+ records = [
+ {"station": "011990-99999", "temp": 0, "time": 1433269388},
+ {"station": "011990-99999", "temp": 22, "time": 1433270389},
+ {"station": "011990-99999", "temp": -11, "time": 1433273379},
+ {"station": "012650-99999", "temp": 111, "time": 1433275478},
+ ]
+
+ file = MemoryIO()
+ with pytest.raises(
+ ValueError,
+ match="snappy codec is supported but you need to install python-snappy"
+ ):
+ fastavro.writer(file, schema, records, codec="snappy")
+
+
+def test_unsupported_codec():
+ schema = {
+ "doc": "A weather reading.",
+ "name": "Weather",
+ "namespace": "test",
+ "type": "record",
+ "fields": [
+ {"name": "station", "type": "string"},
+ {"name": "time", "type": "long"},
+ {"name": "temp", "type": "int"},
+ ],
+ }
+
+ records = [
+ {"station": "011990-99999", "temp": 0, "time": 1433269388},
+ {"station": "011990-99999", "temp": 22, "time": 1433270389},
+ {"station": "011990-99999", "temp": -11, "time": 1433273379},
+ {"station": "012650-99999", "temp": 111, "time": 1433275478},
+ ]
+
+ file = MemoryIO()
+ with pytest.raises(ValueError, match="unrecognized codec"):
+ fastavro.writer(file, schema, records, codec="unsupported")
+
+ file = MemoryIO()
+ fastavro.writer(file, schema, records, codec="deflate")
+
+ # Change the avro binary to act as if it were written with a codec called
+ # `unsupported`
+ modified_avro = file.getvalue().replace(b"\x0edeflate", b"\x16unsupported")
+ modified_file = MemoryIO(modified_avro)
+
+ with pytest.raises(ValueError, match="Unrecognized codec"):
+ list(fastavro.reader(modified_file))

differentiate between codec not supported and codec library not installed