ubunye-engine 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 (71) hide show
  1. ubunye_engine-0.1.1/LICENSE +1 -0
  2. ubunye_engine-0.1.1/PKG-INFO +289 -0
  3. ubunye_engine-0.1.1/README.md +260 -0
  4. ubunye_engine-0.1.1/pyproject.toml +72 -0
  5. ubunye_engine-0.1.1/setup.cfg +4 -0
  6. ubunye_engine-0.1.1/tests/test_config.py +7 -0
  7. ubunye_engine-0.1.1/tests/test_rest_api_plugin.py +356 -0
  8. ubunye_engine-0.1.1/tests/test_runtime.py +6 -0
  9. ubunye_engine-0.1.1/ubunye/__init__.py +10 -0
  10. ubunye_engine-0.1.1/ubunye/backends/__init__.py +1 -0
  11. ubunye_engine-0.1.1/ubunye/backends/spark_backend.py +127 -0
  12. ubunye_engine-0.1.1/ubunye/cli/__init__.py +0 -0
  13. ubunye_engine-0.1.1/ubunye/cli/lineage.py +304 -0
  14. ubunye_engine-0.1.1/ubunye/cli/main.py +444 -0
  15. ubunye_engine-0.1.1/ubunye/cli/models.py +301 -0
  16. ubunye_engine-0.1.1/ubunye/cli/test_cmd.py +220 -0
  17. ubunye_engine-0.1.1/ubunye/compat/__init__.py +0 -0
  18. ubunye_engine-0.1.1/ubunye/compat/analytics_engine_shim.py +1 -0
  19. ubunye_engine-0.1.1/ubunye/config/__init__.py +6 -0
  20. ubunye_engine-0.1.1/ubunye/config/loader.py +136 -0
  21. ubunye_engine-0.1.1/ubunye/config/resolver.py +121 -0
  22. ubunye_engine-0.1.1/ubunye/config/schema.py +246 -0
  23. ubunye_engine-0.1.1/ubunye/core/__init__.py +0 -0
  24. ubunye_engine-0.1.1/ubunye/core/interfaces.py +67 -0
  25. ubunye_engine-0.1.1/ubunye/core/runtime.py +373 -0
  26. ubunye_engine-0.1.1/ubunye/lineage/__init__.py +23 -0
  27. ubunye_engine-0.1.1/ubunye/lineage/context.py +154 -0
  28. ubunye_engine-0.1.1/ubunye/lineage/hasher.py +149 -0
  29. ubunye_engine-0.1.1/ubunye/lineage/recorder.py +175 -0
  30. ubunye_engine-0.1.1/ubunye/lineage/storage.py +210 -0
  31. ubunye_engine-0.1.1/ubunye/models/__init__.py +17 -0
  32. ubunye_engine-0.1.1/ubunye/models/base.py +140 -0
  33. ubunye_engine-0.1.1/ubunye/models/gates.py +161 -0
  34. ubunye_engine-0.1.1/ubunye/models/loader.py +130 -0
  35. ubunye_engine-0.1.1/ubunye/models/registry.py +457 -0
  36. ubunye_engine-0.1.1/ubunye/orchestration/__init__.py +0 -0
  37. ubunye_engine-0.1.1/ubunye/orchestration/airflow_exporter.py +74 -0
  38. ubunye_engine-0.1.1/ubunye/orchestration/base.py +17 -0
  39. ubunye_engine-0.1.1/ubunye/orchestration/databricks_expoter.py +69 -0
  40. ubunye_engine-0.1.1/ubunye/plugins/__init__.py +0 -0
  41. ubunye_engine-0.1.1/ubunye/plugins/ml/__init__.py +0 -0
  42. ubunye_engine-0.1.1/ubunye/plugins/ml/adapters.py +35 -0
  43. ubunye_engine-0.1.1/ubunye/plugins/ml/base.py +231 -0
  44. ubunye_engine-0.1.1/ubunye/plugins/ml/pysparkml.py +47 -0
  45. ubunye_engine-0.1.1/ubunye/plugins/ml/sklearn.py +58 -0
  46. ubunye_engine-0.1.1/ubunye/plugins/readers/__init__.py +0 -0
  47. ubunye_engine-0.1.1/ubunye/plugins/readers/hive.py +25 -0
  48. ubunye_engine-0.1.1/ubunye/plugins/readers/jdbc.py +101 -0
  49. ubunye_engine-0.1.1/ubunye/plugins/readers/rest_api.py +444 -0
  50. ubunye_engine-0.1.1/ubunye/plugins/readers/s3.py +43 -0
  51. ubunye_engine-0.1.1/ubunye/plugins/readers/unity.py +46 -0
  52. ubunye_engine-0.1.1/ubunye/plugins/transforms/__init__.py +0 -0
  53. ubunye_engine-0.1.1/ubunye/plugins/transforms/model_transform.py +188 -0
  54. ubunye_engine-0.1.1/ubunye/plugins/transforms/noop.py +14 -0
  55. ubunye_engine-0.1.1/ubunye/plugins/writers/__init__.py +0 -0
  56. ubunye_engine-0.1.1/ubunye/plugins/writers/jdbc.py +76 -0
  57. ubunye_engine-0.1.1/ubunye/plugins/writers/rest_api.py +244 -0
  58. ubunye_engine-0.1.1/ubunye/plugins/writers/s3.py +22 -0
  59. ubunye_engine-0.1.1/ubunye/plugins/writers/unity.py +98 -0
  60. ubunye_engine-0.1.1/ubunye/telemetry/__init__.py +0 -0
  61. ubunye_engine-0.1.1/ubunye/telemetry/events.py +131 -0
  62. ubunye_engine-0.1.1/ubunye/telemetry/mlflow.py +75 -0
  63. ubunye_engine-0.1.1/ubunye/telemetry/monitors.py +54 -0
  64. ubunye_engine-0.1.1/ubunye/telemetry/otel.py +106 -0
  65. ubunye_engine-0.1.1/ubunye/telemetry/prometheus.py +128 -0
  66. ubunye_engine-0.1.1/ubunye_engine.egg-info/PKG-INFO +289 -0
  67. ubunye_engine-0.1.1/ubunye_engine.egg-info/SOURCES.txt +69 -0
  68. ubunye_engine-0.1.1/ubunye_engine.egg-info/dependency_links.txt +1 -0
  69. ubunye_engine-0.1.1/ubunye_engine.egg-info/entry_points.txt +27 -0
  70. ubunye_engine-0.1.1/ubunye_engine.egg-info/requires.txt +22 -0
  71. ubunye_engine-0.1.1/ubunye_engine.egg-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ MIT
@@ -0,0 +1,289 @@
1
+ Metadata-Version: 2.4
2
+ Name: ubunye-engine
3
+ Version: 0.1.1
4
+ Summary: Config-first, Spark-native ETL/ML engine with a modular plugin system
5
+ Author: Ubunye Team
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: pyyaml>=6
10
+ Requires-Dist: jinja2>=3
11
+ Requires-Dist: pydantic>=2
12
+ Requires-Dist: typer[all]>=0.12
13
+ Provides-Extra: spark
14
+ Requires-Dist: pyspark>=3.3; extra == "spark"
15
+ Provides-Extra: ml
16
+ Requires-Dist: scikit-learn; extra == "ml"
17
+ Requires-Dist: torch; extra == "ml"
18
+ Requires-Dist: mlflow; extra == "ml"
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: pytest-cov>=4; extra == "dev"
22
+ Requires-Dist: pytest-timeout; extra == "dev"
23
+ Requires-Dist: hypothesis>=6; extra == "dev"
24
+ Requires-Dist: requests>=2.28; extra == "dev"
25
+ Requires-Dist: black; extra == "dev"
26
+ Requires-Dist: ruff; extra == "dev"
27
+ Requires-Dist: build; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ <p align="center">
31
+ <img src="docs/assets/ubunye-logo-white-v2.png" alt="Ubunye Engine" width="400"/>
32
+ </p>
33
+
34
+ <p align="center">
35
+ <em>Ubunye (oo-BOON-yeh) β€” isiZulu for "unity"</em>
36
+ </p>
37
+
38
+ <h3 align="center">One framework. Every pipeline. Any environment.</h3>
39
+
40
+ <p align="center">
41
+ <a href="https://ubunye-ai-ecosystems.github.io/ubunye_engine">Docs</a> β€’
42
+ <a href="#quickstart">Quickstart</a> β€’
43
+ <a href="#why-ubunye">Why Ubunye</a> β€’
44
+ <a href="https://github.com/ubunye-ai-ecosystems/ubunye_engine/discussions">Community</a>
45
+ </p>
46
+
47
+ ---
48
+
49
+ ## Hey there πŸ‘‹
50
+
51
+ If you've ever spent more time wiring up Spark boilerplate than writing actual data logic β€” this is for you.
52
+
53
+ **Ubunye Engine** lets you define your entire data pipeline in a simple YAML config and a Python file. No Spark session setup. No connection management. No environment-specific scripts. Just tell the engine *what* you want, and it handles the *how*.
54
+
55
+ It works on your laptop, on YARN, on Kubernetes, on Databricks β€” same config, same code, everywhere.
56
+
57
+ ---
58
+
59
+ ## Quickstart
60
+
61
+ ```bash
62
+ pip install ubunye-engine
63
+ ```
64
+
65
+ Scaffold your first pipeline:
66
+
67
+ ```bash
68
+ ubunye init -d ./pipelines -u fraud_detection -p ingestion -t claim_etl
69
+ ```
70
+
71
+ You'll get:
72
+
73
+ ```
74
+ pipelines/
75
+ fraud_detection/
76
+ ingestion/
77
+ claim_etl/
78
+ config.yaml ← tell the engine what to do
79
+ transformations.py ← your logic goes here
80
+ ```
81
+
82
+ Open `config.yaml` and describe your pipeline:
83
+
84
+ ```yaml
85
+ MODEL: "etl"
86
+ VERSION: "0.1.0"
87
+
88
+ ENGINE:
89
+ profiles:
90
+ dev:
91
+ spark_conf:
92
+ spark.master: "local[*]"
93
+ prod:
94
+ spark_conf:
95
+ spark.master: "yarn"
96
+
97
+ CONFIG:
98
+ inputs:
99
+ raw_claims:
100
+ format: hive
101
+ db_name: fraud_db
102
+ tbl_name: raw_claims
103
+
104
+ transform:
105
+ type: noop
106
+
107
+ outputs:
108
+ bronze:
109
+ format: delta
110
+ table: main.fraud.bronze_claims
111
+ mode: overwrite
112
+ ```
113
+
114
+ Add your logic in `transformations.py`:
115
+
116
+ ```python
117
+ def transform(df):
118
+ return df.filter("claim_amount > 0").dropDuplicates(["claim_id"])
119
+ ```
120
+
121
+ Run it:
122
+
123
+ ```bash
124
+ ubunye run -d ./pipelines -u fraud_detection -p ingestion -t claim_etl --profile dev
125
+ ```
126
+
127
+ That's it. You just built and ran a pipeline. Same config runs in production β€” just swap `--profile prod`.
128
+
129
+ ---
130
+
131
+ ## Why Ubunye
132
+
133
+ We've all been there. You join a new team, open the repo, and find five Spark projects β€” each structured differently, each with its own way of handling configs, credentials, and deployment. One uses a JSON file, another has everything hardcoded, a third has a 300-line bash script that "Dave wrote and it just works."
134
+
135
+ Ubunye says: **let's agree on how pipelines look.** One folder structure. One config format. One CLI. Whether you're building an ETL job, a feature pipeline, or an ML training run.
136
+
137
+ | Without Ubunye | With Ubunye |
138
+ |---|---|
139
+ | Every project looks different | One standard: `use_case / pipeline / task` |
140
+ | Spark setup scattered everywhere | Engine handles it from YAML config |
141
+ | Credentials hardcoded or inconsistent | `{{ env.DB_PASSWORD }}` everywhere |
142
+ | "Works on my machine" | Same config runs local, YARN, K8s, Databricks |
143
+ | New teammate needs a week to onboard | `ubunye init` and they're running in minutes |
144
+
145
+ ---
146
+
147
+ ## How It Works
148
+
149
+ Three simple ideas:
150
+
151
+ **Config over code.** Your pipeline is a YAML file. Inputs, outputs, Spark settings, orchestration β€” all declared, not coded.
152
+
153
+ **Plugins for everything.** The `format` field in your config selects a connector β€” `hive`, `jdbc`, `delta`, `s3`, `unity`, `rest_api`, and more. Need a new data source? Add a plugin.
154
+
155
+ **Folders as architecture.** Pipelines are organized as `project / use_case / pipeline / task`. The CLI uses this for scaffolding, execution, and discovery:
156
+
157
+ ```
158
+ pipelines/
159
+ fraud_detection/
160
+ ingestion/
161
+ claim_etl/
162
+ policy_etl/
163
+ feature_engineering/
164
+ claim_features/
165
+ risk_scoring/
166
+ train_model/
167
+ score_claims/
168
+ ```
169
+
170
+ ---
171
+
172
+ ## What Can You Build With It
173
+
174
+ **ETL pipelines** β€” move data between Hive, JDBC databases, Delta Lake, S3, REST APIs. Config-driven, scheduled, reproducible.
175
+
176
+ **ML training and inference** β€” define your model behind a simple contract, let the engine handle versioning, storage, and deployment.
177
+
178
+ **RAG document pipelines** β€” ingest documents, extract text, chunk, compute embeddings, load into a vector store. All from YAML.
179
+
180
+ **Feature engineering** β€” compute features once, write to a shared table, reuse across use cases.
181
+
182
+ **Data drift detection** β€” monitor feature distributions between runs, flag when things shift.
183
+
184
+ Check out the [Patterns](https://ubunye-ai-ecosystems.github.io/ubunye_engine) section in our docs for full examples.
185
+
186
+ ---
187
+
188
+ ## Connectors
189
+
190
+ | Format | Read | Write | Description |
191
+ |---|:---:|:---:|---|
192
+ | `hive` | βœ“ | βœ“ | Apache Hive tables |
193
+ | `jdbc` | βœ“ | βœ“ | PostgreSQL, MySQL, Teradata, and more |
194
+ | `delta` | βœ“ | βœ“ | Delta Lake (standalone or Unity Catalog) |
195
+ | `s3` | βœ“ | βœ“ | S3, HDFS, or local filesystem |
196
+ | `unity` | βœ“ | βœ“ | Databricks Unity Catalog |
197
+ | `binary` | βœ“ | | Binary files (images, PDFs) |
198
+ | `rest_api` | βœ“ | βœ“ | REST APIs with pagination and auth |
199
+
200
+ Want to add one? See the [plugin guide](https://ubunye-ai-ecosystems.github.io/ubunye_engine).
201
+
202
+ ---
203
+
204
+ ## Run Anywhere
205
+
206
+ Same pipeline, no changes:
207
+
208
+ | Environment | Just set |
209
+ |---|---|
210
+ | Local | `spark.master: "local[*]"` |
211
+ | YARN / Hadoop | `spark.master: "yarn"` |
212
+ | Kubernetes | `spark.master: "k8s://..."` |
213
+ | Databricks | Via ORCHESTRATION config |
214
+ | AWS EMR | Via EMR Steps |
215
+
216
+ ---
217
+
218
+ ## Jinja Templating
219
+
220
+ All config values support Jinja2:
221
+
222
+ ```yaml
223
+ # Environment variables
224
+ password: "{{ env.DB_PASSWORD }}"
225
+
226
+ # CLI variables (--var ds=2025-01-01)
227
+ path: "s3a://bucket/{{ ds }}/"
228
+
229
+ # Defaults
230
+ path: "s3a://bucket/{{ ds | default('2025-01-01') }}/"
231
+ ```
232
+
233
+ ---
234
+
235
+ ## CLI
236
+
237
+ ```bash
238
+ ubunye init -d ./pipelines -u <use_case> -p <pipeline> -t <task> # scaffold
239
+ ubunye run -d ./pipelines -u <use_case> -p <pipeline> -t <task> # execute
240
+ ubunye validate -d ./pipelines -u <use_case> -p <pipeline> -t <task> # check config
241
+ ```
242
+
243
+ ---
244
+
245
+ ## What Ubunye Is Not
246
+
247
+ It's not an agent framework β€” use LangChain or CrewAI for that.
248
+ It's not an orchestrator β€” use Airflow, Prefect, or Dagster.
249
+ It's not a compute engine β€” it runs on Spark.
250
+
251
+ Ubunye is the **standardization layer** between your data sources and your applications. It makes the plumbing boring so you can focus on what matters.
252
+
253
+ ---
254
+
255
+ ## Roadmap
256
+
257
+ - [x] Config-driven ETL pipelines
258
+ - [x] Multi-environment profiles
259
+ - [x] Jinja templating
260
+ - [x] Plugin-based connectors
261
+ - [x] CLI scaffolding and execution
262
+ - [ ] Pydantic config validation
263
+ - [ ] ML model contract
264
+ - [ ] Model registry with versioning
265
+ - [ ] Data drift detection
266
+ - [ ] Lineage tracking
267
+
268
+ ---
269
+
270
+ ## Get Involved
271
+
272
+ We'd love your help. Whether it's a new connector, a bug fix, a typo, or just telling us what you're building β€” all contributions matter.
273
+
274
+ - πŸ› [Report a bug](https://github.com/ubunye-ai-ecosystems/ubunye_engine/issues)
275
+ - πŸ’‘ [Request a feature](https://github.com/ubunye-ai-ecosystems/ubunye_engine/discussions)
276
+ - πŸ“– [Read the contributing guide](CONTRIBUTING.md)
277
+ - ⭐ Star the repo if you find it useful β€” it helps more than you'd think
278
+
279
+ ---
280
+
281
+ ## License
282
+
283
+ [MIT License](LICENSE)
284
+
285
+ ---
286
+
287
+ <p align="center">
288
+ Built with πŸ‡ΏπŸ‡¦ by <a href="https://github.com/ubunye-ai-ecosystems">Ubunye AI Ecosystems</a>
289
+ </p>
@@ -0,0 +1,260 @@
1
+ <p align="center">
2
+ <img src="docs/assets/ubunye-logo-white-v2.png" alt="Ubunye Engine" width="400"/>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <em>Ubunye (oo-BOON-yeh) β€” isiZulu for "unity"</em>
7
+ </p>
8
+
9
+ <h3 align="center">One framework. Every pipeline. Any environment.</h3>
10
+
11
+ <p align="center">
12
+ <a href="https://ubunye-ai-ecosystems.github.io/ubunye_engine">Docs</a> β€’
13
+ <a href="#quickstart">Quickstart</a> β€’
14
+ <a href="#why-ubunye">Why Ubunye</a> β€’
15
+ <a href="https://github.com/ubunye-ai-ecosystems/ubunye_engine/discussions">Community</a>
16
+ </p>
17
+
18
+ ---
19
+
20
+ ## Hey there πŸ‘‹
21
+
22
+ If you've ever spent more time wiring up Spark boilerplate than writing actual data logic β€” this is for you.
23
+
24
+ **Ubunye Engine** lets you define your entire data pipeline in a simple YAML config and a Python file. No Spark session setup. No connection management. No environment-specific scripts. Just tell the engine *what* you want, and it handles the *how*.
25
+
26
+ It works on your laptop, on YARN, on Kubernetes, on Databricks β€” same config, same code, everywhere.
27
+
28
+ ---
29
+
30
+ ## Quickstart
31
+
32
+ ```bash
33
+ pip install ubunye-engine
34
+ ```
35
+
36
+ Scaffold your first pipeline:
37
+
38
+ ```bash
39
+ ubunye init -d ./pipelines -u fraud_detection -p ingestion -t claim_etl
40
+ ```
41
+
42
+ You'll get:
43
+
44
+ ```
45
+ pipelines/
46
+ fraud_detection/
47
+ ingestion/
48
+ claim_etl/
49
+ config.yaml ← tell the engine what to do
50
+ transformations.py ← your logic goes here
51
+ ```
52
+
53
+ Open `config.yaml` and describe your pipeline:
54
+
55
+ ```yaml
56
+ MODEL: "etl"
57
+ VERSION: "0.1.0"
58
+
59
+ ENGINE:
60
+ profiles:
61
+ dev:
62
+ spark_conf:
63
+ spark.master: "local[*]"
64
+ prod:
65
+ spark_conf:
66
+ spark.master: "yarn"
67
+
68
+ CONFIG:
69
+ inputs:
70
+ raw_claims:
71
+ format: hive
72
+ db_name: fraud_db
73
+ tbl_name: raw_claims
74
+
75
+ transform:
76
+ type: noop
77
+
78
+ outputs:
79
+ bronze:
80
+ format: delta
81
+ table: main.fraud.bronze_claims
82
+ mode: overwrite
83
+ ```
84
+
85
+ Add your logic in `transformations.py`:
86
+
87
+ ```python
88
+ def transform(df):
89
+ return df.filter("claim_amount > 0").dropDuplicates(["claim_id"])
90
+ ```
91
+
92
+ Run it:
93
+
94
+ ```bash
95
+ ubunye run -d ./pipelines -u fraud_detection -p ingestion -t claim_etl --profile dev
96
+ ```
97
+
98
+ That's it. You just built and ran a pipeline. Same config runs in production β€” just swap `--profile prod`.
99
+
100
+ ---
101
+
102
+ ## Why Ubunye
103
+
104
+ We've all been there. You join a new team, open the repo, and find five Spark projects β€” each structured differently, each with its own way of handling configs, credentials, and deployment. One uses a JSON file, another has everything hardcoded, a third has a 300-line bash script that "Dave wrote and it just works."
105
+
106
+ Ubunye says: **let's agree on how pipelines look.** One folder structure. One config format. One CLI. Whether you're building an ETL job, a feature pipeline, or an ML training run.
107
+
108
+ | Without Ubunye | With Ubunye |
109
+ |---|---|
110
+ | Every project looks different | One standard: `use_case / pipeline / task` |
111
+ | Spark setup scattered everywhere | Engine handles it from YAML config |
112
+ | Credentials hardcoded or inconsistent | `{{ env.DB_PASSWORD }}` everywhere |
113
+ | "Works on my machine" | Same config runs local, YARN, K8s, Databricks |
114
+ | New teammate needs a week to onboard | `ubunye init` and they're running in minutes |
115
+
116
+ ---
117
+
118
+ ## How It Works
119
+
120
+ Three simple ideas:
121
+
122
+ **Config over code.** Your pipeline is a YAML file. Inputs, outputs, Spark settings, orchestration β€” all declared, not coded.
123
+
124
+ **Plugins for everything.** The `format` field in your config selects a connector β€” `hive`, `jdbc`, `delta`, `s3`, `unity`, `rest_api`, and more. Need a new data source? Add a plugin.
125
+
126
+ **Folders as architecture.** Pipelines are organized as `project / use_case / pipeline / task`. The CLI uses this for scaffolding, execution, and discovery:
127
+
128
+ ```
129
+ pipelines/
130
+ fraud_detection/
131
+ ingestion/
132
+ claim_etl/
133
+ policy_etl/
134
+ feature_engineering/
135
+ claim_features/
136
+ risk_scoring/
137
+ train_model/
138
+ score_claims/
139
+ ```
140
+
141
+ ---
142
+
143
+ ## What Can You Build With It
144
+
145
+ **ETL pipelines** β€” move data between Hive, JDBC databases, Delta Lake, S3, REST APIs. Config-driven, scheduled, reproducible.
146
+
147
+ **ML training and inference** β€” define your model behind a simple contract, let the engine handle versioning, storage, and deployment.
148
+
149
+ **RAG document pipelines** β€” ingest documents, extract text, chunk, compute embeddings, load into a vector store. All from YAML.
150
+
151
+ **Feature engineering** β€” compute features once, write to a shared table, reuse across use cases.
152
+
153
+ **Data drift detection** β€” monitor feature distributions between runs, flag when things shift.
154
+
155
+ Check out the [Patterns](https://ubunye-ai-ecosystems.github.io/ubunye_engine) section in our docs for full examples.
156
+
157
+ ---
158
+
159
+ ## Connectors
160
+
161
+ | Format | Read | Write | Description |
162
+ |---|:---:|:---:|---|
163
+ | `hive` | βœ“ | βœ“ | Apache Hive tables |
164
+ | `jdbc` | βœ“ | βœ“ | PostgreSQL, MySQL, Teradata, and more |
165
+ | `delta` | βœ“ | βœ“ | Delta Lake (standalone or Unity Catalog) |
166
+ | `s3` | βœ“ | βœ“ | S3, HDFS, or local filesystem |
167
+ | `unity` | βœ“ | βœ“ | Databricks Unity Catalog |
168
+ | `binary` | βœ“ | | Binary files (images, PDFs) |
169
+ | `rest_api` | βœ“ | βœ“ | REST APIs with pagination and auth |
170
+
171
+ Want to add one? See the [plugin guide](https://ubunye-ai-ecosystems.github.io/ubunye_engine).
172
+
173
+ ---
174
+
175
+ ## Run Anywhere
176
+
177
+ Same pipeline, no changes:
178
+
179
+ | Environment | Just set |
180
+ |---|---|
181
+ | Local | `spark.master: "local[*]"` |
182
+ | YARN / Hadoop | `spark.master: "yarn"` |
183
+ | Kubernetes | `spark.master: "k8s://..."` |
184
+ | Databricks | Via ORCHESTRATION config |
185
+ | AWS EMR | Via EMR Steps |
186
+
187
+ ---
188
+
189
+ ## Jinja Templating
190
+
191
+ All config values support Jinja2:
192
+
193
+ ```yaml
194
+ # Environment variables
195
+ password: "{{ env.DB_PASSWORD }}"
196
+
197
+ # CLI variables (--var ds=2025-01-01)
198
+ path: "s3a://bucket/{{ ds }}/"
199
+
200
+ # Defaults
201
+ path: "s3a://bucket/{{ ds | default('2025-01-01') }}/"
202
+ ```
203
+
204
+ ---
205
+
206
+ ## CLI
207
+
208
+ ```bash
209
+ ubunye init -d ./pipelines -u <use_case> -p <pipeline> -t <task> # scaffold
210
+ ubunye run -d ./pipelines -u <use_case> -p <pipeline> -t <task> # execute
211
+ ubunye validate -d ./pipelines -u <use_case> -p <pipeline> -t <task> # check config
212
+ ```
213
+
214
+ ---
215
+
216
+ ## What Ubunye Is Not
217
+
218
+ It's not an agent framework β€” use LangChain or CrewAI for that.
219
+ It's not an orchestrator β€” use Airflow, Prefect, or Dagster.
220
+ It's not a compute engine β€” it runs on Spark.
221
+
222
+ Ubunye is the **standardization layer** between your data sources and your applications. It makes the plumbing boring so you can focus on what matters.
223
+
224
+ ---
225
+
226
+ ## Roadmap
227
+
228
+ - [x] Config-driven ETL pipelines
229
+ - [x] Multi-environment profiles
230
+ - [x] Jinja templating
231
+ - [x] Plugin-based connectors
232
+ - [x] CLI scaffolding and execution
233
+ - [ ] Pydantic config validation
234
+ - [ ] ML model contract
235
+ - [ ] Model registry with versioning
236
+ - [ ] Data drift detection
237
+ - [ ] Lineage tracking
238
+
239
+ ---
240
+
241
+ ## Get Involved
242
+
243
+ We'd love your help. Whether it's a new connector, a bug fix, a typo, or just telling us what you're building β€” all contributions matter.
244
+
245
+ - πŸ› [Report a bug](https://github.com/ubunye-ai-ecosystems/ubunye_engine/issues)
246
+ - πŸ’‘ [Request a feature](https://github.com/ubunye-ai-ecosystems/ubunye_engine/discussions)
247
+ - πŸ“– [Read the contributing guide](CONTRIBUTING.md)
248
+ - ⭐ Star the repo if you find it useful β€” it helps more than you'd think
249
+
250
+ ---
251
+
252
+ ## License
253
+
254
+ [MIT License](LICENSE)
255
+
256
+ ---
257
+
258
+ <p align="center">
259
+ Built with πŸ‡ΏπŸ‡¦ by <a href="https://github.com/ubunye-ai-ecosystems">Ubunye AI Ecosystems</a>
260
+ </p>
@@ -0,0 +1,72 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ubunye-engine"
7
+ version = "0.1.1"
8
+ description = "Config-first, Spark-native ETL/ML engine with a modular plugin system"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ authors = [{name="Ubunye Team"}]
12
+ dependencies = [
13
+ "pyyaml>=6",
14
+ "jinja2>=3",
15
+ "pydantic>=2",
16
+ "typer[all]>=0.12",
17
+ # pyspark is large; declare as optional so users can choose version
18
+ ]
19
+
20
+ [project.optional-dependencies]
21
+ spark = ["pyspark>=3.3"]
22
+ ml = ["scikit-learn", "torch", "mlflow"]
23
+ dev = ["pytest", "pytest-cov>=4", "pytest-timeout", "hypothesis>=6", "requests>=2.28", "black", "ruff", "build"]
24
+
25
+ [project.scripts]
26
+ ubunye = "ubunye.cli.main:app"
27
+
28
+ [project.entry-points."ubunye.readers"]
29
+ hive = "ubunye.plugins.readers.hive:HiveReader"
30
+ jdbc = "ubunye.plugins.readers.jdbc:JdbcReader"
31
+ s3 = "ubunye.plugins.readers.s3:S3Reader"
32
+ unity = "ubunye.plugins.readers.unity:UnityTableReader"
33
+ rest_api = "ubunye.plugins.readers.rest_api:RestApiReader"
34
+
35
+ [project.entry-points."ubunye.writers"]
36
+ s3 = "ubunye.plugins.writers.s3:S3Writer"
37
+ jdbc = "ubunye.plugins.writers.jdbc:JdbcWriter"
38
+ unity = "ubunye.plugins.writers.unity:UnityTableWriter"
39
+ rest_api = "ubunye.plugins.writers.rest_api:RestApiWriter"
40
+
41
+ [project.entry-points."ubunye.transforms"]
42
+ noop = "ubunye.plugins.transforms.noop:NoOpTransform"
43
+ model = "ubunye.plugins.transforms.model_transform:ModelTransform"
44
+
45
+ [project.entry-points."ubunye.ml"]
46
+ sklearn = "ubunye.plugins.ml.sklearn:SklearnModel"
47
+ sparkml = "ubunye.plugins.ml.pysparkml:SparkMLModel"
48
+
49
+ [project.entry-points."ubunye.monitors"]
50
+ mlflow = "ubunye.telemetry.mlflow:MLflowMonitor"
51
+ lineage = "ubunye.lineage.recorder:LineageRecorder"
52
+
53
+ [tool.setuptools.packages.find]
54
+ include = ["ubunye*"]
55
+
56
+ [tool.pytest.ini_options]
57
+ testpaths = ["tests"]
58
+ markers = [
59
+ "integration: requires a local Spark session and Java 11",
60
+ ]
61
+
62
+ [tool.black]
63
+ line-length = 100
64
+
65
+ [tool.ruff]
66
+ line-length = 100
67
+
68
+ [tool.ruff.lint]
69
+ select = ["E", "F", "I"]
70
+ ignore = [
71
+ "E501", # line too long β€” handled by Black; long help strings in CLI are acceptable
72
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ from ubunye.config import load_config
2
+
3
+
4
+ def test_load_config():
5
+ # Minimal config (string) saved to temp file during CI would be ideal.
6
+ # Here we simply assert loader callable exists.
7
+ assert callable(load_config)