acquirium 0.1.1__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 (208) hide show
  1. acquirium-0.1.1/.env.example +35 -0
  2. acquirium-0.1.1/.github/workflows/ci.yml +134 -0
  3. acquirium-0.1.1/.github/workflows/release.yml +101 -0
  4. acquirium-0.1.1/.gitignore +219 -0
  5. acquirium-0.1.1/.python-version +1 -0
  6. acquirium-0.1.1/CHANGELOG.md +38 -0
  7. acquirium-0.1.1/LICENSE +21 -0
  8. acquirium-0.1.1/Makefile +129 -0
  9. acquirium-0.1.1/PKG-INFO +194 -0
  10. acquirium-0.1.1/README.md +145 -0
  11. acquirium-0.1.1/acquirium.docker.toml +38 -0
  12. acquirium-0.1.1/acquirium.testing.toml +16 -0
  13. acquirium-0.1.1/acquirium.toml +99 -0
  14. acquirium-0.1.1/compose.minimal.yaml +98 -0
  15. acquirium-0.1.1/compose.testing.yaml +103 -0
  16. acquirium-0.1.1/compose.yaml +191 -0
  17. acquirium-0.1.1/data/.gitignore +3 -0
  18. acquirium-0.1.1/data/readme.md +0 -0
  19. acquirium-0.1.1/deployments/BENICIA/benicia-model-100.ttl +1258 -0
  20. acquirium-0.1.1/deployments/BENICIA/benicia-model.ttl +874 -0
  21. acquirium-0.1.1/deployments/BENICIA/scripts/Dockerfile +9 -0
  22. acquirium-0.1.1/deployments/BENICIA/scripts/add_external_refs_and_thresholds.py +491 -0
  23. acquirium-0.1.1/deployments/BENICIA/scripts/add_external_refs_bench.py +143 -0
  24. acquirium-0.1.1/deployments/BENICIA/scripts/generate_parquet_data.py +378 -0
  25. acquirium-0.1.1/deployments/BENICIA/scripts/requirements.txt +3 -0
  26. acquirium-0.1.1/deployments/BENICIA/scripts/stream_simulator.py +432 -0
  27. acquirium-0.1.1/deployments/WATERTAP/models/watertap-simple-pipe-model.ttl +41 -0
  28. acquirium-0.1.1/deployments/WATERTAP/readme.md +35 -0
  29. acquirium-0.1.1/deployments/WATERTAP/scripts/Dockerfile +92 -0
  30. acquirium-0.1.1/deployments/WATERTAP/scripts/insert_external_ref.py +44 -0
  31. acquirium-0.1.1/deployments/WATERTAP/scripts/pump_model.py +90 -0
  32. acquirium-0.1.1/deployments/WATERTAP/scripts/pump_model_simulation.py +158 -0
  33. acquirium-0.1.1/deployments/WATERTAP/scripts/stream_simulation.py +104 -0
  34. acquirium-0.1.1/deployments/WATERTAP2/models/test-model.ttl +402 -0
  35. acquirium-0.1.1/deployments/WATERTAP2/scripts/Dockerfile +68 -0
  36. acquirium-0.1.1/deployments/WATERTAP2/scripts/acquirium_ingest.py +15 -0
  37. acquirium-0.1.1/deployments/WATERTAP2/scripts/acquirium_watertap.ipynb +426 -0
  38. acquirium-0.1.1/deployments/WATERTAP2/scripts/example_watertap.py +135 -0
  39. acquirium-0.1.1/deployments/WATERTAP2/scripts/input_gui.py +324 -0
  40. acquirium-0.1.1/deployments/WATERTAP2/scripts/push_watertap_points.py +152 -0
  41. acquirium-0.1.1/docker/grafana/provisioning/datasources/postgres.yaml +18 -0
  42. acquirium-0.1.1/docs/data-api.md +152 -0
  43. acquirium-0.1.1/docs/data-stream-lifecycle.md +326 -0
  44. acquirium-0.1.1/docs/drivers.md +574 -0
  45. acquirium-0.1.1/docs/external_references.md +252 -0
  46. acquirium-0.1.1/improvements.md +83 -0
  47. acquirium-0.1.1/notebooks/data_object_demo.ipynb +998 -0
  48. acquirium-0.1.1/notebooks/figs/acquirium_pull.png +0 -0
  49. acquirium-0.1.1/notebooks/figs/kg_model.png +0 -0
  50. acquirium-0.1.1/notebooks/figs/property.png +0 -0
  51. acquirium-0.1.1/notebooks/figs/watertap_process.png +0 -0
  52. acquirium-0.1.1/notebooks/watertap-single-pump.ipynb +258 -0
  53. acquirium-0.1.1/ontologies/Brick.ttl +49219 -0
  54. acquirium-0.1.1/ontologies/qudt_qk.ttl +33280 -0
  55. acquirium-0.1.1/ontologies/qudt_unit.ttl +87555 -0
  56. acquirium-0.1.1/ontologies/ref-schema.ttl +417 -0
  57. acquirium-0.1.1/ontologies/water.ttl +1790 -0
  58. acquirium-0.1.1/ontologies/water2.ttl +93846 -0
  59. acquirium-0.1.1/pyproject.toml +94 -0
  60. acquirium-0.1.1/scripts/api_example.py +96 -0
  61. acquirium-0.1.1/scripts/benchmark/README.md +211 -0
  62. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_chain_sum_latency_completed_to_endpoint_ms.png +0 -0
  63. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_chain_sum_latency_measurement_to_received_ms.png +0 -0
  64. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_chain_sum_latency_received_to_completed_ms.png +0 -0
  65. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_chain_sum_latency_total_ms.png +0 -0
  66. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_chain_sum_processing_time_ms.png +0 -0
  67. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_latency_completed_to_endpoint_ms.png +0 -0
  68. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_latency_measurement_to_received_ms.png +0 -0
  69. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_latency_received_to_completed_ms.png +0 -0
  70. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_latency_total_ms.png +0 -0
  71. acquirium-0.1.1/scripts/benchmark/chain/plots/boxplot_processing_time_ms.png +0 -0
  72. acquirium-0.1.1/scripts/benchmark/chain/visual.py +286 -0
  73. acquirium-0.1.1/scripts/benchmark/chain_latency.py +418 -0
  74. acquirium-0.1.1/scripts/benchmark/chain_receiver.py +292 -0
  75. acquirium-0.1.1/scripts/benchmark/chlorine_level_monitoring/acq.py +51 -0
  76. acquirium-0.1.1/scripts/benchmark/chlorine_level_monitoring/chrontext.py +54 -0
  77. acquirium-0.1.1/scripts/benchmark/chlorine_level_monitoring/energon.py +42 -0
  78. acquirium-0.1.1/scripts/benchmark/chlorine_level_monitoring/mor.py +63 -0
  79. acquirium-0.1.1/scripts/benchmark/dataset_construction/acq1.py +15 -0
  80. acquirium-0.1.1/scripts/benchmark/dataset_construction/acq2.py +15 -0
  81. acquirium-0.1.1/scripts/benchmark/dataset_construction/acq3.py +15 -0
  82. acquirium-0.1.1/scripts/benchmark/dataset_construction/chrontext1.py +20 -0
  83. acquirium-0.1.1/scripts/benchmark/dataset_construction/chrontext2.py +16 -0
  84. acquirium-0.1.1/scripts/benchmark/dataset_construction/chrontext3.py +20 -0
  85. acquirium-0.1.1/scripts/benchmark/dataset_construction/energon1.py +8 -0
  86. acquirium-0.1.1/scripts/benchmark/dataset_construction/energon2.py +9 -0
  87. acquirium-0.1.1/scripts/benchmark/dataset_construction/energon3.py +9 -0
  88. acquirium-0.1.1/scripts/benchmark/dataset_construction/mor1.py +53 -0
  89. acquirium-0.1.1/scripts/benchmark/dataset_construction/mor2.py +28 -0
  90. acquirium-0.1.1/scripts/benchmark/dataset_construction/mor3.py +48 -0
  91. acquirium-0.1.1/scripts/benchmark/dataset_construction.py +15 -0
  92. acquirium-0.1.1/scripts/benchmark/fault_detection/acq.py +29 -0
  93. acquirium-0.1.1/scripts/benchmark/fault_detection/chrontext.py +51 -0
  94. acquirium-0.1.1/scripts/benchmark/fault_detection/energon.py +28 -0
  95. acquirium-0.1.1/scripts/benchmark/fault_detection/mortar.py +46 -0
  96. acquirium-0.1.1/scripts/benchmark/latency_receiver.py +154 -0
  97. acquirium-0.1.1/scripts/benchmark/metadata_exploration.py +10 -0
  98. acquirium-0.1.1/scripts/benchmark/scalability/plots/boxplot_latency_completed_to_endpoint_ms.png +0 -0
  99. acquirium-0.1.1/scripts/benchmark/scalability/plots/boxplot_latency_measurement_to_received_ms.png +0 -0
  100. acquirium-0.1.1/scripts/benchmark/scalability/plots/boxplot_latency_received_to_completed_ms.png +0 -0
  101. acquirium-0.1.1/scripts/benchmark/scalability/plots/boxplot_latency_total_ms.png +0 -0
  102. acquirium-0.1.1/scripts/benchmark/scalability/visual.py +127 -0
  103. acquirium-0.1.1/scripts/benchmark/scalability.py +208 -0
  104. acquirium-0.1.1/scripts/benchmark/system_info.sh +133 -0
  105. acquirium-0.1.1/scripts/benchmark/threshold.py +56 -0
  106. acquirium-0.1.1/scripts/custom_mqtt_driver.py +57 -0
  107. acquirium-0.1.1/scripts/e2e/test_graph_version_refresh.py +190 -0
  108. acquirium-0.1.1/scripts/e2e/version_refresh_app.py +38 -0
  109. acquirium-0.1.1/scripts/logging_example.py +83 -0
  110. acquirium-0.1.1/scripts/stop_app_containers.sh +21 -0
  111. acquirium-0.1.1/scripts/text_matcher_example.py +33 -0
  112. acquirium-0.1.1/src/acquirium/Apps/base.py +110 -0
  113. acquirium-0.1.1/src/acquirium/Apps/output_emission.py +94 -0
  114. acquirium-0.1.1/src/acquirium/Apps/worker.py +360 -0
  115. acquirium-0.1.1/src/acquirium/BuiltinDrivers/__init__.py +0 -0
  116. acquirium-0.1.1/src/acquirium/BuiltinDrivers/_tabular_base.py +477 -0
  117. acquirium-0.1.1/src/acquirium/BuiltinDrivers/csv_ingest.py +107 -0
  118. acquirium-0.1.1/src/acquirium/BuiltinDrivers/mqtt_ingestion.py +344 -0
  119. acquirium-0.1.1/src/acquirium/BuiltinDrivers/system_metrics.py +108 -0
  120. acquirium-0.1.1/src/acquirium/BuiltinDrivers/watertap.py +285 -0
  121. acquirium-0.1.1/src/acquirium/BuiltinDrivers/xlsx_ingest.py +69 -0
  122. acquirium-0.1.1/src/acquirium/Client/acquirium.py +609 -0
  123. acquirium-0.1.1/src/acquirium/Client/client.py +493 -0
  124. acquirium-0.1.1/src/acquirium/Client/data_object.py +917 -0
  125. acquirium-0.1.1/src/acquirium/Client/query.py +1606 -0
  126. acquirium-0.1.1/src/acquirium/Client/query_graph.py +107 -0
  127. acquirium-0.1.1/src/acquirium/Dockerfile +29 -0
  128. acquirium-0.1.1/src/acquirium/Driver.py +245 -0
  129. acquirium-0.1.1/src/acquirium/Grafana/grafana_dashboard_creator.py +78 -0
  130. acquirium-0.1.1/src/acquirium/Grafana/grafana_panel_creator.py +71 -0
  131. acquirium-0.1.1/src/acquirium/Grafana/grafana_upload.py +42 -0
  132. acquirium-0.1.1/src/acquirium/Server/acq_app_runner.py +212 -0
  133. acquirium-0.1.1/src/acquirium/Server/app.py +571 -0
  134. acquirium-0.1.1/src/acquirium/Server/direct_client.py +155 -0
  135. acquirium-0.1.1/src/acquirium/Server/insert_stats.py +52 -0
  136. acquirium-0.1.1/src/acquirium/Server/manager.py +1258 -0
  137. acquirium-0.1.1/src/acquirium/Storage/__init__.py +49 -0
  138. acquirium-0.1.1/src/acquirium/Storage/base.py +89 -0
  139. acquirium-0.1.1/src/acquirium/Storage/duckdb_store.py +538 -0
  140. acquirium-0.1.1/src/acquirium/Storage/graph_store.py +301 -0
  141. acquirium-0.1.1/src/acquirium/Storage/timescale_store.py +618 -0
  142. acquirium-0.1.1/src/acquirium/Storage/values.py +138 -0
  143. acquirium-0.1.1/src/acquirium/TextMatch/decorators.py +47 -0
  144. acquirium-0.1.1/src/acquirium/TextMatch/embedding_matcher.py +326 -0
  145. acquirium-0.1.1/src/acquirium/TextMatch/qudt_store.py +210 -0
  146. acquirium-0.1.1/src/acquirium/__init__.py +6 -0
  147. acquirium-0.1.1/src/acquirium/cli.py +343 -0
  148. acquirium-0.1.1/src/acquirium/internals/app_utils.py +13 -0
  149. acquirium-0.1.1/src/acquirium/internals/init-timescaledb.sql +2 -0
  150. acquirium-0.1.1/src/acquirium/internals/internals_namespaces.py +124 -0
  151. acquirium-0.1.1/src/acquirium/internals/models.py +195 -0
  152. acquirium-0.1.1/src/acquirium/internals/mosquitto.conf +12 -0
  153. acquirium-0.1.1/src/acquirium/internals/qudt_units.py +468 -0
  154. acquirium-0.1.1/src/acquirium/py.typed +0 -0
  155. acquirium-0.1.1/tests/Dockerfile +11 -0
  156. acquirium-0.1.1/tests/conftest.py +114 -0
  157. acquirium-0.1.1/tests/integration/__init__.py +0 -0
  158. acquirium-0.1.1/tests/integration/test_api_endpoints.py +348 -0
  159. acquirium-0.1.1/tests/integration/test_graph_store.py +208 -0
  160. acquirium-0.1.1/tests/integration/test_timescale_store.py +350 -0
  161. acquirium-0.1.1/tests/sample_data.csv +8761 -0
  162. acquirium-0.1.1/tests/smoke_test.py +41 -0
  163. acquirium-0.1.1/tests/src/data_generator.py +30 -0
  164. acquirium-0.1.1/tests/src/graph_generator.py +84 -0
  165. acquirium-0.1.1/tests/src/graph_structure.pdf +0 -0
  166. acquirium-0.1.1/tests/src/requirements.txt +2 -0
  167. acquirium-0.1.1/tests/src/stream_simulation.py +77 -0
  168. acquirium-0.1.1/tests/test_data_object.py +211 -0
  169. acquirium-0.1.1/tests/test_duckdb_store.py +436 -0
  170. acquirium-0.1.1/tests/test_logs.py +297 -0
  171. acquirium-0.1.1/tests/test_model.ttl +260 -0
  172. acquirium-0.1.1/tests/test_model_copy.ttl +265 -0
  173. acquirium-0.1.1/tests/test_model_csv.ttl +116 -0
  174. acquirium-0.1.1/tests/test_model_nodata.ttl +41 -0
  175. acquirium-0.1.1/tests/test_model_stream.ttl +78 -0
  176. acquirium-0.1.1/tests/test_model_units.ttl +49 -0
  177. acquirium-0.1.1/tests/test_query_data.py +124 -0
  178. acquirium-0.1.1/tests/test_query_metadata.py +433 -0
  179. acquirium-0.1.1/tests/test_resolve_text.py +411 -0
  180. acquirium-0.1.1/tests/test_timeseries_store_contract.py +226 -0
  181. acquirium-0.1.1/tests/test_unit_conversion.py +214 -0
  182. acquirium-0.1.1/tests/unit/__init__.py +0 -0
  183. acquirium-0.1.1/tests/unit/conftest.py +32 -0
  184. acquirium-0.1.1/tests/unit/test_acquirium_polars_insert.py +62 -0
  185. acquirium-0.1.1/tests/unit/test_acquirium_stream_registration.py +136 -0
  186. acquirium-0.1.1/tests/unit/test_app_runner_caching.py +286 -0
  187. acquirium-0.1.1/tests/unit/test_app_utils.py +32 -0
  188. acquirium-0.1.1/tests/unit/test_apps_output.py +186 -0
  189. acquirium-0.1.1/tests/unit/test_client_http.py +200 -0
  190. acquirium-0.1.1/tests/unit/test_csv_ingest.py +460 -0
  191. acquirium-0.1.1/tests/unit/test_driver_helpers.py +59 -0
  192. acquirium-0.1.1/tests/unit/test_embedding_matcher_helpers.py +97 -0
  193. acquirium-0.1.1/tests/unit/test_grafana.py +76 -0
  194. acquirium-0.1.1/tests/unit/test_graph_store_helpers.py +60 -0
  195. acquirium-0.1.1/tests/unit/test_manager_external_refs.py +99 -0
  196. acquirium-0.1.1/tests/unit/test_manager_recreate_warning.py +9 -0
  197. acquirium-0.1.1/tests/unit/test_manager_timeseries_batch.py +143 -0
  198. acquirium-0.1.1/tests/unit/test_models.py +184 -0
  199. acquirium-0.1.1/tests/unit/test_mqtt_helpers.py +124 -0
  200. acquirium-0.1.1/tests/unit/test_qudt_store_helpers.py +88 -0
  201. acquirium-0.1.1/tests/unit/test_query_graph.py +116 -0
  202. acquirium-0.1.1/tests/unit/test_query_value_mode.py +55 -0
  203. acquirium-0.1.1/tests/unit/test_server_helpers.py +27 -0
  204. acquirium-0.1.1/tests/unit/test_storage_values.py +77 -0
  205. acquirium-0.1.1/tests/unit/test_watertap_driver.py +205 -0
  206. acquirium-0.1.1/tests/unit/test_worker_query_refresh.py +142 -0
  207. acquirium-0.1.1/tests/unit/test_xlsx_ingest.py +119 -0
  208. acquirium-0.1.1/uv.lock +2626 -0
@@ -0,0 +1,35 @@
1
+ # Copy this file to .env and adjust values for your environment.
2
+ # docker compose automatically loads .env from the project root.
3
+
4
+ # ── TimescaleDB ───────────────────────────────────────────────────────────────
5
+ POSTGRES_USER=acquirium
6
+ POSTGRES_PASSWORD=acquirium
7
+ POSTGRES_DB=acquirium_test
8
+
9
+ # ── Acquirium Server ──────────────────────────────────────────────────────────
10
+
11
+ # Connection string for the TimescaleDB instance.
12
+ # Inside Docker Compose the hostname is the service name ("timescaledb").
13
+ PG_DSN=postgresql://acquirium:acquirium@timescaledb:5432/acquirium_test
14
+
15
+ # Directory where the server persists RDF graph data and other state.
16
+ ACQUIRIUM_DATA_DIR=/app/.acquirium
17
+
18
+ # Where fastembed caches downloaded embedding models.
19
+ FASTEMBED_CACHE_PATH=/app/.fastembed_cache
20
+
21
+ # Set to "true" to wipe and reinitialise all data on startup.
22
+ # Forced to true by `make test` and `make rebuild`.
23
+ ACQUIRIUM_RECREATE=false
24
+
25
+ # Docker network name used when the server launches App containers.
26
+ # Default matches the Compose-generated name: <project-dir>_acquirium_net.
27
+ # Override if you run Compose with a custom project name (-p flag).
28
+ ACQUIRIUM_APP_NETWORK=acquirium_acquirium_net
29
+
30
+ # ── Ports (host-side) ─────────────────────────────────────────────────────────
31
+ # Uncomment and change these if default ports conflict with other services.
32
+ # TIMESCALEDB_PORT=5432
33
+ # MOSQUITTO_PORT=1883
34
+ # ACQUIRIUM_PORT=8000
35
+ # GRAFANA_PORT=3000
@@ -0,0 +1,134 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ unit-tests:
15
+ name: Unit Tests
16
+ runs-on: ubuntu-latest
17
+
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v5
21
+
22
+ - name: Install UV
23
+ uses: astral-sh/setup-uv@v5
24
+ with:
25
+ version: "latest"
26
+
27
+ - name: Set up Python
28
+ run: uv python install 3.12
29
+
30
+ - name: Cache UV dependencies
31
+ uses: actions/cache@v5
32
+ with:
33
+ path: |
34
+ ~/.cache/uv
35
+ .venv
36
+ key: uv-${{ runner.os }}-py3.12-${{ hashFiles('pyproject.toml', 'uv.lock') }}
37
+ restore-keys: |
38
+ uv-${{ runner.os }}-py3.12-
39
+
40
+ - name: Install dependencies
41
+ run: uv sync --python 3.12 --locked --all-extras
42
+
43
+ - name: Run unit tests with coverage
44
+ run: |
45
+ uv run pytest tests/unit/ \
46
+ -v \
47
+ --tb=short \
48
+ --junitxml=junit-results.xml \
49
+ --cov=acquirium \
50
+ --cov-report=term-missing \
51
+ --cov-report=xml:coverage.xml
52
+
53
+ - name: Upload test results
54
+ if: always()
55
+ uses: actions/upload-artifact@v5
56
+ with:
57
+ name: unit-test-results
58
+ path: |
59
+ junit-results.xml
60
+ coverage.xml
61
+
62
+ integration-tests:
63
+ name: Integration Tests
64
+ runs-on: ubuntu-latest
65
+ needs: unit-tests
66
+
67
+ steps:
68
+ - name: Checkout code
69
+ uses: actions/checkout@v5
70
+
71
+ - name: Install UV
72
+ uses: astral-sh/setup-uv@v5
73
+ with:
74
+ version: "latest"
75
+
76
+ - name: Set up Python
77
+ run: uv python install 3.12
78
+
79
+ - name: Cache UV dependencies
80
+ uses: actions/cache@v5
81
+ with:
82
+ path: |
83
+ ~/.cache/uv
84
+ .venv
85
+ key: uv-${{ runner.os }}-py3.12-${{ hashFiles('pyproject.toml', 'uv.lock') }}
86
+ restore-keys: |
87
+ uv-${{ runner.os }}-py3.12-
88
+
89
+ - name: Install dependencies
90
+ run: uv sync --python 3.12 --locked --all-extras
91
+
92
+ - name: Check Docker Compose
93
+ run: docker compose version
94
+
95
+ - name: Start services
96
+ run: make testing-up
97
+ env:
98
+ ACQUIRIUM_RECREATE: "true"
99
+
100
+ - name: Wait for server health
101
+ run: make wait-health ACQUIRIUM_PORT=8010
102
+
103
+ - name: Run integration tests
104
+ env:
105
+ ACQUIRIUM_TEST_SERVER_HOST: localhost
106
+ ACQUIRIUM_TEST_SERVER_PORT: "8010"
107
+ ACQUIRIUM_TEST_PG_DSN: postgresql://acquirium:acquirium@localhost:55432/acquirium_test
108
+ run: |
109
+ uv run pytest tests/ \
110
+ -v \
111
+ --tb=short \
112
+ --ignore=tests/unit \
113
+ --junitxml=junit-integration.xml
114
+
115
+ - name: Collect service logs
116
+ if: failure()
117
+ run: COMPOSE_PROJECT_NAME=acquirium_test docker compose -f compose.testing.yaml --profile server --profile test logs --tail=200 > service-logs.txt 2>&1
118
+
119
+ - name: Show service status
120
+ if: failure()
121
+ run: COMPOSE_PROJECT_NAME=acquirium_test docker compose -f compose.testing.yaml --profile server --profile test ps
122
+
123
+ - name: Upload results
124
+ if: always()
125
+ uses: actions/upload-artifact@v5
126
+ with:
127
+ name: integration-test-results
128
+ path: |
129
+ junit-integration.xml
130
+ service-logs.txt
131
+
132
+ - name: Tear down
133
+ if: always()
134
+ run: make testing-down
@@ -0,0 +1,101 @@
1
+ name: "Publish release to PyPI"
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ # Pushing a tag like v0.2.0 publishes to TestPyPI.
7
+ - 'v*'
8
+ release:
9
+ # Publishing a GitHub Release publishes to PyPI.
10
+ types: [published]
11
+
12
+ jobs:
13
+ build:
14
+ name: Build distribution
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v6
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
22
+
23
+ - name: Install Python 3.12
24
+ run: uv python install 3.12
25
+
26
+ - name: Verify ref tag matches pyproject version
27
+ run: |
28
+ if [ "${{ github.event_name }}" = "release" ]; then
29
+ REF="${{ github.event.release.tag_name }}"
30
+ else
31
+ REF="${GITHUB_REF#refs/tags/}"
32
+ fi
33
+ TAG="${REF#v}"
34
+ VERSION="$(uv version --short)"
35
+ if [ "$TAG" != "$VERSION" ]; then
36
+ echo "::error::Ref tag v$TAG does not match pyproject version $VERSION"
37
+ exit 1
38
+ fi
39
+
40
+ - name: Build
41
+ run: uv build
42
+
43
+ - name: Smoke test (wheel)
44
+ run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
45
+
46
+ - name: Smoke test (source distribution)
47
+ run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
48
+
49
+ - name: Upload dist
50
+ uses: actions/upload-artifact@v5
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+
55
+ publish-testpypi:
56
+ name: Publish to TestPyPI
57
+ needs: build
58
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
59
+ runs-on: ubuntu-latest
60
+ environment:
61
+ name: testpypi
62
+ url: https://test.pypi.org/p/acquirium
63
+ permissions:
64
+ id-token: write
65
+ contents: read
66
+ steps:
67
+ - name: Download dist
68
+ uses: actions/download-artifact@v5
69
+ with:
70
+ name: dist
71
+ path: dist/
72
+
73
+ - name: Install uv
74
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
75
+
76
+ - name: Publish to TestPyPI
77
+ run: uv publish --publish-url https://test.pypi.org/legacy/ --trusted-publishing always
78
+
79
+ publish-pypi:
80
+ name: Publish to PyPI
81
+ needs: build
82
+ if: github.event_name == 'release' && github.event.action == 'published'
83
+ runs-on: ubuntu-latest
84
+ environment:
85
+ name: pypi
86
+ url: https://pypi.org/p/acquirium
87
+ permissions:
88
+ id-token: write
89
+ contents: read
90
+ steps:
91
+ - name: Download dist
92
+ uses: actions/download-artifact@v5
93
+ with:
94
+ name: dist
95
+ path: dist/
96
+
97
+ - name: Install uv
98
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
99
+
100
+ - name: Publish to PyPI
101
+ run: uv publish --trusted-publishing always
@@ -0,0 +1,219 @@
1
+ # default data location
2
+ .acquirium
3
+
4
+ scripts/dev_examples
5
+ # Byte-compiled / optimized / DLL files
6
+ __pycache__/
7
+ *.py[codz]
8
+ *$py.class
9
+
10
+ # C extensions
11
+ *.so
12
+
13
+ # Distribution / packaging
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Installer logs
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .nox/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py.cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+ cover/
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+ db.sqlite3
66
+ db.sqlite3-journal
67
+
68
+ # Flask stuff:
69
+ instance/
70
+ .webassets-cache
71
+
72
+ # Scrapy stuff:
73
+ .scrapy
74
+
75
+ # Sphinx documentation
76
+ docs/_build/
77
+
78
+ # PyBuilder
79
+ .pybuilder/
80
+ target/
81
+
82
+ # Jupyter Notebook
83
+ .ipynb_checkpoints
84
+
85
+ # IPython
86
+ profile_default/
87
+ ipython_config.py
88
+
89
+ # pyenv
90
+ # For a library or package, you might want to ignore these files since the code is
91
+ # intended to run in multiple environments; otherwise, check them in:
92
+ # .python-version
93
+
94
+ # pipenv
95
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
97
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
98
+ # install all needed dependencies.
99
+ #Pipfile.lock
100
+
101
+ # UV
102
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
103
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
104
+ # commonly ignored for libraries.
105
+ #uv.lock
106
+
107
+ # poetry
108
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
109
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
110
+ # commonly ignored for libraries.
111
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
112
+ #poetry.lock
113
+ #poetry.toml
114
+
115
+ # pdm
116
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
117
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
118
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
119
+ #pdm.lock
120
+ #pdm.toml
121
+ .pdm-python
122
+ .pdm-build/
123
+
124
+ # pixi
125
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
126
+ #pixi.lock
127
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
128
+ # in the .venv directory. It is recommended not to include this directory in version control.
129
+ .pixi
130
+
131
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
132
+ __pypackages__/
133
+
134
+ # Celery stuff
135
+ celerybeat-schedule
136
+ celerybeat.pid
137
+
138
+ # SageMath parsed files
139
+ *.sage.py
140
+
141
+ # Environments
142
+ .env
143
+ .envrc
144
+ .venv
145
+ env/
146
+ venv/
147
+ ENV/
148
+ env.bak/
149
+ venv.bak/
150
+
151
+ # Spyder project settings
152
+ .spyderproject
153
+ .spyproject
154
+
155
+ # Rope project settings
156
+ .ropeproject
157
+
158
+ # mkdocs documentation
159
+ /site
160
+
161
+ # mypy
162
+ .mypy_cache/
163
+ .dmypy.json
164
+ dmypy.json
165
+
166
+ # Pyre type checker
167
+ .pyre/
168
+
169
+ # pytype static type analyzer
170
+ .pytype/
171
+
172
+ # Cython debug symbols
173
+ cython_debug/
174
+
175
+ # PyCharm
176
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
177
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
178
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
179
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
180
+ #.idea/
181
+
182
+ # Abstra
183
+ # Abstra is an AI-powered process automation framework.
184
+ # Ignore directories containing user credentials, local state, and settings.
185
+ # Learn more at https://abstra.io/docs
186
+ .abstra/
187
+
188
+ # Visual Studio Code
189
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
190
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
191
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
192
+ # you could uncomment the following to ignore the entire vscode folder
193
+ # .vscode/
194
+
195
+ # Ruff stuff:
196
+ .ruff_cache/
197
+
198
+ # PyPI configuration file
199
+ .pypirc
200
+
201
+ # Cursor
202
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
203
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
204
+ # refer to https://docs.cursor.com/context/ignore-files
205
+ .cursorignore
206
+ .cursorindexingignore
207
+
208
+ # Marimo
209
+ marimo/_static/
210
+ marimo/_lsp/
211
+ __marimo__/
212
+
213
+ scripts/benchmark/chain/*.csv
214
+ scripts/benchmark/chain/*.parquet
215
+ scripts/benchmark/chain/memo
216
+ scripts/benchmark/scalability/*.csv
217
+
218
+ # Local DPR trailer data exports and generated databases.
219
+ dpr-trailer-data/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ While the version is `0.y.z`, the public API is considered unstable and may
9
+ change in any release.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.1.1] - 2026-05-19
14
+
15
+ ### Changed
16
+ - Default `timeseries_backend` is now `duckdb` when no `acquirium.toml` is
17
+ present, so `pip install acquirium && acquirium server` starts a working
18
+ server with no external services. Set
19
+ `ACQUIRIUM_TIMESERIES_BACKEND=timescale` (or configure it in
20
+ `acquirium.toml`) to opt back into Postgres/TimescaleDB.
21
+ - `ipykernel` moved out of the runtime dependency set into a `notebook`
22
+ optional extra; install with `pip install "acquirium[notebook]"`.
23
+
24
+ ## [0.1.0] - 2026-05-19
25
+
26
+ ### Added
27
+ - Initial public release on PyPI.
28
+ - `acquirium` CLI entry point.
29
+ - Client API (`Acquirium`, `Query`, `DataObject`).
30
+ - Apps framework (`App`, `Output`, `AppContext`).
31
+ - Driver framework (`Driver`, `IngestDriver`, `EventIngestDriver`, `PollingIngestDriver`).
32
+ - Built-in drivers and WaterTAP integration (optional `watertap` extra).
33
+ - Text matcher backed by FastEmbed with QUDT and graph indexes.
34
+ - Grafana dashboard helpers.
35
+
36
+ [Unreleased]: https://github.com/DataDrivenCPS/acquirium/compare/v0.1.1...HEAD
37
+ [0.1.1]: https://github.com/DataDrivenCPS/acquirium/compare/v0.1.0...v0.1.1
38
+ [0.1.0]: https://github.com/DataDrivenCPS/acquirium/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 DataDrivenCPS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,129 @@
1
+ SHELL := /bin/bash
2
+
3
+ COMPOSE ?= docker compose
4
+ TEST_COMPOSE ?= COMPOSE_PROJECT_NAME=acquirium_test $(COMPOSE) -f compose.testing.yaml
5
+
6
+ # Default; user can override: make up ACQUIRIUM_RECREATE=true
7
+ ACQUIRIUM_RECREATE ?= false
8
+ ACQUIRIUM_HOST ?= localhost
9
+ ACQUIRIUM_PORT ?= 8000
10
+ ACQUIRIUM_HOST_PORT ?= $(ACQUIRIUM_PORT)
11
+ ACQUIRIUM_HEALTH_URL := http://$(ACQUIRIUM_HOST):$(ACQUIRIUM_PORT)/health
12
+ ACQUIRIUM_HEALTH_TIMEOUT_SEC ?= 180
13
+ ACQUIRIUM_HEALTH_SLEEP_SEC ?= 2
14
+ # Optional flag: make up RECREATE=true
15
+ ifeq ($(RECREATE),true)
16
+ ACQUIRIUM_RECREATE := true
17
+ endif
18
+
19
+ export ACQUIRIUM_RECREATE
20
+
21
+ # Config file mounted into the acquirium container; override per-target for testing.
22
+ ACQUIRIUM_CONFIG_FILE ?= acquirium.toml
23
+ export ACQUIRIUM_CONFIG_FILE
24
+
25
+ POSTGRES_DB ?= acquirium
26
+ POSTGRES_HOST_PORT ?= 5432
27
+ PG_DSN ?= postgresql://acquirium:acquirium@timescaledb:5432/$(POSTGRES_DB)
28
+ TSDB_VOLUME ?= acquirium_tsdb_data
29
+ MQTT_HOST_PORT ?= 1883
30
+ ACQUIRIUM_APP_NETWORK ?= acquirium_acquirium_net
31
+
32
+ export POSTGRES_DB
33
+ export POSTGRES_HOST_PORT
34
+ export PG_DSN
35
+ export TSDB_VOLUME
36
+ export MQTT_HOST_PORT
37
+ export ACQUIRIUM_HOST_PORT
38
+ export ACQUIRIUM_APP_NETWORK
39
+
40
+ TEST_PYTEST_ENV := ACQUIRIUM_TEST_SERVER_HOST=localhost ACQUIRIUM_TEST_SERVER_PORT=8010 ACQUIRIUM_TEST_PG_DSN=postgresql://acquirium:acquirium@localhost:55432/acquirium_test
41
+
42
+ .PHONY: up rebuild down no-server-up no-server-down test testing-up testing-down watertap-up watertap-down logs ps
43
+
44
+ up:
45
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server up -d --build
46
+ @$(MAKE) wait-health
47
+
48
+ wait-health:
49
+ @echo "Waiting for Acquirium server health check: $(ACQUIRIUM_HEALTH_URL)"
50
+ @deadline=$$(( $$(date +%s) + $(ACQUIRIUM_HEALTH_TIMEOUT_SEC) )); \
51
+ while true; do \
52
+ if curl -fsS "$(ACQUIRIUM_HEALTH_URL)" >/dev/null 2>&1; then \
53
+ echo "Acquirium server is ready."; \
54
+ break; \
55
+ fi; \
56
+ if [ $$(date +%s) -ge $$deadline ]; then \
57
+ echo "ERROR: Acquirium server did not become ready within $(ACQUIRIUM_HEALTH_TIMEOUT_SEC)s"; \
58
+ echo "Tip: check logs with: $(COMPOSE) logs -f acquirium_server"; \
59
+ exit 1; \
60
+ fi; \
61
+ sleep $(ACQUIRIUM_HEALTH_SLEEP_SEC); \
62
+ done
63
+ # Always enable for rebuild
64
+ rebuild: ACQUIRIUM_RECREATE := true
65
+ rebuild:
66
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server build --no-cache
67
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server up -d --force-recreate
68
+
69
+ down:
70
+ $(COMPOSE) down --remove-orphans
71
+
72
+ # Infrastructure-only mode for running Acquirium externally on the host.
73
+ # Starts TimescaleDB and Grafana, but not the Acquirium server container.
74
+ no-server-up:
75
+ $(COMPOSE) --profile no-server up -d timescaledb grafana
76
+
77
+ no-server-down:
78
+ $(COMPOSE) --profile no-server rm -sf grafana timescaledb
79
+
80
+ # Always tear down even on failure
81
+ test:
82
+ uv sync --locked --all-extras
83
+ status=0; \
84
+ $(TEST_COMPOSE) --profile server --profile test rm -sf timescaledb acquirium mosquitto testing_service >/dev/null 2>&1 || true; \
85
+ $(TEST_COMPOSE) --profile server --profile test up -d --build || status=$$?; \
86
+ if [ $$status -eq 0 ]; then $(TEST_PYTEST_ENV) uv run pytest tests || status=$$?; fi; \
87
+ $(MAKE) testing-down; \
88
+ exit $$status
89
+
90
+ testing-up:
91
+ $(TEST_COMPOSE) --profile server --profile test rm -sf timescaledb acquirium mosquitto testing_service >/dev/null 2>&1 || true
92
+ $(TEST_COMPOSE) --profile server --profile test up -d --build
93
+
94
+
95
+ testing-down:
96
+ $(TEST_COMPOSE) --profile server --profile test down --remove-orphans
97
+
98
+ watertap-up: ACQUIRIUM_RECREATE := true
99
+ watertap-up:
100
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server --profile watertap_simulation up -d --build
101
+
102
+ watertap-down:
103
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server --profile watertap_simulation down --remove-orphans
104
+
105
+ benicia-up:
106
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server --profile benicia_simulation up -d --build
107
+
108
+ benicia-down:
109
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server --profile benicia_simulation down --remove-orphans
110
+
111
+ unit-test:
112
+ uv run pytest tests/unit/ -v --tb=short
113
+
114
+ unit-test-cov:
115
+ uv run pytest tests/unit/ -v --tb=short --cov=acquirium --cov-report=term-missing
116
+
117
+ integration-test:
118
+ $(MAKE) testing-up
119
+ $(MAKE) wait-health ACQUIRIUM_PORT=8010
120
+ status=0; \
121
+ $(TEST_PYTEST_ENV) uv run pytest tests/ -v --tb=short --ignore=tests/unit || status=$$?; \
122
+ $(MAKE) testing-down; \
123
+ exit $$status
124
+
125
+ watertap-gui-up:
126
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server --profile watertap_gui up -d --build
127
+
128
+ watertap-gui-down:
129
+ ACQUIRIUM_RECREATE=$(ACQUIRIUM_RECREATE) $(COMPOSE) --profile server --profile watertap_gui down --remove-orphans