Skip to content
This repository was archived by the owner on Oct 29, 2024. It is now read-only.

Commit fe46aa0

Browse files
authored
Merge branch 'master' into master
2 parents 4e576a5 + c300105 commit fe46aa0

6 files changed

Lines changed: 66 additions & 14 deletions

File tree

examples/tutorial_pandas.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ def main(host='localhost', port=8086):
1212
user = 'root'
1313
password = 'root'
1414
dbname = 'demo'
15-
# Temporarily avoid line protocol time conversion issues #412, #426, #431.
1615
protocol = 'json'
1716

1817
client = DataFrameClient(host, port, user, password, dbname)

influxdb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818
]
1919

2020

21-
__version__ = '5.0.0'
21+
__version__ = '5.1.0'

influxdb/_dataframe_client.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def _convert_dataframe_to_json(dataframe,
236236
field_columns = list(
237237
set(dataframe.columns).difference(set(tag_columns)))
238238

239-
dataframe.index = dataframe.index.to_datetime()
239+
dataframe.index = pd.to_datetime(dataframe.index)
240240
if dataframe.index.tzinfo is None:
241241
dataframe.index = dataframe.index.tz_localize('UTC')
242242

@@ -288,6 +288,8 @@ def _convert_dataframe_to_lines(self,
288288
raise TypeError('Must be DataFrame with DatetimeIndex or '
289289
'PeriodIndex.')
290290

291+
dataframe = dataframe.rename(
292+
columns={item: _escape_tag(item) for item in dataframe.columns})
291293
# Create a Series of columns for easier indexing
292294
column_series = pd.Series(dataframe.columns)
293295

@@ -363,16 +365,18 @@ def _convert_dataframe_to_lines(self,
363365

364366
# Make an array of formatted field keys and values
365367
field_df = dataframe[field_columns]
368+
# Keep the positions where Null values are found
369+
mask_null = field_df.isnull().values
366370

367371
field_df = self._stringify_dataframe(field_df,
368372
numeric_precision,
369373
datatype='field')
370374

371-
def format_line(line):
372-
line = line[~line.isnull()] # drop None entries
373-
return ",".join((line.index + '=' + line.values))
374-
375-
fields = field_df.apply(format_line, axis=1)
375+
field_df = (field_df.columns.values + '=').tolist() + field_df
376+
field_df[field_df.columns[1:]] = ',' + field_df[
377+
field_df.columns[1:]]
378+
field_df = field_df.where(~mask_null, '') # drop Null entries
379+
fields = field_df.sum(axis=1)
376380
del field_df
377381

378382
# Generate line protocol string
@@ -386,9 +390,6 @@ def _stringify_dataframe(dframe, numeric_precision, datatype='field'):
386390
# Prevent modification of input dataframe
387391
dframe = dframe.copy()
388392

389-
# Keep the positions where Null values are found
390-
mask_null = dframe.isnull().values
391-
392393
# Find int and string columns for field-type data
393394
int_columns = dframe.select_dtypes(include=['integer']).columns
394395
string_columns = dframe.select_dtypes(include=['object']).columns
@@ -433,7 +434,6 @@ def _stringify_dataframe(dframe, numeric_precision, datatype='field'):
433434

434435
dframe.columns = dframe.columns.astype(str)
435436

436-
dframe = dframe.where(~mask_null, None)
437437
return dframe
438438

439439
def _datetime_to_epoch(self, datetime, time_precision='s'):

influxdb/client.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ class InfluxDBClient(object):
5959
:type udp_port: int
6060
:param proxies: HTTP(S) proxy to use for Requests, defaults to {}
6161
:type proxies: dict
62+
:param path: path of InfluxDB on the server to connect, defaults to ''
63+
:type path: str
6264
"""
6365

6466
def __init__(self,
@@ -75,6 +77,7 @@ def __init__(self,
7577
udp_port=4444,
7678
proxies=None,
7779
pool_size=10,
80+
path='',
7881
):
7982
"""Construct a new InfluxDBClient object."""
8083
self.__host = host
@@ -98,6 +101,13 @@ def __init__(self,
98101
if use_udp:
99102
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
100103

104+
if not path:
105+
self.__path = ''
106+
elif path[0] == '/':
107+
self.__path = path
108+
else:
109+
self.__path = '/' + path
110+
101111
self._scheme = "http"
102112

103113
if ssl is True:
@@ -110,10 +120,11 @@ def __init__(self,
110120
else:
111121
self._proxies = proxies
112122

113-
self.__baseurl = "{0}://{1}:{2}".format(
123+
self.__baseurl = "{0}://{1}:{2}{3}".format(
114124
self._scheme,
115125
self._host,
116-
self._port)
126+
self._port,
127+
self._path)
117128

118129
self._headers = {
119130
'Content-Type': 'application/json',
@@ -132,6 +143,10 @@ def _host(self):
132143
def _port(self):
133144
return self.__port
134145

146+
@property
147+
def _path(self):
148+
return self.__path
149+
135150
@property
136151
def _udp_port(self):
137152
return self.__udp_port

influxdb/tests/client_test.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@ def test_scheme(self):
109109
)
110110
self.assertEqual('https://host:8086', cli._baseurl)
111111

112+
cli = InfluxDBClient(
113+
'host', 8086, 'username', 'password', 'database', ssl=True,
114+
path="somepath"
115+
)
116+
self.assertEqual('https://host:8086/somepath', cli._baseurl)
117+
118+
cli = InfluxDBClient(
119+
'host', 8086, 'username', 'password', 'database', ssl=True,
120+
path=None
121+
)
122+
self.assertEqual('https://host:8086', cli._baseurl)
123+
124+
cli = InfluxDBClient(
125+
'host', 8086, 'username', 'password', 'database', ssl=True,
126+
path="/somepath"
127+
)
128+
self.assertEqual('https://host:8086/somepath', cli._baseurl)
129+
112130
def test_dsn(self):
113131
"""Set up the test datasource name for TestInfluxDBClient object."""
114132
cli = InfluxDBClient.from_dsn('influxdb://192.168.0.1:1886')

influxdb/tests/dataframe_client_test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,26 @@ def test_dataframe_write_points_with_whitespace_measurement(self):
8181
cli.write_points(dataframe, 'meas with space')
8282
self.assertEqual(m.last_request.body, expected)
8383

84+
def test_dataframe_write_points_with_whitespace_in_column_names(self):
85+
"""write_points should escape white space in column names."""
86+
now = pd.Timestamp('1970-01-01 00:00+00:00')
87+
dataframe = pd.DataFrame(data=[["1", 1, 1.0], ["2", 2, 2.0]],
88+
index=[now, now + timedelta(hours=1)],
89+
columns=["column one", "column two",
90+
"column three"])
91+
expected = (
92+
b"foo column\\ one=\"1\",column\\ two=1i,column\\ three=1.0 0\n"
93+
b"foo column\\ one=\"2\",column\\ two=2i,column\\ three=2.0 "
94+
b"3600000000000\n"
95+
)
96+
with requests_mock.Mocker() as m:
97+
m.register_uri(requests_mock.POST,
98+
"http://localhost:8086/write",
99+
status_code=204)
100+
cli = DataFrameClient(database='db')
101+
cli.write_points(dataframe, 'foo')
102+
self.assertEqual(m.last_request.body, expected)
103+
84104
def test_write_points_from_dataframe_with_none(self):
85105
"""Test write points from df in TestDataFrameClient object."""
86106
now = pd.Timestamp('1970-01-01 00:00+00:00')

0 commit comments

Comments
 (0)