arc-tsdb-client 0.1.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 (43) hide show
  1. arc_tsdb_client-0.1.0/.gitignore +61 -0
  2. arc_tsdb_client-0.1.0/PKG-INFO +410 -0
  3. arc_tsdb_client-0.1.0/README.md +359 -0
  4. arc_tsdb_client-0.1.0/pyproject.toml +91 -0
  5. arc_tsdb_client-0.1.0/src/arc_client/__init__.py +38 -0
  6. arc_tsdb_client-0.1.0/src/arc_client/async_client.py +179 -0
  7. arc_tsdb_client-0.1.0/src/arc_client/auth/__init__.py +9 -0
  8. arc_tsdb_client-0.1.0/src/arc_client/auth/async_manager.py +174 -0
  9. arc_tsdb_client-0.1.0/src/arc_client/auth/manager.py +186 -0
  10. arc_tsdb_client-0.1.0/src/arc_client/client.py +179 -0
  11. arc_tsdb_client-0.1.0/src/arc_client/config.py +28 -0
  12. arc_tsdb_client-0.1.0/src/arc_client/dataframe/__init__.py +1 -0
  13. arc_tsdb_client-0.1.0/src/arc_client/exceptions.py +61 -0
  14. arc_tsdb_client-0.1.0/src/arc_client/http/__init__.py +11 -0
  15. arc_tsdb_client-0.1.0/src/arc_client/http/async_http.py +136 -0
  16. arc_tsdb_client-0.1.0/src/arc_client/http/base.py +90 -0
  17. arc_tsdb_client-0.1.0/src/arc_client/http/sync_http.py +136 -0
  18. arc_tsdb_client-0.1.0/src/arc_client/ingestion/__init__.py +47 -0
  19. arc_tsdb_client-0.1.0/src/arc_client/ingestion/async_buffered.py +163 -0
  20. arc_tsdb_client-0.1.0/src/arc_client/ingestion/async_writer.py +209 -0
  21. arc_tsdb_client-0.1.0/src/arc_client/ingestion/buffered.py +219 -0
  22. arc_tsdb_client-0.1.0/src/arc_client/ingestion/compression.py +67 -0
  23. arc_tsdb_client-0.1.0/src/arc_client/ingestion/line_protocol.py +261 -0
  24. arc_tsdb_client-0.1.0/src/arc_client/ingestion/msgpack.py +349 -0
  25. arc_tsdb_client-0.1.0/src/arc_client/ingestion/writer.py +326 -0
  26. arc_tsdb_client-0.1.0/src/arc_client/management/__init__.py +17 -0
  27. arc_tsdb_client-0.1.0/src/arc_client/management/async_continuous_query.py +191 -0
  28. arc_tsdb_client-0.1.0/src/arc_client/management/async_delete.py +60 -0
  29. arc_tsdb_client-0.1.0/src/arc_client/management/async_retention.py +153 -0
  30. arc_tsdb_client-0.1.0/src/arc_client/management/continuous_query.py +191 -0
  31. arc_tsdb_client-0.1.0/src/arc_client/management/delete.py +63 -0
  32. arc_tsdb_client-0.1.0/src/arc_client/management/retention.py +153 -0
  33. arc_tsdb_client-0.1.0/src/arc_client/models/__init__.py +43 -0
  34. arc_tsdb_client-0.1.0/src/arc_client/models/auth.py +96 -0
  35. arc_tsdb_client-0.1.0/src/arc_client/models/common.py +22 -0
  36. arc_tsdb_client-0.1.0/src/arc_client/models/continuous_query.py +64 -0
  37. arc_tsdb_client-0.1.0/src/arc_client/models/delete.py +49 -0
  38. arc_tsdb_client-0.1.0/src/arc_client/models/query.py +67 -0
  39. arc_tsdb_client-0.1.0/src/arc_client/models/retention.py +51 -0
  40. arc_tsdb_client-0.1.0/src/arc_client/py.typed +0 -0
  41. arc_tsdb_client-0.1.0/src/arc_client/query/__init__.py +9 -0
  42. arc_tsdb_client-0.1.0/src/arc_client/query/async_executor.py +297 -0
  43. arc_tsdb_client-0.1.0/src/arc_client/query/executor.py +336 -0
@@ -0,0 +1,61 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ ENV/
27
+
28
+ # Testing
29
+ .pytest_cache/
30
+ .coverage
31
+ htmlcov/
32
+ .tox/
33
+ .nox/
34
+ coverage.xml
35
+ *.cover
36
+ *.py,cover
37
+
38
+ # mypy
39
+ .mypy_cache/
40
+
41
+ # ruff
42
+ .ruff_cache/
43
+
44
+ # IDEs
45
+ .idea/
46
+ .vscode/
47
+ *.swp
48
+ *.swo
49
+ *~
50
+
51
+ # OS
52
+ .DS_Store
53
+ Thumbs.db
54
+
55
+ # Jupyter
56
+ .ipynb_checkpoints/
57
+
58
+ # Local dev
59
+ .env
60
+ .env.local
61
+ *.local
@@ -0,0 +1,410 @@
1
+ Metadata-Version: 2.4
2
+ Name: arc-tsdb-client
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Arc time-series database
5
+ Project-URL: Homepage, https://github.com/basekick-labs/arc-client-python
6
+ Project-URL: Documentation, https://docs.basekick.net/arc/python-sdk
7
+ Project-URL: Repository, https://github.com/basekick-labs/arc-client-python
8
+ Project-URL: Issues, https://github.com/basekick-labs/arc-client-python/issues
9
+ Author-email: Basekick Labs <dev@basekick.io>
10
+ License: MIT
11
+ Keywords: arc,arrow,database,duckdb,parquet,time-series
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Database
22
+ Classifier: Topic :: Scientific/Engineering
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: httpx>=0.27.0
26
+ Requires-Dist: msgpack>=1.0.7
27
+ Requires-Dist: pyarrow>=15.0.0
28
+ Requires-Dist: pydantic>=2.6.0
29
+ Provides-Extra: all
30
+ Requires-Dist: pandas>=2.0.0; extra == 'all'
31
+ Requires-Dist: polars>=0.20.0; extra == 'all'
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
34
+ Requires-Dist: pre-commit>=3.6.0; extra == 'dev'
35
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
36
+ Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
37
+ Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
38
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
39
+ Requires-Dist: ruff>=0.2.0; extra == 'dev'
40
+ Provides-Extra: docs
41
+ Requires-Dist: myst-parser>=2.0.0; extra == 'docs'
42
+ Requires-Dist: nbsphinx>=0.9.0; extra == 'docs'
43
+ Requires-Dist: sphinx-autodoc-typehints>=2.0.0; extra == 'docs'
44
+ Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == 'docs'
45
+ Requires-Dist: sphinx>=7.2.0; extra == 'docs'
46
+ Provides-Extra: pandas
47
+ Requires-Dist: pandas>=2.0.0; extra == 'pandas'
48
+ Provides-Extra: polars
49
+ Requires-Dist: polars>=0.20.0; extra == 'polars'
50
+ Description-Content-Type: text/markdown
51
+
52
+ # arc-client
53
+
54
+ Python SDK for [Arc](https://github.com/basekick-labs/arc) time-series database.
55
+
56
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
57
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install arc-client
63
+
64
+ # With pandas support
65
+ pip install arc-client[pandas]
66
+
67
+ # With polars support
68
+ pip install arc-client[polars]
69
+
70
+ # With all optional dependencies
71
+ pip install arc-client[all]
72
+ ```
73
+
74
+ Or with uv:
75
+
76
+ ```bash
77
+ uv add arc-client
78
+ uv add arc-client --extra pandas
79
+ uv add arc-client --extra all
80
+ ```
81
+
82
+ ## Quick Start
83
+
84
+ ```python
85
+ from arc_client import ArcClient
86
+
87
+ with ArcClient(host="localhost", token="your-token") as client:
88
+ # Write data (columnar format - fastest)
89
+ client.write.write_columnar(
90
+ measurement="cpu",
91
+ columns={
92
+ "time": [1633024800000000, 1633024801000000],
93
+ "host": ["server01", "server01"],
94
+ "usage_idle": [95.0, 94.5],
95
+ },
96
+ )
97
+
98
+ # Query to pandas DataFrame
99
+ df = client.query.query_pandas("SELECT * FROM default.cpu WHERE host = 'server01'")
100
+ print(df)
101
+ ```
102
+
103
+ ## Features
104
+
105
+ - **High-performance ingestion**: MessagePack columnar format (9M+ records/sec)
106
+ - **Multiple formats**: MessagePack columnar/row, InfluxDB Line Protocol
107
+ - **DataFrame integration**: Pandas, Polars, PyArrow
108
+ - **Sync and async APIs**: Full async support with httpx
109
+ - **Buffered writes**: Automatic batching with size and time thresholds
110
+ - **Query support**: SQL queries with JSON or Arrow IPC streaming
111
+ - **Management**: Retention policies, continuous queries, delete operations
112
+ - **Authentication**: Token management (create, rotate, revoke)
113
+
114
+ ## Data Ingestion
115
+
116
+ ### Columnar Format (Recommended)
117
+
118
+ The fastest way to write data. Uses MessagePack with gzip compression:
119
+
120
+ ```python
121
+ client.write.write_columnar(
122
+ measurement="cpu",
123
+ columns={
124
+ "time": [1633024800000000, 1633024801000000], # microseconds
125
+ "host": ["server01", "server02"],
126
+ "region": ["us-east", "us-west"],
127
+ "usage_idle": [95.0, 87.3],
128
+ "usage_system": [3.2, 8.1],
129
+ },
130
+ database="default", # optional
131
+ )
132
+ ```
133
+
134
+ ### DataFrame Ingestion
135
+
136
+ Write directly from pandas or polars DataFrames:
137
+
138
+ ```python
139
+ import pandas as pd
140
+
141
+ df = pd.DataFrame({
142
+ "time": pd.to_datetime(["2024-01-01", "2024-01-02"]),
143
+ "host": ["server01", "server02"],
144
+ "value": [42.0, 43.5],
145
+ })
146
+
147
+ client.write.write_dataframe(
148
+ df,
149
+ measurement="metrics",
150
+ time_column="time",
151
+ tag_columns=["host"],
152
+ )
153
+ ```
154
+
155
+ ### Buffered Writes
156
+
157
+ For high-throughput scenarios, use buffered writes with automatic batching:
158
+
159
+ ```python
160
+ with client.write.buffered(batch_size=10000, flush_interval=5.0) as buffer:
161
+ for record in records:
162
+ buffer.write(
163
+ measurement="events",
164
+ tags={"source": record.source},
165
+ fields={"value": record.value},
166
+ timestamp=record.timestamp,
167
+ )
168
+ # Auto-flushes on exit or when batch_size/flush_interval reached
169
+ ```
170
+
171
+ ### Line Protocol
172
+
173
+ For compatibility with InfluxDB tooling:
174
+
175
+ ```python
176
+ # Single line
177
+ client.write.write_line_protocol("cpu,host=server01 usage=45.2 1633024800000000000")
178
+
179
+ # Multiple lines
180
+ lines = [
181
+ "cpu,host=server01 usage=45.2",
182
+ "cpu,host=server02 usage=67.8",
183
+ ]
184
+ client.write.write_line_protocol(lines)
185
+ ```
186
+
187
+ ## Querying Data
188
+
189
+ ### JSON Response
190
+
191
+ ```python
192
+ result = client.query.query("SELECT * FROM default.cpu WHERE time > now() - INTERVAL '1 hour'")
193
+ print(result.columns) # ['time', 'host', 'usage']
194
+ print(result.data) # [[1633024800000000, 'server01', 45.2], ...]
195
+ print(result.row_count)
196
+ ```
197
+
198
+ ### pandas DataFrame
199
+
200
+ ```python
201
+ df = client.query.query_pandas("SELECT * FROM default.cpu LIMIT 1000")
202
+ ```
203
+
204
+ ### Polars DataFrame
205
+
206
+ ```python
207
+ pl_df = client.query.query_polars("SELECT * FROM default.cpu LIMIT 1000")
208
+ ```
209
+
210
+ ### PyArrow Table (Zero-Copy)
211
+
212
+ ```python
213
+ table = client.query.query_arrow("SELECT * FROM default.cpu LIMIT 1000")
214
+ ```
215
+
216
+ ### Query Estimation
217
+
218
+ Preview query cost before execution:
219
+
220
+ ```python
221
+ estimate = client.query.estimate("SELECT * FROM default.cpu")
222
+ print(f"Estimated rows: {estimate.estimated_rows}")
223
+ print(f"Warning level: {estimate.warning_level}") # none, low, medium, high
224
+ ```
225
+
226
+ ### List Measurements
227
+
228
+ ```python
229
+ measurements = client.query.list_measurements(database="default")
230
+ for m in measurements:
231
+ print(f"{m.measurement}: {m.file_count} files, {m.total_size_mb:.1f} MB")
232
+ ```
233
+
234
+ ## Async Support
235
+
236
+ All operations have async equivalents:
237
+
238
+ ```python
239
+ import asyncio
240
+ from arc_client import AsyncArcClient
241
+
242
+ async def main():
243
+ async with AsyncArcClient(host="localhost", token="your-token") as client:
244
+ # Write
245
+ await client.write.write_columnar(
246
+ measurement="cpu",
247
+ columns={"time": [...], "host": [...], "usage": [...]},
248
+ )
249
+
250
+ # Query
251
+ df = await client.query.query_pandas("SELECT * FROM default.cpu")
252
+
253
+ # Buffered writes
254
+ async with client.write.buffered(batch_size=5000) as buffer:
255
+ for record in records:
256
+ await buffer.write(measurement="events", fields={"v": record.v})
257
+
258
+ asyncio.run(main())
259
+ ```
260
+
261
+ ## Management Operations
262
+
263
+ ### Retention Policies
264
+
265
+ Automatically delete old data:
266
+
267
+ ```python
268
+ # Create policy
269
+ policy = client.retention.create(
270
+ name="30-day-retention",
271
+ database="default",
272
+ retention_days=30,
273
+ measurement="logs", # optional, applies to all if not specified
274
+ )
275
+
276
+ # List policies
277
+ policies = client.retention.list()
278
+
279
+ # Execute (with dry_run first)
280
+ result = client.retention.execute(policy.id, dry_run=True)
281
+ print(f"Would delete {result.deleted_count} rows")
282
+
283
+ # Execute for real
284
+ result = client.retention.execute(policy.id, dry_run=False, confirm=True)
285
+ ```
286
+
287
+ ### Continuous Queries
288
+
289
+ Aggregate and downsample data automatically:
290
+
291
+ ```python
292
+ # Create a CQ to downsample CPU metrics to 1-hour averages
293
+ cq = client.continuous_queries.create(
294
+ name="cpu-hourly",
295
+ database="default",
296
+ source_measurement="cpu",
297
+ destination_measurement="cpu_1h",
298
+ query="SELECT time_bucket('1 hour', time) as time, host, avg(usage) as usage FROM default.cpu GROUP BY 1, 2",
299
+ interval="1h",
300
+ )
301
+
302
+ # Manual execution with time range
303
+ result = client.continuous_queries.execute(
304
+ cq.id,
305
+ start_time="2024-01-01T00:00:00Z",
306
+ end_time="2024-01-02T00:00:00Z",
307
+ dry_run=True,
308
+ )
309
+
310
+ # List CQs
311
+ cqs = client.continuous_queries.list(database="default")
312
+ ```
313
+
314
+ ### Delete Operations
315
+
316
+ Delete data with WHERE clause:
317
+
318
+ ```python
319
+ # Always dry_run first
320
+ result = client.delete.delete(
321
+ database="default",
322
+ measurement="logs",
323
+ where="time < '2024-01-01'",
324
+ dry_run=True,
325
+ )
326
+ print(f"Would delete {result.deleted_count} rows from {result.affected_files} files")
327
+
328
+ # Execute deletion
329
+ result = client.delete.delete(
330
+ database="default",
331
+ measurement="logs",
332
+ where="time < '2024-01-01'",
333
+ dry_run=False,
334
+ confirm=True, # Required for large deletes
335
+ )
336
+ ```
337
+
338
+ ### Authentication
339
+
340
+ ```python
341
+ # Verify current token
342
+ verify = client.auth.verify()
343
+ if verify.valid:
344
+ print(f"Token: {verify.token_info.name}")
345
+ print(f"Permissions: {verify.permissions}")
346
+
347
+ # Create new token
348
+ result = client.auth.create_token(
349
+ name="my-app-token",
350
+ description="Token for my application",
351
+ permissions=["read", "write"],
352
+ )
353
+ print(f"New token: {result.token}") # Save this - shown only once!
354
+
355
+ # List tokens
356
+ tokens = client.auth.list_tokens()
357
+
358
+ # Rotate token
359
+ rotated = client.auth.rotate_token(token_id=123)
360
+ print(f"New token: {rotated.new_token}")
361
+
362
+ # Revoke token
363
+ client.auth.revoke_token(token_id=123)
364
+ ```
365
+
366
+ ## Configuration
367
+
368
+ ```python
369
+ client = ArcClient(
370
+ host="localhost", # Arc server hostname
371
+ port=8000, # Arc server port (default: 8000)
372
+ token="your-token", # API token
373
+ database="default", # Default database
374
+ timeout=30.0, # Request timeout in seconds
375
+ compression=True, # Enable gzip compression for writes
376
+ ssl=False, # Use HTTPS
377
+ verify_ssl=True, # Verify SSL certificates
378
+ )
379
+ ```
380
+
381
+ ## Error Handling
382
+
383
+ ```python
384
+ from arc_client.exceptions import (
385
+ ArcError, # Base exception
386
+ ArcConnectionError, # Connection failures
387
+ ArcAuthenticationError,# Auth failures (401)
388
+ ArcQueryError, # Query execution errors
389
+ ArcIngestionError, # Write failures
390
+ ArcValidationError, # Invalid input
391
+ ArcNotFoundError, # Resource not found (404)
392
+ ArcRateLimitError, # Rate limited (429)
393
+ ArcServerError, # Server errors (5xx)
394
+ )
395
+
396
+ try:
397
+ client.query.query("INVALID SQL")
398
+ except ArcQueryError as e:
399
+ print(f"Query failed: {e}")
400
+ except ArcConnectionError as e:
401
+ print(f"Connection failed: {e}")
402
+ ```
403
+
404
+ ## Documentation
405
+
406
+ See the [full documentation](https://docs.basekick.net/arc/python-sdk) for detailed guides and API reference.
407
+
408
+ ## License
409
+
410
+ MIT License - see [LICENSE](LICENSE) for details.