influxdb3-python 0.9.0__tar.gz → 0.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- influxdb3_python-0.11.0/Examples/batching_example.py +141 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/PKG-INFO +19 -7
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/README.md +6 -5
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb3_python.egg-info/PKG-INFO +19 -7
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/__init__.py +3 -2
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/query/query_api.py +5 -1
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/version.py +1 -1
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/write_api.py +2 -1
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/setup.py +1 -0
- influxdb3_python-0.11.0/tests/test_influxdb_client_3_integration.py +186 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_polars.py +29 -1
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_query.py +14 -0
- influxdb3_python-0.9.0/Examples/batching_example.py +0 -114
- influxdb3_python-0.9.0/tests/test_influxdb_client_3_integration.py +0 -74
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/cloud_dedicated_query.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/cloud_dedicated_write.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/config.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/flight_options_example.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/handle_http_error.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/pandas_write.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/Examples/query_type.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/LICENSE +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb3_python.egg-info/SOURCES.txt +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb3_python.egg-info/dependency_links.txt +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb3_python.egg-info/requires.txt +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb3_python.egg-info/top_level.txt +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/py.typed +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/query/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/read_file.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/_sync/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/_sync/api_client.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/_sync/rest.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/_base.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/exceptions.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/influxdb_client.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/logging_handler.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/util/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/util/date_utils.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/util/date_utils_pandas.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/util/helpers.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/util/multiprocessing_helper.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/warnings.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/write/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/write/dataframe_serializer.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/write/point.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/write/retry.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/configuration.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/domain/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/domain/write_precision.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/extras.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/rest.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/service/__init__.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/service/_base_service.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/service/signin_service.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/service/signout_service.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/service/write_service.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/setup.cfg +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_api_client.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_dataframe_serializer.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_date_helper.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_deep_merge.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_influxdb_client_3.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_merge_options.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_point.py +0 -0
- {influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/tests/test_write_file.py +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import random
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from bson import ObjectId
|
|
6
|
+
|
|
7
|
+
import influxdb_client_3 as InfluxDBClient3
|
|
8
|
+
from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions, InfluxDBError
|
|
9
|
+
|
|
10
|
+
from config import Config
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BatchingCallback(object):
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.write_status_msg = None
|
|
17
|
+
self.write_count = 0
|
|
18
|
+
self.retry_count = 0
|
|
19
|
+
self.start = time.time_ns()
|
|
20
|
+
|
|
21
|
+
def success(self, conf, data: str):
|
|
22
|
+
print(f"Written batch: {conf}, data: {data}")
|
|
23
|
+
self.write_count += 1
|
|
24
|
+
self.write_status_msg = f"SUCCESS: {self.write_count} writes"
|
|
25
|
+
|
|
26
|
+
def error(self, conf, data: str, exception: InfluxDBError):
|
|
27
|
+
print(f"Cannot write batch: {conf}, data: {data} due: {exception}")
|
|
28
|
+
self.write_status_msg = f"FAILURE - cause: {exception}"
|
|
29
|
+
|
|
30
|
+
def retry(self, conf, data: str, exception: InfluxDBError):
|
|
31
|
+
print(f"Retryable error occurs for batch: {conf}, data: {data} retry: {exception}")
|
|
32
|
+
self.retry_count += 1
|
|
33
|
+
|
|
34
|
+
def elapsed(self) -> int:
|
|
35
|
+
return time.time_ns() - self.start
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main() -> None:
|
|
39
|
+
conf = Config()
|
|
40
|
+
|
|
41
|
+
# Creating 5.000 gatewayId values as MongoDB ObjectIDs
|
|
42
|
+
gatewayIds = [ObjectId() for x in range(0, 100)]
|
|
43
|
+
|
|
44
|
+
# Setting decimal precision to 2
|
|
45
|
+
precision = 2
|
|
46
|
+
|
|
47
|
+
# Setting timestamp for first sensor reading
|
|
48
|
+
sample_window_days = 7
|
|
49
|
+
now = datetime.datetime.now()
|
|
50
|
+
now = now - datetime.timedelta(days=sample_window_days)
|
|
51
|
+
target_sample_count = sample_window_days * 24 * 60 * 6
|
|
52
|
+
|
|
53
|
+
callback = BatchingCallback()
|
|
54
|
+
|
|
55
|
+
write_options = WriteOptions(batch_size=5_000,
|
|
56
|
+
flush_interval=10_000,
|
|
57
|
+
jitter_interval=2_000,
|
|
58
|
+
retry_interval=5_000,
|
|
59
|
+
max_retries=5,
|
|
60
|
+
max_retry_delay=30_000,
|
|
61
|
+
max_close_wait=600_000,
|
|
62
|
+
exponential_base=2)
|
|
63
|
+
|
|
64
|
+
wco = write_client_options(success_callback=callback.success,
|
|
65
|
+
error_callback=callback.error,
|
|
66
|
+
retry_callback=callback.retry,
|
|
67
|
+
write_options=write_options)
|
|
68
|
+
|
|
69
|
+
# Opening InfluxDB client with a batch size of 5k points or flush interval
|
|
70
|
+
# of 10k ms and gzip compression
|
|
71
|
+
with InfluxDBClient3.InfluxDBClient3(token=conf.token,
|
|
72
|
+
host=conf.host,
|
|
73
|
+
org=conf.org,
|
|
74
|
+
database=conf.database,
|
|
75
|
+
enable_gzip=True,
|
|
76
|
+
write_client_options=wco) as _client:
|
|
77
|
+
# Creating iterator for one hour worth of data (6 sensor readings per
|
|
78
|
+
# minute)
|
|
79
|
+
print(f"Writing {target_sample_count} data points.")
|
|
80
|
+
for i in range(0, target_sample_count):
|
|
81
|
+
# Adding 10 seconds to timestamp of previous sensor reading
|
|
82
|
+
now = now + datetime.timedelta(seconds=10)
|
|
83
|
+
# Iterating over gateways
|
|
84
|
+
for gatewayId in gatewayIds:
|
|
85
|
+
# Creating random test data for 12 fields to be stored in
|
|
86
|
+
# timeseries database
|
|
87
|
+
bcW = random.randrange(1501)
|
|
88
|
+
bcWh = round(random.uniform(0, 4.17), precision)
|
|
89
|
+
bdW = random.randrange(71)
|
|
90
|
+
bdWh = round(random.uniform(0, 0.12), precision)
|
|
91
|
+
cPvWh = round(random.uniform(0.51, 27.78), precision)
|
|
92
|
+
cW = random.randrange(172, 10001)
|
|
93
|
+
cWh = round(random.uniform(0.51, 27.78), precision)
|
|
94
|
+
eWh = round(random.uniform(0, 41.67), precision)
|
|
95
|
+
iWh = round(random.uniform(0, 16.67), precision)
|
|
96
|
+
pW = random.randrange(209, 20001)
|
|
97
|
+
pWh = round(random.uniform(0.58, 55.56), precision)
|
|
98
|
+
scWh = round(random.uniform(0.58, 55.56), precision)
|
|
99
|
+
# Creating point to be ingested into InfluxDB
|
|
100
|
+
p = InfluxDBClient3.Point("stream").tag(
|
|
101
|
+
"gatewayId",
|
|
102
|
+
str(gatewayId)).field(
|
|
103
|
+
"bcW",
|
|
104
|
+
bcW).field(
|
|
105
|
+
"bcWh",
|
|
106
|
+
bcWh).field(
|
|
107
|
+
"bdW",
|
|
108
|
+
bdW).field(
|
|
109
|
+
"bdWh",
|
|
110
|
+
bdWh).field(
|
|
111
|
+
"cPvWh",
|
|
112
|
+
cPvWh).field(
|
|
113
|
+
"cW",
|
|
114
|
+
cW).field(
|
|
115
|
+
"cWh",
|
|
116
|
+
cWh).field(
|
|
117
|
+
"eWh",
|
|
118
|
+
eWh).field(
|
|
119
|
+
"iWh",
|
|
120
|
+
iWh).field(
|
|
121
|
+
"pW",
|
|
122
|
+
pW).field(
|
|
123
|
+
"pWh",
|
|
124
|
+
pWh).field(
|
|
125
|
+
"scWh",
|
|
126
|
+
scWh).time(
|
|
127
|
+
now.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
|
128
|
+
WritePrecision.S)
|
|
129
|
+
|
|
130
|
+
# Writing point (InfluxDB automatically batches writes into sets of
|
|
131
|
+
# 5k points)
|
|
132
|
+
_client.write(record=p)
|
|
133
|
+
|
|
134
|
+
print(callback.write_status_msg)
|
|
135
|
+
print(f"Write retries: {callback.retry_count}")
|
|
136
|
+
print(f"Wrote {target_sample_count} data points.")
|
|
137
|
+
print(f"Elapsed time ms: {int(callback.elapsed() / 1_000_000)}")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: influxdb3-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Community Python client for InfluxDB 3.0
|
|
5
5
|
Home-page: https://github.com/InfluxCommunity/influxdb3-python
|
|
6
6
|
Author: InfluxData
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
17
|
Requires-Python: >=3.8
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
18
19
|
License-File: LICENSE
|
|
@@ -32,6 +33,16 @@ Requires-Dist: polars; extra == "dataframe"
|
|
|
32
33
|
Provides-Extra: test
|
|
33
34
|
Requires-Dist: pytest; extra == "test"
|
|
34
35
|
Requires-Dist: pytest-cov; extra == "test"
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: author-email
|
|
38
|
+
Dynamic: classifier
|
|
39
|
+
Dynamic: description
|
|
40
|
+
Dynamic: description-content-type
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: provides-extra
|
|
43
|
+
Dynamic: requires-dist
|
|
44
|
+
Dynamic: requires-python
|
|
45
|
+
Dynamic: summary
|
|
35
46
|
|
|
36
47
|
<p align="center">
|
|
37
48
|
<img src="https://github.com/InfluxCommunity/influxdb3-python/blob/main/python-logo.png?raw=true" alt="Your Image" width="150px">
|
|
@@ -127,7 +138,11 @@ from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions
|
|
|
127
138
|
|
|
128
139
|
class BatchingCallback(object):
|
|
129
140
|
|
|
141
|
+
def __init__(self):
|
|
142
|
+
self.write_count = 0
|
|
143
|
+
|
|
130
144
|
def success(self, conf, data: str):
|
|
145
|
+
self.write_count += 1
|
|
131
146
|
print(f"Written batch: {conf}, data: {data}")
|
|
132
147
|
|
|
133
148
|
def error(self, conf, data: str, exception: InfluxDBError):
|
|
@@ -138,7 +153,7 @@ class BatchingCallback(object):
|
|
|
138
153
|
|
|
139
154
|
callback = BatchingCallback()
|
|
140
155
|
|
|
141
|
-
write_options = WriteOptions(batch_size=
|
|
156
|
+
write_options = WriteOptions(batch_size=100,
|
|
142
157
|
flush_interval=10_000,
|
|
143
158
|
jitter_interval=2_000,
|
|
144
159
|
retry_interval=5_000,
|
|
@@ -163,10 +178,7 @@ with InfluxDBClient3.InfluxDBClient3(
|
|
|
163
178
|
file='./out.csv',
|
|
164
179
|
timestamp_column='time', tag_columns=["provider", "machineID"])
|
|
165
180
|
|
|
166
|
-
|
|
167
|
-
file='./out.json',
|
|
168
|
-
timestamp_column='time', tag_columns=["provider", "machineID"], date_unit='ns' )
|
|
169
|
-
|
|
181
|
+
print(f'DONE writing from csv in {callback.write_count} batch(es)')
|
|
170
182
|
|
|
171
183
|
```
|
|
172
184
|
|
|
@@ -92,7 +92,11 @@ from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions
|
|
|
92
92
|
|
|
93
93
|
class BatchingCallback(object):
|
|
94
94
|
|
|
95
|
+
def __init__(self):
|
|
96
|
+
self.write_count = 0
|
|
97
|
+
|
|
95
98
|
def success(self, conf, data: str):
|
|
99
|
+
self.write_count += 1
|
|
96
100
|
print(f"Written batch: {conf}, data: {data}")
|
|
97
101
|
|
|
98
102
|
def error(self, conf, data: str, exception: InfluxDBError):
|
|
@@ -103,7 +107,7 @@ class BatchingCallback(object):
|
|
|
103
107
|
|
|
104
108
|
callback = BatchingCallback()
|
|
105
109
|
|
|
106
|
-
write_options = WriteOptions(batch_size=
|
|
110
|
+
write_options = WriteOptions(batch_size=100,
|
|
107
111
|
flush_interval=10_000,
|
|
108
112
|
jitter_interval=2_000,
|
|
109
113
|
retry_interval=5_000,
|
|
@@ -128,10 +132,7 @@ with InfluxDBClient3.InfluxDBClient3(
|
|
|
128
132
|
file='./out.csv',
|
|
129
133
|
timestamp_column='time', tag_columns=["provider", "machineID"])
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
file='./out.json',
|
|
133
|
-
timestamp_column='time', tag_columns=["provider", "machineID"], date_unit='ns' )
|
|
134
|
-
|
|
135
|
+
print(f'DONE writing from csv in {callback.write_count} batch(es)')
|
|
135
136
|
|
|
136
137
|
```
|
|
137
138
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: influxdb3-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Community Python client for InfluxDB 3.0
|
|
5
5
|
Home-page: https://github.com/InfluxCommunity/influxdb3-python
|
|
6
6
|
Author: InfluxData
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
17
|
Requires-Python: >=3.8
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
18
19
|
License-File: LICENSE
|
|
@@ -32,6 +33,16 @@ Requires-Dist: polars; extra == "dataframe"
|
|
|
32
33
|
Provides-Extra: test
|
|
33
34
|
Requires-Dist: pytest; extra == "test"
|
|
34
35
|
Requires-Dist: pytest-cov; extra == "test"
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: author-email
|
|
38
|
+
Dynamic: classifier
|
|
39
|
+
Dynamic: description
|
|
40
|
+
Dynamic: description-content-type
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: provides-extra
|
|
43
|
+
Dynamic: requires-dist
|
|
44
|
+
Dynamic: requires-python
|
|
45
|
+
Dynamic: summary
|
|
35
46
|
|
|
36
47
|
<p align="center">
|
|
37
48
|
<img src="https://github.com/InfluxCommunity/influxdb3-python/blob/main/python-logo.png?raw=true" alt="Your Image" width="150px">
|
|
@@ -127,7 +138,11 @@ from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions
|
|
|
127
138
|
|
|
128
139
|
class BatchingCallback(object):
|
|
129
140
|
|
|
141
|
+
def __init__(self):
|
|
142
|
+
self.write_count = 0
|
|
143
|
+
|
|
130
144
|
def success(self, conf, data: str):
|
|
145
|
+
self.write_count += 1
|
|
131
146
|
print(f"Written batch: {conf}, data: {data}")
|
|
132
147
|
|
|
133
148
|
def error(self, conf, data: str, exception: InfluxDBError):
|
|
@@ -138,7 +153,7 @@ class BatchingCallback(object):
|
|
|
138
153
|
|
|
139
154
|
callback = BatchingCallback()
|
|
140
155
|
|
|
141
|
-
write_options = WriteOptions(batch_size=
|
|
156
|
+
write_options = WriteOptions(batch_size=100,
|
|
142
157
|
flush_interval=10_000,
|
|
143
158
|
jitter_interval=2_000,
|
|
144
159
|
retry_interval=5_000,
|
|
@@ -163,10 +178,7 @@ with InfluxDBClient3.InfluxDBClient3(
|
|
|
163
178
|
file='./out.csv',
|
|
164
179
|
timestamp_column='time', tag_columns=["provider", "machineID"])
|
|
165
180
|
|
|
166
|
-
|
|
167
|
-
file='./out.json',
|
|
168
|
-
timestamp_column='time', tag_columns=["provider", "machineID"], date_unit='ns' )
|
|
169
|
-
|
|
181
|
+
print(f'DONE writing from csv in {callback.write_count} batch(es)')
|
|
170
182
|
|
|
171
183
|
```
|
|
172
184
|
|
|
@@ -121,7 +121,7 @@ class InfluxDBClient3:
|
|
|
121
121
|
possible.
|
|
122
122
|
:key str proxy: Set this to configure the http proxy to be used (ex. http://localhost:3128)
|
|
123
123
|
:key str proxy_headers: A dictionary containing headers that will be sent to the proxy. Could be used for proxy
|
|
124
|
-
authentication.
|
|
124
|
+
authentication. (Applies to Write API only)
|
|
125
125
|
:key int connection_pool_maxsize: Number of connections to save that can be reused by urllib3.
|
|
126
126
|
Defaults to "multiprocessing.cpu_count() * 5".
|
|
127
127
|
:key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests
|
|
@@ -166,7 +166,8 @@ class InfluxDBClient3:
|
|
|
166
166
|
else:
|
|
167
167
|
connection_string = f"grpc+tcp://{hostname}:{port}"
|
|
168
168
|
self._query_api = _QueryApi(connection_string=connection_string, token=token,
|
|
169
|
-
flight_client_options=flight_client_options
|
|
169
|
+
flight_client_options=flight_client_options,
|
|
170
|
+
proxy=kwargs.get("proxy", None))
|
|
170
171
|
|
|
171
172
|
def write(self, record=None, database=None, **kwargs):
|
|
172
173
|
"""
|
|
@@ -25,7 +25,8 @@ class QueryApi(object):
|
|
|
25
25
|
def __init__(self,
|
|
26
26
|
connection_string,
|
|
27
27
|
token,
|
|
28
|
-
flight_client_options
|
|
28
|
+
flight_client_options,
|
|
29
|
+
proxy=None) -> None:
|
|
29
30
|
"""
|
|
30
31
|
Initialize defaults.
|
|
31
32
|
|
|
@@ -35,9 +36,12 @@ class QueryApi(object):
|
|
|
35
36
|
"""
|
|
36
37
|
self._token = token
|
|
37
38
|
self._flight_client_options = flight_client_options or {}
|
|
39
|
+
self._proxy = proxy
|
|
38
40
|
self._flight_client_options["generic_options"] = [
|
|
39
41
|
("grpc.secondary_user_agent", USER_AGENT)
|
|
40
42
|
]
|
|
43
|
+
if self._proxy:
|
|
44
|
+
self._flight_client_options["generic_options"].append(("grpc.http_proxy", self._proxy))
|
|
41
45
|
self._flight_client = FlightClient(connection_string, **self._flight_client_options)
|
|
42
46
|
|
|
43
47
|
def query(self, query: str, language: str, mode: str, database: str, **kwargs):
|
|
@@ -461,7 +461,8 @@ You can use native asynchronous version of the client:
|
|
|
461
461
|
precision, **kwargs)
|
|
462
462
|
|
|
463
463
|
elif 'polars' in str(type(data)):
|
|
464
|
-
from influxdb_client_3.write_client.client.write.
|
|
464
|
+
from influxdb_client_3.write_client.client.write.polars_dataframe_serializer \
|
|
465
|
+
import PolarsDataframeSerializer
|
|
465
466
|
serializer = PolarsDataframeSerializer(data,
|
|
466
467
|
self._point_settings, precision,
|
|
467
468
|
self._write_options.batch_size, **kwargs)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import random
|
|
4
|
+
import string
|
|
5
|
+
import time
|
|
6
|
+
import unittest
|
|
7
|
+
|
|
8
|
+
import pyarrow
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from influxdb_client_3 import InfluxDBClient3, InfluxDBError, write_client_options, WriteOptions
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def random_hex(len=6):
|
|
15
|
+
return ''.join(random.choice(string.hexdigits) for i in range(len))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.integration
|
|
19
|
+
@pytest.mark.skipif(
|
|
20
|
+
not all(
|
|
21
|
+
[
|
|
22
|
+
os.getenv('TESTING_INFLUXDB_URL'),
|
|
23
|
+
os.getenv('TESTING_INFLUXDB_TOKEN'),
|
|
24
|
+
os.getenv('TESTING_INFLUXDB_DATABASE'),
|
|
25
|
+
]
|
|
26
|
+
),
|
|
27
|
+
reason="Integration test environment variables not set.",
|
|
28
|
+
)
|
|
29
|
+
class TestInfluxDBClient3Integration(unittest.TestCase):
|
|
30
|
+
|
|
31
|
+
@pytest.fixture(autouse=True)
|
|
32
|
+
def inject_fixtures(self, caplog):
|
|
33
|
+
self._caplog = caplog
|
|
34
|
+
|
|
35
|
+
def setUp(self):
|
|
36
|
+
self.host = os.getenv('TESTING_INFLUXDB_URL')
|
|
37
|
+
self.token = os.getenv('TESTING_INFLUXDB_TOKEN')
|
|
38
|
+
self.database = os.getenv('TESTING_INFLUXDB_DATABASE')
|
|
39
|
+
self.client = InfluxDBClient3(host=self.host, database=self.database, token=self.token)
|
|
40
|
+
|
|
41
|
+
def tearDown(self):
|
|
42
|
+
self._caplog.clear()
|
|
43
|
+
self._caplog.set_level(logging.ERROR)
|
|
44
|
+
if self.client:
|
|
45
|
+
self.client.close()
|
|
46
|
+
|
|
47
|
+
def test_write_and_query(self):
|
|
48
|
+
test_id = time.time_ns()
|
|
49
|
+
self.client.write(f"integration_test_python,type=used value=123.0,test_id={test_id}i")
|
|
50
|
+
|
|
51
|
+
sql = 'SELECT * FROM integration_test_python where type=$type and test_id=$test_id'
|
|
52
|
+
|
|
53
|
+
df = self.client.query(sql, mode="pandas", query_parameters={'type': 'used', 'test_id': test_id})
|
|
54
|
+
|
|
55
|
+
self.assertIsNotNone(df)
|
|
56
|
+
self.assertEqual(1, len(df))
|
|
57
|
+
self.assertEqual(test_id, df['test_id'][0])
|
|
58
|
+
self.assertEqual(123.0, df['value'][0])
|
|
59
|
+
|
|
60
|
+
def test_auth_error_token(self):
|
|
61
|
+
self.client = InfluxDBClient3(host=self.host, database=self.database, token='fake token')
|
|
62
|
+
test_id = time.time_ns()
|
|
63
|
+
with self.assertRaises(InfluxDBError) as err:
|
|
64
|
+
self.client.write(f"integration_test_python,type=used value=123.0,test_id={test_id}i")
|
|
65
|
+
self.assertEqual('unauthorized access', err.exception.message) # Cloud
|
|
66
|
+
|
|
67
|
+
def test_auth_error_auth_scheme(self):
|
|
68
|
+
self.client = InfluxDBClient3(host=self.host, database=self.database, token=self.token, auth_scheme='Any')
|
|
69
|
+
test_id = time.time_ns()
|
|
70
|
+
with self.assertRaises(InfluxDBError) as err:
|
|
71
|
+
self.client.write(f"integration_test_python,type=used value=123.0,test_id={test_id}i")
|
|
72
|
+
self.assertEqual('unauthorized access', err.exception.message) # Cloud
|
|
73
|
+
|
|
74
|
+
def test_error_headers(self):
|
|
75
|
+
self.client = InfluxDBClient3(host=self.host, database=self.database, token=self.token)
|
|
76
|
+
with self.assertRaises(InfluxDBError) as err:
|
|
77
|
+
self.client.write("integration_test_python,type=used value=123.0,test_id=")
|
|
78
|
+
self.assertIn("Could not parse entire line. Found trailing content:", err.exception.message)
|
|
79
|
+
headers = err.exception.getheaders()
|
|
80
|
+
try:
|
|
81
|
+
self.assertIsNotNone(headers)
|
|
82
|
+
self.assertRegex(headers['trace-id'], '[0-9a-f]{16}')
|
|
83
|
+
self.assertEqual('false', headers['trace-sampled'])
|
|
84
|
+
self.assertIsNotNone(headers['Strict-Transport-Security'])
|
|
85
|
+
self.assertRegex(headers['X-Influxdb-Request-ID'], '[0-9a-f]+')
|
|
86
|
+
self.assertIsNotNone(headers['X-Influxdb-Build'])
|
|
87
|
+
except KeyError as ke:
|
|
88
|
+
self.fail(f'Header {ke} not found')
|
|
89
|
+
|
|
90
|
+
def test_batch_write_callbacks(self):
|
|
91
|
+
write_success = False
|
|
92
|
+
write_error = False
|
|
93
|
+
write_count = 0
|
|
94
|
+
|
|
95
|
+
measurement = f'test{random_hex(6)}'
|
|
96
|
+
data_set_size = 40
|
|
97
|
+
batch_size = 10
|
|
98
|
+
|
|
99
|
+
def success(conf, data):
|
|
100
|
+
nonlocal write_success, write_count
|
|
101
|
+
write_success = True
|
|
102
|
+
write_count += 1
|
|
103
|
+
|
|
104
|
+
def error(conf, data, exception: InfluxDBError):
|
|
105
|
+
nonlocal write_error
|
|
106
|
+
write_error = True
|
|
107
|
+
|
|
108
|
+
w_opts = WriteOptions(
|
|
109
|
+
batch_size=batch_size,
|
|
110
|
+
flush_interval=1_000,
|
|
111
|
+
jitter_interval=500
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
wc_opts = write_client_options(
|
|
115
|
+
success_callback=success,
|
|
116
|
+
error_callback=error,
|
|
117
|
+
write_options=w_opts
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
now = time.time_ns()
|
|
121
|
+
with InfluxDBClient3(host=self.host,
|
|
122
|
+
database=self.database,
|
|
123
|
+
token=self.token,
|
|
124
|
+
write_client_options=wc_opts) as w_client:
|
|
125
|
+
|
|
126
|
+
for i in range(0, data_set_size):
|
|
127
|
+
w_client.write(f'{measurement},location=harfa val={i}i {now - (i * 1_000_000_000)}')
|
|
128
|
+
|
|
129
|
+
self.assertEqual(data_set_size / batch_size, write_count)
|
|
130
|
+
self.assertTrue(write_success)
|
|
131
|
+
self.assertFalse(write_error)
|
|
132
|
+
|
|
133
|
+
with InfluxDBClient3(host=self.host,
|
|
134
|
+
database=self.database,
|
|
135
|
+
token=self.token,
|
|
136
|
+
write_client_options=wc_opts) as r_client:
|
|
137
|
+
|
|
138
|
+
query = f"SELECT * FROM \"{measurement}\" WHERE time >= now() - interval '3 minute'"
|
|
139
|
+
reader: pyarrow.Table = r_client.query(query)
|
|
140
|
+
list_results = reader.to_pylist()
|
|
141
|
+
self.assertEqual(data_set_size, len(list_results))
|
|
142
|
+
|
|
143
|
+
def test_batch_write_closed(self):
|
|
144
|
+
|
|
145
|
+
self._caplog.set_level(logging.DEBUG)
|
|
146
|
+
# writing measurement for last cca 3hrs
|
|
147
|
+
# so repeat runs in that time frame could
|
|
148
|
+
# result in clashed result data if always
|
|
149
|
+
# using same measurement name
|
|
150
|
+
measurement = f'test{random_hex()}'
|
|
151
|
+
data_size = 10_000
|
|
152
|
+
w_opts = WriteOptions(
|
|
153
|
+
batch_size=100,
|
|
154
|
+
flush_interval=3_000,
|
|
155
|
+
jitter_interval=500
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
wc_opts = write_client_options(
|
|
159
|
+
write_options=w_opts
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
now = time.time_ns()
|
|
163
|
+
with InfluxDBClient3(host=self.host,
|
|
164
|
+
database=self.database,
|
|
165
|
+
token=self.token,
|
|
166
|
+
write_client_options=wc_opts,
|
|
167
|
+
debug=True) as w_client:
|
|
168
|
+
|
|
169
|
+
for i in range(0, data_size):
|
|
170
|
+
w_client.write(f'{measurement},location=harfa val={i}i {now - (i * 1_000_000_000)}')
|
|
171
|
+
|
|
172
|
+
lines = self._caplog.text.splitlines()
|
|
173
|
+
self.assertRegex(lines[len(lines) - 1], ".*the batching processor was disposed$")
|
|
174
|
+
|
|
175
|
+
logging.info("WRITING DONE")
|
|
176
|
+
with InfluxDBClient3(host=self.host,
|
|
177
|
+
database=self.database,
|
|
178
|
+
token=self.token,
|
|
179
|
+
write_client_options=wc_opts) as r_client:
|
|
180
|
+
|
|
181
|
+
logging.info("PREPARING QUERY")
|
|
182
|
+
|
|
183
|
+
query = f"SELECT * FROM \"{measurement}\" WHERE time >= now() - interval '3 hours'"
|
|
184
|
+
reader: pyarrow.Table = r_client.query(query, mode="")
|
|
185
|
+
list_results = reader.to_pylist()
|
|
186
|
+
self.assertEqual(data_size, len(list_results))
|
|
@@ -2,7 +2,7 @@ import importlib.util
|
|
|
2
2
|
import unittest
|
|
3
3
|
from unittest.mock import Mock
|
|
4
4
|
|
|
5
|
-
from influxdb_client_3 import PointSettings, InfluxDBClient3
|
|
5
|
+
from influxdb_client_3 import PointSettings, InfluxDBClient3, write_client_options, WriteOptions
|
|
6
6
|
from influxdb_client_3.write_client import WriteService
|
|
7
7
|
from influxdb_client_3.write_client.client.write.polars_dataframe_serializer import polars_data_frame_to_list_of_points
|
|
8
8
|
|
|
@@ -61,3 +61,31 @@ class TestWritePolars(unittest.TestCase):
|
|
|
61
61
|
actual = self.client._write_api._write_service.post_write.call_args[1]['body']
|
|
62
62
|
self.assertEqual(b'measurement temperature=22.4 1722470400000000000\n'
|
|
63
63
|
b'measurement temperature=21.8 1722474000000000000', actual)
|
|
64
|
+
|
|
65
|
+
def test_write_polars_batching(self):
|
|
66
|
+
import polars as pl
|
|
67
|
+
df = pl.DataFrame({
|
|
68
|
+
"time": pl.Series(["2024-08-01 00:00:00", "2024-08-01 01:00:00"]).str.to_datetime(time_unit='ns'),
|
|
69
|
+
"temperature": [22.4, 21.8],
|
|
70
|
+
})
|
|
71
|
+
self.client = InfluxDBClient3(
|
|
72
|
+
host="localhost",
|
|
73
|
+
org="my_org",
|
|
74
|
+
database="my_db",
|
|
75
|
+
token="my_token", write_client_options=write_client_options(
|
|
76
|
+
write_options=WriteOptions(batch_size=2)
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
self.client._write_api._write_options = WriteOptions(batch_size=2)
|
|
80
|
+
self.client._write_api._write_service = Mock(spec=WriteService)
|
|
81
|
+
|
|
82
|
+
self.client.write(
|
|
83
|
+
database="database",
|
|
84
|
+
record=df,
|
|
85
|
+
data_frame_measurement_name="measurement",
|
|
86
|
+
data_frame_timestamp_column="time",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
actual = self.client._write_api._write_service.post_write.call_args[1]['body']
|
|
90
|
+
self.assertEqual(b'measurement temperature=22.4 1722470400000000000\n'
|
|
91
|
+
b'measurement temperature=21.8 1722474000000000000', actual)
|
|
@@ -150,3 +150,17 @@ class TestQuery(unittest.TestCase):
|
|
|
150
150
|
)
|
|
151
151
|
|
|
152
152
|
mock_do_get.assert_called_once_with(expected_ticket, ANY)
|
|
153
|
+
|
|
154
|
+
def test_query_proxy_base_client(self):
|
|
155
|
+
test_proxy = "http://testproxy:5432"
|
|
156
|
+
client = InfluxDBClient3(
|
|
157
|
+
host="http://localhost:8443",
|
|
158
|
+
token="my-token",
|
|
159
|
+
org="my-org",
|
|
160
|
+
database="my-database",
|
|
161
|
+
proxy=test_proxy
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
assert client._query_api._proxy == test_proxy
|
|
165
|
+
assert ('grpc.http_proxy', test_proxy) in\
|
|
166
|
+
client._query_api._flight_client_options.get('generic_options')
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import random
|
|
3
|
-
|
|
4
|
-
from bson import ObjectId
|
|
5
|
-
|
|
6
|
-
import influxdb_client_3 as InfluxDBClient3
|
|
7
|
-
from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions, InfluxDBError
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class BatchingCallback(object):
|
|
11
|
-
|
|
12
|
-
def success(self, conf, data: str):
|
|
13
|
-
print(f"Written batch: {conf}, data: {data}")
|
|
14
|
-
|
|
15
|
-
def error(self, conf, data: str, exception: InfluxDBError):
|
|
16
|
-
print(f"Cannot write batch: {conf}, data: {data} due: {exception}")
|
|
17
|
-
|
|
18
|
-
def retry(self, conf, data: str, exception: InfluxDBError):
|
|
19
|
-
print(f"Retryable error occurs for batch: {conf}, data: {data} retry: {exception}")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# Creating 5.000 gatewayId values as MongoDB ObjectIDs
|
|
23
|
-
gatewayIds = [ObjectId() for x in range(0, 100)]
|
|
24
|
-
|
|
25
|
-
# Setting decimal precision to 2
|
|
26
|
-
precision = 2
|
|
27
|
-
|
|
28
|
-
# Setting timestamp for first sensor reading
|
|
29
|
-
now = datetime.datetime.now()
|
|
30
|
-
now = now - datetime.timedelta(days=30)
|
|
31
|
-
teststart = datetime.datetime.now()
|
|
32
|
-
|
|
33
|
-
# InfluxDB connection details
|
|
34
|
-
token = ""
|
|
35
|
-
org = ""
|
|
36
|
-
database = ""
|
|
37
|
-
url = "eu-central-1-1.aws.cloud2.influxdata.com"
|
|
38
|
-
|
|
39
|
-
callback = BatchingCallback()
|
|
40
|
-
|
|
41
|
-
write_options = WriteOptions(batch_size=5_000,
|
|
42
|
-
flush_interval=10_000,
|
|
43
|
-
jitter_interval=2_000,
|
|
44
|
-
retry_interval=5_000,
|
|
45
|
-
max_retries=5,
|
|
46
|
-
max_retry_delay=30_000,
|
|
47
|
-
exponential_base=2)
|
|
48
|
-
|
|
49
|
-
wco = write_client_options(success_callback=callback.success,
|
|
50
|
-
error_callback=callback.error,
|
|
51
|
-
retry_callback=callback.retry,
|
|
52
|
-
write_options=write_options
|
|
53
|
-
)
|
|
54
|
-
# Opening InfluxDB client with a batch size of 5k points or flush interval
|
|
55
|
-
# of 10k ms and gzip compression
|
|
56
|
-
with InfluxDBClient3.InfluxDBClient3(token=token,
|
|
57
|
-
host=url,
|
|
58
|
-
org=org,
|
|
59
|
-
database=database, enable_gzip=True, write_client_options=wco) as _client:
|
|
60
|
-
# Creating iterator for one hour worth of data (6 sensor readings per
|
|
61
|
-
# minute)
|
|
62
|
-
for i in range(0, 525600):
|
|
63
|
-
# Adding 10 seconds to timestamp of previous sensor reading
|
|
64
|
-
now = now + datetime.timedelta(seconds=10)
|
|
65
|
-
# Iterating over gateways
|
|
66
|
-
for gatewayId in gatewayIds:
|
|
67
|
-
# Creating random test data for 12 fields to be stored in
|
|
68
|
-
# timeseries database
|
|
69
|
-
bcW = random.randrange(1501)
|
|
70
|
-
bcWh = round(random.uniform(0, 4.17), precision)
|
|
71
|
-
bdW = random.randrange(71)
|
|
72
|
-
bdWh = round(random.uniform(0, 0.12), precision)
|
|
73
|
-
cPvWh = round(random.uniform(0.51, 27.78), precision)
|
|
74
|
-
cW = random.randrange(172, 10001)
|
|
75
|
-
cWh = round(random.uniform(0.51, 27.78), precision)
|
|
76
|
-
eWh = round(random.uniform(0, 41.67), precision)
|
|
77
|
-
iWh = round(random.uniform(0, 16.67), precision)
|
|
78
|
-
pW = random.randrange(209, 20001)
|
|
79
|
-
pWh = round(random.uniform(0.58, 55.56), precision)
|
|
80
|
-
scWh = round(random.uniform(0.58, 55.56), precision)
|
|
81
|
-
# Creating point to be ingested into InfluxDB
|
|
82
|
-
p = InfluxDBClient3.Point("stream").tag(
|
|
83
|
-
"gatewayId",
|
|
84
|
-
str(gatewayId)).field(
|
|
85
|
-
"bcW",
|
|
86
|
-
bcW).field(
|
|
87
|
-
"bcWh",
|
|
88
|
-
bcWh).field(
|
|
89
|
-
"bdW",
|
|
90
|
-
bdW).field(
|
|
91
|
-
"bdWh",
|
|
92
|
-
bdWh).field(
|
|
93
|
-
"cPvWh",
|
|
94
|
-
cPvWh).field(
|
|
95
|
-
"cW",
|
|
96
|
-
cW).field(
|
|
97
|
-
"cWh",
|
|
98
|
-
cWh).field(
|
|
99
|
-
"eWh",
|
|
100
|
-
eWh).field(
|
|
101
|
-
"iWh",
|
|
102
|
-
iWh).field(
|
|
103
|
-
"pW",
|
|
104
|
-
pW).field(
|
|
105
|
-
"pWh",
|
|
106
|
-
pWh).field(
|
|
107
|
-
"scWh",
|
|
108
|
-
scWh).time(
|
|
109
|
-
now.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
|
110
|
-
WritePrecision.S)
|
|
111
|
-
|
|
112
|
-
# Writing point (InfluxDB automatically batches writes into sets of
|
|
113
|
-
# 5k points)
|
|
114
|
-
_client.write(record=p)
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import time
|
|
3
|
-
import unittest
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
from influxdb_client_3 import InfluxDBClient3, InfluxDBError
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@pytest.mark.integration
|
|
11
|
-
@pytest.mark.skipif(
|
|
12
|
-
not all(
|
|
13
|
-
[
|
|
14
|
-
os.getenv('TESTING_INFLUXDB_URL'),
|
|
15
|
-
os.getenv('TESTING_INFLUXDB_TOKEN'),
|
|
16
|
-
os.getenv('TESTING_INFLUXDB_DATABASE'),
|
|
17
|
-
]
|
|
18
|
-
),
|
|
19
|
-
reason="Integration test environment variables not set.",
|
|
20
|
-
)
|
|
21
|
-
class TestInfluxDBClient3Integration(unittest.TestCase):
|
|
22
|
-
|
|
23
|
-
def setUp(self):
|
|
24
|
-
self.host = os.getenv('TESTING_INFLUXDB_URL')
|
|
25
|
-
self.token = os.getenv('TESTING_INFLUXDB_TOKEN')
|
|
26
|
-
self.database = os.getenv('TESTING_INFLUXDB_DATABASE')
|
|
27
|
-
self.client = InfluxDBClient3(host=self.host, database=self.database, token=self.token)
|
|
28
|
-
|
|
29
|
-
def tearDown(self):
|
|
30
|
-
if self.client:
|
|
31
|
-
self.client.close()
|
|
32
|
-
|
|
33
|
-
def test_write_and_query(self):
|
|
34
|
-
test_id = time.time_ns()
|
|
35
|
-
self.client.write(f"integration_test_python,type=used value=123.0,test_id={test_id}i")
|
|
36
|
-
|
|
37
|
-
sql = 'SELECT * FROM integration_test_python where type=$type and test_id=$test_id'
|
|
38
|
-
|
|
39
|
-
df = self.client.query(sql, mode="pandas", query_parameters={'type': 'used', 'test_id': test_id})
|
|
40
|
-
|
|
41
|
-
self.assertIsNotNone(df)
|
|
42
|
-
self.assertEqual(1, len(df))
|
|
43
|
-
self.assertEqual(test_id, df['test_id'][0])
|
|
44
|
-
self.assertEqual(123.0, df['value'][0])
|
|
45
|
-
|
|
46
|
-
def test_auth_error_token(self):
|
|
47
|
-
self.client = InfluxDBClient3(host=self.host, database=self.database, token='fake token')
|
|
48
|
-
test_id = time.time_ns()
|
|
49
|
-
with self.assertRaises(InfluxDBError) as err:
|
|
50
|
-
self.client.write(f"integration_test_python,type=used value=123.0,test_id={test_id}i")
|
|
51
|
-
self.assertEqual('unauthorized access', err.exception.message) # Cloud
|
|
52
|
-
|
|
53
|
-
def test_auth_error_auth_scheme(self):
|
|
54
|
-
self.client = InfluxDBClient3(host=self.host, database=self.database, token=self.token, auth_scheme='Any')
|
|
55
|
-
test_id = time.time_ns()
|
|
56
|
-
with self.assertRaises(InfluxDBError) as err:
|
|
57
|
-
self.client.write(f"integration_test_python,type=used value=123.0,test_id={test_id}i")
|
|
58
|
-
self.assertEqual('unauthorized access', err.exception.message) # Cloud
|
|
59
|
-
|
|
60
|
-
def test_error_headers(self):
|
|
61
|
-
self.client = InfluxDBClient3(host=self.host, database=self.database, token=self.token)
|
|
62
|
-
with self.assertRaises(InfluxDBError) as err:
|
|
63
|
-
self.client.write("integration_test_python,type=used value=123.0,test_id=")
|
|
64
|
-
self.assertIn("Could not parse entire line. Found trailing content:", err.exception.message)
|
|
65
|
-
headers = err.exception.getheaders()
|
|
66
|
-
try:
|
|
67
|
-
self.assertIsNotNone(headers)
|
|
68
|
-
self.assertRegex(headers['trace-id'], '[0-9a-f]{16}')
|
|
69
|
-
self.assertEqual('false', headers['trace-sampled'])
|
|
70
|
-
self.assertIsNotNone(headers['Strict-Transport-Security'])
|
|
71
|
-
self.assertRegex(headers['X-Influxdb-Request-ID'], '[0-9a-f]+')
|
|
72
|
-
self.assertIsNotNone(headers['X-Influxdb-Build'])
|
|
73
|
-
except KeyError as ke:
|
|
74
|
-
self.fail(f'Header {ke} not found')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb3_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/__init__.py
RENAMED
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/_sync/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/_sync/rest.py
RENAMED
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/__init__.py
RENAMED
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/client/warnings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/configuration.py
RENAMED
|
File without changes
|
{influxdb3_python-0.9.0 → influxdb3_python-0.11.0}/influxdb_client_3/write_client/domain/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|