Compare commits

...

3 Commits

Author SHA1 Message Date
Quigley Malcolm
d7c2e83253 Move resource names with spaces deprecation to using new deprecations manager 2025-04-01 09:24:45 -05:00
Quigley Malcolm
6d89d103f0 Add ability to show_summary of a ManagedDeprecationWarning 2025-03-31 15:48:34 -05:00
Quigley Malcolm
d6aeb313f5 Create new ManagedDeprecationWarning class
This class will do more heavy weight managing of deprecation warnings
2025-03-31 15:21:19 -05:00
7 changed files with 760 additions and 675 deletions

View File

@@ -1,14 +1,17 @@
import abc
from dataclasses import dataclass
from typing import Callable, ClassVar, Dict, List, Optional, Set
import dbt.tracking
from dbt.events import types as core_types
from dbt_common.events.functions import warn_or_error
from dbt_common.events.base_types import EventLevel
from dbt_common.events.functions import fire_event, warn_or_error
class DBTDeprecation:
_name: ClassVar[Optional[str]] = None
_event: ClassVar[Optional[str]] = None
_summary_event: ClassVar[Optional[str]] = None
@property
def name(self) -> str:
@@ -33,6 +36,21 @@ class DBTDeprecation:
raise NameError(msg)
raise NotImplementedError("event not implemented for {}".format(self._event))
@property
def summary_event(self) -> abc.ABCMeta:
if self._summary_event is not None:
module_path = core_types
class_name = self._summary_event
try:
return getattr(module_path, class_name)
except AttributeError:
msg = f"Event Class `{class_name}` is not defined in `{module_path}`"
raise NameError(msg)
else:
raise NotImplementedError(
"summary_event not implemented for {}".format(self._summary_event)
)
def show(self, *args, **kwargs) -> None:
if self.name not in active_deprecations:
event = self.event(**kwargs)
@@ -110,7 +128,8 @@ class PackageMaterializationOverrideDeprecation(DBTDeprecation):
class ResourceNamesWithSpacesDeprecation(DBTDeprecation):
_name = "resource-names-with-spaces"
_event = "ResourceNamesWithSpacesDeprecation"
_event = "SpacesInResourceNameDeprecation"
_summary_event = "ResourceNamesWithSpacesDeprecation"
class SourceFreshnessProjectHooksNotRun(DBTDeprecation):
@@ -198,3 +217,41 @@ def reset_deprecations():
def fire_buffered_deprecations():
[dep_fn() for dep_fn in buffered_deprecations]
buffered_deprecations.clear()
@dataclass
class ManagedDeprecationWarning:
deprecation_warning: DBTDeprecation
occurances: int = 0
only_show_once: bool = True
def show(self, fire_as_error: bool = False, *args, **kwargs) -> None:
# We don't use the `show` built into the DBTDeprecation class,
# because we want to handle gating whether the warning should is
# fired or not, and we want to track the number of times the warning
# has been shown.
if not self.only_show_once or self.occurances == 0:
event = self.deprecation_warning.event(*args, **kwargs)
# This is for maintaining current functionality wherein certain deprecations
# allow for force firing as an error outside of warn_or_error.
if fire_as_error:
fire_event(event, level=EventLevel.ERROR)
else:
warn_or_error(event)
self.deprecation_warning.track_deprecation_warn()
self.occurances += 1
def show_summary(self) -> None:
event = self.deprecation_warning.summary_event(
occurances=self.occurances,
show_debug_hint=(self.only_show_once),
)
warn_or_error(event)
if dbt.tracking.active_user is not None:
dbt.tracking.track_deprecation_warn_summary(
{"deprecation_name": self.deprecation_warning.name, "occurances": self.occurances}
)

View File

@@ -417,9 +417,10 @@ message SpacesInResourceNameDeprecationMsg {
// D015
message ResourceNamesWithSpacesDeprecation {
int32 count_invalid_names = 1;
int32 count_invalid_names = 1; // Field no longer used, but kept for backwards compatibility
bool show_debug_hint = 2;
string level = 3;
int32 occurances = 4;
}
message ResourceNamesWithSpacesDeprecationMsg {

File diff suppressed because one or more lines are too long

View File

@@ -436,7 +436,9 @@ class ResourceNamesWithSpacesDeprecation(WarnLevel):
return "D015"
def message(self) -> str:
description = f"Spaces found in {self.count_invalid_names} resource name(s). This is deprecated, and may lead to errors when using dbt."
# set the count_invalid_names field to the occurances field for
self.count_invalid_names = self.occurances
description = f"Spaces found in {self.occurances} resource name(s). This is deprecated, and may lead to errors when using dbt."
if self.show_debug_hint:
description += " Run again with `--debug` to see them all."

View File

@@ -64,6 +64,10 @@ from dbt.contracts.graph.nodes import (
SourceDefinition,
)
from dbt.contracts.graph.semantic_manifest import SemanticManifest
from dbt.deprecations import (
ManagedDeprecationWarning,
ResourceNamesWithSpacesDeprecation,
)
from dbt.events.types import (
ArtifactWritten,
DeprecatedModel,
@@ -78,7 +82,6 @@ from dbt.events.types import (
PartialParsingErrorProcessingFile,
PartialParsingNotEnabled,
PartialParsingSkipParsing,
SpacesInResourceNameDeprecation,
StateCheckVarsHash,
UnableToPartialParse,
UpcomingReferenceDeprecation,
@@ -618,7 +621,7 @@ class ManifestLoader:
)
)
def check_for_spaces_in_resource_names(self):
def check_for_spaces_in_resource_names(self) -> None:
"""Validates that resource names do not contain spaces
If `DEBUG` flag is `False`, logs only first bad model name
@@ -626,7 +629,6 @@ class ManifestLoader:
If `REQUIRE_RESOURCE_NAMES_WITHOUT_SPACES` is `True`, logs are `ERROR` level and an exception is raised if any names are bad
If `REQUIRE_RESOURCE_NAMES_WITHOUT_SPACES` is `False`, logs are `WARN` level
"""
improper_resource_names = 0
level = (
EventLevel.ERROR
if self.root_project.args.REQUIRE_RESOURCE_NAMES_WITHOUT_SPACES
@@ -634,26 +636,22 @@ class ManifestLoader:
)
flags = get_flags()
deprecation_manager = ManagedDeprecationWarning(
deprecation_warning=ResourceNamesWithSpacesDeprecation(),
only_show_once=(not flags.DEBUG),
)
for node in self.manifest.nodes.values():
if " " in node.name:
if improper_resource_names == 0 or flags.DEBUG:
fire_event(
SpacesInResourceNameDeprecation(
unique_id=node.unique_id,
level=level.value,
),
level=level,
)
improper_resource_names += 1
if improper_resource_names > 0:
if level == EventLevel.WARN:
dbt.deprecations.warn(
"resource-names-with-spaces",
count_invalid_names=improper_resource_names,
show_debug_hint=(not flags.DEBUG),
deprecation_manager.show(
fire_as_error=(level == EventLevel.ERROR),
unique_id=node.unique_id,
level=level.value,
)
if deprecation_manager.occurances > 0:
if level == EventLevel.WARN:
deprecation_manager.show_summary()
else: # ERROR level
raise DbtValidationError("Resource names cannot contain spaces")

View File

@@ -38,6 +38,7 @@ DBT_INVOCATION_ENV = "DBT_INVOCATION_ENV"
ADAPTER_INFO_SPEC = "iglu:com.dbt/adapter_info/jsonschema/1-0-1"
DEPRECATION_WARN_SPEC = "iglu:com.dbt/deprecation_warn/jsonschema/1-0-0"
DEPRECATION_WARN_SUMMARY_SPEC = "iglu:com.dbt/deprecation_warn_summary/jsonschema/1-0-0"
BEHAVIOR_CHANGE_WARN_SPEC = "iglu:com.dbt/behavior_change_warn/jsonschema/1-0-0"
EXPERIMENTAL_PARSER = "iglu:com.dbt/experimental_parser/jsonschema/1-0-0"
INVOCATION_ENV_SPEC = "iglu:com.dbt/invocation_env/jsonschema/1-0-0"
@@ -368,6 +369,24 @@ def track_deprecation_warn(options):
)
def track_deprecation_warn_summary(options):
assert (
active_user is not None
), "Cannot track deprecation warnings summary when active user is None"
context = [SelfDescribingJson(DEPRECATION_WARN_SUMMARY_SPEC, options)]
track(
active_user,
category="dbt",
action="deprecation_summary",
label=get_invocation_id(),
property_="warn",
context=context,
)
def track_behavior_change_warn(msg: EventMsg) -> None:
if msg.info.name != "BehaviorChangeEvent" or active_user is None:
return

View File

@@ -149,9 +149,7 @@ sample_values = [
core_types.TestsConfigDeprecation(deprecated_path="", exp_path=""),
core_types.ProjectFlagsMovedDeprecation(),
core_types.SpacesInResourceNameDeprecation(unique_id="", level=""),
core_types.ResourceNamesWithSpacesDeprecation(
count_invalid_names=1, show_debug_hint=True, level=""
),
core_types.ResourceNamesWithSpacesDeprecation(occurances=1, show_debug_hint=True, level=""),
core_types.PackageMaterializationOverrideDeprecation(
package_name="my_package", materialization_name="view"
),