Compare commits

...

6 Commits

Author SHA1 Message Date
Michelle Ark
8f1c7c5d6d pop external nodes from manifest after removing dependent project references 2023-08-24 20:13:41 -04:00
Michelle Ark
2215eb5112 Merge branch 'main' into build-manifest-parent-child-maps-parsing 2023-08-24 19:50:37 -04:00
Michelle Ark
437aee6862 Merge branch 'main' into build-manifest-parent-child-maps-parsing 2023-08-11 23:22:38 -04:00
Michelle Ark
bde1598dc9 changelog entry 2023-08-11 21:20:15 -04:00
Michelle Ark
fe2a6aa801 add functional tests 2023-08-11 21:16:31 -04:00
Michelle Ark
933b9ef3f7 build parent/child maps before injecting external nodes on partial parsing 2023-08-07 13:23:10 -04:00
3 changed files with 52 additions and 4 deletions

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: 'Fix: DbtInternalError after model that previously ref''d external model is
deleted'
time: 2023-08-11T21:20:08.145554-04:00
custom:
Author: michelleark
Issue: "8375"

View File

@@ -559,7 +559,7 @@ class ManifestLoader:
) )
# parent and child maps will be rebuilt by write_manifest # parent and child maps will be rebuilt by write_manifest
if not skip_parsing: if not skip_parsing or external_nodes_modified:
# write out the fully parsed manifest # write out the fully parsed manifest
self.write_manifest_for_partial_parse() self.write_manifest_for_partial_parse()
@@ -757,10 +757,13 @@ class ManifestLoader:
def inject_external_nodes(self) -> bool: def inject_external_nodes(self) -> bool:
# Remove previously existing external nodes since we are regenerating them # Remove previously existing external nodes since we are regenerating them
manifest_nodes_modified = False manifest_nodes_modified = False
# Remove all dependent nodes before removing referencing nodes
for unique_id in self.manifest.external_node_unique_ids: for unique_id in self.manifest.external_node_unique_ids:
self.manifest.nodes.pop(unique_id)
remove_dependent_project_references(self.manifest, unique_id) remove_dependent_project_references(self.manifest, unique_id)
manifest_nodes_modified = True manifest_nodes_modified = True
for unique_id in self.manifest.external_node_unique_ids:
# remove external nodes from manifest only after dependent project references safely removed
self.manifest.nodes.pop(unique_id)
# Inject any newly-available external nodes # Inject any newly-available external nodes
pm = plugins.get_plugin_manager(self.root_project.project_name) pm = plugins.get_plugin_manager(self.root_project.project_name)

View File

@@ -760,20 +760,45 @@ class TestExternalModels:
version=1, version=1,
) )
@pytest.fixture(scope="class")
def external_model_node_depends_on(self):
return ModelNodeArgs(
name="external_model_depends_on",
package_name="external",
identifier="test_identifier_depends_on",
schema="test_schema",
depends_on_nodes=["model.external.external_model_depends_on_parent"],
)
@pytest.fixture(scope="class")
def external_model_node_depends_on_parent(self):
return ModelNodeArgs(
name="external_model_depends_on_parent",
package_name="external",
identifier="test_identifier_depends_on_parent",
schema="test_schema",
)
@pytest.fixture(scope="class") @pytest.fixture(scope="class")
def models(self): def models(self):
return {"model_one.sql": model_one_sql} return {"model_one.sql": model_one_sql}
@mock.patch("dbt.plugins.get_plugin_manager") @mock.patch("dbt.plugins.get_plugin_manager")
def test_pp_external_models( def test_pp_external_models(
self, get_plugin_manager, project, external_model_node, external_model_node_versioned self,
get_plugin_manager,
project,
external_model_node,
external_model_node_versioned,
external_model_node_depends_on,
external_model_node_depends_on_parent,
): ):
# initial plugin - one external model # initial plugin - one external model
external_nodes = PluginNodes() external_nodes = PluginNodes()
external_nodes.add_model(external_model_node) external_nodes.add_model(external_model_node)
get_plugin_manager.return_value.get_nodes.return_value = external_nodes get_plugin_manager.return_value.get_nodes.return_value = external_nodes
# initial run # initial parse
manifest = run_dbt(["parse"]) manifest = run_dbt(["parse"])
assert len(manifest.nodes) == 2 assert len(manifest.nodes) == 2
assert set(manifest.nodes.keys()) == { assert set(manifest.nodes.keys()) == {
@@ -803,8 +828,21 @@ class TestExternalModels:
) )
manifest = run_dbt(["--partial-parse", "parse"]) manifest = run_dbt(["--partial-parse", "parse"])
assert len(manifest.nodes) == 5 assert len(manifest.nodes) == 5
assert len(manifest.external_node_unique_ids) == 2
# remove a model file that depends on external model # remove a model file that depends on external model
rm_file(project.project_root, "models", "model_depends_on_external.sql") rm_file(project.project_root, "models", "model_depends_on_external.sql")
manifest = run_dbt(["--partial-parse", "parse"]) manifest = run_dbt(["--partial-parse", "parse"])
assert len(manifest.nodes) == 4 assert len(manifest.nodes) == 4
# add an external node with depends on
external_nodes.add_model(external_model_node_depends_on)
external_nodes.add_model(external_model_node_depends_on_parent)
manifest = run_dbt(["--partial-parse", "parse"])
assert len(manifest.nodes) == 6
assert len(manifest.external_node_unique_ids) == 4
# skip files parsing - ensure no issues
run_dbt(["--partial-parse", "parse"])
assert len(manifest.nodes) == 6
assert len(manifest.external_node_unique_ids) == 4