mirror of
https://github.com/dbt-labs/dbt-core
synced 2025-12-19 15:41:28 +00:00
Compare commits
2 Commits
test-sqlpa
...
er/excepti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad9aabca1d | ||
|
|
ea1304f8bb |
@@ -14,7 +14,7 @@ from dbt.exceptions import DbtProfileError
|
||||
from dbt.exceptions import DbtProjectError
|
||||
from dbt.exceptions import ValidationException
|
||||
from dbt.exceptions import RuntimeException
|
||||
from dbt.exceptions import validator_error_message
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.events.types import MissingProfileTarget
|
||||
from dbt.events.functions import fire_event
|
||||
from dbt.utils import coerce_dict_str
|
||||
|
||||
@@ -21,9 +21,9 @@ from dbt.clients.system import path_exists
|
||||
from dbt.clients.system import load_file_contents
|
||||
from dbt.clients.yaml_helper import load_yaml_text
|
||||
from dbt.contracts.connection import QueryComment
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.exceptions import DbtProjectError
|
||||
from dbt.exceptions import SemverException
|
||||
from dbt.exceptions import validator_error_message
|
||||
from dbt.exceptions import RuntimeException
|
||||
from dbt.graph import SelectionSpec
|
||||
from dbt.helper_types import NoValue
|
||||
|
||||
@@ -24,11 +24,11 @@ from dbt.contracts.graph.manifest import ManifestMetadata
|
||||
from dbt.contracts.project import Configuration, UserConfig
|
||||
from dbt.contracts.relation import ComponentName
|
||||
from dbt.dataclass_schema import ValidationError
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.exceptions import (
|
||||
DbtProjectError,
|
||||
RuntimeException,
|
||||
raise_compiler_error,
|
||||
validator_error_message,
|
||||
)
|
||||
from dbt.events.functions import warn_or_error
|
||||
from dbt.events.types import UnusedResourceConfigPath
|
||||
|
||||
@@ -31,7 +31,7 @@ class DBTDeprecation:
|
||||
except AttributeError:
|
||||
msg = f"Event Class `{class_name}` is not defined in `{module_path}`"
|
||||
raise NameError(msg)
|
||||
raise NotImplementedError("event not implemented for {}".format(self._event))
|
||||
raise NotImplementedError("event not implemented for {}".format(self))
|
||||
|
||||
def show(self, *args, **kwargs) -> None:
|
||||
if self.name not in active_deprecations:
|
||||
|
||||
237
core/dbt/deps/exceptions.py
Normal file
237
core/dbt/deps/exceptions.py
Normal file
@@ -0,0 +1,237 @@
|
||||
import abc
|
||||
import builtins
|
||||
from typing import ClassVar, NoReturn, Dict
|
||||
|
||||
import dbt.events
|
||||
from dbt.events.helpers import env_secrets, scrub_secrets
|
||||
|
||||
|
||||
# TODO: using this special case here to not break the rest of exceptions but this would normally
|
||||
# live centrally
|
||||
class Exception(builtins.Exception):
|
||||
CODE = -32000
|
||||
MESSAGE = "Server Error"
|
||||
_event: ClassVar[str] = "GeneralException"
|
||||
_category: str = "general exception"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.log()
|
||||
|
||||
def data(self) -> Dict[str, str]:
|
||||
# do not override
|
||||
constant_exception_data = {
|
||||
"type": self.__class__.__name__, # is this used outside logbook logs?
|
||||
"message": str(self),
|
||||
"event": self._event, # does not always match type
|
||||
"category": self._category,
|
||||
}
|
||||
# TODO: can't guarantee this is always serializable...
|
||||
return {**constant_exception_data, **vars(self)}
|
||||
|
||||
@property
|
||||
def event(self) -> abc.ABCMeta:
|
||||
if self._event is not None:
|
||||
module_path = dbt.events.types
|
||||
class_name = self._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)
|
||||
raise NotImplementedError("event not implemented for {}".format(self))
|
||||
|
||||
def log(self, *args, **kwargs) -> None:
|
||||
log_event = self.event(data=self.data(), **kwargs)
|
||||
dbt.events.functions.fire_event(log_event)
|
||||
|
||||
|
||||
class RuntimeException(RuntimeError, Exception):
|
||||
CODE = 10001
|
||||
MESSAGE = "Runtime error"
|
||||
|
||||
def __init__(self, msg, node=None):
|
||||
self.stack = []
|
||||
self.node = node
|
||||
self.message = scrub_secrets(msg, env_secrets())
|
||||
|
||||
def add_node(self, node=None):
|
||||
if node is not None and node is not self.node:
|
||||
if self.node is not None:
|
||||
self.stack.append(self.node)
|
||||
self.node = node
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "Runtime"
|
||||
|
||||
def node_to_string(self, node):
|
||||
if node is None:
|
||||
return "<Unknown>"
|
||||
if not hasattr(node, "name"):
|
||||
# we probably failed to parse a block, so we can't know the name
|
||||
return "{} ({})".format(node.resource_type, node.original_file_path)
|
||||
|
||||
if hasattr(node, "contents"):
|
||||
# handle FileBlocks. They aren't really nodes but we want to render
|
||||
# out the path we know at least. This indicates an error during
|
||||
# block parsing.
|
||||
return "{}".format(node.path.original_file_path)
|
||||
return "{} {} ({})".format(node.resource_type, node.name, node.original_file_path)
|
||||
|
||||
def process_stack(self):
|
||||
lines = []
|
||||
stack = self.stack + [self.node]
|
||||
first = True
|
||||
|
||||
if len(stack) > 1:
|
||||
lines.append("")
|
||||
|
||||
for item in stack:
|
||||
msg = "called by"
|
||||
|
||||
if first:
|
||||
msg = "in"
|
||||
first = False
|
||||
|
||||
lines.append("> {} {}".format(msg, self.node_to_string(item)))
|
||||
|
||||
return lines
|
||||
|
||||
def __str__(self, prefix="! "):
|
||||
node_string = ""
|
||||
|
||||
if self.node is not None:
|
||||
node_string = " in {}".format(self.node_to_string(self.node))
|
||||
|
||||
if hasattr(self.message, "split"):
|
||||
split_msg = self.message.split("\n")
|
||||
else:
|
||||
split_msg = str(self.message).split("\n")
|
||||
|
||||
lines = ["{}{}".format(self.type + " Error", node_string)] + split_msg
|
||||
|
||||
lines += self.process_stack()
|
||||
|
||||
return lines[0] + "\n" + "\n".join([" " + line for line in lines[1:]])
|
||||
|
||||
def data(self):
|
||||
result = Exception.data(self)
|
||||
if self.node is None:
|
||||
return result
|
||||
|
||||
result.update(
|
||||
{
|
||||
"raw_code": self.node.raw_code,
|
||||
# the node isn't always compiled, but if it is, include that!
|
||||
"compiled_code": getattr(self.node, "compiled_code", None),
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
# TODO: caused some circular imports. copied here. doesn't belong here.
|
||||
class CommandError(RuntimeException):
|
||||
def __init__(self, cwd, cmd, message="Error running command"):
|
||||
cmd_scrubbed = list(scrub_secrets(cmd_txt, env_secrets()) for cmd_txt in cmd)
|
||||
super().__init__(message)
|
||||
self.cwd = cwd
|
||||
self.cmd = cmd_scrubbed
|
||||
self.args = (cwd, cmd_scrubbed, message)
|
||||
|
||||
def __str__(self):
|
||||
if len(self.cmd) == 0:
|
||||
return "{}: No arguments given".format(self.message)
|
||||
return '{}: "{}"'.format(self.message, self.cmd[0])
|
||||
|
||||
|
||||
# Start actual deps exceptions
|
||||
|
||||
|
||||
class DependencyException(Exception):
|
||||
# this can happen due to raise_dependency_error and its callers
|
||||
CODE = 10006
|
||||
MESSAGE = "Dependency Error"
|
||||
_event: ClassVar[str] = "DependencyException"
|
||||
_category: str = "general deps"
|
||||
|
||||
def __init__(self, message):
|
||||
super().__init__()
|
||||
self.message = scrub_secrets(message, env_secrets())
|
||||
|
||||
|
||||
# TODO: explore where this should live
|
||||
class ExecutableError(CommandError):
|
||||
def __init__(self, cwd, cmd, message):
|
||||
super().__init__(cwd, cmd, message)
|
||||
|
||||
|
||||
class InternalException(DependencyException):
|
||||
_category: str = "internal"
|
||||
|
||||
|
||||
# This was using SemverException previously...
|
||||
class DependencyVersionException(DependencyException):
|
||||
_category: str = "version"
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
msg = "Version error for package {}: {}".format(self.name, self)
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
class MultipleDependencyVersionException(DependencyException):
|
||||
_category: str = "git"
|
||||
|
||||
def __init__(self, git, requested):
|
||||
self.git = git
|
||||
self.requested = requested
|
||||
msg = "git dependencies should contain exactly one version. " "{} contains: {}".format(
|
||||
self.git, requested
|
||||
)
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
class PackageNotFound(DependencyException):
|
||||
def __init__(self, package_name):
|
||||
self.package_name = package_name
|
||||
msg = f"Package {self.package_name} was not found in the package index"
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
class PackageVersionNotFound(DependencyException):
|
||||
_category: str = "config"
|
||||
|
||||
def __init__(self, package_name, version_range, available_versions, should_version_check):
|
||||
self.package_name = package_name
|
||||
self.version_range = str(version_range)
|
||||
self.available_versions = available_versions
|
||||
self.should_version_check = should_version_check
|
||||
msg = self.build_msg()
|
||||
super().__init__(msg)
|
||||
|
||||
def build_msg(self):
|
||||
base_msg = (
|
||||
"Could not find a matching compatible version for package {}\n"
|
||||
" Requested range: {}\n"
|
||||
" Compatible versions: {}\n"
|
||||
)
|
||||
addendum = (
|
||||
(
|
||||
"\n"
|
||||
" Not shown: package versions incompatible with installed version of dbt-core\n"
|
||||
" To include them, run 'dbt --no-version-check deps'"
|
||||
)
|
||||
if self.should_version_check
|
||||
else ""
|
||||
)
|
||||
return (
|
||||
base_msg.format(self.package_name, self.version_range, self.available_versions)
|
||||
+ addendum
|
||||
)
|
||||
|
||||
|
||||
# should these all become their own exceptions? They have to all share a category if not.
|
||||
def raise_dependency_error(msg) -> NoReturn:
|
||||
raise DependencyException(scrub_secrets(msg, env_secrets()))
|
||||
@@ -9,7 +9,7 @@ from dbt.contracts.project import (
|
||||
GitPackage,
|
||||
)
|
||||
from dbt.deps.base import PinnedPackage, UnpinnedPackage, get_downloads_path
|
||||
from dbt.exceptions import ExecutableError, raise_dependency_error
|
||||
from .exceptions import ExecutableError, MultipleDependencyVersionException
|
||||
from dbt.events.functions import fire_event, warn_or_error
|
||||
from dbt.events.types import EnsureGitInstalled, DepsUnpinned
|
||||
|
||||
@@ -143,10 +143,7 @@ class GitUnpinnedPackage(GitPackageMixin, UnpinnedPackage[GitPinnedPackage]):
|
||||
if len(requested) == 0:
|
||||
requested = {"HEAD"}
|
||||
elif len(requested) > 1:
|
||||
raise_dependency_error(
|
||||
"git dependencies should contain exactly one version. "
|
||||
"{} contains: {}".format(self.git, requested)
|
||||
)
|
||||
raise MultipleDependencyVersionException(git=self.git, requested=requested)
|
||||
|
||||
return GitPinnedPackage(
|
||||
git=self.git,
|
||||
|
||||
@@ -11,11 +11,13 @@ from dbt.contracts.project import (
|
||||
RegistryPackage,
|
||||
)
|
||||
from dbt.deps.base import PinnedPackage, UnpinnedPackage, get_downloads_path
|
||||
from dbt.exceptions import (
|
||||
package_version_not_found,
|
||||
VersionsNotCompatibleException,
|
||||
DependencyException,
|
||||
package_not_found,
|
||||
from dbt.deps.exceptions import (
|
||||
DependencyVersionException,
|
||||
)
|
||||
from dbt.exceptions import VersionsNotCompatibleException
|
||||
from .exceptions import (
|
||||
PackageVersionNotFound,
|
||||
PackageNotFound,
|
||||
)
|
||||
from dbt.utils import _connection_exception_retry as connection_exception_retry
|
||||
|
||||
@@ -99,7 +101,7 @@ class RegistryUnpinnedPackage(RegistryPackageMixin, UnpinnedPackage[RegistryPinn
|
||||
def _check_in_index(self):
|
||||
index = registry.index_cached()
|
||||
if self.package not in index:
|
||||
package_not_found(self.package)
|
||||
raise PackageNotFound(self.package)
|
||||
|
||||
@classmethod
|
||||
def from_contract(cls, contract: RegistryPackage) -> "RegistryUnpinnedPackage":
|
||||
@@ -124,8 +126,7 @@ class RegistryUnpinnedPackage(RegistryPackageMixin, UnpinnedPackage[RegistryPinn
|
||||
try:
|
||||
range_ = semver.reduce_versions(*self.versions)
|
||||
except VersionsNotCompatibleException as e:
|
||||
new_msg = "Version error for package {}: {}".format(self.name, e)
|
||||
raise DependencyException(new_msg) from e
|
||||
raise DependencyVersionException(self.name) from e
|
||||
|
||||
should_version_check = bool(flags.VERSION_CHECK)
|
||||
dbt_version = get_installed_version()
|
||||
@@ -146,7 +147,12 @@ class RegistryUnpinnedPackage(RegistryPackageMixin, UnpinnedPackage[RegistryPinn
|
||||
target = None
|
||||
if not target:
|
||||
# raise an exception if no installable target version is found
|
||||
package_version_not_found(self.package, range_, installable, should_version_check)
|
||||
raise PackageVersionNotFound(
|
||||
package_name=self.package,
|
||||
version_range=range_,
|
||||
available_versions=installable,
|
||||
should_version_check=should_version_check,
|
||||
)
|
||||
latest_compatible = installable[-1]
|
||||
return RegistryPinnedPackage(
|
||||
package=self.package, version=target, version_latest=latest_compatible
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, List, NoReturn, Union, Type, Iterator, Set
|
||||
|
||||
from dbt.exceptions import raise_dependency_error, InternalException
|
||||
from .exceptions import raise_dependency_error, InternalException
|
||||
|
||||
from dbt.config import Project, RuntimeConfig
|
||||
from dbt.config.renderer import DbtProjectYamlRenderer
|
||||
|
||||
@@ -1495,6 +1495,16 @@ class NoNodesForSelectionCriteria(betterproto.Message):
|
||||
spec_raw: str = betterproto.string_field(2)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DependencyException(betterproto.Message):
|
||||
"""M031"""
|
||||
|
||||
info: "EventInfo" = betterproto.message_field(1)
|
||||
data: Dict[str, str] = betterproto.map_field(
|
||||
3, betterproto.TYPE_STRING, betterproto.TYPE_STRING
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class RunningOperationCaughtError(betterproto.Message):
|
||||
"""Q001"""
|
||||
@@ -1827,6 +1837,13 @@ class FoundStats(betterproto.Message):
|
||||
stat_line: str = betterproto.string_field(2)
|
||||
|
||||
|
||||
@dataclass
|
||||
class GeneralException(betterproto.Message):
|
||||
"""X001"""
|
||||
|
||||
info: "EventInfo" = betterproto.message_field(1)
|
||||
|
||||
|
||||
@dataclass
|
||||
class MainKeyboardInterrupt(betterproto.Message):
|
||||
"""Z001"""
|
||||
|
||||
@@ -1136,6 +1136,12 @@ message NoNodesForSelectionCriteria {
|
||||
string spec_raw = 2;
|
||||
}
|
||||
|
||||
// M031
|
||||
message DependencyException {
|
||||
EventInfo info = 1;
|
||||
map<string, string> data = 3;
|
||||
}
|
||||
|
||||
// Q - Node execution
|
||||
|
||||
// Q001
|
||||
@@ -1416,6 +1422,14 @@ message FoundStats {
|
||||
string stat_line = 2;
|
||||
}
|
||||
|
||||
// X - Exceptions
|
||||
|
||||
//X001
|
||||
message GeneralException {
|
||||
EventInfo info = 1;
|
||||
}
|
||||
|
||||
|
||||
// Z - Misc
|
||||
|
||||
// Z001
|
||||
|
||||
@@ -18,6 +18,7 @@ from dbt.events.format import format_fancy_output_line, pluralize
|
||||
from dbt.events.proto_types import EventInfo, RunResultMsg, ListOfStrings # noqa
|
||||
from dbt.events.proto_types import NodeInfo, ReferenceKeyMsg # noqa
|
||||
from dbt.events import proto_types as pt
|
||||
from dbt.exception_messages import get_not_found_or_disabled_msg_2
|
||||
|
||||
from dbt.node_types import NodeType
|
||||
|
||||
@@ -40,6 +41,7 @@ from dbt.node_types import NodeType
|
||||
# | M | Deps generation |
|
||||
# | Q | Node execution |
|
||||
# | W | Node testing |
|
||||
# | X | Exceptions |
|
||||
# | Z | Misc |
|
||||
# | T | Test only |
|
||||
#
|
||||
@@ -1491,28 +1493,14 @@ class NodeNotFoundOrDisabled(WarnLevel, pt.NodeNotFoundOrDisabled):
|
||||
return "I060"
|
||||
|
||||
def message(self) -> str:
|
||||
# this is duplicated logic from exceptions.get_not_found_or_disabled_msg
|
||||
# when we convert exceptions to be stuctured maybe it can be combined?
|
||||
# convverting the bool to a string since None is also valid
|
||||
if self.disabled == "None":
|
||||
reason = "was not found or is disabled"
|
||||
elif self.disabled == "True":
|
||||
reason = "is disabled"
|
||||
else:
|
||||
reason = "was not found"
|
||||
|
||||
target_package_string = ""
|
||||
if self.target_package is not None:
|
||||
target_package_string = "in package '{}' ".format(self.target_package)
|
||||
|
||||
msg = "{} '{}' ({}) depends on a {} named '{}' {}which {}".format(
|
||||
self.resource_type_title,
|
||||
self.unique_id,
|
||||
self.original_file_path,
|
||||
self.target_kind,
|
||||
self.target_name,
|
||||
target_package_string,
|
||||
reason,
|
||||
msg = get_not_found_or_disabled_msg_2(
|
||||
original_file_path=self.original_file_path,
|
||||
unique_id=self.unique_id,
|
||||
resource_type_title=self.resource_type_title,
|
||||
target_name=self.target_name,
|
||||
target_kind=self.target_kind,
|
||||
target_package=self.target_package,
|
||||
disabled=self.disabled,
|
||||
)
|
||||
|
||||
return warning_tag(msg)
|
||||
@@ -1824,6 +1812,15 @@ class NoNodesForSelectionCriteria(WarnLevel, pt.NoNodesForSelectionCriteria):
|
||||
return f"The selection criterion '{self.spec_raw}' does not match any nodes"
|
||||
|
||||
|
||||
@dataclass
|
||||
class DependencyException(ErrorLevel, pt.DependencyException):
|
||||
def code(self):
|
||||
return "M031"
|
||||
|
||||
def message(self) -> str:
|
||||
return f"This is the custom message: {self.data.get('message')}"
|
||||
|
||||
|
||||
# =======================================================
|
||||
# Q - Node execution
|
||||
# =======================================================
|
||||
@@ -2298,6 +2295,20 @@ class FoundStats(InfoLevel, pt.FoundStats):
|
||||
return f"Found {self.stat_line}"
|
||||
|
||||
|
||||
# =======================================================
|
||||
# X - Exceptions
|
||||
# =======================================================
|
||||
|
||||
|
||||
@dataclass
|
||||
class GeneralException(ErrorLevel, pt.GeneralException):
|
||||
def code(self):
|
||||
return "X001"
|
||||
|
||||
def message(self) -> str:
|
||||
return "General Exception"
|
||||
|
||||
|
||||
# =======================================================
|
||||
# Z - Misc
|
||||
# =======================================================
|
||||
|
||||
75
core/dbt/exception_messages.py
Normal file
75
core/dbt/exception_messages.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import dbt.dataclass_schema
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def validator_error_message(exc):
|
||||
"""Given a dbt.dataclass_schema.ValidationError (which is basically a
|
||||
jsonschema.ValidationError), return the relevant parts as a string
|
||||
"""
|
||||
if not isinstance(exc, dbt.dataclass_schema.ValidationError):
|
||||
return str(exc)
|
||||
path = "[%s]" % "][".join(map(repr, exc.relative_path))
|
||||
return "at path {}: {}".format(path, exc.message)
|
||||
|
||||
|
||||
def get_not_found_or_disabled_msg(
|
||||
original_file_path,
|
||||
unique_id,
|
||||
resource_type_title,
|
||||
target_name: str,
|
||||
target_kind: str,
|
||||
target_package: Optional[str] = None,
|
||||
disabled: Optional[bool] = None,
|
||||
) -> str:
|
||||
if disabled is None:
|
||||
reason = "was not found or is disabled"
|
||||
elif disabled is True:
|
||||
reason = "is disabled"
|
||||
else:
|
||||
reason = "was not found"
|
||||
|
||||
target_package_string = ""
|
||||
if target_package is not None:
|
||||
target_package_string = "in package '{}' ".format(target_package)
|
||||
|
||||
return "{} '{}' ({}) depends on a {} named '{}' {}which {}".format(
|
||||
resource_type_title,
|
||||
unique_id,
|
||||
original_file_path,
|
||||
target_kind,
|
||||
target_name,
|
||||
target_package_string,
|
||||
reason,
|
||||
)
|
||||
|
||||
|
||||
# TODO: temp fix for mypy/proto sanity - combine later
|
||||
def get_not_found_or_disabled_msg_2(
|
||||
original_file_path,
|
||||
unique_id,
|
||||
resource_type_title,
|
||||
target_name: str,
|
||||
target_kind: str,
|
||||
disabled: str,
|
||||
target_package: Optional[str] = None,
|
||||
) -> str:
|
||||
if disabled == "None":
|
||||
reason = "was not found or is disabled"
|
||||
elif disabled == "True":
|
||||
reason = "is disabled"
|
||||
else:
|
||||
reason = "was not found"
|
||||
|
||||
target_package_string = ""
|
||||
if target_package is not None:
|
||||
target_package_string = "in package '{}' ".format(target_package)
|
||||
|
||||
return "{} '{}' ({}) depends on a {} named '{}' {}which {}".format(
|
||||
resource_type_title,
|
||||
unique_id,
|
||||
original_file_path,
|
||||
target_kind,
|
||||
target_name,
|
||||
target_package_string,
|
||||
reason,
|
||||
)
|
||||
@@ -1,24 +1,15 @@
|
||||
import builtins
|
||||
import functools
|
||||
from typing import NoReturn, Optional, Mapping, Any
|
||||
from typing import Any, Mapping, NoReturn, Optional
|
||||
|
||||
from dbt.events.helpers import env_secrets, scrub_secrets
|
||||
from dbt.events.types import JinjaLogWarning
|
||||
from dbt.exception_messages import get_not_found_or_disabled_msg
|
||||
from dbt.node_types import NodeType
|
||||
|
||||
import dbt.dataclass_schema
|
||||
|
||||
|
||||
def validator_error_message(exc):
|
||||
"""Given a dbt.dataclass_schema.ValidationError (which is basically a
|
||||
jsonschema.ValidationError), return the relevant parts as a string
|
||||
"""
|
||||
if not isinstance(exc, dbt.dataclass_schema.ValidationError):
|
||||
return str(exc)
|
||||
path = "[%s]" % "][".join(map(repr, exc.relative_path))
|
||||
return "at path {}: {}".format(path, exc.message)
|
||||
|
||||
|
||||
class Exception(builtins.Exception):
|
||||
CODE = -32000
|
||||
MESSAGE = "Server Error"
|
||||
@@ -309,12 +300,6 @@ class AliasException(ValidationException):
|
||||
pass
|
||||
|
||||
|
||||
class DependencyException(Exception):
|
||||
# this can happen due to raise_dependency_error and its callers
|
||||
CODE = 10006
|
||||
MESSAGE = "Dependency Error"
|
||||
|
||||
|
||||
class DbtConfigError(RuntimeException):
|
||||
CODE = 10007
|
||||
MESSAGE = "DBT Configuration Error"
|
||||
@@ -451,10 +436,6 @@ def raise_database_error(msg, node=None) -> NoReturn:
|
||||
raise DatabaseException(msg, node)
|
||||
|
||||
|
||||
def raise_dependency_error(msg) -> NoReturn:
|
||||
raise DependencyException(scrub_secrets(msg, env_secrets()))
|
||||
|
||||
|
||||
def raise_git_cloning_error(error: CommandResultError) -> NoReturn:
|
||||
error.cmd = scrub_secrets(str(error.cmd), env_secrets())
|
||||
raise error
|
||||
@@ -568,37 +549,6 @@ def doc_target_not_found(
|
||||
raise_compiler_error(msg, model)
|
||||
|
||||
|
||||
def get_not_found_or_disabled_msg(
|
||||
original_file_path,
|
||||
unique_id,
|
||||
resource_type_title,
|
||||
target_name: str,
|
||||
target_kind: str,
|
||||
target_package: Optional[str] = None,
|
||||
disabled: Optional[bool] = None,
|
||||
) -> str:
|
||||
if disabled is None:
|
||||
reason = "was not found or is disabled"
|
||||
elif disabled is True:
|
||||
reason = "is disabled"
|
||||
else:
|
||||
reason = "was not found"
|
||||
|
||||
target_package_string = ""
|
||||
if target_package is not None:
|
||||
target_package_string = "in package '{}' ".format(target_package)
|
||||
|
||||
return "{} '{}' ({}) depends on a {} named '{}' {}which {}".format(
|
||||
resource_type_title,
|
||||
unique_id,
|
||||
original_file_path,
|
||||
target_kind,
|
||||
target_name,
|
||||
target_package_string,
|
||||
reason,
|
||||
)
|
||||
|
||||
|
||||
def target_not_found(
|
||||
node,
|
||||
target_name: str,
|
||||
@@ -718,31 +668,6 @@ def relation_wrong_type(relation, expected_type, model=None):
|
||||
)
|
||||
|
||||
|
||||
def package_not_found(package_name):
|
||||
raise_dependency_error("Package {} was not found in the package index".format(package_name))
|
||||
|
||||
|
||||
def package_version_not_found(
|
||||
package_name, version_range, available_versions, should_version_check
|
||||
):
|
||||
base_msg = (
|
||||
"Could not find a matching compatible version for package {}\n"
|
||||
" Requested range: {}\n"
|
||||
" Compatible versions: {}\n"
|
||||
)
|
||||
addendum = (
|
||||
(
|
||||
"\n"
|
||||
" Not shown: package versions incompatible with installed version of dbt-core\n"
|
||||
" To include them, run 'dbt --no-version-check deps'"
|
||||
)
|
||||
if should_version_check
|
||||
else ""
|
||||
)
|
||||
msg = base_msg.format(package_name, version_range, available_versions) + addendum
|
||||
raise_dependency_error(msg)
|
||||
|
||||
|
||||
def invalid_materialization_argument(name, argument):
|
||||
raise_compiler_error(
|
||||
"materialization '{}' received unknown argument '{}'.".format(name, argument)
|
||||
@@ -1000,6 +925,9 @@ def warn(msg, node=None):
|
||||
return ""
|
||||
|
||||
|
||||
# TODO: importing here just to track things separately
|
||||
from dbt.deps.exceptions import raise_dependency_error # noqa
|
||||
|
||||
# Update this when a new function should be added to the
|
||||
# dbt context's `exceptions` key!
|
||||
CONTEXT_EXPORTS = {
|
||||
|
||||
@@ -18,7 +18,8 @@ from dbt.context.context_config import ContextConfig
|
||||
from dbt.contracts.graph.manifest import Manifest
|
||||
from dbt.contracts.graph.parsed import HasUniqueID, ManifestNodes
|
||||
from dbt.contracts.graph.unparsed import UnparsedNode, Docs
|
||||
from dbt.exceptions import ParsingException, validator_error_message, InternalException
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.exceptions import ParsingException, InternalException
|
||||
from dbt import hooks
|
||||
from dbt.node_types import NodeType, ModelLanguage
|
||||
from dbt.parser.search import FileBlock
|
||||
|
||||
@@ -978,7 +978,7 @@ def invalid_target_fail_unless_test(
|
||||
target_name=target_name,
|
||||
target_kind=target_kind,
|
||||
target_package=target_package if target_package else "",
|
||||
disabled=str(disabled),
|
||||
disabled="None" if disabled is None else str(disabled),
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
||||
@@ -29,7 +29,8 @@ from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
|
||||
# New for Python models :p
|
||||
import ast
|
||||
from dbt.dataclass_schema import ValidationError
|
||||
from dbt.exceptions import ParsingException, validator_error_message, UndefinedMacroException
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.exceptions import ParsingException, UndefinedMacroException
|
||||
|
||||
|
||||
dbt_function_key_words = set(["ref", "source", "config", "get"])
|
||||
|
||||
@@ -49,8 +49,8 @@ from dbt.contracts.graph.unparsed import (
|
||||
UnparsedMetric,
|
||||
UnparsedSourceDefinition,
|
||||
)
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.exceptions import (
|
||||
validator_error_message,
|
||||
JSONValidationException,
|
||||
raise_invalid_property_yml_version,
|
||||
ValidationException,
|
||||
|
||||
@@ -4,7 +4,8 @@ from typing import List
|
||||
from dbt.dataclass_schema import ValidationError
|
||||
|
||||
from dbt.contracts.graph.parsed import IntermediateSnapshotNode, ParsedSnapshotNode
|
||||
from dbt.exceptions import ParsingException, validator_error_message
|
||||
from dbt.exception_messages import validator_error_message
|
||||
from dbt.exceptions import ParsingException
|
||||
from dbt.node_types import NodeType
|
||||
from dbt.parser.base import SQLParser
|
||||
from dbt.parser.search import BlockContents, BlockSearcher, FileBlock
|
||||
|
||||
@@ -174,6 +174,7 @@ class ModelRunner(CompileRunner):
|
||||
return f"{self.node.language} {self.node.get_materialization()} model {self.get_node_representation()}"
|
||||
|
||||
def print_start_line(self):
|
||||
breakpoint()
|
||||
fire_event(
|
||||
LogStartLine(
|
||||
description=self.describe_node(),
|
||||
|
||||
@@ -4,7 +4,7 @@ import unittest
|
||||
from unittest import mock
|
||||
|
||||
import dbt.deps
|
||||
import dbt.exceptions
|
||||
import dbt.deps.exceptions
|
||||
from dbt.deps.git import GitUnpinnedPackage
|
||||
from dbt.deps.local import LocalUnpinnedPackage
|
||||
from dbt.deps.registry import RegistryUnpinnedPackage
|
||||
@@ -92,7 +92,7 @@ class TestGitPackage(unittest.TestCase):
|
||||
self.assertEqual(c.git, 'http://example.com')
|
||||
self.assertEqual(c.revisions, ['0.0.1', '0.0.2'])
|
||||
|
||||
with self.assertRaises(dbt.exceptions.DependencyException):
|
||||
with self.assertRaises(dbt.deps.exceptions.DependencyException):
|
||||
c.resolved()
|
||||
|
||||
def test_default_revision(self):
|
||||
@@ -223,7 +223,7 @@ class TestHubPackage(unittest.TestCase):
|
||||
package='dbt-labs-test/b',
|
||||
version='0.1.2'
|
||||
))
|
||||
with self.assertRaises(dbt.exceptions.DependencyException) as exc:
|
||||
with self.assertRaises(dbt.deps.exceptions.PackageNotFound) as exc:
|
||||
a.resolved()
|
||||
|
||||
msg = 'Package dbt-labs-test/b was not found in the package index'
|
||||
@@ -235,7 +235,7 @@ class TestHubPackage(unittest.TestCase):
|
||||
version='0.1.4'
|
||||
))
|
||||
|
||||
with self.assertRaises(dbt.exceptions.DependencyException) as exc:
|
||||
with self.assertRaises(dbt.deps.exceptions.PackageVersionNotFound) as exc:
|
||||
a.resolved()
|
||||
msg = (
|
||||
"Could not find a matching compatible version for package "
|
||||
@@ -257,7 +257,7 @@ class TestHubPackage(unittest.TestCase):
|
||||
b = RegistryUnpinnedPackage.from_contract(b_contract)
|
||||
c = a.incorporate(b)
|
||||
|
||||
with self.assertRaises(dbt.exceptions.DependencyException) as exc:
|
||||
with self.assertRaises(dbt.deps.exceptions.DependencyVersionException) as exc:
|
||||
c.resolved()
|
||||
msg = (
|
||||
"Version error for package dbt-labs-test/a: Could not "
|
||||
|
||||
@@ -80,8 +80,11 @@ class BaseAliasErrors:
|
||||
def test_alias_dupe_thorews_exeption(self, project):
|
||||
message = ".*identical database representation.*"
|
||||
with pytest.raises(Exception) as exc:
|
||||
assert message in exc
|
||||
# assert message in exc
|
||||
run_dbt(["run"])
|
||||
assert message in exc
|
||||
# breakpoint()
|
||||
# print("ab")
|
||||
|
||||
|
||||
class BaseSameAliasDifferentSchemas:
|
||||
|
||||
13
tests/unit/test_exceptions.py
Normal file
13
tests/unit/test_exceptions.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# flake8: noqa
|
||||
import pytest
|
||||
from dbt.exceptions import Exception
|
||||
|
||||
|
||||
|
||||
class TestBaseException:
|
||||
|
||||
def test_base_exception(self):
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
raise(Exception())
|
||||
breakpoint()
|
||||
print("hi")
|
||||
Reference in New Issue
Block a user