diff --git a/CHANGELOG.md b/CHANGELOG.md index 839b845..54c278f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ 1. [#198](https://github.com/InfluxCommunity/influxdb3-python/pull/198): Support custom tag order via `tag_order` write option. See [Sort tags by priority](https://docs.influxdata.com/influxdb3/enterprise/write-data/best-practices/schema-design/#sort-tags-by-query-priority) for more. +1. [#202](https://github.com/InfluxCommunity/influxdb3-python/pull/202): Add escape for field keys when serializing to line protocol in `PolarsDataframeSerializer`. ## 0.18.0 [2026-02-19] diff --git a/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py b/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py index 61f272c..7c2e4cf 100644 --- a/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py +++ b/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py @@ -92,12 +92,15 @@ def to_line_protocol(self, row): # add escape symbols for special characters to tags fields = ",".join( - f"{col}=\"{self.escape_value(row[self.column_indices[col]])}\"" if isinstance(row[self.column_indices[col]], - str) - else f"{col}={str(row[self.column_indices[col]]).lower()}" if isinstance(row[self.column_indices[col]], - bool) # Check for bool first - else f"{col}={row[self.column_indices[col]]}i" if isinstance(row[self.column_indices[col]], int) - else f"{col}={row[self.column_indices[col]]}" + f"{self.escape_key(col)}=\"{self.escape_value(row[self.column_indices[col]])}\"" if isinstance( + row[self.column_indices[col]], + str) + else f"{self.escape_key(col)}={str(row[self.column_indices[col]]).lower()}" if isinstance( + row[self.column_indices[col]], + bool) # Check for bool first + else f"{self.escape_key(col)}={row[self.column_indices[col]]}i" if isinstance(row[self.column_indices[col]], + int) + else f"{self.escape_key(col)}={row[self.column_indices[col]]}" for col in self.column_indices if col not in self.tag_columns + [self.timestamp_column] and row[self.column_indices[col]] is not None and row[self.column_indices[col]] != "" diff --git a/tests/test_polars.py b/tests/test_polars.py index 61ff206..44350e1 100644 --- a/tests/test_polars.py +++ b/tests/test_polars.py @@ -123,6 +123,30 @@ def test_to_list_of_points_with_precision_variants(self): data_frame_measurement_name='iot-devices', data_frame_timestamp_column='time') + def test_escape_for_key(self): + import polars as pl + ps = PointSettings(tag="prod") + df = pl.DataFrame(data={ + "name whitespace": ['iot-devices'], + "tag1 whitespace": "something", + "building": ['5a'], + "temperature": [72.3], + "time": pl.Series(["2022-10-01T12:01:00Z"]).str.to_datetime(time_unit='ns') + }) + + actual = polars_data_frame_to_list_of_points( + data_frame=df, point_settings=ps, + data_frame_measurement_name='iot-devices', + data_frame_tag_columns=['building', 'tag1 whitespace'], + data_frame_timestamp_column='time', + ) + + expected = [ + 'iot-devices,building=5a,tag1\\ whitespace=something,tag=prod name\\ whitespace="iot-devices",' + 'temperature=72.3 1664625660000000000' + ] + self.assertEqual(expected, actual) + @unittest.skipIf(importlib.util.find_spec("polars") is None, 'Polars package not installed') class TestWritePolars(unittest.TestCase):