Skip to content

Commit

Permalink
[#4013] Fix multiple disabled models
Browse files Browse the repository at this point in the history
  • Loading branch information
gshank committed Oct 6, 2021
1 parent b501f43 commit e37dfb1
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Add generic tests defined on sources to the manifest once, not twice ([#3347](https://github.com/dbt-labs/dbt/issues/3347), [#3880](https://github.com/dbt-labs/dbt/pull/3880))
- Skip partial parsing if certain macros have changed ([#3810](https://github.com/dbt-labs/dbt/issues/3810), [#3982](https://github.com/dbt-labs/dbt/pull/3892))
- Enable cataloging of unlogged Postgres tables ([3961](https://github.com/dbt-labs/dbt/issues/3961), [#3993](https://github.com/dbt-labs/dbt/pull/3993))
- Fix multiple disabled nodes ([#4013](https://github.com/dbt-labs/dbt/issues/4013), [#4018](https://github.com/dbt-labs/dbt/pull/4018))

### Under the hood

Expand Down
27 changes: 14 additions & 13 deletions core/dbt/contracts/graph/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ def search_name(self) -> str:


@dataclass
class NameSearcher(Generic[N]):
class DisabledNameSearcher():
name: str
package: Optional[str]
nodetypes: List[NodeType]
Expand All @@ -404,9 +404,10 @@ def _matches(self, model: N) -> bool:

def search(self, haystack) -> Optional[N]:
"""Find an entry in the given iterable by name."""
for model in haystack.values():
if self._matches(model):
return model
for model_list in haystack.values():
for model in model_list:
if self._matches(model):
return model
return None


Expand Down Expand Up @@ -563,10 +564,8 @@ class Manifest(MacroMethods, DataClassMessagePackMixin, dbtClassMixin):
metadata: ManifestMetadata = field(default_factory=ManifestMetadata)
flat_graph: Dict[str, Any] = field(default_factory=dict)
state_check: ManifestStateCheck = field(default_factory=ManifestStateCheck)
# Moved from the ParseResult object
source_patches: MutableMapping[SourceKey, SourcePatch] = field(default_factory=dict)
# following is from ParseResult
disabled: MutableMapping[str, CompileResultNode] = field(default_factory=dict)
disabled: MutableMapping[str, List[CompileResultNode]] = field(default_factory=dict)

_doc_lookup: Optional[DocLookup] = field(
default=None, metadata={'serialize': lambda x: None, 'deserialize': lambda x: None}
Expand Down Expand Up @@ -653,7 +652,7 @@ def build_flat_graph(self):
def find_disabled_by_name(
self, name: str, package: Optional[str] = None
) -> Optional[ManifestNode]:
searcher: NameSearcher = NameSearcher(
searcher: DisabledNameSearcher = DisabledNameSearcher(
name, package, NodeType.refable()
)
result = searcher.search(self.disabled)
Expand All @@ -663,7 +662,7 @@ def find_disabled_source_by_name(
self, source_name: str, table_name: str, package: Optional[str] = None
) -> Optional[ParsedSourceDefinition]:
search_name = f'{source_name}.{table_name}'
searcher: NameSearcher = NameSearcher(
searcher: DisabledNameSearcher = DisabledNameSearcher(
search_name, package, [NodeType.Source]
)
result = searcher.search(self.disabled)
Expand Down Expand Up @@ -1008,8 +1007,10 @@ def add_exposure(self, source_file: SchemaSourceFile, exposure: ParsedExposure):

def add_disabled_nofile(self, node: CompileResultNode):
# a disabled node should only show up once
_check_duplicates(node, self.disabled)
self.disabled[node.unique_id] = node
if node.unique_id in self.disabled:
self.disabled[node.unique_id].append(node)
else:
self.disabled[node.unique_id] = [node]

def add_disabled(self, source_file: AnySourceFile, node: CompileResultNode, test_from=None):
self.add_disabled_nofile(node)
Expand Down Expand Up @@ -1099,8 +1100,8 @@ class WritableManifest(ArtifactMixin):
'The selectors defined in selectors.yml'
))
)
disabled: Optional[Mapping[UniqueID, CompileResultNode]] = field(metadata=dict(
description='A list of the disabled nodes in the target'
disabled: Optional[Mapping[UniqueID, List[CompileResultNode]]] = field(metadata=dict(
description='A mapping of the disabled nodes in the target'
))
parent_map: Optional[NodeEdgeMap] = field(metadata=dict(
description='A mapping from child nodes to their dependencies',
Expand Down
3 changes: 2 additions & 1 deletion core/dbt/parser/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import (
Dict, Optional, Mapping, Callable, Any, List, Type, Union, Tuple
)
from itertools import chain
import time

import dbt.exceptions
Expand Down Expand Up @@ -893,7 +894,7 @@ def _warn_for_unused_resource_config_paths(
manifest: Manifest, config: RuntimeConfig
) -> None:
resource_fqns: Mapping[str, PathSet] = manifest.get_resource_fqns()
disabled_fqns: PathSet = frozenset(tuple(n.fqn) for n in manifest.disabled.values())
disabled_fqns: PathSet = frozenset(tuple(n.fqn) for n in list(chain.from_iterable(manifest.disabled.values())))
config.warn_for_unused_resource_config_paths(resource_fqns, disabled_fqns)


Expand Down
16 changes: 14 additions & 2 deletions core/dbt/parser/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,8 +827,20 @@ def parse_patch(
f'file {source_file.path.original_file_path}'
)
if unique_id is None:
# This will usually happen when a node is disabled
return
# Node might be disabled. Following call returns first matching node encountered.
found_node = self.manifest.find_disabled_by_name(patch.package_name, patch.name)
if found_node:
# There might be multiple disabled nodes for this model
for node in self.manifest.disabled[found_node.unique_id]:
# We're saving the patch_path because we need to schedule
# re-application of the patch in partial parsing.
# We could also actually apply the patch to all of the
# disabled nodes, but we haven't patched disabled nodes
# in the past.
node.patch_path = source_file.file_id
else:
# Should we issue a warning message here?
return

# patches can't be overwritten
node = self.manifest.nodes.get(unique_id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
select 100 as somevalue
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{
config(enabled = False)
}}
select 100 as altvalue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{
config(enabled = False)
}}

select 100 as thirdvalue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dbt.exceptions import CompilationException
from test.integration.base import DBTIntegrationTest, use_profile
from test.integration.base import DBTIntegrationTest, use_profile, get_manifest


class TestDuplicateModelEnabled(DBTIntegrationTest):
Expand Down Expand Up @@ -150,3 +150,21 @@ def test_postgres_duplicate_test_model_paths(self):
self.run_dbt(['compile'])
self.run_dbt(['--partial-parse', 'compile'])
self.run_dbt(['--partial-parse', 'compile'])


class TestMultipleDisabledModels(DBTIntegrationTest):

@property
def schema(self):
return "duplicate_model_025"

@property
def models(self):
return "models-5"

@use_profile('postgres')
def test_postgres_multiple_disabled_models(self):
self.run_dbt(['run'])
manifest = get_manifest()
model_id = 'model.test.model_alt'
self.assertIn(model_id, manifest.nodes)

0 comments on commit e37dfb1

Please sign in to comment.