openingest 2.5.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 (99) hide show
  1. openingest-2.5.0/LICENSE +21 -0
  2. openingest-2.5.0/PKG-INFO +299 -0
  3. openingest-2.5.0/README.md +595 -0
  4. openingest-2.5.0/core/__init__.py +0 -0
  5. openingest-2.5.0/core/airflow/__init__.py +0 -0
  6. openingest-2.5.0/core/airflow/runner.py +132 -0
  7. openingest-2.5.0/core/airflow/task_factory.py +37 -0
  8. openingest-2.5.0/core/airflow_runner.py +55 -0
  9. openingest-2.5.0/core/connectors/__init__.py +10 -0
  10. openingest-2.5.0/core/connectors/api/__init__.py +1 -0
  11. openingest-2.5.0/core/connectors/api/rest_connector.py +338 -0
  12. openingest-2.5.0/core/connectors/base.py +52 -0
  13. openingest-2.5.0/core/connectors/cloud/__init__.py +1 -0
  14. openingest-2.5.0/core/connectors/cloud/azure_connector.py +185 -0
  15. openingest-2.5.0/core/connectors/cloud/gcs_connector.py +172 -0
  16. openingest-2.5.0/core/connectors/cloud/s3_connector.py +189 -0
  17. openingest-2.5.0/core/connectors/formats/__init__.py +1 -0
  18. openingest-2.5.0/core/connectors/formats/csv_connector.py +58 -0
  19. openingest-2.5.0/core/connectors/formats/excel_connector.py +106 -0
  20. openingest-2.5.0/core/connectors/formats/json_connector.py +145 -0
  21. openingest-2.5.0/core/connectors/formats/parquet_connector.py +92 -0
  22. openingest-2.5.0/core/connectors/registry.py +85 -0
  23. openingest-2.5.0/core/discovery.py +241 -0
  24. openingest-2.5.0/core/incremental.py +322 -0
  25. openingest-2.5.0/core/ingestion.py +227 -0
  26. openingest-2.5.0/core/lineage.py +234 -0
  27. openingest-2.5.0/core/metadata.py +12 -0
  28. openingest-2.5.0/core/notifications.py +229 -0
  29. openingest-2.5.0/core/observability.py +262 -0
  30. openingest-2.5.0/core/pipeline.py +126 -0
  31. openingest-2.5.0/core/quality.py +44 -0
  32. openingest-2.5.0/core/quality_report.py +32 -0
  33. openingest-2.5.0/core/quality_rules.py +301 -0
  34. openingest-2.5.0/core/reporting.py +82 -0
  35. openingest-2.5.0/core/scheduler.py +188 -0
  36. openingest-2.5.0/core/schema.py +276 -0
  37. openingest-2.5.0/core/validation.py +36 -0
  38. openingest-2.5.0/core/warehouse.py +5 -0
  39. openingest-2.5.0/docs/USABILITY_AND_OBSERVABILITY.md +243 -0
  40. openingest-2.5.0/models/__init__.py +0 -0
  41. openingest-2.5.0/models/dataset.py +49 -0
  42. openingest-2.5.0/models/pipeline_run.py +23 -0
  43. openingest-2.5.0/openingest/__init__.py +3 -0
  44. openingest-2.5.0/openingest/cli.py +5 -0
  45. openingest-2.5.0/openingest/templates/__init__.py +1 -0
  46. openingest-2.5.0/openingest/templates/project/.openingest +1 -0
  47. openingest-2.5.0/openingest/templates/project/README.md +29 -0
  48. openingest-2.5.0/openingest/templates/project/configs/datasets.yaml +19 -0
  49. openingest-2.5.0/openingest/templates/project/configs/pipeline.yaml +2 -0
  50. openingest-2.5.0/openingest/templates/project/configs/validation_rules.yaml +1 -0
  51. openingest-2.5.0/openingest/templates/project/configs/warehouse.yaml +2 -0
  52. openingest-2.5.0/openingest/templates/project/data/raw/.gitkeep +1 -0
  53. openingest-2.5.0/openingest/templates/project/docker-compose.yml +16 -0
  54. openingest-2.5.0/openingest/templates/project/plugins/.gitkeep +1 -0
  55. openingest-2.5.0/openingest/templates/project/reports/.gitkeep +1 -0
  56. openingest-2.5.0/openingest/templates/project/sql/.gitkeep +1 -0
  57. openingest-2.5.0/openingest.egg-info/PKG-INFO +299 -0
  58. openingest-2.5.0/openingest.egg-info/SOURCES.txt +97 -0
  59. openingest-2.5.0/openingest.egg-info/dependency_links.txt +1 -0
  60. openingest-2.5.0/openingest.egg-info/entry_points.txt +2 -0
  61. openingest-2.5.0/openingest.egg-info/requires.txt +56 -0
  62. openingest-2.5.0/openingest.egg-info/top_level.txt +5 -0
  63. openingest-2.5.0/pyproject.toml +113 -0
  64. openingest-2.5.0/scripts/__init__.py +0 -0
  65. openingest-2.5.0/scripts/commands/__init__.py +0 -0
  66. openingest-2.5.0/scripts/commands/add_dataset.py +102 -0
  67. openingest-2.5.0/scripts/commands/airflow_cmd.py +58 -0
  68. openingest-2.5.0/scripts/commands/discover.py +81 -0
  69. openingest-2.5.0/scripts/commands/docker_cmd.py +85 -0
  70. openingest-2.5.0/scripts/commands/doctor.py +108 -0
  71. openingest-2.5.0/scripts/commands/graph.py +59 -0
  72. openingest-2.5.0/scripts/commands/infer.py +110 -0
  73. openingest-2.5.0/scripts/commands/init.py +75 -0
  74. openingest-2.5.0/scripts/commands/profile.py +100 -0
  75. openingest-2.5.0/scripts/commands/schedule.py +65 -0
  76. openingest-2.5.0/scripts/commands/version.py +22 -0
  77. openingest-2.5.0/scripts/dashboard.py +149 -0
  78. openingest-2.5.0/scripts/data_quality_checks.py +69 -0
  79. openingest-2.5.0/scripts/ingest_customers.py +41 -0
  80. openingest-2.5.0/scripts/ingest_orders.py +40 -0
  81. openingest-2.5.0/scripts/ingest_products.py +36 -0
  82. openingest-2.5.0/scripts/load_warehouse.py +21 -0
  83. openingest-2.5.0/scripts/openingest.py +293 -0
  84. openingest-2.5.0/scripts/pipeline_history.py +34 -0
  85. openingest-2.5.0/scripts/report.py +5 -0
  86. openingest-2.5.0/scripts/run_pipeline.py +5 -0
  87. openingest-2.5.0/scripts/setup_database.py +40 -0
  88. openingest-2.5.0/scripts/transform_data.py +0 -0
  89. openingest-2.5.0/setup.cfg +4 -0
  90. openingest-2.5.0/tests/test_quality_report.py +46 -0
  91. openingest-2.5.0/tests/test_quality_rules.py +33 -0
  92. openingest-2.5.0/utils/__init__.py +0 -0
  93. openingest-2.5.0/utils/config.py +24 -0
  94. openingest-2.5.0/utils/config_loader.py +38 -0
  95. openingest-2.5.0/utils/db.py +11 -0
  96. openingest-2.5.0/utils/logger.py +0 -0
  97. openingest-2.5.0/utils/metadata_logger.py +195 -0
  98. openingest-2.5.0/utils/project.py +43 -0
  99. openingest-2.5.0/utils/schema_utils.py +15 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Manish Kudtarkar
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,299 @@
1
+ Metadata-Version: 2.4
2
+ Name: openingest
3
+ Version: 2.5.0
4
+ Summary: Configuration-driven data ingestion framework with quality checks, metadata, and orchestration
5
+ Author: OpenIngest Contributors
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: pandas
11
+ Requires-Dist: sqlalchemy
12
+ Requires-Dist: psycopg2-binary
13
+ Requires-Dist: python-dotenv
14
+ Requires-Dist: PyYAML==6.0.2
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=8.0; extra == "dev"
17
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
18
+ Requires-Dist: ruff>=0.4; extra == "dev"
19
+ Requires-Dist: mypy>=1.10; extra == "dev"
20
+ Provides-Extra: web
21
+ Requires-Dist: streamlit>=1.36; extra == "web"
22
+ Provides-Extra: excel
23
+ Requires-Dist: openpyxl>=3.1.2; extra == "excel"
24
+ Provides-Extra: parquet
25
+ Requires-Dist: pyarrow>=15.0; extra == "parquet"
26
+ Provides-Extra: s3
27
+ Requires-Dist: boto3>=1.34.0; extra == "s3"
28
+ Provides-Extra: azure
29
+ Requires-Dist: azure-storage-blob>=12.19.0; extra == "azure"
30
+ Provides-Extra: gcs
31
+ Requires-Dist: google-cloud-storage>=2.14.0; extra == "gcs"
32
+ Provides-Extra: api
33
+ Requires-Dist: requests>=2.31.0; extra == "api"
34
+ Provides-Extra: notifications
35
+ Requires-Dist: requests>=2.31.0; extra == "notifications"
36
+ Provides-Extra: v2
37
+ Requires-Dist: openpyxl>=3.1.2; extra == "v2"
38
+ Requires-Dist: pyarrow>=15.0; extra == "v2"
39
+ Requires-Dist: boto3>=1.34.0; extra == "v2"
40
+ Requires-Dist: azure-storage-blob>=12.19.0; extra == "v2"
41
+ Requires-Dist: google-cloud-storage>=2.14.0; extra == "v2"
42
+ Requires-Dist: requests>=2.31.0; extra == "v2"
43
+ Provides-Extra: all
44
+ Requires-Dist: openpyxl>=3.1.2; extra == "all"
45
+ Requires-Dist: pyarrow>=15.0; extra == "all"
46
+ Requires-Dist: boto3>=1.34.0; extra == "all"
47
+ Requires-Dist: azure-storage-blob>=12.19.0; extra == "all"
48
+ Requires-Dist: google-cloud-storage>=2.14.0; extra == "all"
49
+ Requires-Dist: requests>=2.31.0; extra == "all"
50
+ Requires-Dist: streamlit>=1.36; extra == "all"
51
+ Requires-Dist: pytest>=8.0; extra == "all"
52
+ Requires-Dist: pytest-cov>=5.0; extra == "all"
53
+ Requires-Dist: ruff>=0.4; extra == "all"
54
+ Requires-Dist: mypy>=1.10; extra == "all"
55
+ Dynamic: license-file
56
+
57
+ # OpenIngest — Usability and Observability
58
+
59
+ This document covers the monitoring, metadata, and notification capabilities of OpenIngest.
60
+
61
+ ---
62
+
63
+ ## Metadata tables
64
+
65
+ Every pipeline execution writes to four PostgreSQL tables automatically created on first run.
66
+
67
+ ### `pipeline_runs`
68
+
69
+ One row per full pipeline execution.
70
+
71
+ | Column | Type | Description |
72
+ |---|---|---|
73
+ | `run_id` | TEXT | Unique ID — format `OI-YYYYMMDD-XXXXXX` |
74
+ | `status` | TEXT | `SUCCESS` or `FAILED` |
75
+ | `total_datasets` | INTEGER | Datasets processed |
76
+ | `total_rows` | BIGINT | Total rows loaded |
77
+ | `total_duration` | FLOAT | Seconds |
78
+ | `started_at` | TIMESTAMP | Run start time |
79
+ | `finished_at` | TIMESTAMP | Run finish time |
80
+
81
+ ### `pipeline_dataset_runs`
82
+
83
+ One row per dataset per execution.
84
+
85
+ | Column | Type | Description |
86
+ |---|---|---|
87
+ | `run_id` | TEXT | Foreign key to `pipeline_runs` |
88
+ | `dataset_name` | TEXT | Dataset name from `datasets.yaml` |
89
+ | `status` | TEXT | `SUCCESS` or `FAILED` |
90
+ | `rows_loaded` | BIGINT | Rows loaded this run |
91
+ | `duration_seconds` | FLOAT | Seconds |
92
+ | `target_table` | TEXT | Staging table name |
93
+ | `load_strategy` | TEXT | `replace`, `append`, or `incremental` |
94
+ | `load_mode` | TEXT | `FULL`, `APPEND`, or `INCREMENTAL` |
95
+ | `watermark_value` | TEXT | Latest watermark (incremental only) |
96
+ | `loaded_at` | TIMESTAMP | Completion timestamp |
97
+
98
+ ### `pipeline_quality_runs`
99
+
100
+ One row per dataset per execution with quality metrics.
101
+
102
+ | Column | Type | Description |
103
+ |---|---|---|
104
+ | `run_id` | TEXT | Foreign key to `pipeline_runs` |
105
+ | `dataset_name` | TEXT | Dataset name |
106
+ | `status` | TEXT | `PASS` or `FAIL` |
107
+ | `score` | FLOAT | Quality score 0.0–100.0 |
108
+ | `checks_total` | INTEGER | Total checks run |
109
+ | `checks_passed` | INTEGER | Checks that passed |
110
+ | `checks_failed` | INTEGER | Checks that failed |
111
+
112
+ ### `pipeline_incremental_state`
113
+
114
+ Persists watermark state between runs for incremental datasets.
115
+
116
+ | Column | Type | Description |
117
+ |---|---|---|
118
+ | `dataset_name` | TEXT | Primary key |
119
+ | `target_table` | TEXT | Staging table |
120
+ | `incremental_column` | TEXT | Watermark column name |
121
+ | `last_watermark_value` | TEXT | Last processed watermark |
122
+ | `last_rows_loaded` | BIGINT | Rows loaded on last run |
123
+ | `last_source_rows` | BIGINT | Total source rows on last run |
124
+ | `last_loaded_at` | TIMESTAMP | Timestamp of last successful run |
125
+
126
+ ---
127
+
128
+ ## CLI monitoring commands
129
+
130
+ ```bash
131
+ # Latest execution report — one-line summary per dataset
132
+ openingest report
133
+
134
+ # Full run history
135
+ openingest history
136
+ openingest history --limit 10
137
+
138
+ # Full monitoring dashboard — KPIs, dataset health, quality trends
139
+ openingest dashboard
140
+ ```
141
+
142
+ The dashboard shows:
143
+ - Pipeline KPIs (latest run status, total rows, quality score, duration)
144
+ - Dataset health snapshot (per-dataset rows, quality, watermark)
145
+ - Dataset-level trends across the last 20 runs
146
+ - Incremental loading statistics (new records, skipped, latest watermark)
147
+ - Quality distribution (PASS / FAIL counts)
148
+ - Slowest datasets by average duration
149
+
150
+ ---
151
+
152
+ ## Notifications (v2.5)
153
+
154
+ Configure in `configs/pipeline.yaml`:
155
+
156
+ ```yaml
157
+ notifications:
158
+ slack:
159
+ webhook: ${SLACK_WEBHOOK_URL}
160
+ on: [success, failure] # which events trigger a notification
161
+
162
+ email:
163
+ smtp_host: smtp.gmail.com
164
+ smtp_port: 587
165
+ username: ${EMAIL_USERNAME}
166
+ password: ${EMAIL_PASSWORD}
167
+ from: openingest@company.com
168
+ to:
169
+ - data-team@company.com
170
+ - oncall@company.com
171
+ on: [failure] # only alert on failure
172
+ ```
173
+
174
+ Both channels support `on: [success]`, `on: [failure]`, or `on: [success, failure]` independently.
175
+
176
+ ### Slack message format
177
+
178
+ Uses Slack Block Kit. Example success notification:
179
+
180
+ ```
181
+ ✅ OpenIngest — Pipeline SUCCESS
182
+
183
+ Run ID : OI-20260703-3BB09C
184
+ Status : SUCCESS
185
+ Datasets : 8
186
+ Rows : 174,777
187
+ Duration : 4.21s
188
+ ```
189
+
190
+ ### Email format
191
+
192
+ Plain-text email via SMTP. Subject line:
193
+
194
+ ```
195
+ ✅ OpenIngest Pipeline: SUCCESS — OI-20260703-3BB09C
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Data lineage (v3.0)
201
+
202
+ The lineage engine builds a directed graph of how data flows through the pipeline per dataset.
203
+
204
+ ```python
205
+ from core.lineage import LineageGraph
206
+
207
+ graph = LineageGraph()
208
+
209
+ # Build lineage for all datasets after a run
210
+ for dataset in datasets:
211
+ graph.add_dataset_lineage(dataset)
212
+
213
+ # Terminal view
214
+ graph.print_ascii()
215
+
216
+ # Mermaid diagram (paste into any Mermaid renderer)
217
+ print(graph.to_mermaid())
218
+
219
+ # JSON for web UI or API
220
+ data = graph.to_dict()
221
+ ```
222
+
223
+ ### ASCII output
224
+
225
+ ```
226
+ customers
227
+ ├─ customers.csv [source]
228
+
229
+ ├─ Dataset Discovery
230
+
231
+ ├─ Schema Validation [PASS]
232
+
233
+ ├─ Quality Engine [PASS] 100.0%
234
+
235
+ ├─ Ingest (replace) 174,777 rows
236
+
237
+ └─ stg_customers [staging]
238
+ ```
239
+
240
+ ### Mermaid output
241
+
242
+ ```
243
+ flowchart TD
244
+ customers_source[("customers.csv")]
245
+ customers_discovery[["Dataset Discovery"]]
246
+ customers_schema_validation[["Schema Validation"]]
247
+ customers_quality_check{{"Quality Engine"}}
248
+ customers_ingest[["Ingest (replace)"]]
249
+ customers_staging[("stg_customers")]
250
+
251
+ customers_source --> customers_discovery
252
+ customers_discovery --> customers_schema_validation
253
+ customers_schema_validation --> customers_quality_check
254
+ customers_quality_check --> customers_ingest
255
+ customers_ingest --> customers_staging
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Observability queries
261
+
262
+ Direct SQL examples against the metadata tables:
263
+
264
+ ```sql
265
+ -- Latest run summary
266
+ SELECT run_id, status, total_datasets, total_rows, total_duration, started_at
267
+ FROM pipeline_runs
268
+ ORDER BY started_at DESC
269
+ LIMIT 1;
270
+
271
+ -- Quality score trend for orders
272
+ SELECT r.started_at, q.score, q.status
273
+ FROM pipeline_quality_runs q
274
+ JOIN pipeline_runs r USING (run_id)
275
+ WHERE q.dataset_name = 'orders'
276
+ ORDER BY r.started_at DESC
277
+ LIMIT 30;
278
+
279
+ -- Rows loaded per dataset on the latest run
280
+ WITH latest AS (SELECT run_id FROM pipeline_runs ORDER BY started_at DESC LIMIT 1)
281
+ SELECT dataset_name, rows_loaded, load_strategy, load_mode, watermark_value
282
+ FROM pipeline_dataset_runs
283
+ WHERE run_id = (SELECT run_id FROM latest)
284
+ ORDER BY dataset_name;
285
+
286
+ -- Datasets that failed quality checks in the last 7 days
287
+ SELECT r.started_at, q.dataset_name, q.score, q.checks_failed
288
+ FROM pipeline_quality_runs q
289
+ JOIN pipeline_runs r USING (run_id)
290
+ WHERE q.status = 'FAIL'
291
+ AND r.started_at >= NOW() - INTERVAL '7 days'
292
+ ORDER BY r.started_at DESC;
293
+
294
+ -- Current watermark state for incremental datasets
295
+ SELECT dataset_name, incremental_column, last_watermark_value,
296
+ last_rows_loaded, last_loaded_at
297
+ FROM pipeline_incremental_state
298
+ ORDER BY dataset_name;
299
+ ```