diff --git a/.changes/unreleased/Fixes-20230605-124425.yaml b/.changes/unreleased/Fixes-20230605-124425.yaml new file mode 100644 index 00000000000..09c23e3f296 --- /dev/null +++ b/.changes/unreleased/Fixes-20230605-124425.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: fix RuntimeError when removing project dependency from dependencies.yml +time: 2023-06-05T12:44:25.978022-04:00 +custom: + Author: michelleark + Issue: "7743" diff --git a/core/dbt/parser/manifest.py b/core/dbt/parser/manifest.py index ada54f575d8..b10cca55e45 100644 --- a/core/dbt/parser/manifest.py +++ b/core/dbt/parser/manifest.py @@ -785,14 +785,15 @@ def build_public_nodes(self) -> bool: for project in self.manifest.project_dependencies.projects: project_dependency_names.append(project.name) - # clean up previous publications that are no longer specified - # and save previous publications, for later removal of references - saved_manifest_publications: MutableMapping[str, PublicationConfig] = {} + # Save previous publications, for later removal of references + saved_manifest_publications: MutableMapping[str, PublicationConfig] = deepcopy( + self.manifest.publications + ) if self.manifest.publications: for project_name, publication in self.manifest.publications.items(): if project_name not in project_dependency_names: remove_dependent_project_references(self.manifest, publication) - self.manifest.publications.pop(project_name) + saved_manifest_publications.pop(project_name) fire_event( PublicationArtifactChanged( action="removed", @@ -803,7 +804,8 @@ def build_public_nodes(self) -> bool: ) ) public_nodes_changed = True - saved_manifest_publications = self.manifest.publications + + # clean up previous publications that are no longer specified self.manifest.publications = {} # Empty public_nodes since we're re-generating them all self.manifest.public_nodes = {} diff --git a/tests/functional/partial_parsing/fixtures.py b/tests/functional/partial_parsing/fixtures.py index 74cef0bff00..fe68d55be36 100644 --- a/tests/functional/partial_parsing/fixtures.py +++ b/tests/functional/partial_parsing/fixtures.py @@ -1234,8 +1234,61 @@ """ -public_models_schema_yml = """ +dependencies_yml = """ +projects: + - name: marketing +""" + +empty_dependencies_yml = """ +projects: [] +""" + +marketing_pub_json = """ +{ + "project_name": "marketing", + "metadata": { + "dbt_schema_version": "https://schemas.getdbt.com/dbt/publication/v1.json", + "dbt_version": "1.5.0", + "generated_at": "2023-04-13T17:17:58.128706Z", + "invocation_id": "56e3126f-78c7-470c-8eb0-c94af7c3eaac", + "env": {}, + "adapter_type": "postgres", + "quoting": { + "database": true, + "schema": true, + "identifier": true + } + }, + "public_models": { + "model.marketing.fct_one": { + "name": "fct_one", + "package_name": "marketing", + "unique_id": "model.marketing.fct_one", + "relation_name": "\\"dbt\\".\\"test_schema\\".\\"fct_one\\"", + "database": "dbt", + "schema": "test_schema", + "identifier": "fct_one", + "version": null, + "latest_version": null, + "public_node_dependencies": [], + "generated_at": "2023-04-13T17:17:58.128706Z" + }, + "model.marketing.fct_two": { + "name": "fct_two", + "package_name": "marketing", + "unique_id": "model.marketing.fct_two", + "relation_name": "\\"dbt\\".\\"test_schema\\".\\"fct_two\\"", + "version": null, + "latest_version": null, + "public_node_dependencies": ["model.test.fct_one"], + "generated_at": "2023-04-13T17:17:58.128706Z" + } + }, + "dependencies": [] +} +""" +public_models_schema_yml = """ models: - name: orders access: public diff --git a/tests/functional/partial_parsing/test_partial_parsing.py b/tests/functional/partial_parsing/test_partial_parsing.py index 941d9ff1aa9..6d7532edee5 100644 --- a/tests/functional/partial_parsing/test_partial_parsing.py +++ b/tests/functional/partial_parsing/test_partial_parsing.py @@ -69,12 +69,18 @@ groups_schema_yml_one_group_model_in_group2, groups_schema_yml_two_groups_private_orders_valid_access, groups_schema_yml_two_groups_private_orders_invalid_access, + dependencies_yml, + empty_dependencies_yml, + marketing_pub_json, public_models_schema_yml, ) from dbt.exceptions import CompilationError, ParsingError, DuplicateVersionedUnversionedError from dbt.contracts.files import ParseFileType from dbt.contracts.results import TestStatus +from dbt.contracts.publication import PublicationArtifact + +import json import re import os @@ -807,6 +813,27 @@ def test_pp_groups(self, project): results = run_dbt(["--partial-parse", "run"]) +class TestDependencies: + @pytest.fixture(scope="class") + def models(self): + return {"orders.sql": orders_sql} + + @pytest.fixture(scope="class") + def marketing_publication(self): + return PublicationArtifact.from_dict(json.loads(marketing_pub_json)) + + def test_dependencies(self, project, marketing_publication): + # initial run with dependencies + write_file(dependencies_yml, "dependencies.yml") + manifest = run_dbt(["parse"], publications=[marketing_publication]) + assert len(manifest.project_dependencies.projects) == 1 + + # remove dependencies + write_file(empty_dependencies_yml, "dependencies.yml") + manifest = run_dbt(["parse"], publications=[marketing_publication]) + assert len(manifest.project_dependencies.projects) == 0 + + class TestPublicationArtifactAvailable: @pytest.fixture(scope="class") def models(self):