sibi-flux 2026.1.7__tar.gz → 2026.1.9__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.
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/PKG-INFO +1 -1
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/pyproject.toml +2 -1
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/cli.py +173 -8
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/generator.py +26 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/cube_proposer.py +7 -3
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/README.md +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_dst/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/base.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/executor.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/manifest.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/planner.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/cli.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/config/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/config/manager.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/config/settings.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/core/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/core/managed_resource/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/core/managed_resource/_managed_resource.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/core/type_maps/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dask_cluster/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dask_cluster/async_core.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dask_cluster/client_manager.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dask_cluster/core.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dask_cluster/exceptions.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dask_cluster/utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/_data_cube.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/config_engine.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/field_factory.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/field_mapper.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/field_registry.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/orchestrator.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/datacube/router.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dataset/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dataset/_dataset.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/dataset/hybrid_loader.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_enricher/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_enricher/async_enricher.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_enricher/attacher.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_enricher/merger.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_enricher/specs.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_enricher/types.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/_df_helper.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/_params.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/_strategies.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/http/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/http/_http_config.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/parquet/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/parquet/_parquet_options.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_db_connection.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_db_gatekeeper.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_io_dask.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_load_from_db.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_model_registry.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_sql_model_builder.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/core/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/core/_defaults.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/core/_filter_handler.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/core/_params_config.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/core/_query_config.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_validator/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_validator/_df_validator.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/app.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/core.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/cube_extender.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/discovery_updater.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/env.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/env_engine.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/env_generator.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/rule_generator.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/templates/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/templates/discovery_params.yaml +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/templates/gen_dc.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/templates/property_template.yaml +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/logger/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/logger/_logger.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/mcp/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/mcp/client.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/mcp/router.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/orchestration/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/orchestration/_artifact_orchestrator.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/orchestration/_pipeline_executor.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/osmnx_helper/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/osmnx_helper/_pbf_handler.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/osmnx_helper/graph_loader.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/osmnx_helper/utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/readers/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/readers/base.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/readers/parquet.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/saver/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/saver/_parquet_saver.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/parquet/saver/_write_gatekeeper.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/pipelines/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/pipelines/base.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/pipelines/template.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/py.typed +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/readers/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/readers/base.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/storage/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/storage/_fs_registry.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/storage/_storage_manager.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/storage/factory.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/clickhouse_writer/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/clickhouse_writer/_clickhouse_writer.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/common.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/dask_utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/data_utils/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/data_utils/_data_utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/dataframe_utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/date_utils/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/date_utils/_business_days.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/date_utils/_date_utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/date_utils/_file_age_checker.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/file_utils.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/filepath_generator/__init__.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/filepath_generator/_filepath_generator.py +0 -0
- {sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/retry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sibi-flux"
|
|
3
|
-
version = "2026.1.
|
|
3
|
+
version = "2026.1.9"
|
|
4
4
|
description = "Sibi Toolkit: A collection of tools for Data Analysis/Engineering."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -97,6 +97,7 @@ members = [
|
|
|
97
97
|
"test-prj",
|
|
98
98
|
"test_prj",
|
|
99
99
|
"test_prj_verify",
|
|
100
|
+
"clean-test-prj",
|
|
100
101
|
]
|
|
101
102
|
|
|
102
103
|
[tool.pytest.ini_options]
|
|
@@ -203,7 +203,7 @@ def set_context_defaults(
|
|
|
203
203
|
|
|
204
204
|
|
|
205
205
|
def _get_db_url_callback(
|
|
206
|
-
registry: DatacubeRegistry, db_url_map: Optional[str]
|
|
206
|
+
registry: DatacubeRegistry, db_url_map: Optional[str], params: Optional[Dict[str, Any]] = None
|
|
207
207
|
) -> Callable[[str], str]:
|
|
208
208
|
"""Helper to create a callback that resolves DB URLs from CLI overrides or registry."""
|
|
209
209
|
cli_urls = json.loads(db_url_map) if db_url_map else {}
|
|
@@ -212,8 +212,24 @@ def _get_db_url_callback(
|
|
|
212
212
|
# 1. CLI Override
|
|
213
213
|
if conf_name in cli_urls:
|
|
214
214
|
return cli_urls[conf_name]
|
|
215
|
+
|
|
215
216
|
# 2. Dynamic Resolution
|
|
216
|
-
|
|
217
|
+
imports = registry.global_imports
|
|
218
|
+
|
|
219
|
+
# Check specific import_spec from params
|
|
220
|
+
if params and "databases" in params:
|
|
221
|
+
for db in params.get("databases", []):
|
|
222
|
+
ref = db.get("connection_ref") or db.get("connection_obj")
|
|
223
|
+
if ref == conf_name:
|
|
224
|
+
spec = db.get("import_spec")
|
|
225
|
+
if spec and isinstance(spec, dict):
|
|
226
|
+
# Prepend specific module
|
|
227
|
+
imports = [spec.get("module")] + imports
|
|
228
|
+
elif db.get("global_import"):
|
|
229
|
+
imports = [db.get("global_import")] + imports
|
|
230
|
+
break
|
|
231
|
+
|
|
232
|
+
url = resolve_db_url(conf_name, imports)
|
|
217
233
|
if url:
|
|
218
234
|
return url
|
|
219
235
|
raise ValueError(
|
|
@@ -283,9 +299,16 @@ def sync(
|
|
|
283
299
|
|
|
284
300
|
flat_tables = {}
|
|
285
301
|
for grp, tbls in existing_reg_data.items():
|
|
286
|
-
if isinstance(tbls, dict):
|
|
302
|
+
if grp == "tables" and isinstance(tbls, dict):
|
|
303
|
+
# Modern format: tables are in 'tables' dict
|
|
304
|
+
for t, t_meta in tbls.items():
|
|
305
|
+
flat_tables[t] = t_meta
|
|
306
|
+
continue
|
|
307
|
+
|
|
308
|
+
if isinstance(tbls, dict) and grp != "global_imports":
|
|
309
|
+
# Legacy Scoped Format (grp is connection_obj)
|
|
287
310
|
for t, t_meta in tbls.items():
|
|
288
|
-
# Inject
|
|
311
|
+
# Inject/Overwrite connection_obj only if implied by scope
|
|
289
312
|
t_meta["connection_obj"] = grp
|
|
290
313
|
flat_tables[t] = t_meta
|
|
291
314
|
|
|
@@ -295,6 +318,11 @@ def sync(
|
|
|
295
318
|
console.print(f"[yellow]Warning: Could not load existing registry: {e}[/yellow]")
|
|
296
319
|
|
|
297
320
|
registry = DatacubeRegistry(config_data, params=context.params)
|
|
321
|
+
|
|
322
|
+
# Fix 2 Re-applied: Ensure global_imports are populated from params if registry loaded from file didn't have them
|
|
323
|
+
# This is critical for Clean Project + Force flows where registry might be partial or JIT
|
|
324
|
+
if not registry.global_imports and context.params.get("global_imports"):
|
|
325
|
+
registry.global_imports = context.params.get("global_imports")
|
|
298
326
|
|
|
299
327
|
# --- Aggregation Phase ---
|
|
300
328
|
# --- Aggregation Phase ---
|
|
@@ -453,7 +481,7 @@ def sync(
|
|
|
453
481
|
registry.valid_paths = list(valid_paths)
|
|
454
482
|
registry.valid_fieldmap_paths = context.valid_fieldmap_paths
|
|
455
483
|
|
|
456
|
-
get_url = _get_db_url_callback(registry, db_url_map)
|
|
484
|
+
get_url = _get_db_url_callback(registry, db_url_map, params=context.params)
|
|
457
485
|
|
|
458
486
|
# Group tables by target file
|
|
459
487
|
file_groups = registry.group_tables_by_file()
|
|
@@ -770,8 +798,22 @@ def discover(
|
|
|
770
798
|
if not wl_filename:
|
|
771
799
|
# Default convention: discovery_whitelist_<db_name>.yaml
|
|
772
800
|
wl_filename = f"discovery_whitelist_{conn_obj}.yaml"
|
|
801
|
+
|
|
773
802
|
whitelist_path = config_path.parent / wl_filename
|
|
774
803
|
|
|
804
|
+
# Fallback 1: Auto-generated per-db (from scan/map fallback logic)
|
|
805
|
+
if not whitelist_path.exists():
|
|
806
|
+
fb = config_path.parent / f"discovery_whitelist_{conn_obj}.yaml"
|
|
807
|
+
if fb.exists():
|
|
808
|
+
whitelist_path = fb
|
|
809
|
+
|
|
810
|
+
# Fallback 2: Global whitelist.yaml (Generated by 'whitelist' command)
|
|
811
|
+
if not whitelist_path.exists():
|
|
812
|
+
global_wl = config_path.parent / "whitelist.yaml"
|
|
813
|
+
if global_wl.exists():
|
|
814
|
+
console.print(f"[dim]Fallback: Using global {global_wl.name} for {db_name}[/dim]")
|
|
815
|
+
whitelist_path = global_wl
|
|
816
|
+
|
|
775
817
|
# Determine rules path
|
|
776
818
|
rules_filename = db_config.get("rules_file")
|
|
777
819
|
if not rules_filename:
|
|
@@ -1014,8 +1056,21 @@ def scan(
|
|
|
1014
1056
|
raise typer.Exit(code=1)
|
|
1015
1057
|
|
|
1016
1058
|
# Resolve global output file
|
|
1017
|
-
|
|
1018
|
-
|
|
1059
|
+
# First check nested discovery block (standard), then root (fallback)
|
|
1060
|
+
discovery_conf = params.get("discovery", {})
|
|
1061
|
+
global_tables_file = (
|
|
1062
|
+
discovery_conf.get("all_tables_file")
|
|
1063
|
+
or params.get("all_tables_file")
|
|
1064
|
+
or "all_tables.yaml"
|
|
1065
|
+
)
|
|
1066
|
+
|
|
1067
|
+
# If using absolute path (resolved from context), use it directly
|
|
1068
|
+
# Otherwise treat as relative to config file location
|
|
1069
|
+
path_obj = Path(global_tables_file)
|
|
1070
|
+
if path_obj.is_absolute():
|
|
1071
|
+
global_tables_path = path_obj
|
|
1072
|
+
else:
|
|
1073
|
+
global_tables_path = config_path.parent / global_tables_file
|
|
1019
1074
|
|
|
1020
1075
|
# Load existing data to preserve config for DBs not being scanned
|
|
1021
1076
|
all_tables_data = {}
|
|
@@ -1089,7 +1144,7 @@ def drift(
|
|
|
1089
1144
|
config_data = _load_and_resolve_config(config_path)
|
|
1090
1145
|
|
|
1091
1146
|
registry = DatacubeRegistry(config_data)
|
|
1092
|
-
get_url = _get_db_url_callback(registry, db_url_map)
|
|
1147
|
+
get_url = _get_db_url_callback(registry, db_url_map, params=config_data)
|
|
1093
1148
|
cli_urls = json.loads(db_url_map) if db_url_map else {}
|
|
1094
1149
|
|
|
1095
1150
|
drift_table = Table(title="Schema Drift Analysis")
|
|
@@ -1493,6 +1548,116 @@ def map(
|
|
|
1493
1548
|
return
|
|
1494
1549
|
|
|
1495
1550
|
|
|
1551
|
+
@app.command()
|
|
1552
|
+
def workflow(
|
|
1553
|
+
config_file: Optional[Path] = typer.Option(None, "--config"),
|
|
1554
|
+
db_url_map: Optional[str] = typer.Option(None, "--db-urls"),
|
|
1555
|
+
env_file: Optional[Path] = typer.Option(None, "--env-file", "-e"),
|
|
1556
|
+
db_name: Optional[str] = typer.Option(
|
|
1557
|
+
None, "--db", help="Target specific database (filtering map/sync)"
|
|
1558
|
+
),
|
|
1559
|
+
app_name: Optional[str] = typer.Option(
|
|
1560
|
+
None, "--app-name", help="Run create_cubes for the specified application"
|
|
1561
|
+
),
|
|
1562
|
+
force: bool = typer.Option(False, "--force", "-f", help="Force rebuild/overwrite"),
|
|
1563
|
+
dry_run: bool = typer.Option(
|
|
1564
|
+
False, "--dry-run", help="Preview changes without executing"
|
|
1565
|
+
),
|
|
1566
|
+
) -> None:
|
|
1567
|
+
"""
|
|
1568
|
+
Executes the full Datacube workflow: Scan -> Propose -> Discover -> Map -> Sync -> (Optional) Create Cubes.
|
|
1569
|
+
"""
|
|
1570
|
+
console.rule("[bold magenta]Starting Datacube Workflow[/]")
|
|
1571
|
+
|
|
1572
|
+
# Resolve env_file: CLI > Params > Default (Consistent with discover/sync)
|
|
1573
|
+
if env_file:
|
|
1574
|
+
env_path = env_file
|
|
1575
|
+
elif context.params and context.params.get("defaults", {}).get("env_file"):
|
|
1576
|
+
env_path = Path(context.params.get("defaults", {})["env_file"])
|
|
1577
|
+
else:
|
|
1578
|
+
env_path = Path(".env.linux")
|
|
1579
|
+
load_environment(env_path, logger=console.print)
|
|
1580
|
+
|
|
1581
|
+
# Ensure context is configured with params from the config file
|
|
1582
|
+
config_path = config_file or context.default_config
|
|
1583
|
+
if config_path and config_path.exists():
|
|
1584
|
+
# Load and resolve config to ensure context.params is populated
|
|
1585
|
+
# This is critical for 'discover' to find 'databases' list
|
|
1586
|
+
try:
|
|
1587
|
+
config_data = _load_and_resolve_config(config_path)
|
|
1588
|
+
context.params = config_data
|
|
1589
|
+
context.default_config = config_path
|
|
1590
|
+
# We don't have easy access to other set_context_defaults args here,
|
|
1591
|
+
# but params is what 'discover' needs most.
|
|
1592
|
+
console.print(f"[dim]Loaded workflow context from {config_path}[/dim]")
|
|
1593
|
+
except Exception as e:
|
|
1594
|
+
console.print(f"[yellow]Warning: Failed to load context from {config_path}: {e}[/yellow]")
|
|
1595
|
+
|
|
1596
|
+
# Step 0: Scan & Propose Rules (Critical for new projects/drift)
|
|
1597
|
+
console.print(f"\n[bold cyan]Step 0a: Scan (Introspection)[/]")
|
|
1598
|
+
scan(
|
|
1599
|
+
config_file=config_file,
|
|
1600
|
+
db_url_map=db_url_map,
|
|
1601
|
+
env_file=env_file,
|
|
1602
|
+
db_name=db_name,
|
|
1603
|
+
)
|
|
1604
|
+
|
|
1605
|
+
console.print(f"\n[bold cyan]Step 0b: Propose Rules[/]")
|
|
1606
|
+
propose_rules(
|
|
1607
|
+
config_file=config_file,
|
|
1608
|
+
dry_run=dry_run, # Preview rules if dry-running
|
|
1609
|
+
)
|
|
1610
|
+
|
|
1611
|
+
console.print(f"\n[bold cyan]Step 0c: Generate Whitelist[/]")
|
|
1612
|
+
whitelist(
|
|
1613
|
+
config_file=config_file,
|
|
1614
|
+
db_name=db_name,
|
|
1615
|
+
db_url_map=db_url_map,
|
|
1616
|
+
env_file=env_file,
|
|
1617
|
+
force=force,
|
|
1618
|
+
)
|
|
1619
|
+
|
|
1620
|
+
# Step 1: Discover
|
|
1621
|
+
# Note: Discover currently runs for all DBs in config.
|
|
1622
|
+
console.print(f"\n[bold cyan]Step 1: Discovery[/]")
|
|
1623
|
+
discover(
|
|
1624
|
+
config_file=config_file,
|
|
1625
|
+
db_conf="replica_db_conf", # Pass explicit string to avoid Typer OptionInfo default
|
|
1626
|
+
db_url_map=db_url_map,
|
|
1627
|
+
env_file=env_file,
|
|
1628
|
+
update=True, # Always update registry to enable chaining
|
|
1629
|
+
prune=False, # Safer default? Or should we expose prune?
|
|
1630
|
+
run_sync=False, # We handle sync explicitly later
|
|
1631
|
+
dry_run=dry_run,
|
|
1632
|
+
generate_fields=False, # We use map command for this
|
|
1633
|
+
force=False, # Discovery force is about fields usually?
|
|
1634
|
+
)
|
|
1635
|
+
|
|
1636
|
+
# Step 2: Map (Skipped - Handled by Sync)
|
|
1637
|
+
# console.print(f"\n[bold cyan]Step 2: Map Generation (Integrated into Sync)[/]")
|
|
1638
|
+
|
|
1639
|
+
# Step 3: Sync -> Generates Code + Field Maps
|
|
1640
|
+
console.print(f"\n[bold cyan]Step 3: Sync (Code Generation)[/]")
|
|
1641
|
+
sync(
|
|
1642
|
+
config_file=config_file,
|
|
1643
|
+
db_url_map=db_url_map,
|
|
1644
|
+
env_file=env_file, # sync command has env_file
|
|
1645
|
+
force=force,
|
|
1646
|
+
dry_run=dry_run,
|
|
1647
|
+
)
|
|
1648
|
+
|
|
1649
|
+
# Step 4: Create Cubes (Optional)
|
|
1650
|
+
if app_name:
|
|
1651
|
+
console.print(f"\n[bold cyan]Step 4: Application Cubes ({app_name})[/]")
|
|
1652
|
+
if dry_run:
|
|
1653
|
+
console.print("[yellow]Skipping create_cubes in dry-run mode.[/yellow]")
|
|
1654
|
+
else:
|
|
1655
|
+
from sibi_flux.init.cube_extender import create_cubes
|
|
1656
|
+
create_cubes(app_name)
|
|
1657
|
+
|
|
1658
|
+
console.rule("[bold magenta]Workflow Completed[/]")
|
|
1659
|
+
|
|
1660
|
+
|
|
1496
1661
|
@app.command()
|
|
1497
1662
|
def init(
|
|
1498
1663
|
config_file: Optional[Path] = typer.Option(None, "--config"),
|
|
@@ -778,6 +778,32 @@ def generate_datacube_module_code(
|
|
|
778
778
|
else:
|
|
779
779
|
imports.add(base_imp)
|
|
780
780
|
|
|
781
|
+
# Config Object Import
|
|
782
|
+
# We need to resolve import for conf_obj (e.g. clickhouse_conf)
|
|
783
|
+
# Using registry.params which contains databases list with import_spec
|
|
784
|
+
params = registry.params
|
|
785
|
+
dbs = params.get("databases", [])
|
|
786
|
+
for db in dbs:
|
|
787
|
+
ref = db.get("connection_ref") or db.get("connection_obj")
|
|
788
|
+
if ref == conf_obj:
|
|
789
|
+
spec = db.get("import_spec")
|
|
790
|
+
if spec and isinstance(spec, dict):
|
|
791
|
+
mod = spec.get("module")
|
|
792
|
+
sym = spec.get("symbol")
|
|
793
|
+
if mod and sym:
|
|
794
|
+
imports.add(f"from {mod} import {sym}")
|
|
795
|
+
elif db.get("global_import"):
|
|
796
|
+
# Legacy or simple string import
|
|
797
|
+
imp_str = db.get("global_import")
|
|
798
|
+
if imp_str and sym and sym in imp_str:
|
|
799
|
+
imports.add(imp_str)
|
|
800
|
+
elif imp_str: # Fallback to add specific object if simple import
|
|
801
|
+
# Try to parse or just add "from ... import conf_obj" logic?
|
|
802
|
+
# If global_import is "from conf.credentials import *" -> hard to know
|
|
803
|
+
# If it is "from conf.credentials import replica_conf" -> easy
|
|
804
|
+
imports.add(imp_str)
|
|
805
|
+
break
|
|
806
|
+
|
|
781
807
|
details = registry.get_table_details(table_name)
|
|
782
808
|
field_map_str = details.get("field_map")
|
|
783
809
|
sticky_filters = details.get("sticky_filters")
|
|
@@ -56,6 +56,8 @@ def propose_cubes(db_domain: str, app_name: str) -> None:
|
|
|
56
56
|
|
|
57
57
|
# Registry Structure: {conf_obj: {table_name: {class_name: ..., path: ...}}}
|
|
58
58
|
for conf_obj, tables in global_data.items():
|
|
59
|
+
if not isinstance(tables, dict):
|
|
60
|
+
continue
|
|
59
61
|
for table_name, meta in tables.items():
|
|
60
62
|
path_str = meta.get("path", "")
|
|
61
63
|
class_name = meta.get("class_name")
|
|
@@ -100,14 +102,16 @@ def propose_cubes(db_domain: str, app_name: str) -> None:
|
|
|
100
102
|
|
|
101
103
|
# 4. Update App Registry
|
|
102
104
|
|
|
103
|
-
# Load existing
|
|
104
105
|
current_config = {"cubes": []}
|
|
105
106
|
if registry_path.exists():
|
|
106
107
|
try:
|
|
107
108
|
with open(registry_path, "r") as f:
|
|
108
109
|
loaded = yaml.safe_load(f)
|
|
109
|
-
if loaded
|
|
110
|
-
|
|
110
|
+
if loaded:
|
|
111
|
+
current_config = loaded
|
|
112
|
+
if "cubes" not in current_config or current_config["cubes"] is None:
|
|
113
|
+
current_config["cubes"] = []
|
|
114
|
+
|
|
111
115
|
except Exception:
|
|
112
116
|
pass
|
|
113
117
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/__init__.py
RENAMED
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/executor.py
RENAMED
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/artifacts/parquet_engine/manifest.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/core/managed_resource/_managed_resource.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/http/_http_config.py
RENAMED
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/parquet/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/df_helper/backends/sqlalchemy/_io_dask.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/templates/discovery_params.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/init/templates/property_template.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/orchestration/_artifact_orchestrator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/date_utils/_file_age_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
{sibi_flux-2026.1.7 → sibi_flux-2026.1.9}/src/sibi_flux/utils/filepath_generator/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|