Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 03f5bd7

Browse filesBrowse files
authored
feat: configure types of integers fields when initializing Point from dict structure (influxdata#538)
1 parent 2d1fb2c commit 03f5bd7
Copy full SHA for 03f5bd7

File tree

3 files changed

+103
-4
lines changed
Filter options

3 files changed

+103
-4
lines changed

‎CHANGELOG.md

Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### Features
44
1. [#536](https://github.com/influxdata/influxdb-client-python/pull/536): Query to `CSV` skip empty lines
5+
1. [#538](https://github.com/influxdata/influxdb-client-python/pull/538): Configure types of `integer` fields when initializing `Point` from `dict` structure
56

67
## 1.35.0 [2022-12-01]
78

‎influxdb_client/client/write/point.py

Copy file name to clipboardExpand all lines: influxdb_client/client/write/point.py
+45-4Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,41 @@ def from_dict(dictionary: dict, write_precision: WritePrecision = DEFAULT_WRITE_
9999
record_tag_keys=["location", "version"],
100100
record_field_keys=["pressure", "temperature"])
101101
102+
Int Types:
103+
The following example shows how to configure the types of integers fields.
104+
It is useful when you want to serialize integers always as ``float`` to avoid ``field type conflict``
105+
or use ``unsigned 64-bit integer`` as the type for serialization.
106+
107+
.. code-block:: python
108+
109+
# Use custom dictionary structure
110+
dict_structure = {
111+
"measurement": "h2o_feet",
112+
"tags": {"location": "coyote_creek"},
113+
"fields": {
114+
"water_level": 1.0,
115+
"some_counter": 108913123234
116+
},
117+
"time": 1
118+
}
119+
120+
point = Point.from_dict(dict_structure, field_types={"some_counter": "uint"})
121+
102122
:param dictionary: dictionary for serialize into data Point
103123
:param write_precision: sets the precision for the supplied time values
104124
:key record_measurement_key: key of dictionary with specified measurement
105125
:key record_measurement_name: static measurement name for data Point
106126
:key record_time_key: key of dictionary with specified timestamp
107127
:key record_tag_keys: list of dictionary keys to use as a tag
108128
:key record_field_keys: list of dictionary keys to use as a field
129+
:key field_types: optional dictionary to specify types of serialized fields. Currently, is supported customization for integer types.
130+
Possible integers types:
131+
- ``int`` - serialize integers as "**Signed 64-bit integers**" - ``9223372036854775807i`` (default behaviour)
132+
- ``uint`` - serialize integers as "**Unsigned 64-bit integers**" - ``9223372036854775807u``
133+
- ``float`` - serialize integers as "**IEEE-754 64-bit floating-point numbers**". Useful for unify number types in your pipeline to avoid field type conflict - ``9223372036854775807``
134+
The ``field_types`` can be also specified as part of incoming dictionary. For more info see an example above.
109135
:return: new data point
110-
"""
136+
""" # noqa: E501
111137
measurement_ = kwargs.get('record_measurement_name', None)
112138
if measurement_ is None:
113139
measurement_ = dictionary[kwargs.get('record_measurement_key', 'measurement')]
@@ -134,6 +160,19 @@ def from_dict(dictionary: dict, write_precision: WritePrecision = DEFAULT_WRITE_
134160
record_time_key = kwargs.get('record_time_key', 'time')
135161
if record_time_key in dictionary:
136162
point.time(dictionary[record_time_key], write_precision=write_precision)
163+
164+
_field_types = kwargs.get('field_types', {})
165+
if 'field_types' in dictionary:
166+
_field_types = dictionary['field_types']
167+
# Map API fields types to Line Protocol types postfix:
168+
# - int: 'i'
169+
# - uint: 'u'
170+
# - float: ''
171+
point._field_types = dict(map(
172+
lambda item: (item[0], 'i' if item[1] == 'int' else 'u' if item[1] == 'uint' else ''),
173+
_field_types.items()
174+
))
175+
137176
return point
138177

139178
def __init__(self, measurement_name):
@@ -143,6 +182,7 @@ def __init__(self, measurement_name):
143182
self._name = measurement_name
144183
self._time = None
145184
self._write_precision = DEFAULT_WRITE_PRECISION
185+
self._field_types = {}
146186

147187
def time(self, time, write_precision=DEFAULT_WRITE_PRECISION):
148188
"""
@@ -190,7 +230,7 @@ def to_line_protocol(self, precision=None):
190230
"""
191231
warnings.warn(message, SyntaxWarning)
192232
_tags = _append_tags(self._tags)
193-
_fields = _append_fields(self._fields)
233+
_fields = _append_fields(self._fields, self._field_types)
194234
if not _fields:
195235
return ""
196236
_time = _append_time(self._time, self._write_precision if precision is None else precision)
@@ -227,7 +267,7 @@ def _append_tags(tags):
227267
return f"{',' if _return else ''}{','.join(_return)} "
228268

229269

230-
def _append_fields(fields):
270+
def _append_fields(fields, field_types):
231271
_return = []
232272

233273
for field, value in sorted(fields.items()):
@@ -246,7 +286,8 @@ def _append_fields(fields):
246286
s = s[:-2]
247287
_return.append(f'{_escape_key(field)}={s}')
248288
elif (isinstance(value, int) or _np_is_subtype(value, 'int')) and not isinstance(value, bool):
249-
_return.append(f'{_escape_key(field)}={str(value)}i')
289+
_type = field_types.get(field, "i")
290+
_return.append(f'{_escape_key(field)}={str(value)}{_type}')
250291
elif isinstance(value, bool):
251292
_return.append(f'{_escape_key(field)}={str(value).lower()}')
252293
elif isinstance(value, str):

‎tests/test_point.py

Copy file name to clipboardExpand all lines: tests/test_point.py
+57Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,63 @@ def test_from_dictionary_tolerant_to_missing_tags_and_fields(self):
482482
record_field_keys=["pressure", "temperature"])
483483
self.assertEqual("sensor_pt859,location=warehouse_125 pressure=125i", point.to_line_protocol())
484484

485+
def test_from_dictionary_uint(self):
486+
dict_structure = {
487+
"measurement": "h2o_feet",
488+
"tags": {"location": "coyote_creek"},
489+
"fields": {
490+
"water_level": 1.0,
491+
"some_counter": 108913123234
492+
},
493+
"time": 1
494+
}
495+
point = Point.from_dict(dict_structure, field_types={"some_counter": "uint"})
496+
self.assertEqual("h2o_feet,location=coyote_creek some_counter=108913123234u,water_level=1 1",
497+
point.to_line_protocol())
498+
499+
def test_from_dictionary_int(self):
500+
dict_structure = {
501+
"measurement": "h2o_feet",
502+
"tags": {"location": "coyote_creek"},
503+
"fields": {
504+
"water_level": 1.0,
505+
"some_counter": 108913123234
506+
},
507+
"time": 1
508+
}
509+
point = Point.from_dict(dict_structure, field_types={"some_counter": "int"})
510+
self.assertEqual("h2o_feet,location=coyote_creek some_counter=108913123234i,water_level=1 1",
511+
point.to_line_protocol())
512+
513+
def test_from_dictionary_float(self):
514+
dict_structure = {
515+
"measurement": "h2o_feet",
516+
"tags": {"location": "coyote_creek"},
517+
"fields": {
518+
"water_level": 1.0,
519+
"some_counter": 108913123234
520+
},
521+
"time": 1
522+
}
523+
point = Point.from_dict(dict_structure, field_types={"some_counter": "float"})
524+
self.assertEqual("h2o_feet,location=coyote_creek some_counter=108913123234,water_level=1 1",
525+
point.to_line_protocol())
526+
527+
def test_from_dictionary_float_from_dict(self):
528+
dict_structure = {
529+
"measurement": "h2o_feet",
530+
"tags": {"location": "coyote_creek"},
531+
"fields": {
532+
"water_level": 1.0,
533+
"some_counter": 108913123234
534+
},
535+
"field_types": {"some_counter": "float"},
536+
"time": 1
537+
}
538+
point = Point.from_dict(dict_structure)
539+
self.assertEqual("h2o_feet,location=coyote_creek some_counter=108913123234,water_level=1 1",
540+
point.to_line_protocol())
541+
485542
def test_static_measurement_name(self):
486543
dictionary = {
487544
"name": "sensor_pt859",

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.