influxdb3-python 0.11.0__tar.gz → 0.12.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.12.0/Examples/basic_ssl_example.py +104 -0
- influxdb3_python-0.12.0/Examples/query_async.py +87 -0
- {influxdb3_python-0.11.0/influxdb3_python.egg-info → influxdb3_python-0.12.0}/PKG-INFO +3 -2
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0/influxdb3_python.egg-info}/PKG-INFO +3 -2
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb3_python.egg-info/SOURCES.txt +2 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/__init__.py +44 -2
- influxdb3_python-0.12.0/influxdb_client_3/query/query_api.py +252 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/version.py +1 -1
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_influxdb_client_3.py +26 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_influxdb_client_3_integration.py +94 -4
- influxdb3_python-0.12.0/tests/test_query.py +432 -0
- influxdb3_python-0.11.0/influxdb_client_3/query/query_api.py +0 -108
- influxdb3_python-0.11.0/tests/test_query.py +0 -166
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/batching_example.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/cloud_dedicated_query.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/cloud_dedicated_write.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/config.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/flight_options_example.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/handle_http_error.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/pandas_write.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/Examples/query_type.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/LICENSE +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/README.md +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb3_python.egg-info/dependency_links.txt +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb3_python.egg-info/requires.txt +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb3_python.egg-info/top_level.txt +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/py.typed +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/query/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/read_file.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/_sync/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/_sync/api_client.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/_sync/rest.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/_base.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/exceptions.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/influxdb_client.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/logging_handler.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/util/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/util/date_utils.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/util/date_utils_pandas.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/util/helpers.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/util/multiprocessing_helper.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/warnings.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/write/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/write/dataframe_serializer.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/write/point.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/write/retry.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/client/write_api.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/configuration.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/domain/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/domain/write_precision.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/extras.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/rest.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/service/__init__.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/service/_base_service.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/service/signin_service.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/service/signout_service.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/influxdb_client_3/write_client/service/write_service.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/setup.cfg +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/setup.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_api_client.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_dataframe_serializer.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_date_helper.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_deep_merge.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_merge_options.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_point.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_polars.py +0 -0
- {influxdb3_python-0.11.0 → influxdb3_python-0.12.0}/tests/test_write_file.py +0 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
import pyarrow
|
|
5
|
+
|
|
6
|
+
from config import Config
|
|
7
|
+
from influxdb_client_3 import InfluxDBClient3
|
|
8
|
+
|
|
9
|
+
bad_cert = """-----BEGIN CERTIFICATE-----
|
|
10
|
+
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
|
|
37
|
+
Aw==
|
|
38
|
+
-----END CERTIFICATE-----"""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def write_cert(cert, file_name):
|
|
42
|
+
f = open(file_name, "w")
|
|
43
|
+
f.write(cert)
|
|
44
|
+
f.close()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def remove_cert(file_name):
|
|
48
|
+
os.remove(file_name)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def print_results(results: list):
|
|
52
|
+
print("%-6s%-6s%-6s%-24s" % ("id", "speed", "ticks", "time"))
|
|
53
|
+
for result in results:
|
|
54
|
+
print("%-6s%-6.2f%-6i%-24s" % (result['id'], result['speed'], result['ticks'], result['time']))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def main() -> None:
|
|
58
|
+
print("Main")
|
|
59
|
+
temp_cert_file = "temp_cert.pem"
|
|
60
|
+
conf = Config()
|
|
61
|
+
|
|
62
|
+
write_and_query_with_explicit_sys_cert(conf)
|
|
63
|
+
|
|
64
|
+
write_cert(bad_cert, temp_cert_file)
|
|
65
|
+
query_with_verify_ssl_off(conf, temp_cert_file)
|
|
66
|
+
remove_cert(temp_cert_file)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def write_and_query_with_explicit_sys_cert(conf):
|
|
70
|
+
print("\nwrite and query with typical linux system cert\n")
|
|
71
|
+
with InfluxDBClient3(token=conf.token,
|
|
72
|
+
host=conf.host,
|
|
73
|
+
org=conf.org,
|
|
74
|
+
database=conf.database,
|
|
75
|
+
ssl_ca_cert="/etc/ssl/certs/ca-certificates.crt",
|
|
76
|
+
verify_ssl=True) as _client:
|
|
77
|
+
now = time.time_ns()
|
|
78
|
+
lp = f"escooter,id=zx80 speed=3.14,ticks=42i {now - (10 * 1_000_000_000)}"
|
|
79
|
+
_client.write(lp)
|
|
80
|
+
|
|
81
|
+
query = "SELECT * FROM \"escooter\" ORDER BY time DESC"
|
|
82
|
+
reader: pyarrow.Table = _client.query(query, mode="")
|
|
83
|
+
print_results(reader.to_pylist())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def query_with_verify_ssl_off(conf, cert):
|
|
87
|
+
print("\nquerying with verify_ssl off\n")
|
|
88
|
+
|
|
89
|
+
# Note that the passed root cert above is bad
|
|
90
|
+
# Switch verify_ssl to True to throw SSL_ERROR_SSL
|
|
91
|
+
with InfluxDBClient3(token=conf.token,
|
|
92
|
+
host=conf.host,
|
|
93
|
+
org=conf.org,
|
|
94
|
+
database=conf.database,
|
|
95
|
+
ssl_ca_cert=cert,
|
|
96
|
+
verify_ssl=False) as _client:
|
|
97
|
+
|
|
98
|
+
query = "SELECT * FROM \"escooter\" ORDER BY time DESC"
|
|
99
|
+
reader: pyarrow.Table = _client.query(query, mode="")
|
|
100
|
+
print_results(reader.to_pylist())
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
main()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import random
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
import pandas
|
|
6
|
+
|
|
7
|
+
from influxdb_client_3 import InfluxDBClient3
|
|
8
|
+
|
|
9
|
+
from config import Config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def fibio(iterations, grit=0.5):
|
|
13
|
+
"""
|
|
14
|
+
example coroutine to run parallel with query_async
|
|
15
|
+
:param iterations:
|
|
16
|
+
:param grit:
|
|
17
|
+
:return:
|
|
18
|
+
"""
|
|
19
|
+
n0 = 1
|
|
20
|
+
n1 = 1
|
|
21
|
+
vals = [n0, n1]
|
|
22
|
+
for _ in range(iterations):
|
|
23
|
+
val = n0 + n1
|
|
24
|
+
n0 = n1
|
|
25
|
+
n1 = val
|
|
26
|
+
print(val)
|
|
27
|
+
vals.append(val)
|
|
28
|
+
await asyncio.sleep(grit)
|
|
29
|
+
return vals
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def write_data(client: InfluxDBClient3, measurement):
|
|
33
|
+
"""
|
|
34
|
+
Synchronous write - only for preparing data
|
|
35
|
+
:param client:
|
|
36
|
+
:param measurement:
|
|
37
|
+
:return:
|
|
38
|
+
"""
|
|
39
|
+
ids = ['s3b1', 'dq41', 'sgw22']
|
|
40
|
+
lp_template = f"{measurement},id=%s speed=%f,alt=%f,bearing=%f %d"
|
|
41
|
+
data_size = 10
|
|
42
|
+
data = []
|
|
43
|
+
interval = 10 * 1_000_000_000
|
|
44
|
+
ts = time.time_ns() - (interval * data_size)
|
|
45
|
+
for _ in range(data_size):
|
|
46
|
+
data.append(lp_template % (ids[random.randint(0, len(ids) - 1)],
|
|
47
|
+
random.random() * 300,
|
|
48
|
+
random.random() * 2000,
|
|
49
|
+
random.random() * 360, ts))
|
|
50
|
+
ts += interval
|
|
51
|
+
|
|
52
|
+
client.write(data)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def query_data(client: InfluxDBClient3, measurement):
|
|
56
|
+
"""
|
|
57
|
+
Query asynchronously - should not block other coroutines
|
|
58
|
+
:param client:
|
|
59
|
+
:param measurement:
|
|
60
|
+
:return:
|
|
61
|
+
"""
|
|
62
|
+
query = f"SELECT * FROM \"{measurement}\" WHERE time >= now() - interval '5 minutes' ORDER BY time DESC"
|
|
63
|
+
print(f"query start: {pandas.Timestamp(time.time_ns())}")
|
|
64
|
+
table = await client.query_async(query)
|
|
65
|
+
print(f"query returned: {pandas.Timestamp(time.time_ns())}")
|
|
66
|
+
return table.to_pandas()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async def main():
|
|
70
|
+
config = Config()
|
|
71
|
+
client = InfluxDBClient3(
|
|
72
|
+
host=config.host,
|
|
73
|
+
token=config.token,
|
|
74
|
+
database=config.database,
|
|
75
|
+
org=config.org
|
|
76
|
+
)
|
|
77
|
+
measurement = 'example_uav'
|
|
78
|
+
write_data(client, measurement)
|
|
79
|
+
|
|
80
|
+
# run both coroutines simultaneously
|
|
81
|
+
result = await asyncio.gather(fibio(10, 0.2), query_data(client, measurement))
|
|
82
|
+
print(f"fibio sequence = {result[0]}")
|
|
83
|
+
print(f"data set =\n{result[1]}")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
asyncio.run(main())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: influxdb3-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.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
|
|
@@ -39,6 +39,7 @@ Dynamic: classifier
|
|
|
39
39
|
Dynamic: description
|
|
40
40
|
Dynamic: description-content-type
|
|
41
41
|
Dynamic: home-page
|
|
42
|
+
Dynamic: license-file
|
|
42
43
|
Dynamic: provides-extra
|
|
43
44
|
Dynamic: requires-dist
|
|
44
45
|
Dynamic: requires-python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: influxdb3-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.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
|
|
@@ -39,6 +39,7 @@ Dynamic: classifier
|
|
|
39
39
|
Dynamic: description
|
|
40
40
|
Dynamic: description-content-type
|
|
41
41
|
Dynamic: home-page
|
|
42
|
+
Dynamic: license-file
|
|
42
43
|
Dynamic: provides-extra
|
|
43
44
|
Dynamic: requires-dist
|
|
44
45
|
Dynamic: requires-python
|
|
@@ -2,6 +2,7 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
setup.py
|
|
4
4
|
Examples/__init__.py
|
|
5
|
+
Examples/basic_ssl_example.py
|
|
5
6
|
Examples/batching_example.py
|
|
6
7
|
Examples/cloud_dedicated_query.py
|
|
7
8
|
Examples/cloud_dedicated_write.py
|
|
@@ -9,6 +10,7 @@ Examples/config.py
|
|
|
9
10
|
Examples/flight_options_example.py
|
|
10
11
|
Examples/handle_http_error.py
|
|
11
12
|
Examples/pandas_write.py
|
|
13
|
+
Examples/query_async.py
|
|
12
14
|
Examples/query_type.py
|
|
13
15
|
influxdb3_python.egg-info/PKG-INFO
|
|
14
16
|
influxdb3_python.egg-info/SOURCES.txt
|
|
@@ -2,7 +2,7 @@ import urllib.parse
|
|
|
2
2
|
import pyarrow as pa
|
|
3
3
|
import importlib.util
|
|
4
4
|
|
|
5
|
-
from influxdb_client_3.query.query_api import QueryApi as _QueryApi
|
|
5
|
+
from influxdb_client_3.query.query_api import QueryApi as _QueryApi, QueryApiOptionsBuilder
|
|
6
6
|
from influxdb_client_3.read_file import UploadFile
|
|
7
7
|
from influxdb_client_3.write_client import InfluxDBClient as _InfluxDBClient, WriteOptions, Point
|
|
8
8
|
from influxdb_client_3.write_client.client.exceptions import InfluxDBError
|
|
@@ -165,9 +165,18 @@ class InfluxDBClient3:
|
|
|
165
165
|
connection_string = f"grpc+tls://{hostname}:{port}"
|
|
166
166
|
else:
|
|
167
167
|
connection_string = f"grpc+tcp://{hostname}:{port}"
|
|
168
|
+
|
|
169
|
+
q_opts_builder = QueryApiOptionsBuilder()
|
|
170
|
+
kw_keys = kwargs.keys()
|
|
171
|
+
if kw_keys.__contains__('ssl_ca_cert'):
|
|
172
|
+
q_opts_builder.root_certs(kwargs.get('ssl_ca_cert', None))
|
|
173
|
+
if kw_keys.__contains__('verify_ssl'):
|
|
174
|
+
q_opts_builder.tls_verify(kwargs.get('verify_ssl', True))
|
|
175
|
+
if kw_keys.__contains__('proxy'):
|
|
176
|
+
q_opts_builder.proxy(kwargs.get('proxy', None))
|
|
168
177
|
self._query_api = _QueryApi(connection_string=connection_string, token=token,
|
|
169
178
|
flight_client_options=flight_client_options,
|
|
170
|
-
proxy=kwargs.get("proxy", None))
|
|
179
|
+
proxy=kwargs.get("proxy", None), options=q_opts_builder.build())
|
|
171
180
|
|
|
172
181
|
def write(self, record=None, database=None, **kwargs):
|
|
173
182
|
"""
|
|
@@ -269,6 +278,39 @@ class InfluxDBClient3:
|
|
|
269
278
|
except InfluxDBError as e:
|
|
270
279
|
raise e
|
|
271
280
|
|
|
281
|
+
async def query_async(self, query: str, language: str = "sql", mode: str = "all", database: str = None, **kwargs):
|
|
282
|
+
"""Query data from InfluxDB asynchronously.
|
|
283
|
+
|
|
284
|
+
If you want to use query parameters, you can pass them as kwargs:
|
|
285
|
+
|
|
286
|
+
>>> await client.query_async("select * from cpu where host=$host", query_parameters={"host": "server01"})
|
|
287
|
+
|
|
288
|
+
:param query: The query to execute on the database.
|
|
289
|
+
:param language: The query language to use. It should be one of "influxql" or "sql". Defaults to "sql".
|
|
290
|
+
:param mode: The mode to use for the query. It should be one of "all", "pandas", "polars", "chunk",
|
|
291
|
+
"reader" or "schema". Defaults to "all".
|
|
292
|
+
:param database: The database to query from. If not provided, uses the database provided during initialization.
|
|
293
|
+
:param kwargs: Additional arguments to pass to the ``FlightCallOptions headers``. For example, it can be used to
|
|
294
|
+
set up per request headers.
|
|
295
|
+
:keyword query_parameters: The query parameters to use in the query.
|
|
296
|
+
It should be a ``dictionary`` of key-value pairs.
|
|
297
|
+
:return: The query result in the specified mode.
|
|
298
|
+
"""
|
|
299
|
+
if mode == "polars" and polars is False:
|
|
300
|
+
raise ImportError("Polars is not installed. Please install it with `pip install polars`.")
|
|
301
|
+
|
|
302
|
+
if database is None:
|
|
303
|
+
database = self._database
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
return await self._query_api.query_async(query=query,
|
|
307
|
+
language=language,
|
|
308
|
+
mode=mode,
|
|
309
|
+
database=database,
|
|
310
|
+
**kwargs)
|
|
311
|
+
except InfluxDBError as e:
|
|
312
|
+
raise e
|
|
313
|
+
|
|
272
314
|
def close(self):
|
|
273
315
|
"""Close the client and clean up resources."""
|
|
274
316
|
self._write_api.close()
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Query data in InfluxDB 3."""
|
|
2
|
+
import asyncio
|
|
3
|
+
# coding: utf-8
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from pyarrow.flight import FlightClient, Ticket, FlightCallOptions, FlightStreamReader
|
|
7
|
+
|
|
8
|
+
from influxdb_client_3.version import USER_AGENT
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class QueryApiOptions(object):
|
|
12
|
+
"""
|
|
13
|
+
Structure for encapsulating options for the QueryApi
|
|
14
|
+
|
|
15
|
+
Attributes
|
|
16
|
+
----------
|
|
17
|
+
tls_root_certs (bytes): contents of an SSL root certificate or chain read as bytes
|
|
18
|
+
tls_verify (bool): whether to verify SSL certificates or not
|
|
19
|
+
proxy (str): URL to a proxy server
|
|
20
|
+
flight_client_options (dict): base set of flight client options passed to internal pyarrow.flight.FlightClient
|
|
21
|
+
"""
|
|
22
|
+
tls_root_certs: bytes = None
|
|
23
|
+
tls_verify: bool = None
|
|
24
|
+
proxy: str = None
|
|
25
|
+
flight_client_options: dict = None
|
|
26
|
+
|
|
27
|
+
def __init__(self, root_certs_path, verify, proxy, flight_client_options):
|
|
28
|
+
"""
|
|
29
|
+
Initialize a set of QueryApiOptions
|
|
30
|
+
|
|
31
|
+
:param root_certs_path: path to a certificate .pem file.
|
|
32
|
+
:param verify: whether to verify SSL certificates or not.
|
|
33
|
+
:param proxy: URL of a proxy server, if required.
|
|
34
|
+
:param flight_client_options: set of flight_client_options
|
|
35
|
+
to be passed to internal pyarrow.flight.FlightClient.
|
|
36
|
+
"""
|
|
37
|
+
if root_certs_path:
|
|
38
|
+
self.tls_root_certs = self._read_certs(root_certs_path)
|
|
39
|
+
self.tls_verify = verify
|
|
40
|
+
self.proxy = proxy
|
|
41
|
+
self.flight_client_options = flight_client_options
|
|
42
|
+
|
|
43
|
+
def _read_certs(self, path):
|
|
44
|
+
with open(path, "rb") as certs_file:
|
|
45
|
+
return certs_file.read()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class QueryApiOptionsBuilder(object):
|
|
49
|
+
"""
|
|
50
|
+
Helper class to make adding QueryApiOptions more dynamic.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
|
|
54
|
+
.. code-block:: python
|
|
55
|
+
|
|
56
|
+
options = QueryApiOptionsBuilder()\
|
|
57
|
+
.proxy("http://internal.tunnel.proxy:8080") \
|
|
58
|
+
.root_certs("/home/fred/.etc/ssl/alt_certs.pem") \
|
|
59
|
+
.tls_verify(True) \
|
|
60
|
+
.build()
|
|
61
|
+
|
|
62
|
+
client = QueryApi(connection, token, None, None, options)
|
|
63
|
+
"""
|
|
64
|
+
_root_certs_path = None
|
|
65
|
+
_tls_verify = True
|
|
66
|
+
_proxy = None
|
|
67
|
+
_flight_client_options = None
|
|
68
|
+
|
|
69
|
+
def root_certs(self, path):
|
|
70
|
+
self._root_certs_path = path
|
|
71
|
+
return self
|
|
72
|
+
|
|
73
|
+
def tls_verify(self, verify):
|
|
74
|
+
self._tls_verify = verify
|
|
75
|
+
return self
|
|
76
|
+
|
|
77
|
+
def proxy(self, proxy):
|
|
78
|
+
self._proxy = proxy
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
def flight_client_options(self, flight_client_options):
|
|
82
|
+
self._flight_client_options = flight_client_options
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
def build(self):
|
|
86
|
+
"""Build a QueryApiOptions object with previously set values"""
|
|
87
|
+
return QueryApiOptions(
|
|
88
|
+
root_certs_path=self._root_certs_path,
|
|
89
|
+
verify=self._tls_verify,
|
|
90
|
+
proxy=self._proxy,
|
|
91
|
+
flight_client_options=self._flight_client_options
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class QueryApi(object):
|
|
96
|
+
"""
|
|
97
|
+
Implementation for '/api/v2/query' endpoint.
|
|
98
|
+
|
|
99
|
+
Example:
|
|
100
|
+
|
|
101
|
+
.. code-block:: python
|
|
102
|
+
|
|
103
|
+
from influxdb_client import InfluxDBClient
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Initialize instance of QueryApi
|
|
107
|
+
with InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org") as client:
|
|
108
|
+
query_api = client.query_api()
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def __init__(self,
|
|
112
|
+
connection_string,
|
|
113
|
+
token,
|
|
114
|
+
flight_client_options,
|
|
115
|
+
proxy=None, options=None) -> None:
|
|
116
|
+
"""
|
|
117
|
+
Initialize defaults.
|
|
118
|
+
|
|
119
|
+
:param connection_string: Flight/gRPC connection string
|
|
120
|
+
:param token: access token
|
|
121
|
+
:param flight_client_options: Flight client options
|
|
122
|
+
"""
|
|
123
|
+
self._token = token
|
|
124
|
+
self._flight_client_options = flight_client_options or {}
|
|
125
|
+
default_user_agent = ("grpc.secondary_user_agent", USER_AGENT)
|
|
126
|
+
if "generic_options" in self._flight_client_options:
|
|
127
|
+
if "grpc.secondary_user_agent" not in dict(self._flight_client_options["generic_options"]).keys():
|
|
128
|
+
self._flight_client_options["generic_options"].append(default_user_agent)
|
|
129
|
+
else:
|
|
130
|
+
self._flight_client_options["generic_options"] = [default_user_agent]
|
|
131
|
+
self._proxy = proxy
|
|
132
|
+
from influxdb_client_3 import _merge_options as merge_options
|
|
133
|
+
if options:
|
|
134
|
+
if options.flight_client_options:
|
|
135
|
+
self._flight_client_options = merge_options(self._flight_client_options,
|
|
136
|
+
None,
|
|
137
|
+
options.flight_client_options)
|
|
138
|
+
if ('generic_options' in options.flight_client_options and
|
|
139
|
+
'grpc.secondary_user_agent' in dict(options.flight_client_options["generic_options"]).keys()):
|
|
140
|
+
self._flight_client_options['generic_options'].remove(default_user_agent)
|
|
141
|
+
if options.tls_root_certs:
|
|
142
|
+
self._flight_client_options["tls_root_certs"] = options.tls_root_certs
|
|
143
|
+
if options.proxy:
|
|
144
|
+
self._proxy = options.proxy
|
|
145
|
+
if options.tls_verify is not None:
|
|
146
|
+
self._flight_client_options["disable_server_verification"] = not options.tls_verify
|
|
147
|
+
if self._proxy:
|
|
148
|
+
self._flight_client_options["generic_options"].append(("grpc.http_proxy", self._proxy))
|
|
149
|
+
self._flight_client = FlightClient(connection_string, **self._flight_client_options)
|
|
150
|
+
|
|
151
|
+
def query(self, query: str, language: str, mode: str, database: str, **kwargs):
|
|
152
|
+
"""Query data from InfluxDB.
|
|
153
|
+
|
|
154
|
+
:param query: The query to execute on the database.
|
|
155
|
+
:param language: The query language.
|
|
156
|
+
:param mode: The mode to use for the query.
|
|
157
|
+
It should be one of "all", "pandas", "polars", "chunk", "reader" or "schema".
|
|
158
|
+
:param database: The database to query from.
|
|
159
|
+
:param kwargs: Additional arguments to pass to the ``FlightCallOptions headers``.
|
|
160
|
+
For example, it can be used to set up per request headers.
|
|
161
|
+
:keyword query_parameters: The query parameters to use in the query.
|
|
162
|
+
It should be a ``dictionary`` of key-value pairs.
|
|
163
|
+
:return: The query result in the specified mode.
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
ticket, _options = self._prepare_query(query, language, database, **kwargs)
|
|
167
|
+
|
|
168
|
+
flight_reader = self._do_get(ticket, _options)
|
|
169
|
+
|
|
170
|
+
return self._translate_stream_reader(flight_reader, mode)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
raise e
|
|
173
|
+
|
|
174
|
+
async def query_async(self, query: str, language: str, mode: str, database: str, **kwargs):
|
|
175
|
+
"""Query data from InfluxDB asynchronously.
|
|
176
|
+
|
|
177
|
+
Wraps internal FlightClient.doGet call in its own executor, so that the event_loop will not be blocked.
|
|
178
|
+
|
|
179
|
+
:param query: The query to execute on the database.
|
|
180
|
+
:param language: The query language.
|
|
181
|
+
:param mode: The mode to use for the query.
|
|
182
|
+
It should be one of "all", "pandas", "polars", "chunk", "reader" or "schema".
|
|
183
|
+
:param database: The database to query from.
|
|
184
|
+
:param kwargs: Additional arguments to pass to the ``FlightCallOptions headers``.
|
|
185
|
+
For example, it can be used to set up per request headers.
|
|
186
|
+
:keyword query_parameters: The query parameters to use in the query.
|
|
187
|
+
It should be a ``dictionary`` of key-value pairs.
|
|
188
|
+
:return: The query result in the specified mode.
|
|
189
|
+
"""
|
|
190
|
+
try:
|
|
191
|
+
ticket, options = self._prepare_query(query, language, database, **kwargs)
|
|
192
|
+
loop = asyncio.get_running_loop()
|
|
193
|
+
_flight_reader = await loop.run_in_executor(None,
|
|
194
|
+
self._flight_client.do_get, ticket, options)
|
|
195
|
+
return await loop.run_in_executor(None, self._translate_stream_reader,
|
|
196
|
+
_flight_reader,
|
|
197
|
+
mode)
|
|
198
|
+
except Exception as e:
|
|
199
|
+
raise e
|
|
200
|
+
|
|
201
|
+
def _translate_stream_reader(self, reader: FlightStreamReader, mode: str):
|
|
202
|
+
from influxdb_client_3 import polars as has_polars
|
|
203
|
+
try:
|
|
204
|
+
mode_funcs = {
|
|
205
|
+
"all": reader.read_all,
|
|
206
|
+
"pandas": reader.read_pandas,
|
|
207
|
+
"chunk": lambda: reader,
|
|
208
|
+
"reader": reader.to_reader,
|
|
209
|
+
"schema": lambda: reader.schema
|
|
210
|
+
}
|
|
211
|
+
if has_polars:
|
|
212
|
+
import polars as pl
|
|
213
|
+
mode_funcs["polars"] = lambda: pl.from_arrow(reader.read_all())
|
|
214
|
+
mode_func = mode_funcs.get(mode, reader.read_all)
|
|
215
|
+
|
|
216
|
+
return mode_func() if callable(mode_func) else mode_func
|
|
217
|
+
except Exception as e:
|
|
218
|
+
raise e
|
|
219
|
+
|
|
220
|
+
def _prepare_query(self, query: str, language: str, database: str, **kwargs):
|
|
221
|
+
from influxdb_client_3 import _merge_options as merge_options
|
|
222
|
+
# Create an authorization header
|
|
223
|
+
optargs = {
|
|
224
|
+
"headers": [(b"authorization", f"Bearer {self._token}".encode('utf-8'))],
|
|
225
|
+
"timeout": 300
|
|
226
|
+
}
|
|
227
|
+
opts = merge_options(optargs, exclude_keys=['query_parameters'], custom=kwargs)
|
|
228
|
+
_options = FlightCallOptions(**opts)
|
|
229
|
+
|
|
230
|
+
#
|
|
231
|
+
# Ticket data
|
|
232
|
+
#
|
|
233
|
+
ticket_data = {
|
|
234
|
+
"database": database,
|
|
235
|
+
"sql_query": query,
|
|
236
|
+
"query_type": language
|
|
237
|
+
}
|
|
238
|
+
# add query parameters
|
|
239
|
+
query_parameters = kwargs.get("query_parameters", None)
|
|
240
|
+
if query_parameters:
|
|
241
|
+
ticket_data["params"] = query_parameters
|
|
242
|
+
|
|
243
|
+
ticket = Ticket(json.dumps(ticket_data).encode('utf-8'))
|
|
244
|
+
|
|
245
|
+
return ticket, _options
|
|
246
|
+
|
|
247
|
+
def _do_get(self, ticket: Ticket, options: FlightCallOptions = None) -> FlightStreamReader:
|
|
248
|
+
return self._flight_client.do_get(ticket, options)
|
|
249
|
+
|
|
250
|
+
def close(self):
|
|
251
|
+
"""Close the Flight client."""
|
|
252
|
+
self._flight_client.close()
|
|
@@ -2,6 +2,8 @@ import unittest
|
|
|
2
2
|
from unittest.mock import patch
|
|
3
3
|
|
|
4
4
|
from influxdb_client_3 import InfluxDBClient3
|
|
5
|
+
from tests.util import asyncio_run
|
|
6
|
+
from tests.util.mocks import ConstantFlightServer, ConstantData
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class TestInfluxDBClient3(unittest.TestCase):
|
|
@@ -48,6 +50,30 @@ class TestInfluxDBClient3(unittest.TestCase):
|
|
|
48
50
|
)
|
|
49
51
|
self.assertEqual(client._client.auth_header_value, "my_scheme my_token")
|
|
50
52
|
|
|
53
|
+
@asyncio_run
|
|
54
|
+
async def test_query_async(self):
|
|
55
|
+
with ConstantFlightServer() as server:
|
|
56
|
+
client = InfluxDBClient3(
|
|
57
|
+
host=f"http://localhost:{server.port}",
|
|
58
|
+
org="my_org",
|
|
59
|
+
database="my_db",
|
|
60
|
+
token="my_token",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
query = "SELECT * FROM my_data"
|
|
64
|
+
|
|
65
|
+
table = await client.query_async(query=query, language="sql")
|
|
66
|
+
|
|
67
|
+
result_list = table.to_pylist()
|
|
68
|
+
|
|
69
|
+
cd = ConstantData()
|
|
70
|
+
for item in cd.to_list():
|
|
71
|
+
assert item in result_list
|
|
72
|
+
|
|
73
|
+
assert {'data': 'database', 'reference': 'my_db', 'value': -1.0} in result_list
|
|
74
|
+
assert {'data': 'sql_query', 'reference': query, 'value': -1.0} in result_list
|
|
75
|
+
assert {'data': 'query_type', 'reference': 'sql', 'value': -1.0} in result_list
|
|
76
|
+
|
|
51
77
|
|
|
52
78
|
if __name__ == '__main__':
|
|
53
79
|
unittest.main()
|