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 import abc
from dataclasses import dataclass
from typing import Callable, ClassVar, Dict, List, Optional, Set from typing import Callable, ClassVar, Dict, List, Optional, Set
import dbt.tracking import dbt.tracking
from dbt.events import types as core_types 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: class DBTDeprecation:
_name: ClassVar[Optional[str]] = None _name: ClassVar[Optional[str]] = None
_event: ClassVar[Optional[str]] = None _event: ClassVar[Optional[str]] = None
_summary_event: ClassVar[Optional[str]] = None
@property @property
def name(self) -> str: def name(self) -> str:
@@ -33,6 +36,21 @@ class DBTDeprecation:
raise NameError(msg) raise NameError(msg)
raise NotImplementedError("event not implemented for {}".format(self._event)) 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: def show(self, *args, **kwargs) -> None:
if self.name not in active_deprecations: if self.name not in active_deprecations:
event = self.event(**kwargs) event = self.event(**kwargs)
@@ -110,7 +128,8 @@ class PackageMaterializationOverrideDeprecation(DBTDeprecation):
class ResourceNamesWithSpacesDeprecation(DBTDeprecation): class ResourceNamesWithSpacesDeprecation(DBTDeprecation):
_name = "resource-names-with-spaces" _name = "resource-names-with-spaces"
_event = "ResourceNamesWithSpacesDeprecation" _event = "SpacesInResourceNameDeprecation"
_summary_event = "ResourceNamesWithSpacesDeprecation"
class SourceFreshnessProjectHooksNotRun(DBTDeprecation): class SourceFreshnessProjectHooksNotRun(DBTDeprecation):
@@ -198,3 +217,41 @@ def reset_deprecations():
def fire_buffered_deprecations(): def fire_buffered_deprecations():
[dep_fn() for dep_fn in buffered_deprecations] [dep_fn() for dep_fn in buffered_deprecations]
buffered_deprecations.clear() 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 // D015
message ResourceNamesWithSpacesDeprecation { 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; bool show_debug_hint = 2;
string level = 3; string level = 3;
int32 occurances = 4;
} }
message ResourceNamesWithSpacesDeprecationMsg { message ResourceNamesWithSpacesDeprecationMsg {

File diff suppressed because one or more lines are too long

View File

@@ -436,7 +436,9 @@ class ResourceNamesWithSpacesDeprecation(WarnLevel):
return "D015" return "D015"
def message(self) -> str: 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: if self.show_debug_hint:
description += " Run again with `--debug` to see them all." description += " Run again with `--debug` to see them all."

View File

@@ -64,6 +64,10 @@ from dbt.contracts.graph.nodes import (
SourceDefinition, SourceDefinition,
) )
from dbt.contracts.graph.semantic_manifest import SemanticManifest from dbt.contracts.graph.semantic_manifest import SemanticManifest
from dbt.deprecations import (
ManagedDeprecationWarning,
ResourceNamesWithSpacesDeprecation,
)
from dbt.events.types import ( from dbt.events.types import (
ArtifactWritten, ArtifactWritten,
DeprecatedModel, DeprecatedModel,
@@ -78,7 +82,6 @@ from dbt.events.types import (
PartialParsingErrorProcessingFile, PartialParsingErrorProcessingFile,
PartialParsingNotEnabled, PartialParsingNotEnabled,
PartialParsingSkipParsing, PartialParsingSkipParsing,
SpacesInResourceNameDeprecation,
StateCheckVarsHash, StateCheckVarsHash,
UnableToPartialParse, UnableToPartialParse,
UpcomingReferenceDeprecation, 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 """Validates that resource names do not contain spaces
If `DEBUG` flag is `False`, logs only first bad model name 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 `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 If `REQUIRE_RESOURCE_NAMES_WITHOUT_SPACES` is `False`, logs are `WARN` level
""" """
improper_resource_names = 0
level = ( level = (
EventLevel.ERROR EventLevel.ERROR
if self.root_project.args.REQUIRE_RESOURCE_NAMES_WITHOUT_SPACES if self.root_project.args.REQUIRE_RESOURCE_NAMES_WITHOUT_SPACES
@@ -634,26 +636,22 @@ class ManifestLoader:
) )
flags = get_flags() flags = get_flags()
deprecation_manager = ManagedDeprecationWarning(
deprecation_warning=ResourceNamesWithSpacesDeprecation(),
only_show_once=(not flags.DEBUG),
)
for node in self.manifest.nodes.values(): for node in self.manifest.nodes.values():
if " " in node.name: if " " in node.name:
if improper_resource_names == 0 or flags.DEBUG: deprecation_manager.show(
fire_event( fire_as_error=(level == EventLevel.ERROR),
SpacesInResourceNameDeprecation( unique_id=node.unique_id,
unique_id=node.unique_id, level=level.value,
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),
) )
if deprecation_manager.occurances > 0:
if level == EventLevel.WARN:
deprecation_manager.show_summary()
else: # ERROR level else: # ERROR level
raise DbtValidationError("Resource names cannot contain spaces") 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" 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_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" 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" EXPERIMENTAL_PARSER = "iglu:com.dbt/experimental_parser/jsonschema/1-0-0"
INVOCATION_ENV_SPEC = "iglu:com.dbt/invocation_env/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: def track_behavior_change_warn(msg: EventMsg) -> None:
if msg.info.name != "BehaviorChangeEvent" or active_user is None: if msg.info.name != "BehaviorChangeEvent" or active_user is None:
return return

View File

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