Repository: influxdata/influxdb-client-python

Issue:
Regression: invalid field format with NaN values
I noticed a regression in the way NaN values are handled when working with pandas dataframes. Could it be a result of [500835](https://github.com/influxdata/influxdb-client-python/commit/500835f3b1d3b2b87214ede830b750a6018c0ca9#diff-02179d31a524332a9b64b57d464f6a56c0725daf636a4a410a20ed2aa71a43e0)? The bug is not observed on 1.23.0.

__Steps to reproduce:__

```
import pandas as pd
import numpy as np
from influxdb_client import InfluxDBClient
from influxdb_client.client.write_api import SYNCHRONOUS

client = InfluxDBClient(url="http://localhost:8086", token="...", org="...")

write_api = client.write_api(write_options=SYNCHRONOUS)

df = pd.DataFrame({
    'a': np.arange(0.,3.),
    'b': [0., np.nan, 1.],
}).set_index(pd.to_datetime(['2021-01-01 0:00','2021-01-01 0:01','2021-01-01 0:02']))

write_api.write(
    bucket='test',
    record=df,
    data_frame_measurement_name='test',
)
```

__Expected behavior:__

Data points successfully written to database.

__Actual behavior:__

Exception is raised:

```
ApiException: (400)
Reason: Bad Request
HTTP response headers: HTTPHeaderDict({'Content-Type': 'application/json; charset=utf-8', 'X-Platform-Error-Code': 'invalid', 'Date': 'Mon, 06 Dec 2021 17:00:47 GMT', 'Content-Length': '128'})
HTTP response body: {"code":"invalid","message":"unable to parse 'test a=1.0,_EMPTY_LINE_PROTOCOL_PART_ 1609459260000000000': invalid field format"}
```

__Specifications:__
 - Client Version: 1.24.0
 - InfluxDB Version: 2.0.7
 - Platform: linux/windows


Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c1cea4..3be0491 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ### Bug Fixes
 1. [#375](https://github.com/influxdata/influxdb-client-python/pull/375): Construct `InfluxDBError` without HTTP response 
+1. [#378](https://github.com/influxdata/influxdb-client-python/pull/378): Correct serialization DataFrame with nan values [DataFrame]
 
 ### CI
 1. [#370](https://github.com/influxdata/influxdb-client-python/pull/370): Add Python 3.10 to CI builds
diff --git a/influxdb_client/client/write/dataframe_serializer.py b/influxdb_client/client/write/dataframe_serializer.py
index 4d83e8d..95ad09b 100644
--- a/influxdb_client/client/write/dataframe_serializer.py
+++ b/influxdb_client/client/write/dataframe_serializer.py
@@ -27,9 +27,6 @@ def _any_not_nan(p, indexes):
     return any(map(lambda x: _not_nan(p[x]), indexes))
 
 
-_EMPTY_EXPRESSION = "_EMPTY_LINE_PROTOCOL_PART_"
-
-
 class DataframeSerializer:
     """Serialize DataFrame into LineProtocols."""
 
@@ -180,15 +177,13 @@ class DataframeSerializer:
                 field_value = f'{sep}{key_format}={{{val_format}}}'
             elif issubclass(value.type, np.floating):
                 if null_columns[index]:
-                    field_value = f"""{{
-                    "{sep}{_EMPTY_EXPRESSION}" if math.isnan({val_format}) else f"{sep}{key_format}={{{val_format}}}"
-                    }}"""
+                    field_value = f"""{{"" if math.isnan({val_format}) else f"{sep}{key_format}={{{val_format}}}"}}"""
                 else:
                     field_value = f'{sep}{key_format}={{{val_format}}}'
             else:
                 if null_columns[index]:
                     field_value = f"""{{
-                            '{sep}{_EMPTY_EXPRESSION}' if type({val_format}) == float and math.isnan({val_format}) else
+                            '' if type({val_format}) == float and math.isnan({val_format}) else
                             f'{sep}{key_format}="{{str({val_format}).translate(_ESCAPE_STRING)}}"'
                         }}"""
                 else:
@@ -249,7 +244,7 @@ class DataframeSerializer:
         if self.first_field_maybe_null:
             # When the first field is null (None/NaN), we'll have
             # a spurious leading comma which needs to be removed.
-            lp = (re.sub(f",{_EMPTY_EXPRESSION}|{_EMPTY_EXPRESSION},|{_EMPTY_EXPRESSION}", '', self.f(p))
+            lp = (re.sub('^(( |[^ ])* ),([a-zA-Z])(.*)', '\\1\\3\\4', self.f(p))
                   for p in filter(lambda x: _any_not_nan(x, self.field_indexes), _itertuples(chunk)))
             return list(lp)
         else:


Test patch:
diff --git a/tests/test_WriteApiDataFrame.py b/tests/test_WriteApiDataFrame.py
index ab1feb2..3e2d91c 100644
--- a/tests/test_WriteApiDataFrame.py
+++ b/tests/test_WriteApiDataFrame.py
@@ -396,6 +396,23 @@ Date;Entry Type;Value;Currencs;Category;Person;Account;Counter Account;Group;Not
         self.assertEqual("bookings,Account=Testaccount,Category=Testcategory,Entry\\ Type=Expense Currencs=\"EUR\",Note=\"This, works\",Recurring=\"no\",Value=-1.0 1538352000000000000", points[0])
         self.assertEqual("bookings,Account=Testaccount,Category=Testcategory,Entry\\ Type=Expense Currencs=\"EUR\",Note=\"This , works not\",Recurring=\"no\",Value=-1.0 1538438400000000000", points[1])
 
+    def test_without_tags_and_fields_with_nan(self):
+        from influxdb_client.extras import pd, np
+
+        df = pd.DataFrame({
+            'a': np.arange(0., 3.),
+            'b': [0., np.nan, 1.],
+        }).set_index(pd.to_datetime(['2021-01-01 0:00', '2021-01-01 0:01', '2021-01-01 0:02']))
+
+        points = data_frame_to_list_of_points(data_frame=df,
+                                              data_frame_measurement_name="test",
+                                              point_settings=PointSettings())
+
+        self.assertEqual(3, len(points))
+        self.assertEqual("test a=0.0,b=0.0 1609459200000000000", points[0])
+        self.assertEqual("test a=1.0 1609459260000000000", points[1])
+        self.assertEqual("test a=2.0,b=1.0 1609459320000000000", points[2])
+
 
 class DataSerializerChunksTest(unittest.TestCase):
     def test_chunks(self):