We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ref uses most recently referenced project rather than current
## Issue
The expected behavior for a reference with no specified project like `{{ref('model_one')}}` is that it will refer to the model "model_one" in the current project. However this is not the case when a ref earlier in the model specifies a project of its own. For instance were I to define a model in a project named "A" with these contents:
```SELECT * FROM {{ref('B', 'model_one')}}, {{ref('model_two')}}```, and then run `dbt docs generate` both model_one and model_two will be searched for in project "B", and dbt will throw an error (in this case, model_two is in the "A" project).

I believe this is due to the variable target_model_package being assigned in the outer loop of method process_refs.  https://github.com/fishtown-analytics/dbt/blob/master/core/dbt/parser/util.py#L163-L169 This causes each ref within a node to use the target_model_package of the previous ref as its default target_model_package, rather than None as I believe was intended.


While based on my reading of the docs and code I don't believe this is the intended behavior, if it is I would argue it should be changed. Having the order in which refs occur change the model they point at could for instance cause a stylistic change like refactoring a query to move part of it into a CTE to have a functional impact.

If this is indeed an issue I'd like to volunteer to make a PR for it!
### Issue description

Profile type "redshift"

### Results
```
(dbt-test-3)  ~/Test/proj_one  dbt docs generate
Running with dbt=0.13.1
Encountered an error:
Compilation Error in model model_one (models/example/model_one.sql)
  Model 'model.proj_one.model_one' depends on model 'model_two' in package 'proj_two' which was not found or is disabled
```
### System information
The output of `dbt --version`:
```
installed version: 0.13.1
   latest version: 0.13.1

Up to date!
```

The operating system you're running on:
Mac OS Mojave 10.14
The python version you're using (probably the output of `python --version`)
Python 3.6.2
### Steps to reproduce
1. dbt init two fresh projects, in this case we're calling them proj_one and proj_two.
2. change the "name" of these projects in the dbt_project.yml file to "proj_one" and "proj_two" respectively
3.delete the default example models in the models folder
4. create a file model_one.sql in the models folder of "proj_one" with this definition "select * from {{ref('proj_two', 'model_a')}}, {{ref('model_two')}}"
5. create a second file in the models folder of "proj_one" named "model_two.sql" with the contents "Select 1"
6. create a file in the models folder of "proj_two" with the name "model_a.sql" with the contents "select 1"
7. in proj_one, define a packages.yml file with these contents """
packages:
  - local: ../proj2
"""
8. run dbt deps in proj_one to install proj_two as a package
9. run dbt docs generate in proj_one. This will raise the error " Model 'model.proj_one.model_one' depends on model 'model_two' in package 'proj_two' which was not found or is disabled". This is incorrect, as the ref for model_two does not specify a project, so the current project should be used by default. Dbt instead appears to be using the project of the most recent ref.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `core/dbt/parser/util.py`
Content:
```
1 
2 import dbt.exceptions
3 import dbt.utils
4 from dbt.node_types import NodeType
5 
6 
7 def docs(node, manifest, config, column_name=None):
8     """Return a function that will process `doc()` references in jinja, look
9     them up in the manifest, and return the appropriate block contents.
10     """
11     current_project = config.project_name
12 
13     def do_docs(*args):
14         if len(args) == 1:
15             doc_package_name = None
16             doc_name = args[0]
17         elif len(args) == 2:
18             doc_package_name, doc_name = args
19         else:
20             dbt.exceptions.doc_invalid_args(node, args)
21 
22         target_doc = ParserUtils.resolve_doc(
23             manifest, doc_name, doc_package_name, current_project,
24             node.package_name
25         )
26 
27         if target_doc is None:
28             dbt.exceptions.doc_target_not_found(node, doc_name,
29                                                 doc_package_name)
30 
31         return target_doc.block_contents
32 
33     return do_docs
34 
35 
36 class ParserUtils(object):
37     DISABLED = object()
38 
39     @classmethod
40     def resolve_source(cls, manifest, target_source_name,
41                        target_table_name, current_project, node_package):
42         candidate_targets = [current_project, node_package, None]
43         target_source = None
44         for candidate in candidate_targets:
45             target_source = manifest.find_source_by_name(
46                 target_source_name,
47                 target_table_name,
48                 candidate
49             )
50             if target_source is not None:
51                 return target_source
52 
53         return None
54 
55     @classmethod
56     def resolve_ref(cls, manifest, target_model_name, target_model_package,
57                     current_project, node_package):
58         if target_model_package is not None:
59             return manifest.find_refable_by_name(
60                 target_model_name,
61                 target_model_package)
62 
63         target_model = None
64         disabled_target = None
65 
66         # first pass: look for models in the current_project
67         # second pass: look for models in the node's package
68         # final pass: look for models in any package
69         # todo: exclude the packages we have already searched. overriding
70         # a package model in another package doesn't necessarily work atm
71         candidates = [current_project, node_package, None]
72         for candidate in candidates:
73             target_model = manifest.find_refable_by_name(
74                 target_model_name,
75                 candidate)
76 
77             if target_model is not None and dbt.utils.is_enabled(target_model):
78                 return target_model
79 
80             # it's possible that the node is disabled
81             if disabled_target is None:
82                 disabled_target = manifest.find_disabled_by_name(
83                     target_model_name, candidate
84                 )
85 
86         if disabled_target is not None:
87             return cls.DISABLED
88         return None
89 
90     @classmethod
91     def resolve_doc(cls, manifest, target_doc_name, target_doc_package,
92                     current_project, node_package):
93         """Resolve the given documentation. This follows the same algorithm as
94         resolve_ref except the is_enabled checks are unnecessary as docs are
95         always enabled.
96         """
97         if target_doc_package is not None:
98             return manifest.find_docs_by_name(target_doc_name,
99                                               target_doc_package)
100 
101         candidate_targets = [current_project, node_package, None]
102         target_doc = None
103         for candidate in candidate_targets:
104             target_doc = manifest.find_docs_by_name(target_doc_name, candidate)
105             if target_doc is not None:
106                 break
107         return target_doc
108 
109     @classmethod
110     def _get_node_column(cls, node, column_name):
111         """Given a ParsedNode, add some fields that might be missing. Return a
112         reference to the dict that refers to the given column, creating it if
113         it doesn't yet exist.
114         """
115         if not hasattr(node, 'columns'):
116             node.set('columns', {})
117 
118         if column_name in node.columns:
119             column = node.columns[column_name]
120         else:
121             column = {'name': column_name, 'description': ''}
122             node.columns[column_name] = column
123 
124         return column
125 
126     @classmethod
127     def process_docs_for_node(cls, manifest, current_project, node):
128         for docref in node.get('docrefs', []):
129             column_name = docref.get('column_name')
130             if column_name is None:
131                 description = node.get('description', '')
132             else:
133                 column = cls._get_node_column(node, column_name)
134                 description = column.get('description', '')
135             context = {
136                 'doc': docs(node, manifest, current_project, column_name),
137             }
138 
139             # At this point, target_doc is a ParsedDocumentation, and we
140             # know that our documentation string has a 'docs("...")'
141             # pointing at it. We want to render it.
142             description = dbt.clients.jinja.get_rendered(description,
143                                                          context)
144             # now put it back.
145             if column_name is None:
146                 node.set('description', description)
147             else:
148                 column['description'] = description
149 
150     @classmethod
151     def process_docs_for_source(cls, manifest, current_project, source):
152         context = {
153             'doc': docs(source, manifest, current_project),
154         }
155         table_description = source.get('description', '')
156         source_description = source.get('source_description', '')
157         table_description = dbt.clients.jinja.get_rendered(table_description,
158                                                            context)
159         source_description = dbt.clients.jinja.get_rendered(source_description,
160                                                             context)
161         source.set('description', table_description)
162         source.set('source_description', source_description)
163 
164     @classmethod
165     def process_docs(cls, manifest, current_project):
166         for node in manifest.nodes.values():
167             if node.resource_type == NodeType.Source:
168                 cls.process_docs_for_source(manifest, current_project, node)
169             else:
170                 cls.process_docs_for_node(manifest, current_project, node)
171         return manifest
172 
173     @classmethod
174     def process_refs_for_node(cls, manifest, current_project, node):
175         """Given a manifest and a node in that manifest, process its refs"""
176         target_model = None
177         target_model_name = None
178         target_model_package = None
179 
180         for ref in node.refs:
181             if len(ref) == 1:
182                 target_model_name = ref[0]
183             elif len(ref) == 2:
184                 target_model_package, target_model_name = ref
185 
186             target_model = cls.resolve_ref(
187                 manifest,
188                 target_model_name,
189                 target_model_package,
190                 current_project,
191                 node.get('package_name'))
192 
193             if target_model is None or target_model is cls.DISABLED:
194                 # This may raise. Even if it doesn't, we don't want to add
195                 # this node to the graph b/c there is no destination node
196                 node.config['enabled'] = False
197                 dbt.utils.invalid_ref_fail_unless_test(
198                     node, target_model_name, target_model_package,
199                     disabled=(target_model is cls.DISABLED)
200                 )
201 
202                 continue
203 
204             target_model_id = target_model.get('unique_id')
205 
206             node.depends_on['nodes'].append(target_model_id)
207             manifest.nodes[node['unique_id']] = node
208 
209     @classmethod
210     def process_refs(cls, manifest, current_project):
211         for node in manifest.nodes.values():
212             cls.process_refs_for_node(manifest, current_project, node)
213         return manifest
214 
215     @classmethod
216     def process_sources_for_node(cls, manifest, current_project, node):
217         target_source = None
218         for source_name, table_name in node.sources:
219             target_source = cls.resolve_source(
220                 manifest,
221                 source_name,
222                 table_name,
223                 current_project,
224                 node.get('package_name'))
225 
226             if target_source is None:
227                 # this folows the same pattern as refs
228                 node.config['enabled'] = False
229                 dbt.utils.invalid_source_fail_unless_test(
230                     node,
231                     source_name,
232                     table_name)
233                 continue
234             target_source_id = target_source.unique_id
235             node.depends_on['nodes'].append(target_source_id)
236             manifest.nodes[node['unique_id']] = node
237 
238     @classmethod
239     def process_sources(cls, manifest, current_project):
240         for node in manifest.nodes.values():
241             cls.process_sources_for_node(manifest, current_project, node)
242         return manifest
243 
244     @classmethod
245     def add_new_refs(cls, manifest, current_project, node, macros):
246         """Given a new node that is not in the manifest, copy the manifest and
247         insert the new node into it as if it were part of regular ref
248         processing
249         """
250         manifest = manifest.deepcopy(config=current_project)
251         # it's ok for macros to silently override a local project macro name
252         manifest.macros.update(macros)
253 
254         if node.unique_id in manifest.nodes:
255             # this should be _impossible_ due to the fact that rpc calls get
256             # a unique ID that starts with 'rpc'!
257             raise dbt.exceptions.raise_duplicate_resource_name(
258                 manifest.nodes[node.unique_id], node
259             )
260         manifest.nodes[node.unique_id] = node
261         cls.process_sources_for_node(manifest, current_project, node)
262         cls.process_refs_for_node(manifest, current_project, node)
263         cls.process_docs_for_node(manifest, current_project, node)
264         return manifest
265
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/core/dbt/parser/util.py b/core/dbt/parser/util.py
--- a/core/dbt/parser/util.py
+++ b/core/dbt/parser/util.py
@@ -173,11 +173,11 @@
     @classmethod
     def process_refs_for_node(cls, manifest, current_project, node):
         """Given a manifest and a node in that manifest, process its refs"""
-        target_model = None
-        target_model_name = None
-        target_model_package = None
-
         for ref in node.refs:
+            target_model = None
+            target_model_name = None
+            target_model_package = None
+
             if len(ref) == 1:
                 target_model_name = ref[0]
             elif len(ref) == 2:

{"golden_diff": "diff --git a/core/dbt/parser/util.py b/core/dbt/parser/util.py\n--- a/core/dbt/parser/util.py\n+++ b/core/dbt/parser/util.py\n@@ -173,11 +173,11 @@\n     @classmethod\n     def process_refs_for_node(cls, manifest, current_project, node):\n         \"\"\"Given a manifest and a node in that manifest, process its refs\"\"\"\n-        target_model = None\n-        target_model_name = None\n-        target_model_package = None\n-\n         for ref in node.refs:\n+            target_model = None\n+            target_model_name = None\n+            target_model_package = None\n+\n             if len(ref) == 1:\n                 target_model_name = ref[0]\n             elif len(ref) == 2:\n", "issue": "ref uses most recently referenced project rather than current\n## Issue\r\nThe expected behavior for a reference with no specified project like `{{ref('model_one')}}` is that it will refer to the model \"model_one\" in the current project. However this is not the case when a ref earlier in the model specifies a project of its own. For instance were I to define a model in a project named \"A\" with these contents:\r\n```SELECT * FROM {{ref('B', 'model_one')}}, {{ref('model_two')}}```, and then run `dbt docs generate` both model_one and model_two will be searched for in project \"B\", and dbt will throw an error (in this case, model_two is in the \"A\" project).\r\n\r\nI believe this is due to the variable target_model_package being assigned in the outer loop of method process_refs.  https://github.com/fishtown-analytics/dbt/blob/master/core/dbt/parser/util.py#L163-L169 This causes each ref within a node to use the target_model_package of the previous ref as its default target_model_package, rather than None as I believe was intended.\r\n\r\n\r\nWhile based on my reading of the docs and code I don't believe this is the intended behavior, if it is I would argue it should be changed. Having the order in which refs occur change the model they point at could for instance cause a stylistic change like refactoring a query to move part of it into a CTE to have a functional impact.\r\n\r\nIf this is indeed an issue I'd like to volunteer to make a PR for it!\r\n### Issue description\r\n\r\nProfile type \"redshift\"\r\n\r\n### Results\r\n```\r\n(dbt-test-3)  ~/Test/proj_one \ue0b0 dbt docs generate\r\nRunning with dbt=0.13.1\r\nEncountered an error:\r\nCompilation Error in model model_one (models/example/model_one.sql)\r\n  Model 'model.proj_one.model_one' depends on model 'model_two' in package 'proj_two' which was not found or is disabled\r\n```\r\n### System information\r\nThe output of `dbt --version`:\r\n```\r\ninstalled version: 0.13.1\r\n   latest version: 0.13.1\r\n\r\nUp to date!\r\n```\r\n\r\nThe operating system you're running on:\r\nMac OS Mojave 10.14\r\nThe python version you're using (probably the output of `python --version`)\r\nPython 3.6.2\r\n### Steps to reproduce\r\n1. dbt init two fresh projects, in this case we're calling them proj_one and proj_two.\r\n2. change the \"name\" of these projects in the dbt_project.yml file to \"proj_one\" and \"proj_two\" respectively\r\n3.delete the default example models in the models folder\r\n4. create a file model_one.sql in the models folder of \"proj_one\" with this definition \"select * from {{ref('proj_two', 'model_a')}}, {{ref('model_two')}}\"\r\n5. create a second file in the models folder of \"proj_one\" named \"model_two.sql\" with the contents \"Select 1\"\r\n6. create a file in the models folder of \"proj_two\" with the name \"model_a.sql\" with the contents \"select 1\"\r\n7. in proj_one, define a packages.yml file with these contents \"\"\"\r\npackages:\r\n  - local: ../proj2\r\n\"\"\"\r\n8. run dbt deps in proj_one to install proj_two as a package\r\n9. run dbt docs generate in proj_one. This will raise the error \" Model 'model.proj_one.model_one' depends on model 'model_two' in package 'proj_two' which was not found or is disabled\". This is incorrect, as the ref for model_two does not specify a project, so the current project should be used by default. Dbt instead appears to be using the project of the most recent ref.\r\n\r\n\n", "before_files": [{"content": "\nimport dbt.exceptions\nimport dbt.utils\nfrom dbt.node_types import NodeType\n\n\ndef docs(node, manifest, config, column_name=None):\n    \"\"\"Return a function that will process `doc()` references in jinja, look\n    them up in the manifest, and return the appropriate block contents.\n    \"\"\"\n    current_project = config.project_name\n\n    def do_docs(*args):\n        if len(args) == 1:\n            doc_package_name = None\n            doc_name = args[0]\n        elif len(args) == 2:\n            doc_package_name, doc_name = args\n        else:\n            dbt.exceptions.doc_invalid_args(node, args)\n\n        target_doc = ParserUtils.resolve_doc(\n            manifest, doc_name, doc_package_name, current_project,\n            node.package_name\n        )\n\n        if target_doc is None:\n            dbt.exceptions.doc_target_not_found(node, doc_name,\n                                                doc_package_name)\n\n        return target_doc.block_contents\n\n    return do_docs\n\n\nclass ParserUtils(object):\n    DISABLED = object()\n\n    @classmethod\n    def resolve_source(cls, manifest, target_source_name,\n                       target_table_name, current_project, node_package):\n        candidate_targets = [current_project, node_package, None]\n        target_source = None\n        for candidate in candidate_targets:\n            target_source = manifest.find_source_by_name(\n                target_source_name,\n                target_table_name,\n                candidate\n            )\n            if target_source is not None:\n                return target_source\n\n        return None\n\n    @classmethod\n    def resolve_ref(cls, manifest, target_model_name, target_model_package,\n                    current_project, node_package):\n        if target_model_package is not None:\n            return manifest.find_refable_by_name(\n                target_model_name,\n                target_model_package)\n\n        target_model = None\n        disabled_target = None\n\n        # first pass: look for models in the current_project\n        # second pass: look for models in the node's package\n        # final pass: look for models in any package\n        # todo: exclude the packages we have already searched. overriding\n        # a package model in another package doesn't necessarily work atm\n        candidates = [current_project, node_package, None]\n        for candidate in candidates:\n            target_model = manifest.find_refable_by_name(\n                target_model_name,\n                candidate)\n\n            if target_model is not None and dbt.utils.is_enabled(target_model):\n                return target_model\n\n            # it's possible that the node is disabled\n            if disabled_target is None:\n                disabled_target = manifest.find_disabled_by_name(\n                    target_model_name, candidate\n                )\n\n        if disabled_target is not None:\n            return cls.DISABLED\n        return None\n\n    @classmethod\n    def resolve_doc(cls, manifest, target_doc_name, target_doc_package,\n                    current_project, node_package):\n        \"\"\"Resolve the given documentation. This follows the same algorithm as\n        resolve_ref except the is_enabled checks are unnecessary as docs are\n        always enabled.\n        \"\"\"\n        if target_doc_package is not None:\n            return manifest.find_docs_by_name(target_doc_name,\n                                              target_doc_package)\n\n        candidate_targets = [current_project, node_package, None]\n        target_doc = None\n        for candidate in candidate_targets:\n            target_doc = manifest.find_docs_by_name(target_doc_name, candidate)\n            if target_doc is not None:\n                break\n        return target_doc\n\n    @classmethod\n    def _get_node_column(cls, node, column_name):\n        \"\"\"Given a ParsedNode, add some fields that might be missing. Return a\n        reference to the dict that refers to the given column, creating it if\n        it doesn't yet exist.\n        \"\"\"\n        if not hasattr(node, 'columns'):\n            node.set('columns', {})\n\n        if column_name in node.columns:\n            column = node.columns[column_name]\n        else:\n            column = {'name': column_name, 'description': ''}\n            node.columns[column_name] = column\n\n        return column\n\n    @classmethod\n    def process_docs_for_node(cls, manifest, current_project, node):\n        for docref in node.get('docrefs', []):\n            column_name = docref.get('column_name')\n            if column_name is None:\n                description = node.get('description', '')\n            else:\n                column = cls._get_node_column(node, column_name)\n                description = column.get('description', '')\n            context = {\n                'doc': docs(node, manifest, current_project, column_name),\n            }\n\n            # At this point, target_doc is a ParsedDocumentation, and we\n            # know that our documentation string has a 'docs(\"...\")'\n            # pointing at it. We want to render it.\n            description = dbt.clients.jinja.get_rendered(description,\n                                                         context)\n            # now put it back.\n            if column_name is None:\n                node.set('description', description)\n            else:\n                column['description'] = description\n\n    @classmethod\n    def process_docs_for_source(cls, manifest, current_project, source):\n        context = {\n            'doc': docs(source, manifest, current_project),\n        }\n        table_description = source.get('description', '')\n        source_description = source.get('source_description', '')\n        table_description = dbt.clients.jinja.get_rendered(table_description,\n                                                           context)\n        source_description = dbt.clients.jinja.get_rendered(source_description,\n                                                            context)\n        source.set('description', table_description)\n        source.set('source_description', source_description)\n\n    @classmethod\n    def process_docs(cls, manifest, current_project):\n        for node in manifest.nodes.values():\n            if node.resource_type == NodeType.Source:\n                cls.process_docs_for_source(manifest, current_project, node)\n            else:\n                cls.process_docs_for_node(manifest, current_project, node)\n        return manifest\n\n    @classmethod\n    def process_refs_for_node(cls, manifest, current_project, node):\n        \"\"\"Given a manifest and a node in that manifest, process its refs\"\"\"\n        target_model = None\n        target_model_name = None\n        target_model_package = None\n\n        for ref in node.refs:\n            if len(ref) == 1:\n                target_model_name = ref[0]\n            elif len(ref) == 2:\n                target_model_package, target_model_name = ref\n\n            target_model = cls.resolve_ref(\n                manifest,\n                target_model_name,\n                target_model_package,\n                current_project,\n                node.get('package_name'))\n\n            if target_model is None or target_model is cls.DISABLED:\n                # This may raise. Even if it doesn't, we don't want to add\n                # this node to the graph b/c there is no destination node\n                node.config['enabled'] = False\n                dbt.utils.invalid_ref_fail_unless_test(\n                    node, target_model_name, target_model_package,\n                    disabled=(target_model is cls.DISABLED)\n                )\n\n                continue\n\n            target_model_id = target_model.get('unique_id')\n\n            node.depends_on['nodes'].append(target_model_id)\n            manifest.nodes[node['unique_id']] = node\n\n    @classmethod\n    def process_refs(cls, manifest, current_project):\n        for node in manifest.nodes.values():\n            cls.process_refs_for_node(manifest, current_project, node)\n        return manifest\n\n    @classmethod\n    def process_sources_for_node(cls, manifest, current_project, node):\n        target_source = None\n        for source_name, table_name in node.sources:\n            target_source = cls.resolve_source(\n                manifest,\n                source_name,\n                table_name,\n                current_project,\n                node.get('package_name'))\n\n            if target_source is None:\n                # this folows the same pattern as refs\n                node.config['enabled'] = False\n                dbt.utils.invalid_source_fail_unless_test(\n                    node,\n                    source_name,\n                    table_name)\n                continue\n            target_source_id = target_source.unique_id\n            node.depends_on['nodes'].append(target_source_id)\n            manifest.nodes[node['unique_id']] = node\n\n    @classmethod\n    def process_sources(cls, manifest, current_project):\n        for node in manifest.nodes.values():\n            cls.process_sources_for_node(manifest, current_project, node)\n        return manifest\n\n    @classmethod\n    def add_new_refs(cls, manifest, current_project, node, macros):\n        \"\"\"Given a new node that is not in the manifest, copy the manifest and\n        insert the new node into it as if it were part of regular ref\n        processing\n        \"\"\"\n        manifest = manifest.deepcopy(config=current_project)\n        # it's ok for macros to silently override a local project macro name\n        manifest.macros.update(macros)\n\n        if node.unique_id in manifest.nodes:\n            # this should be _impossible_ due to the fact that rpc calls get\n            # a unique ID that starts with 'rpc'!\n            raise dbt.exceptions.raise_duplicate_resource_name(\n                manifest.nodes[node.unique_id], node\n            )\n        manifest.nodes[node.unique_id] = node\n        cls.process_sources_for_node(manifest, current_project, node)\n        cls.process_refs_for_node(manifest, current_project, node)\n        cls.process_docs_for_node(manifest, current_project, node)\n        return manifest\n", "path": "core/dbt/parser/util.py"}], "after_files": [{"content": "\nimport dbt.exceptions\nimport dbt.utils\nfrom dbt.node_types import NodeType\n\n\ndef docs(node, manifest, config, column_name=None):\n    \"\"\"Return a function that will process `doc()` references in jinja, look\n    them up in the manifest, and return the appropriate block contents.\n    \"\"\"\n    current_project = config.project_name\n\n    def do_docs(*args):\n        if len(args) == 1:\n            doc_package_name = None\n            doc_name = args[0]\n        elif len(args) == 2:\n            doc_package_name, doc_name = args\n        else:\n            dbt.exceptions.doc_invalid_args(node, args)\n\n        target_doc = ParserUtils.resolve_doc(\n            manifest, doc_name, doc_package_name, current_project,\n            node.package_name\n        )\n\n        if target_doc is None:\n            dbt.exceptions.doc_target_not_found(node, doc_name,\n                                                doc_package_name)\n\n        return target_doc.block_contents\n\n    return do_docs\n\n\nclass ParserUtils(object):\n    DISABLED = object()\n\n    @classmethod\n    def resolve_source(cls, manifest, target_source_name,\n                       target_table_name, current_project, node_package):\n        candidate_targets = [current_project, node_package, None]\n        target_source = None\n        for candidate in candidate_targets:\n            target_source = manifest.find_source_by_name(\n                target_source_name,\n                target_table_name,\n                candidate\n            )\n            if target_source is not None:\n                return target_source\n\n        return None\n\n    @classmethod\n    def resolve_ref(cls, manifest, target_model_name, target_model_package,\n                    current_project, node_package):\n        if target_model_package is not None:\n            return manifest.find_refable_by_name(\n                target_model_name,\n                target_model_package)\n\n        target_model = None\n        disabled_target = None\n\n        # first pass: look for models in the current_project\n        # second pass: look for models in the node's package\n        # final pass: look for models in any package\n        # todo: exclude the packages we have already searched. overriding\n        # a package model in another package doesn't necessarily work atm\n        candidates = [current_project, node_package, None]\n        for candidate in candidates:\n            target_model = manifest.find_refable_by_name(\n                target_model_name,\n                candidate)\n\n            if target_model is not None and dbt.utils.is_enabled(target_model):\n                return target_model\n\n            # it's possible that the node is disabled\n            if disabled_target is None:\n                disabled_target = manifest.find_disabled_by_name(\n                    target_model_name, candidate\n                )\n\n        if disabled_target is not None:\n            return cls.DISABLED\n        return None\n\n    @classmethod\n    def resolve_doc(cls, manifest, target_doc_name, target_doc_package,\n                    current_project, node_package):\n        \"\"\"Resolve the given documentation. This follows the same algorithm as\n        resolve_ref except the is_enabled checks are unnecessary as docs are\n        always enabled.\n        \"\"\"\n        if target_doc_package is not None:\n            return manifest.find_docs_by_name(target_doc_name,\n                                              target_doc_package)\n\n        candidate_targets = [current_project, node_package, None]\n        target_doc = None\n        for candidate in candidate_targets:\n            target_doc = manifest.find_docs_by_name(target_doc_name, candidate)\n            if target_doc is not None:\n                break\n        return target_doc\n\n    @classmethod\n    def _get_node_column(cls, node, column_name):\n        \"\"\"Given a ParsedNode, add some fields that might be missing. Return a\n        reference to the dict that refers to the given column, creating it if\n        it doesn't yet exist.\n        \"\"\"\n        if not hasattr(node, 'columns'):\n            node.set('columns', {})\n\n        if column_name in node.columns:\n            column = node.columns[column_name]\n        else:\n            column = {'name': column_name, 'description': ''}\n            node.columns[column_name] = column\n\n        return column\n\n    @classmethod\n    def process_docs_for_node(cls, manifest, current_project, node):\n        for docref in node.get('docrefs', []):\n            column_name = docref.get('column_name')\n            if column_name is None:\n                description = node.get('description', '')\n            else:\n                column = cls._get_node_column(node, column_name)\n                description = column.get('description', '')\n            context = {\n                'doc': docs(node, manifest, current_project, column_name),\n            }\n\n            # At this point, target_doc is a ParsedDocumentation, and we\n            # know that our documentation string has a 'docs(\"...\")'\n            # pointing at it. We want to render it.\n            description = dbt.clients.jinja.get_rendered(description,\n                                                         context)\n            # now put it back.\n            if column_name is None:\n                node.set('description', description)\n            else:\n                column['description'] = description\n\n    @classmethod\n    def process_docs_for_source(cls, manifest, current_project, source):\n        context = {\n            'doc': docs(source, manifest, current_project),\n        }\n        table_description = source.get('description', '')\n        source_description = source.get('source_description', '')\n        table_description = dbt.clients.jinja.get_rendered(table_description,\n                                                           context)\n        source_description = dbt.clients.jinja.get_rendered(source_description,\n                                                            context)\n        source.set('description', table_description)\n        source.set('source_description', source_description)\n\n    @classmethod\n    def process_docs(cls, manifest, current_project):\n        for node in manifest.nodes.values():\n            if node.resource_type == NodeType.Source:\n                cls.process_docs_for_source(manifest, current_project, node)\n            else:\n                cls.process_docs_for_node(manifest, current_project, node)\n        return manifest\n\n    @classmethod\n    def process_refs_for_node(cls, manifest, current_project, node):\n        \"\"\"Given a manifest and a node in that manifest, process its refs\"\"\"\n        for ref in node.refs:\n            target_model = None\n            target_model_name = None\n            target_model_package = None\n\n            if len(ref) == 1:\n                target_model_name = ref[0]\n            elif len(ref) == 2:\n                target_model_package, target_model_name = ref\n\n            target_model = cls.resolve_ref(\n                manifest,\n                target_model_name,\n                target_model_package,\n                current_project,\n                node.get('package_name'))\n\n            if target_model is None or target_model is cls.DISABLED:\n                # This may raise. Even if it doesn't, we don't want to add\n                # this node to the graph b/c there is no destination node\n                node.config['enabled'] = False\n                dbt.utils.invalid_ref_fail_unless_test(\n                    node, target_model_name, target_model_package,\n                    disabled=(target_model is cls.DISABLED)\n                )\n\n                continue\n\n            target_model_id = target_model.get('unique_id')\n\n            node.depends_on['nodes'].append(target_model_id)\n            manifest.nodes[node['unique_id']] = node\n\n    @classmethod\n    def process_refs(cls, manifest, current_project):\n        for node in manifest.nodes.values():\n            cls.process_refs_for_node(manifest, current_project, node)\n        return manifest\n\n    @classmethod\n    def process_sources_for_node(cls, manifest, current_project, node):\n        target_source = None\n        for source_name, table_name in node.sources:\n            target_source = cls.resolve_source(\n                manifest,\n                source_name,\n                table_name,\n                current_project,\n                node.get('package_name'))\n\n            if target_source is None:\n                # this folows the same pattern as refs\n                node.config['enabled'] = False\n                dbt.utils.invalid_source_fail_unless_test(\n                    node,\n                    source_name,\n                    table_name)\n                continue\n            target_source_id = target_source.unique_id\n            node.depends_on['nodes'].append(target_source_id)\n            manifest.nodes[node['unique_id']] = node\n\n    @classmethod\n    def process_sources(cls, manifest, current_project):\n        for node in manifest.nodes.values():\n            cls.process_sources_for_node(manifest, current_project, node)\n        return manifest\n\n    @classmethod\n    def add_new_refs(cls, manifest, current_project, node, macros):\n        \"\"\"Given a new node that is not in the manifest, copy the manifest and\n        insert the new node into it as if it were part of regular ref\n        processing\n        \"\"\"\n        manifest = manifest.deepcopy(config=current_project)\n        # it's ok for macros to silently override a local project macro name\n        manifest.macros.update(macros)\n\n        if node.unique_id in manifest.nodes:\n            # this should be _impossible_ due to the fact that rpc calls get\n            # a unique ID that starts with 'rpc'!\n            raise dbt.exceptions.raise_duplicate_resource_name(\n                manifest.nodes[node.unique_id], node\n            )\n        manifest.nodes[node.unique_id] = node\n        cls.process_sources_for_node(manifest, current_project, node)\n        cls.process_refs_for_node(manifest, current_project, node)\n        cls.process_docs_for_node(manifest, current_project, node)\n        return manifest\n", "path": "core/dbt/parser/util.py"}]}