Skip to content

Commit

Permalink
Merge pull request #2045 from fishtown-analytics/feature/detect-dupli…
Browse files Browse the repository at this point in the history
…cate-macros

Detect duplicate macros (#1891)
  • Loading branch information
beckjake committed Jan 16, 2020
2 parents 01e97ff + d85a54a commit 1021637
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 3 deletions.
31 changes: 29 additions & 2 deletions core/dbt/parser/results.py
Expand Up @@ -12,8 +12,9 @@
from dbt.contracts.util import Writable, Replaceable
from dbt.exceptions import (
raise_duplicate_resource_name, raise_duplicate_patch_name,
CompilationException, InternalException
CompilationException, InternalException, raise_compiler_error
)
from dbt.ui import printer
from dbt.version import __version__


Expand Down Expand Up @@ -87,7 +88,33 @@ def add_disabled(self, source_file: SourceFile, node: ParsedNode):
self.get_file(source_file).nodes.append(node.unique_id)

def add_macro(self, source_file: SourceFile, macro: ParsedMacro):
# macros can be overwritten (should they be?)
if macro.unique_id in self.macros:
# detect that the macro exists and emit an error
other_path = self.macros[macro.unique_id].original_file_path
# subtract 2 for the "Compilation Error" indent
# note that the line wrap eats newlines, so if you want newlines,
# this is the result :(
msg = '\n'.join([
printer.line_wrap_message(
f'''\
dbt found two macros named "{macro.name}" in the project
"{macro.package_name}".
''',
subtract=2
),
'',
printer.line_wrap_message(
f'''\
To fix this error, rename or remove one of the following
macros:
''',
subtract=2
),
f' - {macro.original_file_path}',
f' - {other_path}'
])
raise_compiler_error(msg)

self.macros[macro.unique_id] = macro
self.get_file(source_file).macros.append(macro.unique_id)

Expand Down
10 changes: 9 additions & 1 deletion core/dbt/ui/printer.py
@@ -1,3 +1,5 @@
import textwrap
import time
from typing import Dict, Optional, Tuple

from dbt.logger import GLOBAL_LOGGER as logger, DbtStatusMessage, TextOnly
Expand All @@ -6,7 +8,6 @@
from dbt.utils import get_materialization
import dbt.ui.colors

import time

USE_COLORS = False

Expand Down Expand Up @@ -380,3 +381,10 @@ def print_run_end_messages(results, early_exit: bool = False) -> None:
print_run_result_error(warning, is_warning=True)

print_run_status_line(results)


def line_wrap_message(msg: str, subtract: int = 0, dedent: bool = True) -> str:
width = PRINTER_WIDTH - subtract
if dedent:
msg = textwrap.dedent(msg)
return textwrap.fill(msg, width=width)
@@ -0,0 +1,3 @@
{% macro some_overridden_macro() -%}
100
{%- endmacro %}
@@ -0,0 +1,4 @@
{# This macro also exists in the dependency -dbt should be fine with that #}
{% macro some_overridden_macro() -%}
999
{%- endmacro %}
@@ -0,0 +1,5 @@
{% macro some_macro() %}
{% endmacro %}

{% macro some_macro() %}
{% endmacro %}
@@ -0,0 +1,2 @@
{% macro some_macro() %}
{% endmacro %}
@@ -0,0 +1,2 @@
{% macro some_macro() %}
{% endmacro %}
52 changes: 52 additions & 0 deletions test/integration/025_duplicate_model_test/test_duplicate_macro.py
@@ -0,0 +1,52 @@
import os
from dbt.exceptions import CompilationException
from test.integration.base import DBTIntegrationTest, use_profile


class TestDuplicateMacroEnabledSameFile(DBTIntegrationTest):

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

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

@property
def project_config(self):
return {
'macro-paths': ['macros-bad-same']
}

@use_profile('postgres')
def test_postgres_duplicate_macros(self):
with self.assertRaises(CompilationException) as exc:
self.run_dbt(['compile'])
self.assertIn('some_macro', str(exc.exception))
self.assertIn(os.path.join('macros-bad-same', 'macros.sql'), str(exc.exception))


class TestDuplicateMacroEnabledDifferentFiles(DBTIntegrationTest):

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

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

@property
def project_config(self):
return {
'macro-paths': ['macros-bad-separate']
}

@use_profile('postgres')
def test_postgres_duplicate_macros(self):
with self.assertRaises(CompilationException) as exc:
self.run_dbt(['compile'])
self.assertIn('some_macro', str(exc.exception))
self.assertIn(os.path.join('macros-bad-separate', 'one.sql'), str(exc.exception))
self.assertIn(os.path.join('macros-bad-separate', 'two.sql'), str(exc.exception))

0 comments on commit 1021637

Please sign in to comment.