Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render profile_name in the base context (#2230) #2251

Merged
merged 3 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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:/fishtown-analytics/dbt/issues/2138) [#2199](https:/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:/fishtown-analytics/dbt/issues/2230), [#2251](https:/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:/fishtown-analytics/dbt/issues/2241), [#2252](https:/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:/fishtown-analytics/dbt/issues/2250), [#2254](https:/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!