Skip to content

Commit

Permalink
Merge pull request #2251 from fishtown-analytics/fix/render-profile-n…
Browse files Browse the repository at this point in the history
…ame-base-context

Render profile_name in the base context (#2230)
  • Loading branch information
beckjake authored Apr 1, 2020
2 parents 9e6e381 + df2ae07 commit b385d17
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Support for appending query comments to SQL queries. ([#2138](https://github.com/fishtown-analytics/dbt/issues/2138) [#2199](https://github.com/fishtown-analytics/dbt/issues/2199))

### Fixes
- dbt now renders the project name in the "base" context, in particular giving it access to `var` and `env_var` ([#2230](https://github.com/fishtown-analytics/dbt/issues/2230), [#2251](https://github.com/fishtown-analytics/dbt/pull/2251))
- Fix an issue with raw blocks where multiple raw blocks in the same file resulted in an error ([#2241](https://github.com/fishtown-analytics/dbt/issues/2241), [#2252](https://github.com/fishtown-analytics/dbt/pull/2252))
- Fix a redshift-only issue that caused an error when `dbt seed` found a seed with an entirely empty column that was set to a `varchar` data type. ([#2250](https://github.com/fishtown-analytics/dbt/issues/2250), [#2254](https://github.com/fishtown-analytics/dbt/pull/2254))

Expand Down
22 changes: 18 additions & 4 deletions core/dbt/config/project.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from copy import deepcopy
from dataclasses import dataclass
from dataclasses import dataclass, field
from itertools import chain
from typing import List, Dict, Any, Optional, TypeVar, Union, Tuple, Callable
import hashlib
Expand Down Expand Up @@ -220,9 +220,18 @@ def _query_comment_from_cfg(

@dataclass
class PartialProject:
profile_name: Optional[str]
project_name: Optional[str]
project_root: str
profile_name: Optional[str] = field(metadata=dict(
description='The unrendered profile name in the project, if set'
))
project_name: Optional[str] = field(metadata=dict(
description=(
'The name of the project. This should always be set and will not '
'be rendered'
)
))
project_root: str = field(
metadata=dict(description='The root directory of the project'),
)
project_dict: Dict[str, Any]

def render(self, renderer):
Expand All @@ -234,6 +243,11 @@ def render(self, renderer):
renderer,
)

def render_profile_name(self, renderer) -> Optional[str]:
if self.profile_name is None:
return None
return renderer.render_value(self.profile_name)


@dataclass
class Project:
Expand Down
3 changes: 3 additions & 0 deletions core/dbt/config/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def _render_project_entry(self, value, keypath):
:param key str: The key to convert on.
:return Any: The rendered entry.
"""
# the project name is never rendered
if keypath == ('name',):
return value
# query comments and hooks should be treated as raw sql, they'll get
# rendered later.
# Same goes for 'vars' declarations inside 'models'/'seeds'
Expand Down
3 changes: 2 additions & 1 deletion core/dbt/config/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ def from_args(cls, args: Any) -> 'RuntimeConfig':
# build the profile using the base renderer and the one fact we know
cli_vars: Dict[str, Any] = parse_cli_vars(getattr(args, 'vars', '{}'))
renderer = ConfigRenderer(generate_base_context(cli_vars=cli_vars))
profile_name = partial.render_profile_name(renderer)
profile = Profile.render_from_args(
args, renderer, partial.profile_name
args, renderer, profile_name
)

# get a new renderer using our target information and render the
Expand Down
6 changes: 4 additions & 2 deletions core/dbt/task/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,11 @@ def _choose_profile_names(self) -> Optional[List[str]]:
project_profile: Optional[str] = None
if os.path.exists(self.project_path):
try:
project_profile = Project.partial_load(
partial = Project.partial_load(
os.path.dirname(self.project_path)
).profile_name
)
renderer = ConfigRenderer(generate_base_context(self.cli_vars))
project_profile = partial.render_profile_name(renderer)
except dbt.exceptions.DbtProjectError:
pass

Expand Down
5 changes: 3 additions & 2 deletions test/integration/001_simple_copy_test/test_simple_copy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import io
import json
import os
from unittest import mock
from pytest import mark

from test.integration.base import DBTIntegrationTest, use_profile
Expand All @@ -23,7 +22,9 @@ def models(self):

@property
def project_config(self):
return self.seed_quote_cfg_with({})
return self.seed_quote_cfg_with({
'profile': '{{ "tes" ~ "t" }}'
})

def seed_quote_cfg_with(self, extra):
cfg = {
Expand Down
6 changes: 6 additions & 0 deletions test/integration/049_dbt_debug_test/test_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ def test_postgres_wronguser(self):
self.assertGotValue(re.compile(r'\s+Connection test'), 'ERROR')


class TestDebugProfileVariable(TestDebug):
@property
def project_config(self):
return {'profile': '{{ "te" ~ "st" }}'}


class TestDebugInvalidProject(DBTIntegrationTest):
@property
def schema(self):
Expand Down
30 changes: 17 additions & 13 deletions test/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def setUp(self):
'env_value_pass': 'env-postgres-pass',
'env_value_dbname': 'env-postgres-dbname',
'env_value_schema': 'env-postgres-schema',
'env_value_project': 'blah',
'env_value_profile': 'default',
}


Expand Down Expand Up @@ -990,7 +990,8 @@ class TestVariableProjectFile(BaseFileTest):
def setUp(self):
super().setUp()
self.default_project_data['version'] = "{{ var('cli_version') }}"
self.default_project_data['name'] = "{{ env_var('env_value_project') }}"
self.default_project_data['name'] = "blah"
self.default_project_data['profile'] = "{{ env_var('env_value_profile') }}"
self.write_project(self.default_project_data)
# and after the fact, add the project root
self.default_project_data['project-root'] = self.project_dir
Expand All @@ -1005,6 +1006,7 @@ def test_cli_and_env_vars(self):

self.assertEqual(project.version, "0.1.2")
self.assertEqual(project.project_name, 'blah')
self.assertEqual(project.profile_name, 'default')


class TestRuntimeConfig(BaseConfigTest):
Expand Down Expand Up @@ -1165,26 +1167,27 @@ def setUp(self):
super().setUp()
self.default_project_data.update({
'version': "{{ var('cli_version') }}",
'name': "{{ env_var('env_value_project') }}",
'name': "blah",
'profile': "{{ env_var('env_value_profile') }}",
'on-run-end': [
"{{ env_var('env_value_project') }}",
"{{ env_var('env_value_profile') }}",
],
'models': {
'foo': {
'post-hook': "{{ env_var('env_value_target') }}",
'post-hook': "{{ env_var('env_value_profile') }}",
},
'bar': {
# just gibberish, make sure it gets interpreted
'materialized': "{{ env_var('env_value_project') }}",
'materialized': "{{ env_var('env_value_profile') }}",
}
},
'seeds': {
'foo': {
'post-hook': "{{ env_var('env_value_target') }}",
'post-hook': "{{ env_var('env_value_profile') }}",
},
'bar': {
# just gibberish, make sure it gets interpreted
'materialized': "{{ env_var('env_value_project') }}",
'materialized': "{{ env_var('env_value_profile') }}",
}
},
})
Expand All @@ -1201,11 +1204,12 @@ def test_cli_and_env_vars(self):

self.assertEqual(config.version, "0.1.2")
self.assertEqual(config.project_name, 'blah')
self.assertEqual(config.profile_name, 'default')
self.assertEqual(config.credentials.host, 'cli-postgres-host')
self.assertEqual(config.credentials.user, 'env-postgres-user')
# make sure hooks are not interpreted
self.assertEqual(config.on_run_end, ["{{ env_var('env_value_project') }}"])
self.assertEqual(config.models['foo']['post-hook'], "{{ env_var('env_value_target') }}")
self.assertEqual(config.models['bar']['materialized'], 'blah')
self.assertEqual(config.seeds['foo']['post-hook'], "{{ env_var('env_value_target') }}")
self.assertEqual(config.seeds['bar']['materialized'], 'blah')
self.assertEqual(config.on_run_end, ["{{ env_var('env_value_profile') }}"])
self.assertEqual(config.models['foo']['post-hook'], "{{ env_var('env_value_profile') }}")
self.assertEqual(config.models['bar']['materialized'], 'default') # rendered!
self.assertEqual(config.seeds['foo']['post-hook'], "{{ env_var('env_value_profile') }}")
self.assertEqual(config.seeds['bar']['materialized'], 'default') # rendered!

0 comments on commit b385d17

Please sign in to comment.