-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Begin warning people about spaces in model names (#9886)
* Add event type for deprecation of spaces in model names * Begin emitting deprecation warning for spaces in model names * Only warn on first model name with spaces unless `--debug` is specified For projects with a lot of models that have spaces in their names, the warning about this deprecation would be incredibly annoying. Now we instead only log the first model name issue and then a count of how many models have the issue, unless `--debug` is specified. * Refactor `EventCatcher` so that the event to catch is setable We want to be able to catch more than just `SpacesInModelNameDeprecation` events, and in the next commit we will alter our tests to do so. Thus instead of writing a new catcher for each event type, a slight modification to the existing `EventCatcher` makes this much easier. * Add project flag to control whether spaces are allowed in model names * Log errors and raise exception when `allow_spaces_in_model_names` is `False` * Use custom event for output invalid name counts instead of `Note` events Using `Note` events was causing test flakiness when run in a multi worker environment using `pytest -nauto`. This is because the event manager is currently a global. So in a situation where test `A` starts and test `tests_debug_when_spaces_in_name` starts shortly there after, the event manager for both tests will have the callbacks set in `tests_debug_when_spaces_in_name`. Then if something in test `A` fired a `Note` event, this would affect the count of `Note` events that `tests_debug_when_spaces_in_name` sees, causing assertion failures. By creating a custom event, `TotalModelNamesWithSpacesDeprecation`, we limit the possible flakiness to only tests that fire the custom event. Thus we didn't _eliminate_ all possibility of flakiness, but realistically only the tests in `test_check_for_spaces_in_model_names.py` can now interfere with each other. Which still isn't great, but to fully resolve the problem we need to work on how the event manager is handled (preferably not globally). * Always log total invalid model names if at least one Previously we only logged out the count of how many invalid model names there were if there was two or more invalid names (and not in debug mode). However this message is important if there is even one invalid model name and regardless of whether you are running debug mode. That is because automated tools might be looking for the event type to track if anything is wrong. A related change in this commit is that we now only output the debug hint if it wasn't run with debug mode. The idea being that if they are already running it in debug mode, the hint could come accross as somewhat patronizing. * Reduce duplicate `if` logic in `check_for_spaces_in_model_names` * Improve readability of logs related to problematic model names We want people running dbt to be able to at a glance see warnings/errors with running their project. In this case we are focused specifically on errors/warnings in regards to model names containing spaces. Previously we were only ever emitting the `warning_tag` in the message even if the event itself was being emitted at an `ERROR` level. We now properly have `[ERROR]` or `[WARNING]` in the message depending on the level. Unfortunately we couldn't just look what level the event was being fired at, because that information doesn't exist on the event itself. Additionally, we're using events that base off of `DynamicEvents` which unfortunately hard coded to `DEBUG`. Changing this would involve still having a `level` property on the definition in `core_types.proto` and then having `DynamicEvent`s look to `self.level` in the `level_tag` method. Then we could change how firing events works based on the an event's `level_tag` return value. This all sounds like a bit of tech debt suited for PR, possibly multiple, and thus is not being done here. * Alter `TotalModelNamesWithSpacesDeprecation` message to handle singular and plural * Remove duplicate import in `test_graph.py` introduced from merging in main --------- Co-authored-by: Emily Rockman <[email protected]>
- Loading branch information
Showing
9 changed files
with
820 additions
and
575 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
kind: Fixes | ||
body: Begin warning people about spaces in model names | ||
time: 2024-04-09T23:33:47.850166-07:00 | ||
custom: | ||
Author: QMalcolm | ||
Issue: "9397" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
tests/functional/manifest_validations/test_check_for_spaces_in_model_names.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import pytest | ||
|
||
from dataclasses import dataclass, field | ||
from dbt.cli.main import dbtRunner | ||
from dbt_common.events.base_types import BaseEvent, EventLevel, EventMsg | ||
from dbt.events.types import SpacesInModelNameDeprecation, TotalModelNamesWithSpacesDeprecation | ||
from dbt.tests.util import update_config_file | ||
from typing import Dict, List | ||
|
||
|
||
@dataclass | ||
class EventCatcher: | ||
event_to_catch: BaseEvent | ||
caught_events: List[EventMsg] = field(default_factory=list) | ||
|
||
def catch(self, event: EventMsg): | ||
if event.info.name == self.event_to_catch.__name__: | ||
self.caught_events.append(event) | ||
|
||
|
||
class TestSpacesInModelNamesHappyPath: | ||
def test_no_warnings_when_no_spaces_in_name(self, project) -> None: | ||
event_catcher = EventCatcher(SpacesInModelNameDeprecation) | ||
runner = dbtRunner(callbacks=[event_catcher.catch]) | ||
runner.invoke(["parse"]) | ||
assert len(event_catcher.caught_events) == 0 | ||
|
||
|
||
class TestSpacesInModelNamesSadPath: | ||
@pytest.fixture(scope="class") | ||
def models(self) -> Dict[str, str]: | ||
return { | ||
"my model.sql": "select 1 as id", | ||
} | ||
|
||
def tests_warning_when_spaces_in_name(self, project) -> None: | ||
event_catcher = EventCatcher(SpacesInModelNameDeprecation) | ||
total_catcher = EventCatcher(TotalModelNamesWithSpacesDeprecation) | ||
runner = dbtRunner(callbacks=[event_catcher.catch, total_catcher.catch]) | ||
runner.invoke(["parse"]) | ||
|
||
assert len(total_catcher.caught_events) == 1 | ||
assert len(event_catcher.caught_events) == 1 | ||
event = event_catcher.caught_events[0] | ||
assert "Model `my model` has spaces in its name. This is deprecated" in event.info.msg | ||
assert event.info.level == EventLevel.WARN | ||
|
||
|
||
class TestSpaceInModelNamesWithDebug: | ||
@pytest.fixture(scope="class") | ||
def models(self) -> Dict[str, str]: | ||
return { | ||
"my model.sql": "select 1 as id", | ||
"my model2.sql": "select 1 as id", | ||
} | ||
|
||
def tests_debug_when_spaces_in_name(self, project) -> None: | ||
spaces_check_catcher = EventCatcher(SpacesInModelNameDeprecation) | ||
total_catcher = EventCatcher(TotalModelNamesWithSpacesDeprecation) | ||
runner = dbtRunner(callbacks=[spaces_check_catcher.catch, total_catcher.catch]) | ||
runner.invoke(["parse"]) | ||
assert len(spaces_check_catcher.caught_events) == 1 | ||
assert len(total_catcher.caught_events) == 1 | ||
assert ( | ||
"Spaces in model names found in 2 model(s)" in total_catcher.caught_events[0].info.msg | ||
) | ||
assert ( | ||
"Run again with `--debug` to see them all." in total_catcher.caught_events[0].info.msg | ||
) | ||
|
||
spaces_check_catcher = EventCatcher(SpacesInModelNameDeprecation) | ||
total_catcher = EventCatcher(TotalModelNamesWithSpacesDeprecation) | ||
runner = dbtRunner(callbacks=[spaces_check_catcher.catch, total_catcher.catch]) | ||
runner.invoke(["parse", "--debug"]) | ||
assert len(spaces_check_catcher.caught_events) == 2 | ||
assert len(total_catcher.caught_events) == 1 | ||
assert ( | ||
"Run again with `--debug` to see them all." | ||
not in total_catcher.caught_events[0].info.msg | ||
) | ||
|
||
|
||
class TestAllowSpacesInModelNamesFalse: | ||
@pytest.fixture(scope="class") | ||
def models(self) -> Dict[str, str]: | ||
return { | ||
"my model.sql": "select 1 as id", | ||
} | ||
|
||
def test_dont_allow_spaces_in_model_names(self, project): | ||
spaces_check_catcher = EventCatcher(SpacesInModelNameDeprecation) | ||
runner = dbtRunner(callbacks=[spaces_check_catcher.catch]) | ||
runner.invoke(["parse"]) | ||
assert len(spaces_check_catcher.caught_events) == 1 | ||
assert spaces_check_catcher.caught_events[0].info.level == EventLevel.WARN | ||
|
||
config_patch = {"flags": {"allow_spaces_in_model_names": False}} | ||
update_config_file(config_patch, project.project_root, "dbt_project.yml") | ||
|
||
spaces_check_catcher = EventCatcher(SpacesInModelNameDeprecation) | ||
runner = dbtRunner(callbacks=[spaces_check_catcher.catch]) | ||
result = runner.invoke(["parse"]) | ||
assert not result.success | ||
assert "Model names cannot contain spaces" in result.exception.__str__() | ||
assert len(spaces_check_catcher.caught_events) == 1 | ||
assert spaces_check_catcher.caught_events[0].info.level == EventLevel.ERROR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters