# Buggy code
def create_macro_capture_env(node):
    class ParserMacroCapture(jinja2.Undefined):
        """
        This class sets up the parser to capture macros.
        """

        def __init__(self, hint=None, obj=None, name=None, exc=None):
            super(jinja2.Undefined, self).__init__()

            self.node = node
            self.name = name
            self.package_name = node.get("package_name")

        def __getattr__(self, name):
            # jinja uses these for safety, so we have to override them.
            # see https://github.com/pallets/jinja/blob/master/jinja2/sandbox.py#L332-L339 # noqa
            if name in ["unsafe_callable", "alters_data"]:
                return False

            self.package_name = self.name
            self.name = name

            return self

        def __call__(self, *args, **kwargs):
            return True

    return ParserMacroCapture


# Traceback (RecursionError)
(MainThread): maximum recursion depth exceeded in comparison
2018-10-22 16:36:31,926 (MainThread): Traceback (most recent call last):
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/main.py", line 72, in main
results, succeeded = handle_and_check(args)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/main.py", line 117, in handle_and_check
task, res = run_from_args(parsed)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/main.py", line 172, in run_from_args
results = run_from_task(task, proj, parsed)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/main.py", line 180, in run_from_task
result = task.run()
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/task/run.py", line 26, in run
results = runner.run(query, ModelRunner)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/runner.py", line 244, in run
return self.run_from_graph(Selector, Runner, query)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/runner.py", line 197, in run_from_graph
manifest, linker = self.compile(self.project)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/runner.py", line 186, in compile
return compiler.compile()
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/compilation.py", line 241, in compile
manifest = dbt.loader.GraphLoader.load_all(self.project, all_projects)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/loader.py", line 21, in load_all
nodes.update(loader.load_all(root_project, all_projects, macros))
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/loader.py", line 86, in load_all
macros)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/loader.py", line 102, in load_project
macros=macros)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/parser/base_sql.py", line 67, in load_and_parse
macros)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/parser/base_sql.py", line 95, in parse_sql_nodes
macros=macros)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/parser/base.py", line 125, in parse_node
schema_override = config.config.get('schema')
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/model.py", line 82, in config
self.in_model_config)
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/model.py", line 50, in _merge
merged_config.copy(), config.copy()
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/utils.py", line 251, in deep_merge
last = copy.deepcopy(lst.pop(len(lst)-1))
File "/Users/azme/anaconda3/lib/python3.6/copy.py", line 150, in deepcopy
y = copier(x, memo)
File "/Users/azme/anaconda3/lib/python3.6/copy.py", line 240, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/Users/azme/anaconda3/lib/python3.6/copy.py", line 180, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/Users/azme/anaconda3/lib/python3.6/copy.py", line 281, in _reconstruct
if hasattr(y, '__setstate__'):
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/clients/jinja.py", line 165, in __getattr__
self.package_name = self.name
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/clients/jinja.py", line 165, in __getattr__
self.package_name = self.name
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/clients/jinja.py", line 165, in __getattr__
self.package_name = self.name
[Previous line repeated 320 more times]
File "/Users/azme/anaconda3/lib/python3.6/site-packages/dbt/clients/jinja.py", line 162, in __getattr__
if name in ['unsafe_callable', 'alters_data']:
RecursionError: maximum recursion depth exceeded in comparison

# Fixed code
def create_macro_capture_env(node):
    class ParserMacroCapture(jinja2.Undefined):
        """
        This class sets up the parser to capture macros.
        """

        def __init__(self, hint=None, obj=None, name=None, exc=None):
            super(jinja2.Undefined, self).__init__()
            self.node = node
            self.name = name
            self.package_name = node.get("package_name")
            # jinja uses these for safety, so we have to override them.
            # see https://github.com/pallets/jinja/blob/master/jinja2/sandbox.py#L332-L339 # noqa
            self.unsafe_callable = False
            self.alters_data = False

        def __deepcopy__(self, memo):
            path = os.path.join(
                self.node.get("root_path"), self.node.get("original_file_path")
            )

            logger.debug(
                "A ParserMacroCapture has been deecopy()d, invalid reference "
                'to "{}" in node {}.{} (source path: {})'.format(
                    self.name,
                    self.node.get("package_name"),
                    self.node.get("name"),
                    path,
                )
            )

            dbt.exceptions.raise_compiler_error(
                "dbt has detected at least one invalid reference in {}.{}. "
                "Check logs for more information".format(
                    self.node.get("package_name"), self.node.get("name")
                )
            )

        def __getattr__(self, name):
            if name == "name" or _is_dunder_name(name):
                raise AttributeError(
                    "'{}' object has no attribute '{}'".format(
                        type(self).__name__, name
                    )
                )

            self.package_name = self.name
            self.name = name

            return self

        def __call__(self, *args, **kwargs):
            return True

    return ParserMacroCapture