diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab86200..df9dbe65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ 1. [#281](https://github.com/influxdata/influxdb-client-python/pull/281): `FluxTable`, `FluxColumn` and `FluxRecord` objects have helpful reprs 1. [#293](https://github.com/influxdata/influxdb-client-python/pull/293): `dataframe_serializer` supports batching 1. [#301](https://github.com/influxdata/influxdb-client-python/pull/301): Add `proxy_headers` to configuration options +1. [#306](https://github.com/influxdata/influxdb-client-python/pull/306): Supports `numpy` type in serialization to Line protocol ### Documentation 1. [#301](https://github.com/influxdata/influxdb-client-python/pull/301): How to configure proxy diff --git a/influxdb_client/client/write/point.py b/influxdb_client/client/write/point.py index 04d3c9ca..f20ce953 100644 --- a/influxdb_client/client/write/point.py +++ b/influxdb_client/client/write/point.py @@ -39,6 +39,13 @@ '\\': r'\\', }) +try: + import numpy as np + + _HAS_NUMPY = True +except ModuleNotFoundError: + _HAS_NUMPY = False + class Point(object): """ @@ -145,7 +152,7 @@ def _append_fields(fields): if value is None: continue - if isinstance(value, float) or isinstance(value, Decimal): + if isinstance(value, float) or isinstance(value, Decimal) or _np_is_subtype(value, 'float'): if not math.isfinite(value): continue s = str(value) @@ -156,7 +163,7 @@ def _append_fields(fields): if s.endswith('.0'): s = s[:-2] _return.append(f'{_escape_key(field)}={s}') - elif isinstance(value, int) and not isinstance(value, bool): + elif (isinstance(value, int) or _np_is_subtype(value, 'int')) and not isinstance(value, bool): _return.append(f'{_escape_key(field)}={str(value)}i') elif isinstance(value, bool): _return.append(f'{_escape_key(field)}={str(value).lower()}') @@ -216,3 +223,14 @@ def _convert_timestamp(timestamp, precision=DEFAULT_WRITE_PRECISION): return ns / 1e9 raise ValueError(timestamp) + + +def _np_is_subtype(value, np_type): + if not _HAS_NUMPY or not hasattr(value, 'dtype'): + return False + + if np_type == 'float': + return np.issubdtype(value, np.floating) + elif np_type == 'int': + return np.issubdtype(value, np.integer) + return False diff --git a/tests/test_point.py b/tests/test_point.py index 40446a9d..8d2de231 100644 --- a/tests/test_point.py +++ b/tests/test_point.py @@ -388,6 +388,26 @@ def test_backslash(self): "test,tag1=value1,tag2=value\2,tag3=value\\3,tag4=value\\4,tag5=value\\\\5 value=10i 1624989000000000000", point.to_line_protocol()) + def test_numpy_types(self): + from influxdb_client.extras import np + + point = Point.measurement("h2o")\ + .tag("location", "europe")\ + .field("np.float1", np.float(1.123))\ + .field("np.float2", np.float16(2.123))\ + .field("np.float3", np.float32(3.123))\ + .field("np.float4", np.float64(4.123))\ + .field("np.int1", np.int8(1))\ + .field("np.int2", np.int16(2))\ + .field("np.int3", np.int32(3))\ + .field("np.int4", np.int64(4))\ + .field("np.uint1", np.uint8(5))\ + .field("np.uint2", np.uint16(6))\ + .field("np.uint3", np.uint32(7))\ + .field("np.uint4", np.uint64(8)) + + self.assertEqual("h2o,location=europe np.float1=1.123,np.float2=2.123,np.float3=3.123,np.float4=4.123,np.int1=1i,np.int2=2i,np.int3=3i,np.int4=4i,np.uint1=5i,np.uint2=6i,np.uint3=7i,np.uint4=8i", point.to_line_protocol()) + if __name__ == '__main__': unittest.main()