added abstract base classes to integral and float types in _write.validate, to support numpy types (and other classes that correctly register the abstract base classes), including tests
MODIFY
fastavro/_write.pyx
fastavro/_write.pyx
@@ -18,6 +18,7 @@ from cpython.tuple cimport PyTuple_GET_ITEM
from libc.string cimport memset
from os import urandom, SEEK_SET
from zlib import compress
+import numbers
from fastavro import const
from .const import DAYS_SHIFT
@@ -428,7 +429,7 @@ cpdef validate(object datum, schema):
if record_type == 'int':
return (
- (isinstance(datum, (int, long,)) and
+ (isinstance(datum, (int, long, numbers.Integral)) and
INT_MIN_VALUE <= datum <= INT_MAX_VALUE) or
isinstance(datum, (
datetime.time, datetime.datetime, datetime.date))
@@ -436,14 +437,14 @@ cpdef validate(object datum, schema):
if record_type == 'long':
return (
- (isinstance(datum, (int, long,)) and
+ (isinstance(datum, (int, long, numbers.Integral)) and
LONG_MIN_VALUE <= datum <= LONG_MAX_VALUE) or
isinstance(datum, (
datetime.time, datetime.datetime, datetime.date))
)
if record_type in ['float', 'double']:
- return isinstance(datum, (int, long, float))
+ return isinstance(datum, (int, long, float, numbers.Real))
if record_type == 'fixed':
return (

MODIFY
fastavro/_write_py.py
fastavro/_write_py.py
@@ -17,6 +17,7 @@ from collections import Iterable, Mapping
from os import urandom, SEEK_SET
from struct import pack
from zlib import compress
+import numbers
from .const import (
MCS_PER_HOUR, MCS_PER_MINUTE, MCS_PER_SECOND, MLS_PER_HOUR, MLS_PER_MINUTE,
@@ -329,7 +330,7 @@ def validate(datum, schema):
if record_type == 'int':
return (
- (isinstance(datum, (int, long,)) and
+ (isinstance(datum, (int, long, numbers.Integral)) and
INT_MIN_VALUE <= datum <= INT_MAX_VALUE) or
isinstance(datum, (
datetime.time, datetime.datetime, datetime.date))
@@ -337,14 +338,14 @@ def validate(datum, schema):
if record_type == 'long':
return (
- (isinstance(datum, (int, long,)) and
+ (isinstance(datum, (int, long, numbers.Integral)) and
LONG_MIN_VALUE <= datum <= LONG_MAX_VALUE) or
isinstance(datum, (
datetime.time, datetime.datetime, datetime.date))
)
if record_type in ['float', 'double']:
- return isinstance(datum, (int, long, float))
+ return isinstance(datum, (int, long, float, numbers.Real))
if record_type == 'fixed':
return (

MODIFY
tests/test_fastavro.py
tests/test_fastavro.py
@@ -745,6 +745,71 @@ def test_validator():
pass
+def test_validator_numeric():
+ for datum, schema in [
+ (1, 'int'),
+ (1, 'long'),
+ (1.0, 'float'),
+ (1.0, 'double'),
+ (1, 'float'),
+ (1, 'double'),
+ ]:
+ assert fastavro._write.validate(datum, schema)
+
+ for datum, schema in [
+ (1.0, 'int'),
+ (1.0, 'long'),
+ ("1.0", 'float'),
+ ("1.0", 'double'),
+ ("1", 'float'),
+ ("1", 'double'),
+ ]:
+ assert not fastavro._write.validate(datum, schema)
+ # and plenty more to add I suppose
+
+
+def test_validator_numeric_numpy():
+ import numpy as np
+ np_ints = [
+ np.int_,
+ np.intc,
+ np.intp,
+ np.int8,
+ np.int16,
+ np.int32,
+ np.int64,
+ np.uint8,
+ np.uint16,
+ np.uint32,
+ np.uint64,
+ ]
+
+ np_floats = [
+ np.float_,
+ np.float16,
+ np.float32,
+ np.float64,
+ ]
+
+ schema_ints = ['int', 'long']
+
+ schema_floats = ['float', 'double']
+
+ # all these should work
+ for nptype, schema in zip(np_ints, schema_ints):
+ assert fastavro._write.validate(nptype(1), schema)
+
+ for nptype, schema in zip(np_ints, schema_floats):
+ assert fastavro._write.validate(nptype(1), schema)
+
+ for nptype, schema in zip(np_floats, schema_floats):
+ assert fastavro._write.validate(nptype(1), schema)
+
+ # these shouldn't work
+ for nptype, schema in zip(np_floats, schema_ints):
+ assert not fastavro._write.validate(nptype(1), schema)
+
+
def test_is_avro_str():
for path in iglob('%s/*.avro' % data_dir):
assert fastavro.is_avro(path)

added abstract base classes to integral and float types in _write.validate, to support numpy types (and other classes that correctly register the abstract base classes), including tests