diff --git a/core/dbt/graph/selector_methods.py b/core/dbt/graph/selector_methods.py index 936d0b3572b..1b029396028 100644 --- a/core/dbt/graph/selector_methods.py +++ b/core/dbt/graph/selector_methods.py @@ -234,7 +234,18 @@ def search( def _getattr_descend(obj: Any, attrs: List[str]) -> Any: value = obj for attr in attrs: - value = getattr(value, attr) + try: + value = getattr(value, attr) + except AttributeError: + # if it implements getitem (dict, list, ...), use that. On failure, + # raise an attribute error instead of the KeyError, TypeError, etc. + # that arbitrary getitem calls might raise + try: + value = value[attr] + except Exception as exc: + raise AttributeError( + f"'{type(value)}' object has no attribute '{attr}'" + ) from exc return value @@ -251,7 +262,7 @@ def search( self, included_nodes: Set[UniqueId], selector: str ) -> Iterator[UniqueId]: parts = self.arguments - # special case: if the user wanted to compoare test severity, + # special case: if the user wanted to compare test severity, # make the comparison case-insensitive if parts == ['severity']: selector = CaseInsensitive(selector) diff --git a/test/integration/047_dbt_ls_test/models/incremental.sql b/test/integration/047_dbt_ls_test/models/incremental.sql new file mode 100644 index 00000000000..2bb15542da9 --- /dev/null +++ b/test/integration/047_dbt_ls_test/models/incremental.sql @@ -0,0 +1,12 @@ +{{ + config( + materialized = "incremental", + incremental_strategy = "delete+insert", + ) +}} + +select * from {{ ref('seed') }} + +{% if is_incremental() %} + where a > (select max(a) from {{this}}) +{% endif %} diff --git a/test/integration/047_dbt_ls_test/test_ls.py b/test/integration/047_dbt_ls_test/test_ls.py index 00683001f59..62ca874103c 100644 --- a/test/integration/047_dbt_ls_test/test_ls.py +++ b/test/integration/047_dbt_ls_test/test_ls.py @@ -33,6 +33,10 @@ def project_config(self): }, } + def setUp(self): + super().setUp() + self.maxDiff = None + def run_dbt_ls(self, args=None, expect_pass=True): log_manager.stdout_console() full_args = ['ls'] @@ -123,8 +127,8 @@ def expect_analyses_output(self): def expect_model_output(self): expectations = { - 'name': ('ephemeral', 'inner', 'outer'), - 'selector': ('test.ephemeral', 'test.sub.inner', 'test.outer'), + 'name': ('ephemeral', 'incremental', 'inner', 'outer'), + 'selector': ('test.ephemeral', 'test.incremental', 'test.sub.inner', 'test.outer'), 'json': ( { 'name': 'ephemeral', @@ -146,6 +150,27 @@ def expect_model_output(self): 'alias': 'ephemeral', 'resource_type': 'model', }, + { + 'name': 'incremental', + 'package_name': 'test', + 'depends_on': {'nodes': ['seed.test.seed'], 'macros': ['macro.dbt.is_incremental']}, + 'tags': [], + 'config': { + 'enabled': True, + 'materialized': 'incremental', + 'post-hook': [], + 'tags': [], + 'pre-hook': [], + 'quoting': {}, + 'vars': {}, + 'column_types': {}, + 'persist_docs': {}, + 'full_refresh': None, + 'incremental_strategy': 'delete+insert', + }, + 'alias': 'incremental', + 'resource_type': 'model', + }, { 'name': 'inner', 'package_name': 'test', @@ -187,7 +212,7 @@ def expect_model_output(self): 'resource_type': 'model', }, ), - 'path': (self.dir('models/ephemeral.sql'), self.dir('models/sub/inner.sql'), self.dir('models/outer.sql')), + 'path': (self.dir('models/ephemeral.sql'), self.dir('models/incremental.sql'), self.dir('models/sub/inner.sql'), self.dir('models/outer.sql')), } self.expect_given_output(['--resource-type', 'model'], expectations) @@ -351,6 +376,7 @@ def expect_all_output(self): # sources are like models - (package.source_name.table_name) expected_default = { 'test.ephemeral', + 'test.incremental', 'test.snapshot.my_snapshot', 'test.sub.inner', 'test.outer', @@ -387,7 +413,13 @@ def expect_select(self): self.assertEqual(set(results), {'test.outer', 'test.sub.inner'}) results = self.run_dbt_ls(['--resource-type', 'model', '--exclude', 'inner']) - self.assertEqual(set(results), {'test.ephemeral', 'test.outer'}) + self.assertEqual(set(results), {'test.ephemeral', 'test.outer', 'test.incremental'}) + + results = self.run_dbt_ls(['--select', 'config.incremental_strategy:delete+insert']) + self.assertEqual(set(results), {'test.incremental'}) + + self.run_dbt_ls(['--select', 'config.incremental_strategy:insert_overwrite'], expect_pass=False) + @use_profile('postgres') def test_postgres_ls(self):