bloomery 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bloomery-0.1.0/.gitignore +245 -0
- bloomery-0.1.0/CHANGELOG.md +154 -0
- bloomery-0.1.0/LICENSE +21 -0
- bloomery-0.1.0/PKG-INFO +224 -0
- bloomery-0.1.0/README.md +174 -0
- bloomery-0.1.0/examples/README.md +33 -0
- bloomery-0.1.0/pyproject.toml +547 -0
- bloomery-0.1.0/src/bloomery/__init__.py +164 -0
- bloomery-0.1.0/src/bloomery/_version.py +24 -0
- bloomery-0.1.0/src/bloomery/cli/__init__.py +482 -0
- bloomery-0.1.0/src/bloomery/cli/io.py +167 -0
- bloomery-0.1.0/src/bloomery/cli/render.py +167 -0
- bloomery-0.1.0/src/bloomery/cli/serialize.py +111 -0
- bloomery-0.1.0/src/bloomery/compile.py +64 -0
- bloomery-0.1.0/src/bloomery/dialects/__init__.py +81 -0
- bloomery-0.1.0/src/bloomery/dialects/base.py +160 -0
- bloomery-0.1.0/src/bloomery/dialects/duckdb.py +70 -0
- bloomery-0.1.0/src/bloomery/dialects/postgres.py +211 -0
- bloomery-0.1.0/src/bloomery/dialects/trino.py +80 -0
- bloomery-0.1.0/src/bloomery/emit/__init__.py +68 -0
- bloomery-0.1.0/src/bloomery/emit/base.py +125 -0
- bloomery-0.1.0/src/bloomery/emit/cube/__init__.py +281 -0
- bloomery-0.1.0/src/bloomery/emit/dbt/__init__.py +731 -0
- bloomery-0.1.0/src/bloomery/emit/lower/__init__.py +97 -0
- bloomery-0.1.0/src/bloomery/emit/lower/marts.py +170 -0
- bloomery-0.1.0/src/bloomery/emit/lower/predicates.py +78 -0
- bloomery-0.1.0/src/bloomery/emit/lower/quality_mart.py +373 -0
- bloomery-0.1.0/src/bloomery/emit/lower/reconcile.py +435 -0
- bloomery-0.1.0/src/bloomery/emit/lower/silver.py +1416 -0
- bloomery-0.1.0/src/bloomery/emit/metricflow/__init__.py +576 -0
- bloomery-0.1.0/src/bloomery/emit/sqlmesh/__init__.py +798 -0
- bloomery-0.1.0/src/bloomery/emit/steps.py +753 -0
- bloomery-0.1.0/src/bloomery/errors.py +673 -0
- bloomery-0.1.0/src/bloomery/evidence.py +336 -0
- bloomery-0.1.0/src/bloomery/guardrails/__init__.py +12 -0
- bloomery-0.1.0/src/bloomery/guardrails/additivity.py +113 -0
- bloomery-0.1.0/src/bloomery/guardrails/arithmetic.py +195 -0
- bloomery-0.1.0/src/bloomery/guardrails/asserts.py +177 -0
- bloomery-0.1.0/src/bloomery/guardrails/conflict.py +75 -0
- bloomery-0.1.0/src/bloomery/guardrails/grain.py +173 -0
- bloomery-0.1.0/src/bloomery/guardrails/operands.py +115 -0
- bloomery-0.1.0/src/bloomery/guardrails/quality.py +1073 -0
- bloomery-0.1.0/src/bloomery/guardrails/stage.py +91 -0
- bloomery-0.1.0/src/bloomery/ir/__init__.py +111 -0
- bloomery-0.1.0/src/bloomery/ir/fingerprint.py +80 -0
- bloomery-0.1.0/src/bloomery/ir/lower.py +88 -0
- bloomery-0.1.0/src/bloomery/ir/nodes.py +820 -0
- bloomery-0.1.0/src/bloomery/marts/__init__.py +18 -0
- bloomery-0.1.0/src/bloomery/marts/flatten.py +634 -0
- bloomery-0.1.0/src/bloomery/naming.py +55 -0
- bloomery-0.1.0/src/bloomery/plan/__init__.py +19 -0
- bloomery-0.1.0/src/bloomery/plan/diff.py +1484 -0
- bloomery-0.1.0/src/bloomery/plan/model.py +131 -0
- bloomery-0.1.0/src/bloomery/planner/__init__.py +70 -0
- bloomery-0.1.0/src/bloomery/planner/coverage.py +259 -0
- bloomery-0.1.0/src/bloomery/planner/explain.py +143 -0
- bloomery-0.1.0/src/bloomery/planner/filters.py +302 -0
- bloomery-0.1.0/src/bloomery/planner/metricflow_planner.py +200 -0
- bloomery-0.1.0/src/bloomery/planner/names.py +218 -0
- bloomery-0.1.0/src/bloomery/planner/parse.py +566 -0
- bloomery-0.1.0/src/bloomery/planner/policy.py +55 -0
- bloomery-0.1.0/src/bloomery/planner/request.py +325 -0
- bloomery-0.1.0/src/bloomery/planner/result.py +114 -0
- bloomery-0.1.0/src/bloomery/py.typed +0 -0
- bloomery-0.1.0/src/bloomery/quality/__init__.py +219 -0
- bloomery-0.1.0/src/bloomery/quality/catalogue.py +122 -0
- bloomery-0.1.0/src/bloomery/quality/charset.py +107 -0
- bloomery-0.1.0/src/bloomery/quality/dedupe.py +87 -0
- bloomery-0.1.0/src/bloomery/quality/flags.py +163 -0
- bloomery-0.1.0/src/bloomery/quality/lower.py +569 -0
- bloomery-0.1.0/src/bloomery/quality/mart.py +343 -0
- bloomery-0.1.0/src/bloomery/quality/pattern.py +107 -0
- bloomery-0.1.0/src/bloomery/quality/predicates.py +648 -0
- bloomery-0.1.0/src/bloomery/quality/reconcile.py +117 -0
- bloomery-0.1.0/src/bloomery/quality/reject.py +105 -0
- bloomery-0.1.0/src/bloomery/resolve/__init__.py +24 -0
- bloomery-0.1.0/src/bloomery/resolve/build.py +1005 -0
- bloomery-0.1.0/src/bloomery/resolve/graph.py +263 -0
- bloomery-0.1.0/src/bloomery/resolve/metrics.py +94 -0
- bloomery-0.1.0/src/bloomery/resolve/order.py +77 -0
- bloomery-0.1.0/src/bloomery/resolve/reach.py +98 -0
- bloomery-0.1.0/src/bloomery/resolve/recipes.py +117 -0
- bloomery-0.1.0/src/bloomery/resolve/refs.py +265 -0
- bloomery-0.1.0/src/bloomery/resolve/resolution.py +116 -0
- bloomery-0.1.0/src/bloomery/resolve/steps.py +785 -0
- bloomery-0.1.0/src/bloomery/runtime/__init__.py +26 -0
- bloomery-0.1.0/src/bloomery/runtime/hydration.py +178 -0
- bloomery-0.1.0/src/bloomery/runtime/sql_client.py +97 -0
- bloomery-0.1.0/src/bloomery/schema.py +287 -0
- bloomery-0.1.0/src/bloomery/spec/__init__.py +107 -0
- bloomery-0.1.0/src/bloomery/spec/catalog.py +119 -0
- bloomery-0.1.0/src/bloomery/spec/common.py +289 -0
- bloomery-0.1.0/src/bloomery/spec/entity.py +128 -0
- bloomery-0.1.0/src/bloomery/spec/mapping.py +204 -0
- bloomery-0.1.0/src/bloomery/spec/marts.py +158 -0
- bloomery-0.1.0/src/bloomery/spec/metrics.py +81 -0
- bloomery-0.1.0/src/bloomery/spec/project.py +182 -0
- bloomery-0.1.0/src/bloomery/spec/quality.py +920 -0
- bloomery-0.1.0/src/bloomery/spec/steps.py +187 -0
- bloomery-0.1.0/src/bloomery/steps/__init__.py +109 -0
- bloomery-0.1.0/src/bloomery/steps/contract.py +212 -0
- bloomery-0.1.0/src/bloomery/steps/manifest.py +399 -0
- bloomery-0.1.0/src/bloomery/steps/registry.py +174 -0
- bloomery-0.1.0/src/bloomery/steps/splice.py +160 -0
- bloomery-0.1.0/src/bloomery/transforms/__init__.py +37 -0
- bloomery-0.1.0/src/bloomery/transforms/_builtins.py +405 -0
- bloomery-0.1.0/src/bloomery/transforms/registry.py +177 -0
- bloomery-0.1.0/src/bloomery/typing/__init__.py +37 -0
- bloomery-0.1.0/src/bloomery/typing/check.py +182 -0
- bloomery-0.1.0/src/bloomery/typing/types.py +184 -0
- bloomery-0.1.0/tests/README.md +60 -0
- bloomery-0.1.0/tests/__init__.py +0 -0
- bloomery-0.1.0/tests/bench/__init__.py +0 -0
- bloomery-0.1.0/tests/bench/test_hydration.py +220 -0
- bloomery-0.1.0/tests/chaos/__init__.py +0 -0
- bloomery-0.1.0/tests/chaos/test_mutation_harness.py +113 -0
- bloomery-0.1.0/tests/conftest.py +189 -0
- bloomery-0.1.0/tests/e2e/__init__.py +0 -0
- bloomery-0.1.0/tests/e2e/test_cube_meta.py +116 -0
- bloomery-0.1.0/tests/e2e/test_dbt_parse.py +298 -0
- bloomery-0.1.0/tests/e2e/test_sqlmesh_replan.py +520 -0
- bloomery-0.1.0/tests/engines/__init__.py +0 -0
- bloomery-0.1.0/tests/engines/test_postgres_execution.py +134 -0
- bloomery-0.1.0/tests/engines/test_postgres_quality.py +160 -0
- bloomery-0.1.0/tests/engines/test_postgres_reconcile.py +121 -0
- bloomery-0.1.0/tests/engines/test_postgres_text_rules.py +132 -0
- bloomery-0.1.0/tests/engines/test_trino.py +341 -0
- bloomery-0.1.0/tests/equivalence/README.md +33 -0
- bloomery-0.1.0/tests/equivalence/__init__.py +0 -0
- bloomery-0.1.0/tests/equivalence/golden_requests.yaml +56 -0
- bloomery-0.1.0/tests/equivalence/known_divergences.yaml +9 -0
- bloomery-0.1.0/tests/equivalence/reference_sql/aov_by_month.sql +6 -0
- bloomery-0.1.0/tests/equivalence/reference_sql/aov_by_store.sql +3 -0
- bloomery-0.1.0/tests/equivalence/reference_sql/revenue_by_month.sql +5 -0
- bloomery-0.1.0/tests/equivalence/reference_sql/revenue_ungrouped.sql +2 -0
- bloomery-0.1.0/tests/equivalence/test_three_way.py +203 -0
- bloomery-0.1.0/tests/execution/__init__.py +0 -0
- bloomery-0.1.0/tests/execution/test_dedupe_and_audits.py +317 -0
- bloomery-0.1.0/tests/execution/test_dirty_corpus.py +587 -0
- bloomery-0.1.0/tests/execution/test_fanout_trap.py +98 -0
- bloomery-0.1.0/tests/execution/test_identity_resolution.py +211 -0
- bloomery-0.1.0/tests/execution/test_marts.py +136 -0
- bloomery-0.1.0/tests/execution/test_merge_gates.py +138 -0
- bloomery-0.1.0/tests/execution/test_path_conflict.py +59 -0
- bloomery-0.1.0/tests/execution/test_pattern_anchoring.py +107 -0
- bloomery-0.1.0/tests/execution/test_planner_filters.py +206 -0
- bloomery-0.1.0/tests/execution/test_planner_numbers.py +290 -0
- bloomery-0.1.0/tests/execution/test_quality_mart.py +261 -0
- bloomery-0.1.0/tests/execution/test_quality_precedence.py +602 -0
- bloomery-0.1.0/tests/execution/test_quarantine_replay.py +425 -0
- bloomery-0.1.0/tests/execution/test_reconcile_null_keys.py +134 -0
- bloomery-0.1.0/tests/execution/test_sqlmesh_duckdb.py +87 -0
- bloomery-0.1.0/tests/execution/test_step_consistency.py +107 -0
- bloomery-0.1.0/tests/fixtures/.gitkeep +0 -0
- bloomery-0.1.0/tests/fixtures/coverage_check/entity_model.yaml +36 -0
- bloomery-0.1.0/tests/fixtures/coverage_check/mapping_customers.yaml +7 -0
- bloomery-0.1.0/tests/fixtures/coverage_check/mapping_orders.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/currency_convert_refusal/entity_model.yaml +15 -0
- bloomery-0.1.0/tests/fixtures/currency_convert_refusal/mapping.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/dirty/README.md +143 -0
- bloomery-0.1.0/tests/fixtures/dirty/dates.csv +22 -0
- bloomery-0.1.0/tests/fixtures/dirty/enums.csv +19 -0
- bloomery-0.1.0/tests/fixtures/dirty/extremes.csv +21 -0
- bloomery-0.1.0/tests/fixtures/dirty/keys.csv +23 -0
- bloomery-0.1.0/tests/fixtures/dirty/numerics.csv +21 -0
- bloomery-0.1.0/tests/fixtures/dirty/refs.csv +17 -0
- bloomery-0.1.0/tests/fixtures/dirty/unicode.csv +23 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/catalog.yaml +13 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/entity_model.yaml +244 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_customers.yaml +10 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_dates.yaml +20 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_enums.yaml +23 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_extremes_decimal.yaml +21 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_extremes_integer.yaml +16 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_extremes_text.yaml +21 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_extremes_timestamp.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_keys.yaml +18 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_numerics.yaml +23 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_ref_parents.yaml +21 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_refs.yaml +20 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_refs_routed.yaml +38 -0
- bloomery-0.1.0/tests/fixtures/dirty_corpus/mapping_unicode.yaml +65 -0
- bloomery-0.1.0/tests/fixtures/ecom_basic/catalog.yaml +54 -0
- bloomery-0.1.0/tests/fixtures/ecom_basic/entity_model.yaml +26 -0
- bloomery-0.1.0/tests/fixtures/ecom_basic/mapping_order_items.yaml +15 -0
- bloomery-0.1.0/tests/fixtures/ecom_basic/mapping_orders.yaml +7 -0
- bloomery-0.1.0/tests/fixtures/ecom_basic/marts.yaml +13 -0
- bloomery-0.1.0/tests/fixtures/ecom_basic/metrics.yaml +21 -0
- bloomery-0.1.0/tests/fixtures/evolution_v1/catalog.yaml +27 -0
- bloomery-0.1.0/tests/fixtures/evolution_v1/entity_model.yaml +13 -0
- bloomery-0.1.0/tests/fixtures/evolution_v1/mapping.yaml +11 -0
- bloomery-0.1.0/tests/fixtures/evolution_v1/metrics.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/evolution_v2/catalog.yaml +27 -0
- bloomery-0.1.0/tests/fixtures/evolution_v2/entity_model.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/evolution_v2/mapping.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/evolution_v2/metrics.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/evolution_v3/catalog.yaml +27 -0
- bloomery-0.1.0/tests/fixtures/evolution_v3/entity_model.yaml +16 -0
- bloomery-0.1.0/tests/fixtures/evolution_v3/mapping.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/evolution_v3/metrics.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/evolution_v4/catalog.yaml +27 -0
- bloomery-0.1.0/tests/fixtures/evolution_v4/entity_model.yaml +15 -0
- bloomery-0.1.0/tests/fixtures/evolution_v4/mapping.yaml +16 -0
- bloomery-0.1.0/tests/fixtures/evolution_v4/metrics.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/evolution_v5/catalog.yaml +27 -0
- bloomery-0.1.0/tests/fixtures/evolution_v5/entity_model.yaml +17 -0
- bloomery-0.1.0/tests/fixtures/evolution_v5/mapping.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/evolution_v5/metrics.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/fanout_trap/catalog.yaml +30 -0
- bloomery-0.1.0/tests/fixtures/fanout_trap/entity_model.yaml +26 -0
- bloomery-0.1.0/tests/fixtures/fanout_trap/mapping_order_items.yaml +18 -0
- bloomery-0.1.0/tests/fixtures/fanout_trap/mapping_orders.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/fanout_trap/marts.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/fanout_trap/metrics.yaml +19 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/catalog.yaml +28 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/entity_model.yaml +33 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/mapping_billing.yaml +11 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/mapping_crm.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/marts.yaml +11 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/metrics.yaml +6 -0
- bloomery-0.1.0/tests/fixtures/identity_resolution/steps.yaml +27 -0
- bloomery-0.1.0/tests/fixtures/minimal/entity_model.yaml +10 -0
- bloomery-0.1.0/tests/fixtures/minimal/mapping.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/multi_mart_refusal/catalog.yaml +10 -0
- bloomery-0.1.0/tests/fixtures/multi_mart_refusal/entity_model.yaml +21 -0
- bloomery-0.1.0/tests/fixtures/multi_mart_refusal/mapping_order_items.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/multi_mart_refusal/mapping_orders.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/multi_mart_refusal/marts.yaml +18 -0
- bloomery-0.1.0/tests/fixtures/multi_mart_refusal/metrics.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/non_additive_aov/catalog.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/non_additive_aov/entity_model.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/non_additive_aov/mapping.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/non_additive_aov/marts.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/non_additive_aov/metrics.yaml +19 -0
- bloomery-0.1.0/tests/fixtures/path_conflict/catalog.yaml +18 -0
- bloomery-0.1.0/tests/fixtures/path_conflict/entity_model.yaml +13 -0
- bloomery-0.1.0/tests/fixtures/path_conflict/mapping.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/catalog.yaml +20 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/entity_model.yaml +82 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/mapping_codes.yaml +22 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/mapping_dups.yaml +24 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/mapping_lines.yaml +31 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/marts.yaml +37 -0
- bloomery-0.1.0/tests/fixtures/quality_precedence/metrics.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/role_playing_dates/catalog.yaml +11 -0
- bloomery-0.1.0/tests/fixtures/role_playing_dates/entity_model.yaml +13 -0
- bloomery-0.1.0/tests/fixtures/role_playing_dates/mapping.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/role_playing_dates/marts.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/role_playing_dates/metrics.yaml +7 -0
- bloomery-0.1.0/tests/fixtures/scd2_customers/entity_model.yaml +14 -0
- bloomery-0.1.0/tests/fixtures/scd2_customers/mapping.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/scd2_mart_refusal/catalog.yaml +10 -0
- bloomery-0.1.0/tests/fixtures/scd2_mart_refusal/entity_model.yaml +35 -0
- bloomery-0.1.0/tests/fixtures/scd2_mart_refusal/mapping_customers.yaml +8 -0
- bloomery-0.1.0/tests/fixtures/scd2_mart_refusal/mapping_orders.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/scd2_mart_refusal/marts.yaml +25 -0
- bloomery-0.1.0/tests/fixtures/scd2_mart_refusal/metrics.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/semi_additive_inventory/catalog.yaml +18 -0
- bloomery-0.1.0/tests/fixtures/semi_additive_inventory/entity_model.yaml +37 -0
- bloomery-0.1.0/tests/fixtures/semi_additive_inventory/mapping.yaml +16 -0
- bloomery-0.1.0/tests/fixtures/semi_additive_inventory/marts.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/semi_additive_inventory/metrics.yaml +12 -0
- bloomery-0.1.0/tests/fixtures/step_resolution/entity_model.yaml +19 -0
- bloomery-0.1.0/tests/fixtures/step_resolution/mapping.yaml +9 -0
- bloomery-0.1.0/tests/fixtures/step_resolution/steps.yaml +11 -0
- bloomery-0.1.0/tests/golden/.gitkeep +0 -0
- bloomery-0.1.0/tests/golden/ecom_basic/cube/model/cubes/order_items.yml +59 -0
- bloomery-0.1.0/tests/golden/ecom_basic/cube/model/views/order_items_view.yml +7 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/dbt_project.yml +17 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/macros/generate_schema_name.sql +9 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/models/gold/dim_date.sql +11 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/models/gold/mart_order_items.sql +20 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/models/schema.yml +9 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/models/silver/order.sql +10 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/models/silver/order_item.sql +13 -0
- bloomery-0.1.0/tests/golden/ecom_basic/dbt/postgres/models/sources.yml +9 -0
- bloomery-0.1.0/tests/golden/ecom_basic/metricflow/manifest.json +201 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/duckdb/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/duckdb/models/gold/mart_order_items.sql +25 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/duckdb/models/silver/order.sql +14 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/duckdb/models/silver/order_item.sql +19 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/postgres/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/postgres/models/gold/mart_order_items.sql +25 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/postgres/models/silver/order.sql +14 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/postgres/models/silver/order_item.sql +19 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/trino/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/trino/models/gold/mart_order_items.sql +25 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/trino/models/silver/order.sql +14 -0
- bloomery-0.1.0/tests/golden/ecom_basic/sqlmesh/trino/models/silver/order_item.sql +19 -0
- bloomery-0.1.0/tests/golden/identity_resolution/cube/model/cubes/customers.yml +46 -0
- bloomery-0.1.0/tests/golden/identity_resolution/cube/model/views/customers_view.yml +7 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/audits/step_customer_confidence_is_high.sql +13 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/audits/step_customer_xref_canonical_id_references_customer.sql +18 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/models/gold/mart_customers.sql +18 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/models/silver/customer.py +63 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/models/silver/customer_billing.sql +16 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/models/silver/customer_crm.sql +16 -0
- bloomery-0.1.0/tests/golden/identity_resolution/sqlmesh/duckdb/models/silver/customer_xref.py +63 -0
- bloomery-0.1.0/tests/golden/minimal/sqlmesh/duckdb/models/silver/event.sql +15 -0
- bloomery-0.1.0/tests/golden/minimal/sqlmesh/postgres/models/silver/event.sql +15 -0
- bloomery-0.1.0/tests/golden/minimal/sqlmesh/trino/models/silver/event.sql +15 -0
- bloomery-0.1.0/tests/golden/multi_mart_refusal/metricflow/manifest.json +305 -0
- bloomery-0.1.0/tests/golden/non_additive_aov/cube/model/cubes/orders.yml +60 -0
- bloomery-0.1.0/tests/golden/non_additive_aov/cube/model/views/orders_view.yml +7 -0
- bloomery-0.1.0/tests/golden/non_additive_aov/metricflow/manifest.json +291 -0
- bloomery-0.1.0/tests/golden/path_conflict/sqlmesh/duckdb/audits/item_net_price_reconcile.sql +7 -0
- bloomery-0.1.0/tests/golden/path_conflict/sqlmesh/duckdb/models/silver/item.sql +17 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/cube/model/cubes/orders.yml +75 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/cube/model/views/orders_view.yml +7 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/metricflow/manifest.json +193 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/duckdb/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/duckdb/models/gold/mart_orders.sql +24 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/duckdb/models/silver/order.sql +16 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/postgres/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/postgres/models/gold/mart_orders.sql +24 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/postgres/models/silver/order.sql +16 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/trino/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/trino/models/gold/mart_orders.sql +24 -0
- bloomery-0.1.0/tests/golden/role_playing_dates/sqlmesh/trino/models/silver/order.sql +16 -0
- bloomery-0.1.0/tests/golden/scd2_customers/dbt/postgres/dbt_project.yml +11 -0
- bloomery-0.1.0/tests/golden/scd2_customers/dbt/postgres/macros/generate_schema_name.sql +9 -0
- bloomery-0.1.0/tests/golden/scd2_customers/dbt/postgres/models/schema.yml +16 -0
- bloomery-0.1.0/tests/golden/scd2_customers/dbt/postgres/models/sources.yml +8 -0
- bloomery-0.1.0/tests/golden/scd2_customers/dbt/postgres/snapshots/customer_snapshot.sql +14 -0
- bloomery-0.1.0/tests/golden/scd2_customers/sqlmesh/duckdb/models/silver/customer.sql +16 -0
- bloomery-0.1.0/tests/golden/schema/catalog.json +403 -0
- bloomery-0.1.0/tests/golden/schema/entity_model.json +632 -0
- bloomery-0.1.0/tests/golden/schema/mapping.json +1158 -0
- bloomery-0.1.0/tests/golden/schema/marts.json +248 -0
- bloomery-0.1.0/tests/golden/schema/metrics.json +241 -0
- bloomery-0.1.0/tests/golden/schema/steps.json +222 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/cube/model/cubes/data_quality.yml +92 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/cube/model/cubes/inventory.yml +53 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/cube/model/views/data_quality_view.yml +7 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/cube/model/views/inventory_view.yml +7 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/metricflow/manifest.json +609 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/audits/inventory_level_conservation.sql +83 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/audits/inventory_level_ingestion_metadata.sql +17 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/audits/inventory_level_stock_level_not_null.sql +44 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/audits/stock_level_matches_snapshot_reconcile.sql +8 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/models/gold/dim_date.sql +15 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/models/gold/mart_data_quality.sql +176 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/models/gold/mart_inventory.sql +19 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/models/silver/inventory_level.sql +84 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/models/silver/inventory_level__reject.sql +132 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/models/silver/stock_level_matches_snapshot__reconcile.sql +49 -0
- bloomery-0.1.0/tests/golden/semi_additive_inventory/sqlmesh/duckdb/replay/inventory_level.sql +282 -0
- bloomery-0.1.0/tests/golden/step_resolution/sqlmesh/duckdb/audits/step_customer_xref_canonical_id_references_customer.sql +18 -0
- bloomery-0.1.0/tests/golden/step_resolution/sqlmesh/duckdb/models/silver/customer.py +51 -0
- bloomery-0.1.0/tests/golden/step_resolution/sqlmesh/duckdb/models/silver/customer_raw.sql +16 -0
- bloomery-0.1.0/tests/golden/step_resolution/sqlmesh/duckdb/models/silver/customer_xref.py +60 -0
- bloomery-0.1.0/tests/golden/test_cube.py +59 -0
- bloomery-0.1.0/tests/golden/test_dbt_postgres.py +48 -0
- bloomery-0.1.0/tests/golden/test_metricflow_manifest.py +37 -0
- bloomery-0.1.0/tests/golden/test_spec_schemas.py +44 -0
- bloomery-0.1.0/tests/golden/test_sqlmesh_dialects.py +49 -0
- bloomery-0.1.0/tests/golden/test_sqlmesh_duckdb.py +91 -0
- bloomery-0.1.0/tests/property/__init__.py +0 -0
- bloomery-0.1.0/tests/property/test_compile_properties.py +190 -0
- bloomery-0.1.0/tests/property/test_conservation.py +204 -0
- bloomery-0.1.0/tests/property/test_guardrail_properties.py +45 -0
- bloomery-0.1.0/tests/property/test_mart_properties.py +73 -0
- bloomery-0.1.0/tests/property/test_metricflow_properties.py +58 -0
- bloomery-0.1.0/tests/property/test_parse_properties.py +342 -0
- bloomery-0.1.0/tests/property/test_plan_properties.py +141 -0
- bloomery-0.1.0/tests/property/test_planner_properties.py +268 -0
- bloomery-0.1.0/tests/property/test_schema_agreement.py +454 -0
- bloomery-0.1.0/tests/support/__init__.py +0 -0
- bloomery-0.1.0/tests/support/chaos.py +178 -0
- bloomery-0.1.0/tests/support/compiling.py +99 -0
- bloomery-0.1.0/tests/support/cube.py +213 -0
- bloomery-0.1.0/tests/support/dirty.py +308 -0
- bloomery-0.1.0/tests/support/docs_claims.py +89 -0
- bloomery-0.1.0/tests/support/equivalence.py +164 -0
- bloomery-0.1.0/tests/support/execution.py +245 -0
- bloomery-0.1.0/tests/support/identity.py +180 -0
- bloomery-0.1.0/tests/support/ir_factory.py +176 -0
- bloomery-0.1.0/tests/support/mart_permutations.py +33 -0
- bloomery-0.1.0/tests/support/plan_ir.py +219 -0
- bloomery-0.1.0/tests/support/planning.py +131 -0
- bloomery-0.1.0/tests/support/precedence.py +212 -0
- bloomery-0.1.0/tests/support/quality_rules.py +80 -0
- bloomery-0.1.0/tests/support/reconcile.py +84 -0
- bloomery-0.1.0/tests/support/steps.py +139 -0
- bloomery-0.1.0/tests/unit/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_changelog_release.py +228 -0
- bloomery-0.1.0/tests/unit/test_cli.py +852 -0
- bloomery-0.1.0/tests/unit/test_compile.py +38 -0
- bloomery-0.1.0/tests/unit/test_coverage_floors_guard.py +271 -0
- bloomery-0.1.0/tests/unit/test_determinism_guard.py +214 -0
- bloomery-0.1.0/tests/unit/test_dialects/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_dialects/test_base.py +131 -0
- bloomery-0.1.0/tests/unit/test_dialects/test_duckdb.py +54 -0
- bloomery-0.1.0/tests/unit/test_dialects/test_postgres.py +79 -0
- bloomery-0.1.0/tests/unit/test_dialects/test_trino.py +63 -0
- bloomery-0.1.0/tests/unit/test_docs_floor.py +361 -0
- bloomery-0.1.0/tests/unit/test_docs_snippets.py +115 -0
- bloomery-0.1.0/tests/unit/test_emit/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_emit/test_audit_vocabulary.py +137 -0
- bloomery-0.1.0/tests/unit/test_emit/test_base.py +121 -0
- bloomery-0.1.0/tests/unit/test_emit/test_cube.py +379 -0
- bloomery-0.1.0/tests/unit/test_emit/test_currency_convert.py +109 -0
- bloomery-0.1.0/tests/unit/test_emit/test_dbt.py +472 -0
- bloomery-0.1.0/tests/unit/test_emit/test_metricflow.py +474 -0
- bloomery-0.1.0/tests/unit/test_emit/test_quality_artifacts.py +745 -0
- bloomery-0.1.0/tests/unit/test_emit/test_quality_mart.py +384 -0
- bloomery-0.1.0/tests/unit/test_emit/test_sqlmesh.py +373 -0
- bloomery-0.1.0/tests/unit/test_error_suggestions.py +242 -0
- bloomery-0.1.0/tests/unit/test_errors.py +198 -0
- bloomery-0.1.0/tests/unit/test_evidence.py +398 -0
- bloomery-0.1.0/tests/unit/test_fixtures.py +221 -0
- bloomery-0.1.0/tests/unit/test_guardrails/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_additivity.py +170 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_arithmetic.py +215 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_asserts.py +207 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_conflict.py +59 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_grain.py +189 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_operands.py +99 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_quality.py +1040 -0
- bloomery-0.1.0/tests/unit/test_guardrails/test_stage.py +304 -0
- bloomery-0.1.0/tests/unit/test_import_contracts.py +96 -0
- bloomery-0.1.0/tests/unit/test_ir/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_ir/test_fingerprint.py +238 -0
- bloomery-0.1.0/tests/unit/test_ir/test_lower.py +38 -0
- bloomery-0.1.0/tests/unit/test_ir/test_nodes.py +194 -0
- bloomery-0.1.0/tests/unit/test_marts/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_marts/test_asserts.py +269 -0
- bloomery-0.1.0/tests/unit/test_marts/test_flatten.py +960 -0
- bloomery-0.1.0/tests/unit/test_metricflow_canary.py +135 -0
- bloomery-0.1.0/tests/unit/test_naming.py +37 -0
- bloomery-0.1.0/tests/unit/test_package.py +91 -0
- bloomery-0.1.0/tests/unit/test_plan/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_plan/test_diff.py +780 -0
- bloomery-0.1.0/tests/unit/test_plan/test_evolution.py +189 -0
- bloomery-0.1.0/tests/unit/test_plan/test_model.py +49 -0
- bloomery-0.1.0/tests/unit/test_plan/test_quality_changes.py +701 -0
- bloomery-0.1.0/tests/unit/test_plan/test_step_changes.py +161 -0
- bloomery-0.1.0/tests/unit/test_planner/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_planner/test_coverage.py +236 -0
- bloomery-0.1.0/tests/unit/test_planner/test_filters.py +364 -0
- bloomery-0.1.0/tests/unit/test_planner/test_metricflow_planner.py +328 -0
- bloomery-0.1.0/tests/unit/test_planner/test_names.py +199 -0
- bloomery-0.1.0/tests/unit/test_planner/test_parse.py +517 -0
- bloomery-0.1.0/tests/unit/test_planner/test_request.py +283 -0
- bloomery-0.1.0/tests/unit/test_planner/test_row_policy.py +150 -0
- bloomery-0.1.0/tests/unit/test_purity_guard.py +159 -0
- bloomery-0.1.0/tests/unit/test_quality/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_quality/test_coverage.py +311 -0
- bloomery-0.1.0/tests/unit/test_quality/test_dedupe_and_reject.py +184 -0
- bloomery-0.1.0/tests/unit/test_quality/test_edges.py +214 -0
- bloomery-0.1.0/tests/unit/test_quality/test_expression_scope.py +239 -0
- bloomery-0.1.0/tests/unit/test_quality/test_flags.py +181 -0
- bloomery-0.1.0/tests/unit/test_quality/test_lower.py +358 -0
- bloomery-0.1.0/tests/unit/test_quality/test_mart.py +148 -0
- bloomery-0.1.0/tests/unit/test_quality/test_predicates.py +673 -0
- bloomery-0.1.0/tests/unit/test_quality/test_reconcile.py +200 -0
- bloomery-0.1.0/tests/unit/test_quality/test_repair.py +338 -0
- bloomery-0.1.0/tests/unit/test_quality/test_text_rules.py +273 -0
- bloomery-0.1.0/tests/unit/test_resolve/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_build.py +283 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_graph.py +137 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_metrics.py +75 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_order.py +107 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_reach.py +116 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_recipes.py +132 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_refs.py +188 -0
- bloomery-0.1.0/tests/unit/test_resolve/test_resolution.py +84 -0
- bloomery-0.1.0/tests/unit/test_rfc_corpus_guard.py +313 -0
- bloomery-0.1.0/tests/unit/test_runtime/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_runtime/test_hydration.py +175 -0
- bloomery-0.1.0/tests/unit/test_runtime/test_sql_client.py +52 -0
- bloomery-0.1.0/tests/unit/test_schema.py +281 -0
- bloomery-0.1.0/tests/unit/test_signature_closure.py +280 -0
- bloomery-0.1.0/tests/unit/test_spec/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_spec/test_catalog.py +160 -0
- bloomery-0.1.0/tests/unit/test_spec/test_common.py +75 -0
- bloomery-0.1.0/tests/unit/test_spec/test_document_versions.py +122 -0
- bloomery-0.1.0/tests/unit/test_spec/test_entity.py +215 -0
- bloomery-0.1.0/tests/unit/test_spec/test_mapping.py +182 -0
- bloomery-0.1.0/tests/unit/test_spec/test_marts.py +134 -0
- bloomery-0.1.0/tests/unit/test_spec/test_metrics.py +107 -0
- bloomery-0.1.0/tests/unit/test_spec/test_project.py +177 -0
- bloomery-0.1.0/tests/unit/test_spec/test_quality.py +674 -0
- bloomery-0.1.0/tests/unit/test_spec/test_relation_names.py +97 -0
- bloomery-0.1.0/tests/unit/test_spec/test_steps.py +198 -0
- bloomery-0.1.0/tests/unit/test_steps/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_steps/test_contract.py +267 -0
- bloomery-0.1.0/tests/unit/test_steps/test_dbt_and_cube_emission.py +217 -0
- bloomery-0.1.0/tests/unit/test_steps/test_emission.py +565 -0
- bloomery-0.1.0/tests/unit/test_steps/test_identity_demo.py +242 -0
- bloomery-0.1.0/tests/unit/test_steps/test_lowering.py +540 -0
- bloomery-0.1.0/tests/unit/test_steps/test_macro_fields.py +414 -0
- bloomery-0.1.0/tests/unit/test_steps/test_manifest_and_registry.py +271 -0
- bloomery-0.1.0/tests/unit/test_steps/test_splice.py +66 -0
- bloomery-0.1.0/tests/unit/test_steps/test_step_canonicals.py +216 -0
- bloomery-0.1.0/tests/unit/test_steps/test_step_entities.py +125 -0
- bloomery-0.1.0/tests/unit/test_tenant_guard.py +56 -0
- bloomery-0.1.0/tests/unit/test_total_lookups.py +81 -0
- bloomery-0.1.0/tests/unit/test_transforms/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_transforms/test_builtins.py +183 -0
- bloomery-0.1.0/tests/unit/test_transforms/test_registry.py +152 -0
- bloomery-0.1.0/tests/unit/test_typing/__init__.py +0 -0
- bloomery-0.1.0/tests/unit/test_typing/test_check.py +229 -0
- bloomery-0.1.0/tests/unit/test_typing/test_types.py +134 -0
- bloomery-0.1.0/uv.lock +3043 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
219
|
+
|
|
220
|
+
# ....................... #
|
|
221
|
+
# bloomery-specific (RFC 0001)
|
|
222
|
+
|
|
223
|
+
# hatch-vcs generated version file
|
|
224
|
+
src/bloomery/_version.py
|
|
225
|
+
|
|
226
|
+
# Docs build output
|
|
227
|
+
pages/site/
|
|
228
|
+
pages/.cache/
|
|
229
|
+
|
|
230
|
+
# Tooling state
|
|
231
|
+
.benchmarks
|
|
232
|
+
.just/
|
|
233
|
+
junit.xml
|
|
234
|
+
# Per-interpreter results the CI test matrix writes (junit-3.12.xml, …).
|
|
235
|
+
junit-*.xml
|
|
236
|
+
coverage-data/
|
|
237
|
+
.envrc
|
|
238
|
+
.claude/projects/
|
|
239
|
+
|
|
240
|
+
# NOTE: rfcs/ is deliberately committed here — the RFC corpus is a deliverable.
|
|
241
|
+
|
|
242
|
+
# Stray warehouse files from local SQLMesh/DuckDB runs — the e2e tier builds
|
|
243
|
+
# its own under tmp_path and never writes into the repo.
|
|
244
|
+
*.duckdb
|
|
245
|
+
*.duckdb.wal
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be 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
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-08-15
|
|
11
|
+
|
|
12
|
+
First release. Everything bloomery does is new here, so this section is one `Added` —
|
|
13
|
+
`Changed`, `Deprecated`, `Removed`, `Fixed` and `Security` describe movement away from a
|
|
14
|
+
version somebody could have installed, and there is not one yet. They begin at 0.2.0.
|
|
15
|
+
|
|
16
|
+
From this tag the [stability promises](https://morzecrew.github.io/bloomery/reference/stability/)
|
|
17
|
+
bind: SemVer over the Python API, per-kind versioning over spec YAML, and emitted
|
|
18
|
+
artifacts explicitly **not** stable across bloomery versions.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
**The compiler**
|
|
23
|
+
|
|
24
|
+
- `compile_project(project, *, target, dialect, naming=None, catalog=None, steps=EMPTY_REGISTRY)`
|
|
25
|
+
— declarative specs to target artifacts as one pure function. No filesystem, no
|
|
26
|
+
network, no clock, no randomness: the same specs produce byte-identical artifacts
|
|
27
|
+
across machines, processes and `PYTHONHASHSEED` values.
|
|
28
|
+
- **Six spec document kinds**, each strict YAML that self-identifies by its version key:
|
|
29
|
+
Catalog (`catalog_version`), EntityModel (`spec_version`), Mapping (`mapping_version`),
|
|
30
|
+
MetricSet (`metrics_version`), MartSet (`marts_version`) and StepSet (`steps_version`).
|
|
31
|
+
Unknown keys, duplicate YAML keys and grammar violations are refused, batched per
|
|
32
|
+
document with a source path each. A version bloomery does not implement is refused
|
|
33
|
+
rather than read as one it does.
|
|
34
|
+
- Deterministic intermediate representation with a `blm1:` content fingerprint
|
|
35
|
+
(`build_project_ir`, `project_fingerprint`), stamped into every artifact header.
|
|
36
|
+
`bloomery_ir_version` is **5**; it covers each node's field names and count, so an IR
|
|
37
|
+
shape change moves every fingerprint by construction.
|
|
38
|
+
- A closed whitelist of 24 typed mapping transforms with a compile-time typecheck of
|
|
39
|
+
every chain, decimal precision and scale tracked through arithmetic, and
|
|
40
|
+
`register_transform` for vetted extensions.
|
|
41
|
+
- Resolution (`resolve`): cross-spec reference validation, recorded-recipe validation,
|
|
42
|
+
cycle detection, and metric reachability naming the specific missing leaf.
|
|
43
|
+
`UnreachableMetric.via` names the chain when a metric is blocked *through* another one.
|
|
44
|
+
|
|
45
|
+
**Guardrails**
|
|
46
|
+
|
|
47
|
+
- Fail-closed unit, tax-basis, currency, grain and additivity checks; mart fan-out and
|
|
48
|
+
grain protection; `assert:` clauses lowered to target-native audits. Every violation is
|
|
49
|
+
a typed error with a source path, and stages batch so a spec is fixed in one round trip.
|
|
50
|
+
- Two constructs that used to compile clean and could not be right are refused:
|
|
51
|
+
`HistoricalFanout` for a mart flattening an `scd: type2` dimension with no validity
|
|
52
|
+
predicate (each base row multiplied by that key's version count, with every declared
|
|
53
|
+
cardinality still honest), and `UnsupportedByTarget` for the `convert` transform, which
|
|
54
|
+
lowered to a `CONVERT_CURRENCY` call no engine defines. `convert` stays registered and
|
|
55
|
+
typechecked; currency conversion needs a dated rate relation bloomery does not model.
|
|
56
|
+
|
|
57
|
+
**Data quality**
|
|
58
|
+
|
|
59
|
+
- Cleansing as spec surface: a closed rule catalogue (`coercible`, `not_null`, `range`,
|
|
60
|
+
`length`, `pattern`, `in_enum`, `in_set`, `unique`, `normalize`, `charset`), entity row
|
|
61
|
+
rules (`expression`, `referential`), `dedupe:`, `quarantine:`, document-level
|
|
62
|
+
`reconcile:`, and cross-entity `coverage:` checks. Every rule carries an explicit
|
|
63
|
+
`on_fail` — `flag`, `quarantine`, `fail` or `repair` — and rules evaluate under a
|
|
64
|
+
strict three-valued discipline, so a NULL-involved comparison never fires.
|
|
65
|
+
- `pattern` speaks a portable regex allowlist, refused at parse with the construct named;
|
|
66
|
+
`range` bounds are exact (int, decimal, or a string carrying an exact decimal or ISO
|
|
67
|
+
date/timestamp); `charset` declares admissible characters as `U+` codepoints.
|
|
68
|
+
- One replayable `<entity>__reject` table per entity with a `reject_id` recomputable from
|
|
69
|
+
the row, a replay artifact that re-runs the current mapping under the pipeline's own
|
|
70
|
+
dedupe order, `retention:` and `redact:`. bloomery emits the artifact and never runs it.
|
|
71
|
+
- `gold.mart_data_quality` — an ordinary mart with one row per rule evaluation plus an
|
|
72
|
+
accounting row per entity, so quarantine rate is a plain `MetricRequest`. Five reserved
|
|
73
|
+
metrics come with it.
|
|
74
|
+
- Every silver model projects `_quality_flags` and `_quality_ok`; a mart over a
|
|
75
|
+
rule-carrying base flattens them into a `has_quality_flags` dimension.
|
|
76
|
+
|
|
77
|
+
**Steps: referenced implementations**
|
|
78
|
+
|
|
79
|
+
- A project may wire platform-owned steps through a `steps_version: 1` document —
|
|
80
|
+
`use: ref@version`, input/output bindings, parameters within the manifest's declared
|
|
81
|
+
bounds, `expression` quality rules on outputs, and `canonical:` links so metrics and
|
|
82
|
+
`reconcile` can read a step output. Manifests reach the compiler as a frozen
|
|
83
|
+
`StepRegistry` passed to `compile_project(..., steps=…)`: bloomery reads no step files
|
|
84
|
+
and has no dynamic loading path, so a spec can never name code to load.
|
|
85
|
+
- Three tiers emit — `sql_macro` splices into the consuming SELECT, `sql_model` emits an
|
|
86
|
+
ordinary model, and `python_model` emits one generated wrapper per declared output,
|
|
87
|
+
each carrying a non-optional `assert_step_contract` call. Step outputs are entities:
|
|
88
|
+
a mart may reference one exactly as it would any silver entity, and `plan()` diffs them.
|
|
89
|
+
- `bloomery.steps.assert_step_contract` — the run-time contract, and the only bloomery
|
|
90
|
+
name intended for import outside compilation. It imports nothing but `bloomery.errors`.
|
|
91
|
+
|
|
92
|
+
**The gold layer and the emitters**
|
|
93
|
+
|
|
94
|
+
- Wide marts: relationship flattening with mandatory prefixes, role-playing date
|
|
95
|
+
dimensions (`ordered_month`, `shipped_month`, …), a generated `dim_date` owned by the
|
|
96
|
+
catalog, and aggregate `assert:` clauses lowering to target-native audits.
|
|
97
|
+
- Emit targets for **SQLMesh** (models, audits, native SCD2, reject/replay, quality
|
|
98
|
+
audits), **dbt** (models through `ref()`/`source()`, sources, snapshots, schema tests,
|
|
99
|
+
a self-contained expression-test macro) and **Cube** (cubes and views with additivity
|
|
100
|
+
metadata, ratios as calculated measures), rendering over **DuckDB**, **Trino** and
|
|
101
|
+
**PostgreSQL**. `register_emitter` adds extension targets. Where a target cannot express
|
|
102
|
+
a declaration it raises `UnsupportedByTarget` rather than dropping it silently.
|
|
103
|
+
|
|
104
|
+
**Request-time planning**
|
|
105
|
+
|
|
106
|
+
- `MetricFlowPlanner`: a structured `MetricRequest` becomes SQL over a wide mart plus
|
|
107
|
+
typed columns, warnings, a deterministic explanation and a fingerprint — refusing
|
|
108
|
+
unknown members, cross-grain requests and ambiguous dimensions instead of guessing.
|
|
109
|
+
MetricFlow is embedded and render-only, never connected to a database. Bind result rows
|
|
110
|
+
by `ColumnDescriptor.sql_alias`; display `name`.
|
|
111
|
+
- Filters are typed CNF clauses (`Predicate` / `AnyOf` — implicit AND, one level of OR),
|
|
112
|
+
with `RowPolicy` for row-level scoping and `parse_filter_json` / `parse_sort_json` /
|
|
113
|
+
`parse_page_json` as the Mongo-flavoured JSON front door. Unsupported constructs raise
|
|
114
|
+
`UnsupportedFilter` with a stable reason code from the closed, drift-guarded set
|
|
115
|
+
exported as `bloomery.planner.KNOWN_UNSUPPORTED`.
|
|
116
|
+
- `LruManifestHydrator` / `HydrationKey`: in-process manifest hydration keyed by spec
|
|
117
|
+
fingerprint and library versions, with an optional caller-owned byte store.
|
|
118
|
+
|
|
119
|
+
**Assessing and evolving a spec**
|
|
120
|
+
|
|
121
|
+
- `evaluate(project) -> SpecEvidence` — everything knowable about a spec without touching
|
|
122
|
+
data, as one value: reachable metrics, unreachable ones with the missing leaf, batched
|
|
123
|
+
refusals with source paths, mart shapes, entities, fingerprint. **Refusals are the
|
|
124
|
+
return value**, and analysis that completed before the refusal comes back with them.
|
|
125
|
+
`InvariantViolated` and every programming error still propagate.
|
|
126
|
+
- `plan()` — every change between two compiled versions classified as additive, widening,
|
|
127
|
+
rename, restating or breaking, with backfill scope, replay scope for the reject tables a
|
|
128
|
+
change invalidates, downstream metric impact and an enforced expand/contract workflow.
|
|
129
|
+
- Structured fix suggestions on five refusals: `UnknownMember.did_you_mean`,
|
|
130
|
+
`UnreachableAtGrain.covering_marts`, `GrainViolation.offending_measures`,
|
|
131
|
+
`UnknownStep.available_versions`, `UnsupportedFilter.nearest_supported`. Always present
|
|
132
|
+
— `()` or `None` when there is nothing to suggest, never absent and never fabricated.
|
|
133
|
+
|
|
134
|
+
**Surfaces**
|
|
135
|
+
|
|
136
|
+
- A total error hierarchy rooted at `BloomeryError`: every failure is typed, carries a
|
|
137
|
+
source path into the offending spec node, and is documented in the errors reference.
|
|
138
|
+
- **A command line** — `bloomery compile|plan|resolve|explain|schema|fingerprint`, plus
|
|
139
|
+
`bloomery --version`. Each command is a thin argument shell over one public function;
|
|
140
|
+
`--format json` emits the same values the Python API returns. A refusal exits `1` and a
|
|
141
|
+
usage error `2`, so a pipeline can tell "your spec is wrong" from "your command is
|
|
142
|
+
wrong". Nothing is executed: `bloomery run` does not exist.
|
|
143
|
+
- **JSON Schema per spec kind** — `spec_json_schema(kind)`, `all_spec_schemas()`, and
|
|
144
|
+
`bloomery schema --out DIR`. Generated from the Pydantic models so they cannot drift
|
|
145
|
+
from the parser, with every closed set enumerated. Also published at
|
|
146
|
+
`https://morzecrew.github.io/bloomery/schemas/v1/<kind>.json`.
|
|
147
|
+
- `bloomery.__all__` is **closed over its own signatures**: every type named in a public
|
|
148
|
+
signature is importable from the root, enforced by a test that walks the whole surface.
|
|
149
|
+
`bloomery.__version__` reports the installed release.
|
|
150
|
+
- Documentation: get-started, concepts, how-to guides for every target and the planner,
|
|
151
|
+
full spec/transform/error/API/stability references, and a runnable `examples/quickstart/`.
|
|
152
|
+
|
|
153
|
+
[Unreleased]: https://github.com/morzecrew/bloomery/compare/v0.1.0...HEAD
|
|
154
|
+
[0.1.0]: https://github.com/morzecrew/bloomery/releases/tag/v0.1.0
|
bloomery-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Morze Technologies
|
|
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.
|
bloomery-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: bloomery
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Entity-first spec compiler: declarative entity/mapping/metric specs → SQLMesh, dbt, and Cube artifacts
|
|
5
|
+
Project-URL: homepage, https://github.com/morzecrew/bloomery
|
|
6
|
+
Project-URL: documentation, https://morzecrew.github.io/bloomery/
|
|
7
|
+
Project-URL: changelog, https://github.com/morzecrew/bloomery/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: issues, https://github.com/morzecrew/bloomery/issues
|
|
9
|
+
Author-email: Lev Litvinov <misery7100@gmail.com>
|
|
10
|
+
Maintainer-email: Lev Litvinov <misery7100@gmail.com>
|
|
11
|
+
License: MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2026 Morze Technologies
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Keywords: analytics,compiler,cube,data-engineering,dbt,semantic-layer,sqlglot,sqlmesh
|
|
34
|
+
Classifier: Development Status :: 3 - Alpha
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
40
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
41
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
42
|
+
Classifier: Typing :: Typed
|
|
43
|
+
Requires-Python: <3.15,>=3.12
|
|
44
|
+
Requires-Dist: jinja2>=3.1
|
|
45
|
+
Requires-Dist: metricflow==0.211.*
|
|
46
|
+
Requires-Dist: pydantic>=2.9
|
|
47
|
+
Requires-Dist: pyyaml>=6
|
|
48
|
+
Requires-Dist: sqlglot<31,>=30.8.0
|
|
49
|
+
Description-Content-Type: text/markdown
|
|
50
|
+
|
|
51
|
+
# bloomery
|
|
52
|
+
|
|
53
|
+
**Entity-first spec compiler: declarative entity/mapping/metric specs, compiled deterministically into SQLMesh, dbt, and Cube artifacts.**
|
|
54
|
+
|
|
55
|
+
## What it is
|
|
56
|
+
|
|
57
|
+
bloomery is a pure function library. You hand it declarative specs — a catalog, entities,
|
|
58
|
+
mappings, metrics, marts, and optionally steps — and it compiles them into ready-to-run
|
|
59
|
+
artifacts for SQLMesh, dbt, and Cube: models, audits, and semantic-layer definitions.
|
|
60
|
+
The same specs also serve metric queries at request time: a structured `MetricRequest`
|
|
61
|
+
becomes SQL over a wide mart, planned by an embedded, render-only MetricFlow.
|
|
62
|
+
|
|
63
|
+
- **Deterministic** — same specs in, byte-identical artifacts out, across machines,
|
|
64
|
+
processes, and hash seeds. No clocks, no randomness, no environment reads.
|
|
65
|
+
- **Fail-closed guardrails** — grain fan-out, additivity violations, and contract breaks
|
|
66
|
+
are compile errors with named reasons, not silent wrong numbers downstream.
|
|
67
|
+
- **Reviewable** — emitted artifacts are stable-sorted, pretty-printed text, so a diff of
|
|
68
|
+
the output is a faithful diff of the semantic change.
|
|
69
|
+
|
|
70
|
+
## What it is not
|
|
71
|
+
|
|
72
|
+
- It does **not execute SQL** — it emits artifacts and plans for engines and frameworks
|
|
73
|
+
that do.
|
|
74
|
+
- It does **no orchestration** — scheduling, backfills, and deployment belong to SQLMesh,
|
|
75
|
+
dbt, or whatever runs the artifacts.
|
|
76
|
+
- It contains **no LLM** — specs are authored by people (or by tools upstream of this
|
|
77
|
+
library); compilation is deterministic all the way down.
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv add bloomery
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Compile specs into SQLMesh artifacts (the library never touches the filesystem —
|
|
86
|
+
writing is your loop):
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from bloomery import Target, compile_project, load_catalog, load_project
|
|
90
|
+
|
|
91
|
+
catalog = load_catalog(catalog_yaml)
|
|
92
|
+
project = load_project(
|
|
93
|
+
{
|
|
94
|
+
"entity_model.yaml": entities_yaml,
|
|
95
|
+
"mapping_orders.yaml": mapping_yaml,
|
|
96
|
+
"metrics.yaml": metrics_yaml,
|
|
97
|
+
"marts.yaml": marts_yaml,
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
artifacts = compile_project(project, target=Target.SQLMESH, dialect="duckdb", catalog=catalog)
|
|
102
|
+
for artifact in artifacts:
|
|
103
|
+
print(artifact.path) # write artifact.content wherever your repo keeps models
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Or from a shell — the CLI is a thin argument shell over exactly these functions, and the
|
|
107
|
+
only part of the package that touches a filesystem:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
bloomery compile specs/ --target sqlmesh --dialect duckdb --out out/
|
|
111
|
+
bloomery resolve specs/ # what is computable, what is missing, what was refused
|
|
112
|
+
bloomery schema --out schemas/ # JSON Schema per spec kind, for editors and validators
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
A refusal exits `1` and a bad invocation exits `2`, so a pipeline can tell "your spec is
|
|
116
|
+
wrong" from "your command is wrong". Nothing is executed: `bloomery run` does not exist.
|
|
117
|
+
|
|
118
|
+
Assess a spec before it compiles — refusals come back as a **value**, alongside whatever
|
|
119
|
+
analysis completed before them, so a draft mid-edit still reports what it would give you:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from bloomery import Stage, evaluate
|
|
123
|
+
|
|
124
|
+
evidence = evaluate(project, catalog=catalog)
|
|
125
|
+
evidence.stage_reached # read this first: at any stage but COMPLETE the rest is a prefix
|
|
126
|
+
evidence.reachable # ('gross_revenue', 'order_count', …)
|
|
127
|
+
evidence.unreachable # margin, blocked on 'cogs' — the specific leaf, not a summary
|
|
128
|
+
evidence.refusals # each with its own source path into the spec that caused it
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Plan a metric request over the mart those specs declared — SQL out, nothing executed:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from bloomery import LruManifestHydrator, MetricFlowPlanner, MetricRequest, build_project_ir
|
|
135
|
+
from bloomery.naming import DefaultNaming
|
|
136
|
+
|
|
137
|
+
naming = DefaultNaming()
|
|
138
|
+
planner = MetricFlowPlanner(LruManifestHydrator(naming), naming=naming)
|
|
139
|
+
plan = planner.plan(
|
|
140
|
+
build_project_ir(project, catalog=catalog),
|
|
141
|
+
MetricRequest(metrics=("revenue",), dimensions=("ordered_month",)),
|
|
142
|
+
dialect="duckdb",
|
|
143
|
+
)
|
|
144
|
+
print(plan.sql)
|
|
145
|
+
print(plan.explanation.render())
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Filters are typed CNF clauses (`Predicate` / `AnyOf` — implicit AND, one level of OR), and
|
|
149
|
+
`bloomery.planner.parse_filter_json` is a public front door for the Mongo-flavoured JSON
|
|
150
|
+
grammar (`$and`/`$or`/`$not`, field maps): it normalizes (De Morgan → complement inversion
|
|
151
|
+
→ capped CNF) before refusing, and refuses only from the closed, drift-guarded list
|
|
152
|
+
exported as `bloomery.planner.KNOWN_UNSUPPORTED`:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from bloomery.planner import parse_filter_json
|
|
156
|
+
|
|
157
|
+
filters = parse_filter_json(
|
|
158
|
+
{
|
|
159
|
+
"customer_id": {"$neq": "internal"},
|
|
160
|
+
"$or": [{"ordered_month": {"$gte": "2024-01-01"}}, {"ordered_month": "2023-12-01"}],
|
|
161
|
+
}
|
|
162
|
+
) # → (Predicate(…), AnyOf(…)) — pass straight to MetricRequest(filters=…)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The runnable version of both snippets lives in
|
|
166
|
+
[`examples/quickstart/`](examples/quickstart/):
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
uv run python examples/quickstart/run.py
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Status
|
|
173
|
+
|
|
174
|
+
**0.1.0** — the first release. Everything the library does ships behind the quality gate:
|
|
175
|
+
the spec layer over six document kinds, the deterministic IR, transforms and typecheck,
|
|
176
|
+
resolution, fail-closed guardrails, declarative data quality with quarantine and replay,
|
|
177
|
+
steps as referenced implementations, wide marts with role-playing dates, the
|
|
178
|
+
SQLMesh/dbt/Cube emitters over DuckDB/Trino/Postgres, the MetricFlow-backed planner with
|
|
179
|
+
manifest hydration, spec-diff planning, spec assessment, the CLI and the JSON Schema
|
|
180
|
+
export. Every test tier runs, including the Docker-backed engine matrix, the target e2e
|
|
181
|
+
tiers and the three-way equivalence tier.
|
|
182
|
+
|
|
183
|
+
From this release the promises in
|
|
184
|
+
[Stability](https://morzecrew.github.io/bloomery/reference/stability/) bind: per-kind
|
|
185
|
+
versioning over spec YAML (fully), SemVer over the Python API (breaking changes are
|
|
186
|
+
allowed in a minor below 1.0, but never silent), and emitted artifacts explicitly **not**
|
|
187
|
+
stable across versions — byte-reproducible for fixed inputs, which is determinism rather
|
|
188
|
+
than a cross-version promise. Pin the minor if you want the API to hold still.
|
|
189
|
+
|
|
190
|
+
Designs that have not yet landed live as RFCs in [`rfcs/`](rfcs/INDEX.md); code that
|
|
191
|
+
contradicts a live RFC is the bug, not the RFC. An RFC is retired once it ships — the
|
|
192
|
+
code, the tests and the documentation are the account of what bloomery already does.
|
|
193
|
+
|
|
194
|
+
## Documentation
|
|
195
|
+
|
|
196
|
+
Full documentation is available at
|
|
197
|
+
[https://morzecrew.github.io/bloomery/](https://morzecrew.github.io/bloomery/):
|
|
198
|
+
|
|
199
|
+
- [Quickstart](https://morzecrew.github.io/bloomery/get-started/quickstart/) — specs to
|
|
200
|
+
compiled artifacts to a planned query.
|
|
201
|
+
- [Concepts](https://morzecrew.github.io/bloomery/concepts/specs-and-catalog/) — the
|
|
202
|
+
domain model, the compile pipeline, determinism, guardrails, wide marts.
|
|
203
|
+
- How-to guides — emit
|
|
204
|
+
[SQLMesh](https://morzecrew.github.io/bloomery/how-to/emit-sqlmesh/),
|
|
205
|
+
[Cube](https://morzecrew.github.io/bloomery/how-to/emit-cube/), or
|
|
206
|
+
[dbt](https://morzecrew.github.io/bloomery/how-to/emit-dbt/);
|
|
207
|
+
[plan a metric request](https://morzecrew.github.io/bloomery/how-to/plan-a-metric-request/);
|
|
208
|
+
[evolve a spec safely](https://morzecrew.github.io/bloomery/how-to/evolve-a-spec/).
|
|
209
|
+
- Reference —
|
|
210
|
+
[spec schemas](https://morzecrew.github.io/bloomery/reference/spec-schemas/),
|
|
211
|
+
[transforms](https://morzecrew.github.io/bloomery/reference/transforms/),
|
|
212
|
+
[errors](https://morzecrew.github.io/bloomery/reference/errors/),
|
|
213
|
+
[API](https://morzecrew.github.io/bloomery/reference/api/),
|
|
214
|
+
[stability](https://morzecrew.github.io/bloomery/reference/stability/).
|
|
215
|
+
|
|
216
|
+
## Contributing
|
|
217
|
+
|
|
218
|
+
Contributions, issues, and feature requests are welcome.
|
|
219
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details — including the RFC process for larger
|
|
220
|
+
changes.
|
|
221
|
+
|
|
222
|
+
## Licence
|
|
223
|
+
|
|
224
|
+
bloomery is licensed under the MIT License — see [LICENSE](LICENSE) for details.
|