From 54beb6e6e5bd623b5356a939465f3b8367191843 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Mon, 27 Jul 2026 02:22:53 +0000 Subject: [PATCH 1/2] chore: replace black with ruff format Completes the toolchain consolidation started in #707, which moved linting to Ruff. The two black hooks are replaced by ruff-format hooks in the existing astral-sh/ruff-pre-commit block, so lint and format share one repo, one version pin, and one [tool.ruff] config block. No new configuration: ruff format reads line-length and target-version from pyproject.toml. Makefile: the black target becomes format; the test target checks formatting with ruff-format-check. Reformats 12 files. All changes are cosmetic: joined implicit string concatenations that now fit in 99 columns, assert message reflow, decorator argument wrapping, and a blank line after a class header. Closes #711 --- .github/scripts/verify_version.py | 2 +- .pre-commit-config.yaml | 14 ++------ Makefile | 8 ++--- dbt/adapters/sqlserver/sqlserver_relation.py | 6 ++-- tests/functional/adapter/dbt/test_basic.py | 1 - tests/functional/adapter/dbt/test_caching.py | 6 ++-- .../functional/adapter/dbt/test_data_types.py | 6 ++-- tests/functional/adapter/dbt/test_dbt_show.py | 2 +- tests/functional/adapter/dbt/test_hooks.py | 18 +++++----- .../adapter/dbt/test_simple_seed.py | 36 ++++++++++++------- tests/functional/adapter/dbt/test_utils.py | 6 ++-- .../adapter/mssql/test_index_config.py | 12 +++++-- .../adapter/mssql/test_query_options.py | 18 +++++----- .../mssql/test_reserved_keywords_schema.py | 6 ++-- 14 files changed, 79 insertions(+), 62 deletions(-) diff --git a/.github/scripts/verify_version.py b/.github/scripts/verify_version.py index 851034297..c20fb06ba 100755 --- a/.github/scripts/verify_version.py +++ b/.github/scripts/verify_version.py @@ -36,7 +36,7 @@ def main(argv: list[str]) -> int: pkg_version = read_package_version() if tag_version != pkg_version: print( - f"Git tag {tag_version!r} does not match " f"package version {pkg_version!r}", + f"Git tag {tag_version!r} does not match package version {pkg_version!r}", file=sys.stderr, ) return 1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0818bd9be..e4442f6a1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,20 +37,12 @@ repos: alias: ruff-check-manual stages: - manual - - repo: 'https://github.com/psf/black' - rev: 26.5.1 - hooks: - - id: black - args: - - '--line-length=99' - - '--target-version=py311' - - id: black - alias: black-check + - id: ruff-format + - id: ruff-format + alias: ruff-format-check stages: - manual args: - - '--line-length=99' - - '--target-version=py311' - '--check' - '--diff' - repo: 'https://github.com/pre-commit/mirrors-mypy' diff --git a/Makefile b/Makefile index 60d8faed8..677f6d62a 100644 --- a/Makefile +++ b/Makefile @@ -16,10 +16,10 @@ ruff: ## Runs ruff against staged changes to enforce style guide. @\ pre-commit run --hook-stage manual ruff-check-manual | grep -v "INFO" -.PHONY: black -black: ## Runs black against staged changes to enforce style guide. +.PHONY: format +format: ## Runs ruff format against staged changes to enforce style guide. @\ - pre-commit run --hook-stage manual black-check -v | grep -v "INFO" + pre-commit run --hook-stage manual ruff-format-check -v | grep -v "INFO" .PHONY: lint lint: ## Runs ruff and mypy code checks against staged changes. @@ -46,7 +46,7 @@ functional: ## Runs functional tests. test: ## Runs unit tests and code checks against staged changes. @\ uv run pytest -n auto -ra -v tests/unit; \ - pre-commit run black-check --hook-stage manual | grep -v "INFO"; \ + pre-commit run ruff-format-check --hook-stage manual | grep -v "INFO"; \ pre-commit run ruff-check-manual --hook-stage manual | grep -v "INFO"; \ pre-commit run mypy-check --hook-stage manual | grep -v "INFO" diff --git a/dbt/adapters/sqlserver/sqlserver_relation.py b/dbt/adapters/sqlserver/sqlserver_relation.py index ff5cedae9..20f5047ef 100644 --- a/dbt/adapters/sqlserver/sqlserver_relation.py +++ b/dbt/adapters/sqlserver/sqlserver_relation.py @@ -71,13 +71,11 @@ def _render_event_time_filtered(self, event_time_filter: EventTimeFilter) -> str ) elif event_time_filter.start: filter = ( - f"{event_time_filter.field_name} >=" - f" cast('{event_time_filter.start}' as datetime2)" + f"{event_time_filter.field_name} >= cast('{event_time_filter.start}' as datetime2)" ) elif event_time_filter.end: filter = ( - f"{event_time_filter.field_name} <" - f" cast('{event_time_filter.end}' as datetime2)" + f"{event_time_filter.field_name} < cast('{event_time_filter.end}' as datetime2)" ) return filter diff --git a/tests/functional/adapter/dbt/test_basic.py b/tests/functional/adapter/dbt/test_basic.py index 56ead9ac6..9ba7db09a 100644 --- a/tests/functional/adapter/dbt/test_basic.py +++ b/tests/functional/adapter/dbt/test_basic.py @@ -16,7 +16,6 @@ class TestSimpleMaterializations(BaseSimpleMaterializations): - def test_existing_view_materialization(self, project, models): """Test that materializing an existing view works correctly.""" # Create a temporary model file directly in the project diff --git a/tests/functional/adapter/dbt/test_caching.py b/tests/functional/adapter/dbt/test_caching.py index 429bdbe5e..70d3b9286 100644 --- a/tests/functional/adapter/dbt/test_caching.py +++ b/tests/functional/adapter/dbt/test_caching.py @@ -12,10 +12,12 @@ class TestCachingLowercaseModel(BaseCachingLowercaseModel): pass -@pytest.mark.skip(reason=""" +@pytest.mark.skip( + reason=""" Fails because of case sensitivity. MODEL is coereced to model which fails the test as it sees conflicting naming - """) + """ +) class TestCachingUppercaseModel(BaseCachingUppercaseModel): pass diff --git a/tests/functional/adapter/dbt/test_data_types.py b/tests/functional/adapter/dbt/test_data_types.py index 70fcdc7b8..a7670beae 100644 --- a/tests/functional/adapter/dbt/test_data_types.py +++ b/tests/functional/adapter/dbt/test_data_types.py @@ -34,9 +34,9 @@ class TestTypeStringSQLServer(BaseTypeString): def assert_columns_equal(self, project, expected_cols, actual_cols): # ignore the size of the varchar since we do # an optimization to not use varchar(max) all the time - assert ( - expected_cols[:-1] == actual_cols[:-1] - ), f"Type difference detected: {expected_cols} vs. {actual_cols}" + assert expected_cols[:-1] == actual_cols[:-1], ( + f"Type difference detected: {expected_cols} vs. {actual_cols}" + ) class TestTypeTimestampSQLServer(BaseTypeTimestamp): diff --git a/tests/functional/adapter/dbt/test_dbt_show.py b/tests/functional/adapter/dbt/test_dbt_show.py index 0bf0e241b..862f90ade 100644 --- a/tests/functional/adapter/dbt/test_dbt_show.py +++ b/tests/functional/adapter/dbt/test_dbt_show.py @@ -40,7 +40,7 @@ def test_limit(self, project, args, expected): limit = results.args.get("limit") if limit > 0: assert ( - f"offset 0 rows fetch first { limit } rows only" + f"offset 0 rows fetch first {limit} rows only" in results.results[0].node.compiled_code ) diff --git a/tests/functional/adapter/dbt/test_hooks.py b/tests/functional/adapter/dbt/test_hooks.py index 24c44b418..5fe8c4342 100644 --- a/tests/functional/adapter/dbt/test_hooks.py +++ b/tests/functional/adapter/dbt/test_hooks.py @@ -129,12 +129,12 @@ def check_hooks(self, state, project, host, count=1): # assert ctx["target_user"] == "root" # assert ctx["target_pass"] == "" - assert ( - ctx["run_started_at"] is not None and len(ctx["run_started_at"]) > 0 - ), "run_started_at was not set" - assert ( - ctx["invocation_id"] is not None and len(ctx["invocation_id"]) > 0 - ), "invocation_id was not set" + assert ctx["run_started_at"] is not None and len(ctx["run_started_at"]) > 0, ( + "run_started_at was not set" + ) + assert ctx["invocation_id"] is not None and len(ctx["invocation_id"]) > 0, ( + "invocation_id was not set" + ) assert ctx["thread_id"].startswith("Thread-") @@ -196,7 +196,8 @@ def project_config_update(self): "models": { "test": { "hooked": { - "post-hook": [""" + "post-hook": [ + """ insert into {{this.schema}}.on_model_hook select test_state, '{{ target.dbname }}' as target_dbname, @@ -210,7 +211,8 @@ def project_config_update(self): '{{ run_started_at }}' as run_started_at, '{{ invocation_id }}' as invocation_id, '{{ thread_id }}' as thread_id - from {{ ref('post') }}""".strip()], + from {{ ref('post') }}""".strip() + ], } }, } diff --git a/tests/functional/adapter/dbt/test_simple_seed.py b/tests/functional/adapter/dbt/test_simple_seed.py index 54927b879..c239cfda2 100644 --- a/tests/functional/adapter/dbt/test_simple_seed.py +++ b/tests/functional/adapter/dbt/test_simple_seed.py @@ -163,10 +163,12 @@ def test_simple_seed_with_disabled(self, clear_test_schema, project): check_table_does_not_exist(project.adapter, "seed_disabled") check_table_does_exist(project.adapter, "seed_tricky") - @pytest.mark.skip(reason=""" + @pytest.mark.skip( + reason=""" Running all the tests in the same schema causes the tests to fail as they all share the same schema across the tests - """) + """ + ) def test_simple_seed_selection(self, clear_test_schema, project): results = run_dbt(["seed", "--select", "seed_enabled"]) assert len(results) == 1 @@ -174,10 +176,12 @@ def test_simple_seed_selection(self, clear_test_schema, project): check_table_does_not_exist(project.adapter, "seed_disabled") check_table_does_not_exist(project.adapter, "seed_tricky") - @pytest.mark.skip(reason=""" + @pytest.mark.skip( + reason=""" Running all the tests in the same schema causes the tests to fail as they all share the same schema across the tests - """) + """ + ) def test_simple_seed_exclude(self, clear_test_schema, project): results = run_dbt(["seed", "--exclude", "seed_enabled"]) assert len(results) == 1 @@ -204,10 +208,12 @@ def clear_test_schema(self, project): project.run_sql(f"drop view if exists {project.test_schema}.seed_tricky") project.run_sql(f"drop schema if exists {project.test_schema}") - @pytest.mark.skip(reason=""" + @pytest.mark.skip( + reason=""" Running all the tests in the same schema causes the tests to fail as they all share the same schema across the tests - """) + """ + ) def test_simple_seed_with_disabled(self, clear_test_schema, project): results = run_dbt(["seed"]) assert len(results) == 2 @@ -222,10 +228,12 @@ def test_simple_seed_selection(self, clear_test_schema, project): check_table_does_not_exist(project.adapter, "seed_disabled") check_table_does_not_exist(project.adapter, "seed_tricky") - @pytest.mark.skip(reason=""" + @pytest.mark.skip( + reason=""" Running all the tests in the same schema causes the tests to fail as they all share the same schema across the tests - """) + """ + ) def test_simple_seed_exclude(self, clear_test_schema, project): results = run_dbt(["seed", "--exclude", "seed_enabled"]) assert len(results) == 1 @@ -252,10 +260,12 @@ def clear_test_schema(self, project): project.run_sql(f"drop view if exists {project.test_schema}.seed_tricky") project.run_sql(f"drop schema if exists {project.test_schema}") - @pytest.mark.skip(reason=""" + @pytest.mark.skip( + reason=""" Running all the tests in the same schema causes the tests to fail as they all share the same schema across the tests - """) + """ + ) def test_simple_seed_with_disabled(self, clear_test_schema, project): results = run_dbt(["seed"]) assert len(results) == 2 @@ -263,10 +273,12 @@ def test_simple_seed_with_disabled(self, clear_test_schema, project): check_table_does_not_exist(project.adapter, "seed_disabled") check_table_does_exist(project.adapter, "seed_tricky") - @pytest.mark.skip(reason=""" + @pytest.mark.skip( + reason=""" Running all the tests in the same schema causes the tests to fail as they all share the same schema across the tests - """) + """ + ) def test_simple_seed_selection(self, clear_test_schema, project): results = run_dbt(["seed", "--select", "seed_enabled"]) assert len(results) == 1 diff --git a/tests/functional/adapter/dbt/test_utils.py b/tests/functional/adapter/dbt/test_utils.py index 6cd2ec926..120f30d9f 100644 --- a/tests/functional/adapter/dbt/test_utils.py +++ b/tests/functional/adapter/dbt/test_utils.py @@ -364,10 +364,12 @@ class TestStringLiteral(BaseStringLiteral): pass -@pytest.mark.skip(reason=""" +@pytest.mark.skip( + reason=""" comment here about why this is skipped. https://github.com/dbt-labs/dbt-adapters/blob/f1987d4313cc94bac9906963dff1337ee0bffbc6/dbt/include/global_project/macros/adapters/timestamps.sql#L39 - """) + """ +) class TestCurrentTimestamps(BaseCurrentTimestamps): pass diff --git a/tests/functional/adapter/mssql/test_index_config.py b/tests/functional/adapter/mssql/test_index_config.py index 1eadab761..348a223f4 100644 --- a/tests/functional/adapter/mssql/test_index_config.py +++ b/tests/functional/adapter/mssql/test_index_config.py @@ -55,7 +55,9 @@ ) """ -index_count = base_validation + """ +index_count = ( + base_validation + + """ select index_type + case when [unique] = 'Unique' then ' unique' else '' end as index_type, count(*) index_count @@ -65,8 +67,11 @@ schema_name='{schema_name}' group by index_type + case when [unique] = 'Unique' then ' unique' else '' end """ +) -indexes_def = base_validation + """ +indexes_def = ( + base_validation + + """ SELECT index_name, [columns], @@ -84,6 +89,7 @@ table_view='{schema_name}.{table_name}' """ +) # Altered from: https://github.com/dbt-labs/dbt-postgres @@ -898,7 +904,7 @@ def models(self): def test_clustered_collision_fails_with_clear_error(self, project, unique_schema): run_dbt(["run", "--models", "collision"]) project.run_sql( - f"CREATE CLUSTERED INDEX ix_dba_clustered " f"ON {unique_schema}.collision (column_a)" + f"CREATE CLUSTERED INDEX ix_dba_clustered ON {unique_schema}.collision (column_a)" ) _, output = run_dbt_and_capture( diff --git a/tests/functional/adapter/mssql/test_query_options.py b/tests/functional/adapter/mssql/test_query_options.py index b6b540bbb..6abfad0a6 100644 --- a/tests/functional/adapter/mssql/test_query_options.py +++ b/tests/functional/adapter/mssql/test_query_options.py @@ -432,7 +432,8 @@ class TestApplyLabelBackwardCompat: @pytest.fixture(scope="class") def macros(self): - return {"verify_apply_label.sql": """ + return { + "verify_apply_label.sql": """ {% macro verify_apply_label() %} {%- set result = apply_label() -%} {{ log("apply_label returned: " ~ result, info=True) }} @@ -443,7 +444,8 @@ def macros(self): {{ exceptions.raise_compiler_error("apply_label() must not emit query_options hints") }} {%- endif -%} {% endmacro %} -"""} +""" + } def test_apply_label_callable_and_label_only(self, project): # run-operation will fail (non-zero exit) if apply_label is undefined @@ -904,9 +906,9 @@ def test_options_render_on_both_dml_statements(self, project): logs, re.IGNORECASE, ) - assert ( - main_match is not None - ), "query_options missing from the 'main' SELECT INTO statement of the DML refresh" + assert main_match is not None, ( + "query_options missing from the 'main' SELECT INTO statement of the DML refresh" + ) # 'dml_refresh_swap' — INSERT ... SELECT ... FROM , must carry # the hint too. The INSERT...SELECT spans newlines but has no interior @@ -916,9 +918,9 @@ def test_options_render_on_both_dml_statements(self, project): logs, re.IGNORECASE, ) - assert ( - swap_match is not None - ), "query_options missing from the 'dml_refresh_swap' INSERT statement of the DML refresh" + assert swap_match is not None, ( + "query_options missing from the 'dml_refresh_swap' INSERT statement of the DML refresh" + ) def write_model(project, filename, contents): diff --git a/tests/functional/adapter/mssql/test_reserved_keywords_schema.py b/tests/functional/adapter/mssql/test_reserved_keywords_schema.py index ed944df6b..daa83a4cb 100644 --- a/tests/functional/adapter/mssql/test_reserved_keywords_schema.py +++ b/tests/functional/adapter/mssql/test_reserved_keywords_schema.py @@ -31,7 +31,8 @@ def project_config_update(self): @pytest.fixture(scope="class") def macros(self): - return {"generate_schema_name.sql": """ + return { + "generate_schema_name.sql": """ {% macro generate_schema_name(custom_schema_name, node) -%} {%- if custom_schema_name -%} {{ custom_schema_name | trim }} @@ -39,7 +40,8 @@ def macros(self): {{ target.schema }} {%- endif -%} {%- endmacro %} -"""} +""" + } @pytest.fixture(autouse=True, scope="class") def cleanup_schema(self, project): From f5372c6f5f6297539ba11e04da4993d8eb3b8652 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Mon, 27 Jul 2026 02:24:09 +0000 Subject: [PATCH 2/2] chore: ignore the ruff format reformat in git blame Adds the previous commit to .git-blame-ignore-revs so the cosmetic reformat does not shadow the real authors of those lines. Both git blame --ignore-revs-file and GitHub's blame view honour the file. --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 3170b0e2e..73e56a8ee 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,3 +3,5 @@ 4eff3237f2bf9d3d206c9234353fb07e70ac6013 # Updated README.md and blackified the code. 29bab50f0e7d9e09b9110500f6e41e1255d3f3f6 +# Replaced black with ruff format. +3d77e975c41bb6be2a13afd0df8cbb596d84fe9f