Skip to content

Commit

Permalink
fire proper event for inline query error (#7960)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChenyuLInx authored and jtcohen6 committed Jul 3, 2023
1 parent a935df9 commit 236681c
Show file tree
Hide file tree
Showing 9 changed files with 521 additions and 452 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Fixes-20230628-144125.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Fixes
body: Inline query emit proper error message
time: 2023-06-28T14:41:25.699046-07:00
custom:
Author: ChenyuLInx
Issue: "7940"
10 changes: 10 additions & 0 deletions core/dbt/events/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,16 @@ message UnsupportedConstraintMaterializationMsg {
UnsupportedConstraintMaterialization data = 2;
}

// I069
message ParseInlineNodeError{
NodeInfo node_info = 1;
string exc = 2;
}
message ParseInlineNodeErrorMsg {
EventInfo info = 1;
ParseInlineNodeError data = 2;
}

// M - Deps generation

// M001
Expand Down
8 changes: 8 additions & 0 deletions core/dbt/events/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,14 @@ def message(self) -> str:
return line_wrap_message(warning_tag(msg))


class ParseInlineNodeError(ErrorLevel):
def code(self):
return "I069"

def message(self) -> str:
return "Error while parsing node: " + self.node_info.node_name + "\n" + self.exc


# =======================================================
# M - Deps generation
# =======================================================
Expand Down
870 changes: 437 additions & 433 deletions core/dbt/events/types_pb2.py

Large diffs are not rendered by default.

38 changes: 28 additions & 10 deletions core/dbt/task/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
from dbt.contracts.results import RunStatus, RunResult
from dbt.events.base_types import EventLevel
from dbt.events.functions import fire_event
from dbt.events.types import CompiledNode, Note
from dbt.exceptions import DbtInternalError, DbtRuntimeError
from dbt.events.types import CompiledNode, Note, ParseInlineNodeError
from dbt.exceptions import (
CompilationError,
DbtInternalError,
DbtRuntimeError,
Exception as DbtException,
)

from dbt.graph import ResourceTypeSelector
from dbt.node_types import NodeType
from dbt.parser.manifest import write_manifest, process_node
Expand Down Expand Up @@ -129,14 +135,26 @@ def defer_to_manifest(self, adapter, selected_uids: AbstractSet[str]):

def _runtime_initialize(self):
if getattr(self.args, "inline", None):
block_parser = SqlBlockParser(
project=self.config, manifest=self.manifest, root_project=self.config
)
sql_node = block_parser.parse_remote(self.args.inline, "inline_query")
process_node(self.config, self.manifest, sql_node)
# keep track of the node added to the manifest
self._inline_node_id = sql_node.unique_id

try:
block_parser = SqlBlockParser(
project=self.config, manifest=self.manifest, root_project=self.config
)
sql_node = block_parser.parse_remote(self.args.inline, "inline_query")
process_node(self.config, self.manifest, sql_node)
# keep track of the node added to the manifest
self._inline_node_id = sql_node.unique_id
except CompilationError as exc:
fire_event(
ParseInlineNodeError(
exc=str(exc.msg),
node_info={
"node_path": "sql/inline_query",
"node_name": "inline_query",
"unique_id": "sqloperation.test.inline_query",
},
)
)
raise DbtException("Error parsing inline query")
super()._runtime_initialize()

def after_run(self, adapter, results):
Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ types-pytz
types-requests
types-setuptools
wheel
mocker
33 changes: 28 additions & 5 deletions tests/functional/compile/test_compile.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import pytest

from dbt.cli.main import dbtRunner
from dbt.exceptions import DbtRuntimeError, TargetNotFoundError
from dbt.tests.util import run_dbt, run_dbt_and_capture
from dbt.exceptions import DbtRuntimeError, Exception as DbtException
from dbt.tests.util import run_dbt, run_dbt_and_capture, read_file
from tests.functional.compile.fixtures import (
first_model_sql,
second_model_sql,
Expand Down Expand Up @@ -137,9 +137,7 @@ def test_select_pass_empty(self, project):
assert "Compiled node 'second_model' is:" in log_output

def test_inline_fail(self, project):
with pytest.raises(
TargetNotFoundError, match="depends on a node named 'third_model' which was not found"
):
with pytest.raises(DbtException, match="Error parsing inline query"):
run_dbt(["compile", "--inline", "select * from {{ ref('third_model') }}"])

def test_multiline_jinja(self, project):
Expand Down Expand Up @@ -174,3 +172,28 @@ def test_compile_inline_not_add_node(self, project):
populate_cache=False,
)
assert len(manifest.nodes) == 4

def test_compile_inline_syntax_error(self, project, mocker):
patched_fire_event = mocker.patch("dbt.task.compile.fire_event")
with pytest.raises(DbtException, match="Error parsing inline query"):
run_dbt(["compile", "--inline", "select * from {{ ref(1) }}"])
# Event for parsing error fired
patched_fire_event.assert_called_once()

def test_compile_inline_ref_node_not_exist(self, project, mocker):
patched_fire_event = mocker.patch("dbt.task.compile.fire_event")
with pytest.raises(DbtException, match="Error parsing inline query"):
run_dbt(["compile", "--inline", "select * from {{ ref('third_model') }}"])
# Event for parsing error fired
patched_fire_event.assert_called_once()

def test_graph_summary_output(self, project):
"""Ensure that the compile command generates a file named graph_summary.json
in the target directory, that the file contains valid json, and that the
json has the high level structure it should."""
dbtRunner().invoke(["compile"])
summary_path = pathlib.Path(project.project_root, "target/graph_summary.json")
with open(summary_path, "r") as summary_file:
summary = json.load(summary_file)
assert "_invocation_id" in summary
assert "linked" in summary
6 changes: 2 additions & 4 deletions tests/functional/show/test_show.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from dbt.exceptions import DbtRuntimeError
from dbt.exceptions import DbtRuntimeError, Exception as DbtException
from dbt.tests.util import run_dbt_and_capture, run_dbt
from tests.functional.show.fixtures import (
models__second_ephemeral_model,
Expand Down Expand Up @@ -73,9 +73,7 @@ def test_inline_pass(self, project):

def test_inline_fail(self, project):
run_dbt(["build"])
with pytest.raises(
DbtRuntimeError, match="depends on a node named 'third_model' which was not found"
):
with pytest.raises(DbtException, match="Error parsing inline query"):
run_dbt(["show", "--inline", "select * from {{ ref('third_model') }}"])

def test_ephemeral_model(self, project):
Expand Down
1 change: 1 addition & 0 deletions tests/unit/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ def test_event_codes(self):
ref_node_name="", ref_node_package="", ref_node_version="", ref_max_version=""
),
types.UnsupportedConstraintMaterialization(materialized=""),
types.ParseInlineNodeError(exc=""),
# M - Deps generation ======================
types.GitSparseCheckoutSubdirectory(subdir=""),
types.GitProgressCheckoutRevision(revision=""),
Expand Down

0 comments on commit 236681c

Please sign in to comment.