influxdb3-python 0.9.0__tar.gz → 0.10.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.
Files changed (69) hide show
  1. influxdb3_python-0.10.0/Examples/batching_example.py +141 -0
  2. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/PKG-INFO +8 -6
  3. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/README.md +6 -5
  4. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb3_python.egg-info/PKG-INFO +8 -6
  5. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/version.py +1 -1
  6. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/write_api.py +2 -1
  7. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/setup.py +1 -0
  8. influxdb3_python-0.10.0/tests/test_influxdb_client_3_integration.py +186 -0
  9. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_polars.py +29 -1
  10. influxdb3_python-0.9.0/Examples/batching_example.py +0 -114
  11. influxdb3_python-0.9.0/tests/test_influxdb_client_3_integration.py +0 -74
  12. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/__init__.py +0 -0
  13. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/cloud_dedicated_query.py +0 -0
  14. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/cloud_dedicated_write.py +0 -0
  15. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/config.py +0 -0
  16. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/flight_options_example.py +0 -0
  17. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/handle_http_error.py +0 -0
  18. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/pandas_write.py +0 -0
  19. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/Examples/query_type.py +0 -0
  20. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/LICENSE +0 -0
  21. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb3_python.egg-info/SOURCES.txt +0 -0
  22. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb3_python.egg-info/dependency_links.txt +0 -0
  23. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb3_python.egg-info/requires.txt +0 -0
  24. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb3_python.egg-info/top_level.txt +0 -0
  25. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/__init__.py +0 -0
  26. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/py.typed +0 -0
  27. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/query/__init__.py +0 -0
  28. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/query/query_api.py +0 -0
  29. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/read_file.py +0 -0
  30. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/__init__.py +0 -0
  31. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/_sync/__init__.py +0 -0
  32. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/_sync/api_client.py +0 -0
  33. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/_sync/rest.py +0 -0
  34. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/__init__.py +0 -0
  35. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/_base.py +0 -0
  36. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/exceptions.py +0 -0
  37. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/influxdb_client.py +0 -0
  38. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/logging_handler.py +0 -0
  39. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/util/__init__.py +0 -0
  40. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/util/date_utils.py +0 -0
  41. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/util/date_utils_pandas.py +0 -0
  42. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/util/helpers.py +0 -0
  43. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/util/multiprocessing_helper.py +0 -0
  44. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/warnings.py +0 -0
  45. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/write/__init__.py +0 -0
  46. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/write/dataframe_serializer.py +0 -0
  47. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/write/point.py +0 -0
  48. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/write/polars_dataframe_serializer.py +0 -0
  49. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/client/write/retry.py +0 -0
  50. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/configuration.py +0 -0
  51. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/domain/__init__.py +0 -0
  52. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/domain/write_precision.py +0 -0
  53. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/extras.py +0 -0
  54. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/rest.py +0 -0
  55. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/service/__init__.py +0 -0
  56. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/service/_base_service.py +0 -0
  57. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/service/signin_service.py +0 -0
  58. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/service/signout_service.py +0 -0
  59. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/influxdb_client_3/write_client/service/write_service.py +0 -0
  60. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/setup.cfg +0 -0
  61. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_api_client.py +0 -0
  62. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_dataframe_serializer.py +0 -0
  63. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_date_helper.py +0 -0
  64. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_deep_merge.py +0 -0
  65. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_influxdb_client_3.py +0 -0
  66. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_merge_options.py +0 -0
  67. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_point.py +0 -0
  68. {influxdb3_python-0.9.0 → influxdb3_python-0.10.0}/tests/test_query.py +0 -0
  69. {influxdb3_python-0.9.0 → influxdb3_python-0.10.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
1
  Metadata-Version: 2.1
2
2
  Name: influxdb3-python
3
- Version: 0.9.0
3
+ Version: 0.10.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
@@ -127,7 +128,11 @@ from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions
127
128
 
128
129
  class BatchingCallback(object):
129
130
 
131
+ def __init__(self):
132
+ self.write_count = 0
133
+
130
134
  def success(self, conf, data: str):
135
+ self.write_count += 1
131
136
  print(f"Written batch: {conf}, data: {data}")
132
137
 
133
138
  def error(self, conf, data: str, exception: InfluxDBError):
@@ -138,7 +143,7 @@ class BatchingCallback(object):
138
143
 
139
144
  callback = BatchingCallback()
140
145
 
141
- write_options = WriteOptions(batch_size=500,
146
+ write_options = WriteOptions(batch_size=100,
142
147
  flush_interval=10_000,
143
148
  jitter_interval=2_000,
144
149
  retry_interval=5_000,
@@ -163,10 +168,7 @@ with InfluxDBClient3.InfluxDBClient3(
163
168
  file='./out.csv',
164
169
  timestamp_column='time', tag_columns=["provider", "machineID"])
165
170
 
166
- client.write_file(
167
- file='./out.json',
168
- timestamp_column='time', tag_columns=["provider", "machineID"], date_unit='ns' )
169
-
171
+ print(f'DONE writing from csv in {callback.write_count} batch(es)')
170
172
 
171
173
  ```
172
174
 
@@ -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=500,
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
- client.write_file(
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
1
  Metadata-Version: 2.1
2
2
  Name: influxdb3-python
3
- Version: 0.9.0
3
+ Version: 0.10.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
@@ -127,7 +128,11 @@ from influxdb_client_3 import write_client_options, WritePrecision, WriteOptions
127
128
 
128
129
  class BatchingCallback(object):
129
130
 
131
+ def __init__(self):
132
+ self.write_count = 0
133
+
130
134
  def success(self, conf, data: str):
135
+ self.write_count += 1
131
136
  print(f"Written batch: {conf}, data: {data}")
132
137
 
133
138
  def error(self, conf, data: str, exception: InfluxDBError):
@@ -138,7 +143,7 @@ class BatchingCallback(object):
138
143
 
139
144
  callback = BatchingCallback()
140
145
 
141
- write_options = WriteOptions(batch_size=500,
146
+ write_options = WriteOptions(batch_size=100,
142
147
  flush_interval=10_000,
143
148
  jitter_interval=2_000,
144
149
  retry_interval=5_000,
@@ -163,10 +168,7 @@ with InfluxDBClient3.InfluxDBClient3(
163
168
  file='./out.csv',
164
169
  timestamp_column='time', tag_columns=["provider", "machineID"])
165
170
 
166
- client.write_file(
167
- file='./out.json',
168
- timestamp_column='time', tag_columns=["provider", "machineID"], date_unit='ns' )
169
-
171
+ print(f'DONE writing from csv in {callback.write_count} batch(es)')
170
172
 
171
173
  ```
172
174
 
@@ -1,4 +1,4 @@
1
1
  """Version of the Client that is used in User-Agent header."""
2
2
 
3
- VERSION = '0.9.0'
3
+ VERSION = '0.10.0'
4
4
  USER_AGENT = f'influxdb3-python/{VERSION}'
@@ -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.dataframe_serializer import PolarsDataframeSerializer
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)
@@ -65,5 +65,6 @@ setup(
65
65
  'Programming Language :: Python :: 3.10',
66
66
  'Programming Language :: Python :: 3.11',
67
67
  'Programming Language :: Python :: 3.12',
68
+ 'Programming Language :: Python :: 3.13',
68
69
  ]
69
70
  )
@@ -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)
@@ -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')