pytest-dbt-macros 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytest_dbt_macros-0.2.1/.gitignore +11 -0
- pytest_dbt_macros-0.2.1/CONTRIBUTING.md +8 -0
- pytest_dbt_macros-0.2.1/LICENSE +21 -0
- pytest_dbt_macros-0.2.1/NOTICE +28 -0
- pytest_dbt_macros-0.2.1/PKG-INFO +203 -0
- pytest_dbt_macros-0.2.1/README.md +176 -0
- pytest_dbt_macros-0.2.1/examples/README.md +22 -0
- pytest_dbt_macros-0.2.1/pyproject.toml +42 -0
- pytest_dbt_macros-0.2.1/scripts/baseline-requirements.txt +6 -0
- pytest_dbt_macros-0.2.1/scripts/make_baselines.py +126 -0
- pytest_dbt_macros-0.2.1/scripts/make_baselines.sh +8 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/__init__.py +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/core.py +318 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/plugin.py +15 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/SOURCES.json +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/LICENSE +201 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/array_append.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/array_concat.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/array_construct.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/bool_or.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/date.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/date_trunc.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/dateadd.sql +8 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/datediff.sql +15 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/equals.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/escape_single_quotes.sql +4 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/except.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/get_columns_spec_ddl.sql +37 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/hash.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/intersect.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/listagg.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/position.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/right.sql +12 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/safe_cast.sql +27 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/split_part.sql +20 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/string_literal.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/bigquery/timestamps.sql +12 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/LICENSE +201 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/any_value.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/date.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/dateadd.sql +22 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/datediff.sql +12 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/external_location.sql +8 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/generate_series.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/lastday.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/listagg.sql +22 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/normalize.sql +19 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/splitpart.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/duckdb/upstream.sql +42 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/LICENSE +201 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/_timestamps.sql +52 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/any_value.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/array_append.sql +8 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/array_concat.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/array_construct.sql +12 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/bool_or.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/cast.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/cast_bool_to_text.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/concat.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/data_types.sql +129 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/date.sql +10 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/date_spine.sql +75 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/date_trunc.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/dateadd.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/datediff.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/equals.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/escape_single_quotes.sql +8 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/except.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/generate_series.sql +53 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/hash.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/intersect.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/last_day.sql +15 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/length.sql +11 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/listagg.sql +30 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/literal.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/position.sql +11 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/replace.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/right.sql +12 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/safe_cast.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/global_project/split_part.sql +26 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/LICENSE +201 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/_timestamps.sql +20 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/any_value.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/columns_spec_ddl.sql +0 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/dateadd.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/datediff.sql +32 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/equals.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/last_day.sql +14 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/listagg.sql +23 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/postgres/split_part.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/LICENSE +201 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/array_construct.sql +3 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/bool_or.sql +5 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/cast.sql +9 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/equals.sql +7 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/escape_single_quotes.sql +4 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/optional.sql +16 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/right.sql +12 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/safe_cast.sql +13 -0
- pytest_dbt_macros-0.2.1/src/pytest_dbt_macros/vendored/snowflake/timestamps.sql +20 -0
- pytest_dbt_macros-0.2.1/tests/baselines/VERSIONS.txt +7 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/concat.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/dateadd.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/datediff.sql +9 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/deduplicate.sql +11 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/generate_series.sql +43 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/generate_surrogate_key.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/get_url_host.sql +46 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/get_url_parameter.sql +19 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/haversine_distance.sql +9 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/pivot.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/project_to_text.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/project_var.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/safe_add.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/safe_divide_overridden.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/safe_subtract.sql +2 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/type_string.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/bigquery/width_bucket.sql +20 -0
- pytest_dbt_macros-0.2.1/tests/baselines/cases.json +19 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/concat.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/dateadd.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/datediff.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/deduplicate.sql +16 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/generate_series.sql +43 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/generate_surrogate_key.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/get_url_host.sql +34 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/get_url_parameter.sql +5 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/haversine_distance.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/pivot.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/project_to_text.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/project_var.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/safe_add.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/safe_divide_overridden.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/safe_subtract.sql +2 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/type_string.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/duckdb/width_bucket.sql +26 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/concat.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/dateadd.sql +4 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/datediff.sql +5 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/deduplicate.sql +4 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/generate_series.sql +43 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/generate_surrogate_key.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/get_url_host.sql +58 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/get_url_parameter.sql +29 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/haversine_distance.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/pivot.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/project_to_text.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/project_var.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/safe_add.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/safe_divide_overridden.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/safe_subtract.sql +2 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/type_string.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/postgres/width_bucket.sql +26 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/concat.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/dateadd.sql +8 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/datediff.sql +5 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/deduplicate.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/generate_series.sql +43 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/generate_surrogate_key.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/get_url_host.sql +47 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/get_url_parameter.sql +17 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/haversine_distance.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/pivot.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/project_to_text.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/project_var.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/safe_add.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/safe_divide_overridden.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/safe_subtract.sql +2 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/type_string.sql +1 -0
- pytest_dbt_macros-0.2.1/tests/baselines/snowflake/width_bucket.sql +2 -0
- pytest_dbt_macros-0.2.1/tests/baselines_star/star_all.sql +3 -0
- pytest_dbt_macros-0.2.1/tests/baselines_star/star_except_prefix.sql +2 -0
- pytest_dbt_macros-0.2.1/tests/conftest.py +10 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/LICENSE +201 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/dbt_project.yml +11 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/accepted_range.sql +33 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/at_least_one.sql +48 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/cardinality_equality.sql +53 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/equal_rowcount.sql +76 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/equality.sql +166 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/expression_is_true.sql +18 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/fewer_rows_than.sql +80 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/mutually_exclusive_ranges.sql +97 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/not_accepted_values.sql +37 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/not_constant.sql +27 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/not_empty_string.sql +39 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/not_null_proportion.sql +34 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/recency.sql +46 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/relationships_where.sql +51 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/sequential_values.sql +42 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/generic_tests/unique_combination_of_columns.sql +37 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/jinja_helpers/_is_ephemeral.sql +16 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/jinja_helpers/_is_relation.sql +5 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/jinja_helpers/log_info.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/jinja_helpers/pretty_log_format.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/jinja_helpers/pretty_time.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/jinja_helpers/slugify.sql +18 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/date_spine.sql +75 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/deduplicate.sql +110 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/generate_series.sql +53 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/generate_surrogate_key.sql +29 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_column_values.sql +65 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_filtered_columns_in_relation.sql +25 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_query_results_as_dict.sql +26 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_relations_by_pattern.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_relations_by_prefix.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_single_value.sql +33 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_table_types_sql.sql +32 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_tables_by_pattern_sql.sql +96 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/get_tables_by_prefix_sql.sql +14 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/groupby.sql +11 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/haversine_distance.sql +51 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/nullcheck.sql +21 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/nullcheck_table.sql +14 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/pivot.sql +86 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/safe_add.sql +28 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/safe_divide.sql +7 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/safe_subtract.sql +28 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/star.sql +51 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/surrogate_key.sql +20 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/union.sql +134 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/unpivot.sql +67 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/sql/width_bucket.sql +34 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/web/get_url_host.sql +27 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/web/get_url_parameter.sql +13 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_packages/dbt_utils/macros/web/get_url_path.sql +34 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/dbt_project.yml +10 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/macros/project_macros.sql +30 -0
- pytest_dbt_macros-0.2.1/tests/fixtures/project/packages.yml +3 -0
- pytest_dbt_macros-0.2.1/tests/test_baselines.py +21 -0
- pytest_dbt_macros-0.2.1/tests/test_macros.py +81 -0
- pytest_dbt_macros-0.2.1/tests/test_star.py +24 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
This project is an experiment by AI agents at start-up-team-k; humans are very welcome to file issues and PRs.
|
|
4
|
+
|
|
5
|
+
- Dev setup: `python -m venv .venv && . .venv/bin/activate && pip install -e . pytest && pytest`
|
|
6
|
+
- A bug where a rendered macro differs from `dbt compile` is the most valuable kind of report. Please include the macro, the `target.type`, and the dbt output. To add a regression case, put the Jinja in `tests/baselines/cases.json` and run `scripts/make_baselines.sh` (needs `uv`; no database needed), then commit the regenerated baselines.
|
|
7
|
+
- Keep the runtime free of dbt-core and keep the code small. Anything that needs a database connection is out of scope.
|
|
8
|
+
- `src/pytest_dbt_macros/vendored/` and `tests/fixtures/project/dbt_packages/` are third-party Apache-2.0 files; do not edit them by hand (see `NOTICE`).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 start-up-team-k contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
pytest-dbt-macros
|
|
2
|
+
Copyright (c) 2026 start-up-team-k contributors, MIT License (see LICENSE).
|
|
3
|
+
|
|
4
|
+
This product includes third-party files licensed under the Apache License 2.0.
|
|
5
|
+
Each directory below carries its upstream LICENSE file next to the files. The files are
|
|
6
|
+
unmodified copies of the `macros/utils/` directories (plus `timestamps.sql`) taken from the
|
|
7
|
+
published packages listed here (exact versions: src/pytest_dbt_macros/vendored/SOURCES.json).
|
|
8
|
+
They are used as dbt's built-in "dbt" macro namespace (dbt.concat, dbt.hash, dbt.dateadd, ...).
|
|
9
|
+
Regenerate with scripts/make_baselines.sh.
|
|
10
|
+
|
|
11
|
+
src/pytest_dbt_macros/vendored/global_project/ dbt-adapters 1.24.5 Copyright dbt Labs, Inc.
|
|
12
|
+
https://github.com/dbt-labs/dbt-adapters
|
|
13
|
+
src/pytest_dbt_macros/vendored/postgres/ dbt-postgres 1.11.0 Copyright dbt Labs, Inc.
|
|
14
|
+
https://github.com/dbt-labs/dbt-postgres
|
|
15
|
+
src/pytest_dbt_macros/vendored/snowflake/ dbt-snowflake 1.12.4 Copyright dbt Labs, Inc.
|
|
16
|
+
https://github.com/dbt-labs/dbt-adapters
|
|
17
|
+
src/pytest_dbt_macros/vendored/bigquery/ dbt-bigquery 1.12.1 Copyright dbt Labs, Inc.
|
|
18
|
+
https://github.com/dbt-labs/dbt-adapters
|
|
19
|
+
src/pytest_dbt_macros/vendored/duckdb/ dbt-duckdb 1.11.1 Apache-2.0, see its LICENSE
|
|
20
|
+
https://github.com/duckdb/dbt-duckdb
|
|
21
|
+
|
|
22
|
+
Test fixture (not part of the installed package):
|
|
23
|
+
tests/fixtures/project/dbt_packages/dbt_utils/ dbt-utils 1.4.1, Copyright dbt Labs, Inc., Apache-2.0
|
|
24
|
+
https://github.com/dbt-labs/dbt-utils (its LICENSE is in that directory)
|
|
25
|
+
tests/baselines/*/*.sql are outputs of `dbt compile` (dbt-core 1.12.6, Apache-2.0) over those macros.
|
|
26
|
+
|
|
27
|
+
The design of the Jinja stubs (ref/source/var/dispatch) follows dbt-core's documented behaviour;
|
|
28
|
+
no dbt-core source code is copied.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pytest-dbt-macros
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Unit-test dbt macros (Jinja) with pytest, without dbt-core, an adapter, profiles.yml or a database.
|
|
5
|
+
Project-URL: Homepage, https://start-up-team-k.github.io/pytest-dbt-macros/
|
|
6
|
+
Project-URL: Repository, https://github.com/start-up-team-k/pytest-dbt-macros
|
|
7
|
+
Project-URL: Issues, https://github.com/start-up-team-k/pytest-dbt-macros/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/start-up-team-k/pytest-dbt-macros/blob/main/CHANGELOG.md
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: NOTICE
|
|
12
|
+
Keywords: analytics-engineering,dbt,dbt-macros,jinja,pytest,pytest-plugin,sql,unit-testing
|
|
13
|
+
Classifier: Framework :: Pytest
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: jinja2>=3.1
|
|
23
|
+
Requires-Dist: pytest>=7
|
|
24
|
+
Requires-Dist: pyyaml>=6
|
|
25
|
+
Requires-Dist: sqlglot>=25
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# pytest-dbt-macros
|
|
29
|
+
|
|
30
|
+
Unit-test dbt macros (Jinja) with pytest, **without dbt-core, an adapter, `profiles.yml` or a database**.
|
|
31
|
+
|
|
32
|
+
> This is an open-source experiment built by AI agents at start-up-team-k. It is v0.1: expect rough edges, and
|
|
33
|
+
> issues and feedback are welcome.
|
|
34
|
+
|
|
35
|
+
## Why
|
|
36
|
+
|
|
37
|
+
Shared dbt macros grow, branch per warehouse (`adapter.dispatch`), and are hard to test. dbt's built-in unit tests
|
|
38
|
+
cover SQL models only ([dbt-labs/dbt#10547](https://github.com/dbt-labs/dbt/issues/10547) asks for macro tests).
|
|
39
|
+
[pytest-dbt-core](https://github.com/godatadriven/pytest-dbt-core) tests macros with pytest but builds on dbt-core,
|
|
40
|
+
an adapter package and a profile. This plugin instead re-implements the small part of dbt's Jinja context that macros
|
|
41
|
+
need (`ref`, `var`, `target`, `adapter.dispatch`, ...), so a test is: load macros, call, compare SQL strings.
|
|
42
|
+
The same approach is used by [SQLFluff's Jinja templater](https://docs.sqlfluff.com/en/stable/configuration/templating/jinja.html)
|
|
43
|
+
(Apache/MIT-style mocks); here it is packaged for pytest and checked against real `dbt compile` output.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
Not on PyPI yet (publishing is pending); install from GitHub. Python >= 3.10. Examples: [`examples/`](examples/) (dbt-utils multi-target project, GitHub Actions workflow). Docs page: https://start-up-team-k.github.io/pytest-dbt-macros/ .
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python -m venv .venv && . .venv/bin/activate
|
|
51
|
+
pip install pytest git+https://github.com/start-up-team-k/pytest-dbt-macros
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Runtime dependencies: `jinja2`, `pyyaml`, `pytest`, `sqlglot`. dbt-core is **not** installed or imported.
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
Create a tiny dbt-style project (or use your existing one: run pytest from the folder that has `dbt_project.yml`):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
mkdir demo && cd demo && mkdir macros
|
|
62
|
+
printf 'name: demo\n' > dbt_project.yml
|
|
63
|
+
cat > macros/money.sql <<'SQL'
|
|
64
|
+
{% macro cents_to_dollars(col) -%}
|
|
65
|
+
{{ return(adapter.dispatch('cents_to_dollars')(col)) }}
|
|
66
|
+
{%- endmacro %}
|
|
67
|
+
|
|
68
|
+
{% macro default__cents_to_dollars(col) -%}
|
|
69
|
+
({{ col }} / 100.0)
|
|
70
|
+
{%- endmacro %}
|
|
71
|
+
|
|
72
|
+
{% macro bigquery__cents_to_dollars(col) -%}
|
|
73
|
+
safe_divide({{ col }}, 100)
|
|
74
|
+
{%- endmacro %}
|
|
75
|
+
|
|
76
|
+
{% macro require_col(col) -%}
|
|
77
|
+
{%- if not col -%}{{ exceptions.raise_compiler_error("col is required") }}{%- endif -%}
|
|
78
|
+
{{ col }}
|
|
79
|
+
{%- endmacro %}
|
|
80
|
+
SQL
|
|
81
|
+
cat > test_money.py <<'PY'
|
|
82
|
+
import pytest
|
|
83
|
+
from pytest_dbt_macros import CompilationError, assert_sql_equal
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_default(dbt_macros):
|
|
87
|
+
assert_sql_equal(dbt_macros.cents_to_dollars("amount"), "(amount / 100.0)")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_bigquery_branch(dbt_macros):
|
|
91
|
+
dbt_macros.target["type"] = "bigquery" # what `target.type` returns inside the macros
|
|
92
|
+
assert_sql_equal(dbt_macros.cents_to_dollars("amount"), "safe_divide(amount, 100)")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_dbt_global_macro(dbt_macros): # dbt.concat etc. are bundled
|
|
96
|
+
assert_sql_equal(dbt_macros.render("{{ dbt.concat(['a', 'b']) }}"), "a || b")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_error(dbt_macros):
|
|
100
|
+
with pytest.raises(CompilationError, match="col is required"):
|
|
101
|
+
dbt_macros.require_col("")
|
|
102
|
+
PY
|
|
103
|
+
pytest -v
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The `dbt_macros` fixture loads, for the project in the current directory: its `macros/` folders (`macro-paths`),
|
|
107
|
+
every package in `dbt_packages/` (so `dbt_macros.dbt_utils.generate_surrogate_key(["a", "b"])` works after `dbt deps`),
|
|
108
|
+
and dbt's own cross-database macros (`dbt.concat`, `dbt.hash`, `dbt.type_string`, `dbt.dateadd`, ...).
|
|
109
|
+
Calling a macro returns its rendered text (or the value passed to `return(...)`).
|
|
110
|
+
|
|
111
|
+
- `dbt_macros.<macro>(...)`, `dbt_macros.<package>.<macro>(...)`, `dbt_macros.render("{{ ... }}")`
|
|
112
|
+
- `dbt_macros.target["type"]` / `.vars` / `.env`: change `target.type`, `var()`, `env_var()` at any time.
|
|
113
|
+
- `dispatch:` in `dbt_project.yml` is honoured (`macro_namespace`, `search_order`), and so is dbt's lookup order
|
|
114
|
+
`<adapter>__name` -> parent adapter (`redshift` -> `postgres`) -> `default__name`.
|
|
115
|
+
- `assert_sql_equal(actual, expected, dialect=None)` compares after sqlglot normalization (whitespace, keyword and
|
|
116
|
+
identifier case). If sqlglot cannot parse a fragment, it falls back to whitespace-insensitive comparison.
|
|
117
|
+
- To point at another folder, override the `dbt_project_dir` fixture in `conftest.py`.
|
|
118
|
+
|
|
119
|
+
## Test
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git clone https://github.com/start-up-team-k/pytest-dbt-macros && cd pytest-dbt-macros
|
|
123
|
+
python -m venv .venv && . .venv/bin/activate
|
|
124
|
+
pip install -e . pytest
|
|
125
|
+
pytest
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`tests/test_baselines.py` renders 17 cases (dbt-utils 1.4.1 macros, dbt global macros, project macros and a
|
|
129
|
+
`dispatch:` override) for four `target.type`s (postgres, snowflake, bigquery, duckdb) and compares each with the SQL that
|
|
130
|
+
`dbt compile` produced (stored in `tests/baselines/<target>/`). Versions used: see `tests/baselines/VERSIONS.txt`
|
|
131
|
+
(dbt-core 1.12.6, dbt-postgres 1.11.0, dbt-snowflake 1.12.4, dbt-bigquery 1.12.1, dbt-duckdb 1.11.1, dbt-utils 1.4.1).
|
|
132
|
+
To regenerate (needs [uv](https://docs.astral.sh/uv/) and network, no database): `scripts/make_baselines.sh`.
|
|
133
|
+
|
|
134
|
+
## How dbt's built-in macros are handled
|
|
135
|
+
|
|
136
|
+
dbt-utils calls `dbt.concat`, `dbt.hash`, `dbt.dateadd`, ... which live in dbt-adapters and the adapter packages.
|
|
137
|
+
Instead of importing them (which would need dbt-core), the plugin **bundles unmodified copies** of the `macros/utils/`
|
|
138
|
+
folders (plus `timestamps.sql`) of dbt-adapters 1.24.5, dbt-postgres 1.11.0, dbt-snowflake 1.12.4, dbt-bigquery 1.12.1
|
|
139
|
+
and dbt-duckdb 1.11.1 (all Apache-2.0) in `src/pytest_dbt_macros/vendored/`. Each folder keeps its upstream LICENSE;
|
|
140
|
+
see `NOTICE`. Other adapters fall back to `default__` macros, which may not match what that adapter really does.
|
|
141
|
+
|
|
142
|
+
## Comparison
|
|
143
|
+
|
|
144
|
+
The same five checks (`dbt_utils.generate_surrogate_key`, `dbt_utils.deduplicate`, `dbt_utils.haversine_distance`,
|
|
145
|
+
`dbt.dateadd`, `dbt.datediff`; dbt-utils 1.4.1, `target.type` = duckdb) written three ways. Everything is in
|
|
146
|
+
[`bench/`](bench/) and reproduced by [`bench/run.sh`](bench/run.sh) (needs `uv` and network, no database server).
|
|
147
|
+
Measured 2026-11-03 on macOS (Darwin 25.6.0), Apple M4, Python 3.12, fresh uv venvs, dbt-core 1.12.6, dbt-duckdb 1.11.1.
|
|
148
|
+
|
|
149
|
+
| | (a) pytest-dbt-macros | (b) pytest-dbt-core 0.2.4 + dbt-duckdb | (c) dbt unit tests (dummy models) + dbt-duckdb |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| Packages installed (`uv pip freeze` lines) | 12 | 64 | 59 |
|
|
152
|
+
| `site-packages` size | 17.9 MB | 166.0 MB | 157.4 MB |
|
|
153
|
+
| Config files you write | 1 (`dbt_project.yml`) | 3 (`dbt_project.yml`, `profiles.yml`, `packages.yml`) | 4 (same three + `unit_tests.yml`), plus 7 dummy model `.sql` files |
|
|
154
|
+
| Test code lines | 38 | 42 | 51 (38 YAML + 13 SQL) |
|
|
155
|
+
| Wall time, mean of 3 runs (whole process) | 0.214 s | 1.149 s | 2.395 s |
|
|
156
|
+
| Several `target.type` in one run | yes: `dbt_macros.target["type"] = ...` per test (3 targets in `bench/a_pytest_dbt_macros/test_multi_target.py`) | no: one `--dbt-target` per pytest process; each non-DuckDB type needs its adapter package and a profile it can connect with | no: one `--target` per `dbt build`; same adapter requirement |
|
|
157
|
+
| What is checked | rendered SQL string | rendered SQL string | result of executing the SQL on DuckDB |
|
|
158
|
+
|
|
159
|
+
Notes (facts only):
|
|
160
|
+
- (b) works with the latest dbt-core (1.12.6) and Python 3.12; 5/5 pass. It needs `--profiles-dir` (without it
|
|
161
|
+
pytest-dbt-core 0.2.4 raises `TypeError: expected str, bytes or os.PathLike object, not NoneType`), and it does not
|
|
162
|
+
install `pytest` itself. Its last release is 2024-06-04.
|
|
163
|
+
- The dbt-based setups need `dbt deps` once (not timed). (c) also builds the dummy views in a DuckDB file on each run.
|
|
164
|
+
- Times include interpreter start-up and imports; the first (untimed) run per setup warms bytecode caches.
|
|
165
|
+
(a)/(b) timings run only the five-check file; (c) runs `dbt build` (7 views + 5 unit tests).
|
|
166
|
+
- (b)/(c) were not tried on non-DuckDB adapters: their fixtures/commands open a connection to the warehouse.
|
|
167
|
+
- Compare with real warehouses: only (c) runs SQL; (a) and (b) compare strings. Raw numbers: `bench/run.sh` output.
|
|
168
|
+
|
|
169
|
+
## Scope
|
|
170
|
+
|
|
171
|
+
Does:
|
|
172
|
+
- Render macros from your project and from installed packages to SQL strings, call them from Python.
|
|
173
|
+
- Stubs: `ref`, `source`, `var`, `env_var`, `target`, `config`, `log`, `return`, `exceptions.*`, `adapter.dispatch/type/quote`,
|
|
174
|
+
`api.Column.translate_type/numeric_type`, `modules`, `execute`, `dbt_version`.
|
|
175
|
+
- Declare a relation's columns, e.g. `dbt_macros.columns["users"] = ["id", "name"]`; then `ref('users')` works with
|
|
176
|
+
`adapter.get_columns_in_relation` and `dbt_utils.star(ref('users'))` renders (checked against `dbt compile` output on DuckDB
|
|
177
|
+
in `tests/test_star.py`). Names only: no column types.
|
|
178
|
+
- Check cross-database branches by switching `target.type`; assert expected errors with `pytest.raises(CompilationError)`.
|
|
179
|
+
|
|
180
|
+
Does not (yet):
|
|
181
|
+
- Run the SQL: no DuckDB execution of rendered SQL (planned, not implemented).
|
|
182
|
+
- Anything that needs a database: `run_query`, `statement`, `get_column_values`, `date_spine`. `union_relations` also
|
|
183
|
+
fails (needs column types). Columns can be declared by hand for `adapter.get_columns_in_relation` (see below).
|
|
184
|
+
- Models, materializations, hooks, `{% test %}` blocks (parsed and ignored), snapshots, docs blocks.
|
|
185
|
+
- Quoted, fully-qualified relations: `ref('x')` renders as `x`, `source('s', 't')` as `s.t`.
|
|
186
|
+
- dbt Fusion.
|
|
187
|
+
|
|
188
|
+
## Limitations
|
|
189
|
+
|
|
190
|
+
- Fidelity: this is a re-implementation of dbt's Jinja context, not dbt. Known differences: relations render unquoted and
|
|
191
|
+
without database/schema; only the context names listed above exist (no `this`, `model`, `graph`, `flags`,
|
|
192
|
+
`modules.pytz`, ...), so macros using them fail with an `UndefinedError`; `var()` scoping is simplified (project-level
|
|
193
|
+
`vars:` plus `vars=` you pass; no `--vars` or package-scoped lookups beyond the root project's own); `adapter.behavior`
|
|
194
|
+
flags are not available; `target` has only `type`, `name`, `schema`, `database`, `threads`.
|
|
195
|
+
- Baselines cover 17 cases on 4 targets compared against dbt-core 1.12.6 only. Other dbt versions or macros may differ.
|
|
196
|
+
- The bundled dbt macros are pinned to the versions above and are not updated automatically.
|
|
197
|
+
- Some dbt global macros are implemented in Python by an adapter rather than in SQL, so the bundle has no version of
|
|
198
|
+
them. Example: `dbt.current_timestamp()` with `target.type = "duckdb"` fails with "not implemented for adapter duckdb"
|
|
199
|
+
([#1](https://github.com/start-up-team-k/pytest-dbt-macros/issues/1)).
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT (see `LICENSE`). Bundled third-party files are Apache-2.0 (see `NOTICE`).
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# pytest-dbt-macros
|
|
2
|
+
|
|
3
|
+
Unit-test dbt macros (Jinja) with pytest, **without dbt-core, an adapter, `profiles.yml` or a database**.
|
|
4
|
+
|
|
5
|
+
> This is an open-source experiment built by AI agents at start-up-team-k. It is v0.1: expect rough edges, and
|
|
6
|
+
> issues and feedback are welcome.
|
|
7
|
+
|
|
8
|
+
## Why
|
|
9
|
+
|
|
10
|
+
Shared dbt macros grow, branch per warehouse (`adapter.dispatch`), and are hard to test. dbt's built-in unit tests
|
|
11
|
+
cover SQL models only ([dbt-labs/dbt#10547](https://github.com/dbt-labs/dbt/issues/10547) asks for macro tests).
|
|
12
|
+
[pytest-dbt-core](https://github.com/godatadriven/pytest-dbt-core) tests macros with pytest but builds on dbt-core,
|
|
13
|
+
an adapter package and a profile. This plugin instead re-implements the small part of dbt's Jinja context that macros
|
|
14
|
+
need (`ref`, `var`, `target`, `adapter.dispatch`, ...), so a test is: load macros, call, compare SQL strings.
|
|
15
|
+
The same approach is used by [SQLFluff's Jinja templater](https://docs.sqlfluff.com/en/stable/configuration/templating/jinja.html)
|
|
16
|
+
(Apache/MIT-style mocks); here it is packaged for pytest and checked against real `dbt compile` output.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
Not on PyPI yet (publishing is pending); install from GitHub. Python >= 3.10. Examples: [`examples/`](examples/) (dbt-utils multi-target project, GitHub Actions workflow). Docs page: https://start-up-team-k.github.io/pytest-dbt-macros/ .
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python -m venv .venv && . .venv/bin/activate
|
|
24
|
+
pip install pytest git+https://github.com/start-up-team-k/pytest-dbt-macros
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Runtime dependencies: `jinja2`, `pyyaml`, `pytest`, `sqlglot`. dbt-core is **not** installed or imported.
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
Create a tiny dbt-style project (or use your existing one: run pytest from the folder that has `dbt_project.yml`):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
mkdir demo && cd demo && mkdir macros
|
|
35
|
+
printf 'name: demo\n' > dbt_project.yml
|
|
36
|
+
cat > macros/money.sql <<'SQL'
|
|
37
|
+
{% macro cents_to_dollars(col) -%}
|
|
38
|
+
{{ return(adapter.dispatch('cents_to_dollars')(col)) }}
|
|
39
|
+
{%- endmacro %}
|
|
40
|
+
|
|
41
|
+
{% macro default__cents_to_dollars(col) -%}
|
|
42
|
+
({{ col }} / 100.0)
|
|
43
|
+
{%- endmacro %}
|
|
44
|
+
|
|
45
|
+
{% macro bigquery__cents_to_dollars(col) -%}
|
|
46
|
+
safe_divide({{ col }}, 100)
|
|
47
|
+
{%- endmacro %}
|
|
48
|
+
|
|
49
|
+
{% macro require_col(col) -%}
|
|
50
|
+
{%- if not col -%}{{ exceptions.raise_compiler_error("col is required") }}{%- endif -%}
|
|
51
|
+
{{ col }}
|
|
52
|
+
{%- endmacro %}
|
|
53
|
+
SQL
|
|
54
|
+
cat > test_money.py <<'PY'
|
|
55
|
+
import pytest
|
|
56
|
+
from pytest_dbt_macros import CompilationError, assert_sql_equal
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_default(dbt_macros):
|
|
60
|
+
assert_sql_equal(dbt_macros.cents_to_dollars("amount"), "(amount / 100.0)")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_bigquery_branch(dbt_macros):
|
|
64
|
+
dbt_macros.target["type"] = "bigquery" # what `target.type` returns inside the macros
|
|
65
|
+
assert_sql_equal(dbt_macros.cents_to_dollars("amount"), "safe_divide(amount, 100)")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_dbt_global_macro(dbt_macros): # dbt.concat etc. are bundled
|
|
69
|
+
assert_sql_equal(dbt_macros.render("{{ dbt.concat(['a', 'b']) }}"), "a || b")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_error(dbt_macros):
|
|
73
|
+
with pytest.raises(CompilationError, match="col is required"):
|
|
74
|
+
dbt_macros.require_col("")
|
|
75
|
+
PY
|
|
76
|
+
pytest -v
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The `dbt_macros` fixture loads, for the project in the current directory: its `macros/` folders (`macro-paths`),
|
|
80
|
+
every package in `dbt_packages/` (so `dbt_macros.dbt_utils.generate_surrogate_key(["a", "b"])` works after `dbt deps`),
|
|
81
|
+
and dbt's own cross-database macros (`dbt.concat`, `dbt.hash`, `dbt.type_string`, `dbt.dateadd`, ...).
|
|
82
|
+
Calling a macro returns its rendered text (or the value passed to `return(...)`).
|
|
83
|
+
|
|
84
|
+
- `dbt_macros.<macro>(...)`, `dbt_macros.<package>.<macro>(...)`, `dbt_macros.render("{{ ... }}")`
|
|
85
|
+
- `dbt_macros.target["type"]` / `.vars` / `.env`: change `target.type`, `var()`, `env_var()` at any time.
|
|
86
|
+
- `dispatch:` in `dbt_project.yml` is honoured (`macro_namespace`, `search_order`), and so is dbt's lookup order
|
|
87
|
+
`<adapter>__name` -> parent adapter (`redshift` -> `postgres`) -> `default__name`.
|
|
88
|
+
- `assert_sql_equal(actual, expected, dialect=None)` compares after sqlglot normalization (whitespace, keyword and
|
|
89
|
+
identifier case). If sqlglot cannot parse a fragment, it falls back to whitespace-insensitive comparison.
|
|
90
|
+
- To point at another folder, override the `dbt_project_dir` fixture in `conftest.py`.
|
|
91
|
+
|
|
92
|
+
## Test
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/start-up-team-k/pytest-dbt-macros && cd pytest-dbt-macros
|
|
96
|
+
python -m venv .venv && . .venv/bin/activate
|
|
97
|
+
pip install -e . pytest
|
|
98
|
+
pytest
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`tests/test_baselines.py` renders 17 cases (dbt-utils 1.4.1 macros, dbt global macros, project macros and a
|
|
102
|
+
`dispatch:` override) for four `target.type`s (postgres, snowflake, bigquery, duckdb) and compares each with the SQL that
|
|
103
|
+
`dbt compile` produced (stored in `tests/baselines/<target>/`). Versions used: see `tests/baselines/VERSIONS.txt`
|
|
104
|
+
(dbt-core 1.12.6, dbt-postgres 1.11.0, dbt-snowflake 1.12.4, dbt-bigquery 1.12.1, dbt-duckdb 1.11.1, dbt-utils 1.4.1).
|
|
105
|
+
To regenerate (needs [uv](https://docs.astral.sh/uv/) and network, no database): `scripts/make_baselines.sh`.
|
|
106
|
+
|
|
107
|
+
## How dbt's built-in macros are handled
|
|
108
|
+
|
|
109
|
+
dbt-utils calls `dbt.concat`, `dbt.hash`, `dbt.dateadd`, ... which live in dbt-adapters and the adapter packages.
|
|
110
|
+
Instead of importing them (which would need dbt-core), the plugin **bundles unmodified copies** of the `macros/utils/`
|
|
111
|
+
folders (plus `timestamps.sql`) of dbt-adapters 1.24.5, dbt-postgres 1.11.0, dbt-snowflake 1.12.4, dbt-bigquery 1.12.1
|
|
112
|
+
and dbt-duckdb 1.11.1 (all Apache-2.0) in `src/pytest_dbt_macros/vendored/`. Each folder keeps its upstream LICENSE;
|
|
113
|
+
see `NOTICE`. Other adapters fall back to `default__` macros, which may not match what that adapter really does.
|
|
114
|
+
|
|
115
|
+
## Comparison
|
|
116
|
+
|
|
117
|
+
The same five checks (`dbt_utils.generate_surrogate_key`, `dbt_utils.deduplicate`, `dbt_utils.haversine_distance`,
|
|
118
|
+
`dbt.dateadd`, `dbt.datediff`; dbt-utils 1.4.1, `target.type` = duckdb) written three ways. Everything is in
|
|
119
|
+
[`bench/`](bench/) and reproduced by [`bench/run.sh`](bench/run.sh) (needs `uv` and network, no database server).
|
|
120
|
+
Measured 2026-11-03 on macOS (Darwin 25.6.0), Apple M4, Python 3.12, fresh uv venvs, dbt-core 1.12.6, dbt-duckdb 1.11.1.
|
|
121
|
+
|
|
122
|
+
| | (a) pytest-dbt-macros | (b) pytest-dbt-core 0.2.4 + dbt-duckdb | (c) dbt unit tests (dummy models) + dbt-duckdb |
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| Packages installed (`uv pip freeze` lines) | 12 | 64 | 59 |
|
|
125
|
+
| `site-packages` size | 17.9 MB | 166.0 MB | 157.4 MB |
|
|
126
|
+
| Config files you write | 1 (`dbt_project.yml`) | 3 (`dbt_project.yml`, `profiles.yml`, `packages.yml`) | 4 (same three + `unit_tests.yml`), plus 7 dummy model `.sql` files |
|
|
127
|
+
| Test code lines | 38 | 42 | 51 (38 YAML + 13 SQL) |
|
|
128
|
+
| Wall time, mean of 3 runs (whole process) | 0.214 s | 1.149 s | 2.395 s |
|
|
129
|
+
| Several `target.type` in one run | yes: `dbt_macros.target["type"] = ...` per test (3 targets in `bench/a_pytest_dbt_macros/test_multi_target.py`) | no: one `--dbt-target` per pytest process; each non-DuckDB type needs its adapter package and a profile it can connect with | no: one `--target` per `dbt build`; same adapter requirement |
|
|
130
|
+
| What is checked | rendered SQL string | rendered SQL string | result of executing the SQL on DuckDB |
|
|
131
|
+
|
|
132
|
+
Notes (facts only):
|
|
133
|
+
- (b) works with the latest dbt-core (1.12.6) and Python 3.12; 5/5 pass. It needs `--profiles-dir` (without it
|
|
134
|
+
pytest-dbt-core 0.2.4 raises `TypeError: expected str, bytes or os.PathLike object, not NoneType`), and it does not
|
|
135
|
+
install `pytest` itself. Its last release is 2024-06-04.
|
|
136
|
+
- The dbt-based setups need `dbt deps` once (not timed). (c) also builds the dummy views in a DuckDB file on each run.
|
|
137
|
+
- Times include interpreter start-up and imports; the first (untimed) run per setup warms bytecode caches.
|
|
138
|
+
(a)/(b) timings run only the five-check file; (c) runs `dbt build` (7 views + 5 unit tests).
|
|
139
|
+
- (b)/(c) were not tried on non-DuckDB adapters: their fixtures/commands open a connection to the warehouse.
|
|
140
|
+
- Compare with real warehouses: only (c) runs SQL; (a) and (b) compare strings. Raw numbers: `bench/run.sh` output.
|
|
141
|
+
|
|
142
|
+
## Scope
|
|
143
|
+
|
|
144
|
+
Does:
|
|
145
|
+
- Render macros from your project and from installed packages to SQL strings, call them from Python.
|
|
146
|
+
- Stubs: `ref`, `source`, `var`, `env_var`, `target`, `config`, `log`, `return`, `exceptions.*`, `adapter.dispatch/type/quote`,
|
|
147
|
+
`api.Column.translate_type/numeric_type`, `modules`, `execute`, `dbt_version`.
|
|
148
|
+
- Declare a relation's columns, e.g. `dbt_macros.columns["users"] = ["id", "name"]`; then `ref('users')` works with
|
|
149
|
+
`adapter.get_columns_in_relation` and `dbt_utils.star(ref('users'))` renders (checked against `dbt compile` output on DuckDB
|
|
150
|
+
in `tests/test_star.py`). Names only: no column types.
|
|
151
|
+
- Check cross-database branches by switching `target.type`; assert expected errors with `pytest.raises(CompilationError)`.
|
|
152
|
+
|
|
153
|
+
Does not (yet):
|
|
154
|
+
- Run the SQL: no DuckDB execution of rendered SQL (planned, not implemented).
|
|
155
|
+
- Anything that needs a database: `run_query`, `statement`, `get_column_values`, `date_spine`. `union_relations` also
|
|
156
|
+
fails (needs column types). Columns can be declared by hand for `adapter.get_columns_in_relation` (see below).
|
|
157
|
+
- Models, materializations, hooks, `{% test %}` blocks (parsed and ignored), snapshots, docs blocks.
|
|
158
|
+
- Quoted, fully-qualified relations: `ref('x')` renders as `x`, `source('s', 't')` as `s.t`.
|
|
159
|
+
- dbt Fusion.
|
|
160
|
+
|
|
161
|
+
## Limitations
|
|
162
|
+
|
|
163
|
+
- Fidelity: this is a re-implementation of dbt's Jinja context, not dbt. Known differences: relations render unquoted and
|
|
164
|
+
without database/schema; only the context names listed above exist (no `this`, `model`, `graph`, `flags`,
|
|
165
|
+
`modules.pytz`, ...), so macros using them fail with an `UndefinedError`; `var()` scoping is simplified (project-level
|
|
166
|
+
`vars:` plus `vars=` you pass; no `--vars` or package-scoped lookups beyond the root project's own); `adapter.behavior`
|
|
167
|
+
flags are not available; `target` has only `type`, `name`, `schema`, `database`, `threads`.
|
|
168
|
+
- Baselines cover 17 cases on 4 targets compared against dbt-core 1.12.6 only. Other dbt versions or macros may differ.
|
|
169
|
+
- The bundled dbt macros are pinned to the versions above and are not updated automatically.
|
|
170
|
+
- Some dbt global macros are implemented in Python by an adapter rather than in SQL, so the bundle has no version of
|
|
171
|
+
them. Example: `dbt.current_timestamp()` with `target.type = "duckdb"` fails with "not implemented for adapter duckdb"
|
|
172
|
+
([#1](https://github.com/start-up-team-k/pytest-dbt-macros/issues/1)).
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT (see `LICENSE`). Bundled third-party files are Apache-2.0 (see `NOTICE`).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Part of an open-source experiment built by AI agents (start-up-team-k). Copy what is useful.
|
|
4
|
+
|
|
5
|
+
## `dbt_utils_multi_target/`
|
|
6
|
+
|
|
7
|
+
A small dbt project whose macros wrap `dbt_utils.generate_surrogate_key` and branch with `adapter.dispatch`.
|
|
8
|
+
`test_shop.py` checks the SQL for postgres, snowflake and bigquery in one pytest run by changing `target.type`.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
cd examples/dbt_utils_multi_target
|
|
12
|
+
git clone --depth 1 --branch 1.4.1 https://github.com/dbt-labs/dbt-utils dbt_packages/dbt_utils # what `dbt deps` would fetch
|
|
13
|
+
pytest -v
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`dbt_packages/` is git-ignored; the clone replaces `dbt deps` so dbt-core is not needed. Expected SQL strings were
|
|
17
|
+
produced with dbt-utils 1.4.1 and match the baselines in `tests/baselines/`.
|
|
18
|
+
|
|
19
|
+
## `github-actions/test-macros.yml`
|
|
20
|
+
|
|
21
|
+
Minimal GitHub Actions workflow that runs only macro tests. The `examples` job in this repo's CI runs the same steps
|
|
22
|
+
against the example project above.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pytest-dbt-macros"
|
|
7
|
+
version = "0.2.1"
|
|
8
|
+
description = "Unit-test dbt macros (Jinja) with pytest, without dbt-core, an adapter, profiles.yml or a database."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE", "NOTICE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
dependencies = ["jinja2>=3.1", "pyyaml>=6", "pytest>=7", "sqlglot>=25"]
|
|
14
|
+
keywords = ["dbt", "dbt-macros", "pytest", "pytest-plugin", "jinja", "unit-testing", "analytics-engineering", "sql"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Framework :: Pytest",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Topic :: Software Development :: Testing",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://start-up-team-k.github.io/pytest-dbt-macros/"
|
|
28
|
+
Repository = "https://github.com/start-up-team-k/pytest-dbt-macros"
|
|
29
|
+
Issues = "https://github.com/start-up-team-k/pytest-dbt-macros/issues"
|
|
30
|
+
Changelog = "https://github.com/start-up-team-k/pytest-dbt-macros/blob/main/CHANGELOG.md"
|
|
31
|
+
|
|
32
|
+
[project.entry-points.pytest11]
|
|
33
|
+
dbt_macros = "pytest_dbt_macros.plugin"
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.wheel]
|
|
36
|
+
packages = ["src/pytest_dbt_macros"]
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.sdist]
|
|
39
|
+
include = ["src", "tests", "scripts", "LICENSE", "NOTICE", "README.md", "CONTRIBUTING.md"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Run inside the baseline venv (see make_baselines.sh).
|
|
2
|
+
|
|
3
|
+
1. Copies dbt's cross-database `utils` macros (Apache-2.0) into src/pytest_dbt_macros/vendored/.
|
|
4
|
+
2. For every target type, runs `dbt compile` on the fixture project, one model per case in
|
|
5
|
+
tests/baselines/cases.json, and stores the compiled SQL in tests/baselines/<target>/<case>.sql.
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
import tempfile
|
|
12
|
+
from importlib import metadata
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
16
|
+
FIXTURE = ROOT / "tests/fixtures/project"
|
|
17
|
+
BASE = ROOT / "tests/baselines"
|
|
18
|
+
VENDORED = ROOT / "src/pytest_dbt_macros/vendored"
|
|
19
|
+
|
|
20
|
+
# target type -> profile fields (fake values; nothing connects)
|
|
21
|
+
PROFILES = {
|
|
22
|
+
"postgres": dict(host="localhost", port=5432, user="u", password="p", dbname="d", schema="s"),
|
|
23
|
+
"snowflake": dict(account="a", user="u", password="p", database="d", warehouse="w", schema="s"),
|
|
24
|
+
# BigQuery opens a client eagerly, so give it a throwaway service-account key (never used online).
|
|
25
|
+
"bigquery": dict(method="service-account-json", project="p", dataset="s", keyfile_json=None),
|
|
26
|
+
"duckdb": dict(path=":memory:", schema="s"),
|
|
27
|
+
}
|
|
28
|
+
# vendored directory (inside site-packages/dbt/include) -> pip distribution it comes from
|
|
29
|
+
SOURCES = {
|
|
30
|
+
"global_project": "dbt-adapters", "postgres": "dbt-postgres", "snowflake": "dbt-snowflake",
|
|
31
|
+
"bigquery": "dbt-bigquery", "duckdb": "dbt-duckdb",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def vendor():
|
|
36
|
+
include = Path(__import__("dbt.include", fromlist=["x"]).__path__[0])
|
|
37
|
+
shutil.rmtree(VENDORED, ignore_errors=True)
|
|
38
|
+
for d in SOURCES:
|
|
39
|
+
shutil.copytree(include / d / "macros" / "utils", VENDORED / d)
|
|
40
|
+
# current_timestamp & friends
|
|
41
|
+
shutil.copy(include / "global_project/macros/adapters/timestamps.sql", VENDORED / "global_project/_timestamps.sql")
|
|
42
|
+
shutil.copy(include / "postgres/macros/timestamps.sql", VENDORED / "postgres/_timestamps.sql")
|
|
43
|
+
for d, dist in SOURCES.items(): # keep each upstream's own license text next to its files
|
|
44
|
+
d_ = metadata.distribution(dist)
|
|
45
|
+
shutil.copy(d_.locate_file(next(f for f in d_.files if f.name == "LICENSE")), VENDORED / d / "LICENSE")
|
|
46
|
+
versions = {d: f"{dist}=={metadata.version(dist)}" for d, dist in SOURCES.items()}
|
|
47
|
+
(VENDORED / "SOURCES.json").write_text(json.dumps(versions, indent=2) + "\n")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def fake_service_account():
|
|
51
|
+
from cryptography.hazmat.primitives import serialization
|
|
52
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
53
|
+
|
|
54
|
+
pem = rsa.generate_private_key(public_exponent=65537, key_size=2048).private_bytes(
|
|
55
|
+
serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()
|
|
56
|
+
)
|
|
57
|
+
return {
|
|
58
|
+
"type": "service_account", "project_id": "p", "private_key_id": "x", "private_key": pem.decode(),
|
|
59
|
+
"client_email": "x@p.iam.gserviceaccount.com", "client_id": "1",
|
|
60
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def compile_target(target, cases, work):
|
|
65
|
+
proj = work / target
|
|
66
|
+
shutil.copytree(FIXTURE, proj)
|
|
67
|
+
(proj / "models").mkdir()
|
|
68
|
+
for name, expr in cases.items():
|
|
69
|
+
(proj / "models" / f"{name}.sql").write_text(expr)
|
|
70
|
+
fields = {**PROFILES[target]}
|
|
71
|
+
if target == "bigquery":
|
|
72
|
+
fields["keyfile_json"] = fake_service_account()
|
|
73
|
+
profiles = {"cedar_fixture": {"target": target, "outputs": {target: {"type": target, "threads": 1, **fields}}}}
|
|
74
|
+
pdir = work / f"profiles_{target}"
|
|
75
|
+
pdir.mkdir()
|
|
76
|
+
(pdir / "profiles.yml").write_text(json.dumps(profiles)) # JSON is valid YAML
|
|
77
|
+
subprocess.run(
|
|
78
|
+
[sys.executable, "-m", "dbt.cli.main", "compile", "--no-populate-cache",
|
|
79
|
+
"--project-dir", str(proj), "--profiles-dir", str(pdir)],
|
|
80
|
+
check=True,
|
|
81
|
+
)
|
|
82
|
+
out = BASE / target
|
|
83
|
+
shutil.rmtree(out, ignore_errors=True)
|
|
84
|
+
out.mkdir(parents=True)
|
|
85
|
+
for name in cases:
|
|
86
|
+
shutil.copy(proj / "target/compiled/cedar_fixture/models" / f"{name}.sql", out / f"{name}.sql")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
STAR_CASES = { # need a real table: only DuckDB (a local file) can be created without a server
|
|
90
|
+
"star_all": "{{ dbt_utils.star(ref('users')) }}",
|
|
91
|
+
"star_except_prefix": "{{ dbt_utils.star(ref('users'), except=['email'], prefix='u_') }}",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def star_baselines(work):
|
|
96
|
+
"""`dbt run` creates table `users` (id, name, email) in a temp DuckDB file, then `dbt compile` renders star()."""
|
|
97
|
+
proj = work / "star"
|
|
98
|
+
shutil.copytree(FIXTURE, proj)
|
|
99
|
+
(proj / "models").mkdir()
|
|
100
|
+
(proj / "models/users.sql").write_text("select 1 as id, 'x' as name, 'y' as email")
|
|
101
|
+
for name, expr in STAR_CASES.items():
|
|
102
|
+
(proj / "models" / f"{name}.sql").write_text(expr)
|
|
103
|
+
out = {"type": "duckdb", "threads": 1, "path": str(work / "star.duckdb")}
|
|
104
|
+
(work / "profiles.yml").write_text(json.dumps({"cedar_fixture": {"target": "d", "outputs": {"d": out}}}))
|
|
105
|
+
for cmd, extra in (("run", ["--select", "users"]), ("compile", [])):
|
|
106
|
+
subprocess.run([sys.executable, "-m", "dbt.cli.main", cmd, "--project-dir", str(proj),
|
|
107
|
+
"--profiles-dir", str(work), *extra], check=True)
|
|
108
|
+
dest = ROOT / "tests/baselines_star"
|
|
109
|
+
shutil.rmtree(dest, ignore_errors=True)
|
|
110
|
+
dest.mkdir()
|
|
111
|
+
for name in STAR_CASES:
|
|
112
|
+
shutil.copy(proj / "target/compiled/cedar_fixture/models" / f"{name}.sql", dest / f"{name}.sql")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
vendor()
|
|
117
|
+
cases = json.loads((BASE / "cases.json").read_text())
|
|
118
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
119
|
+
for t in PROFILES:
|
|
120
|
+
compile_target(t, cases, Path(tmp))
|
|
121
|
+
(Path(tmp) / "s").mkdir()
|
|
122
|
+
star_baselines(Path(tmp) / "s")
|
|
123
|
+
dists = ["dbt-core", "dbt-adapters", "dbt-postgres", "dbt-snowflake", "dbt-bigquery", "dbt-duckdb"]
|
|
124
|
+
lines = [f"{d}=={metadata.version(d)}" for d in dists]
|
|
125
|
+
lines.append("dbt-utils==1.4.1 (git tag 1.4.1, copied to tests/fixtures/project/dbt_packages/dbt_utils)")
|
|
126
|
+
(BASE / "VERSIONS.txt").write_text("\n".join(lines) + "\n")
|