Skip to content

Commit

Permalink
More macro search changes
Browse files Browse the repository at this point in the history
Unify the lookup for the various macros, all of them are done in the manifest now:
 - dbt's built-in package + all plugins are part of 'core'
 - finding macros has the concept of an optional package name
 - materializations are a special case of finding macros
 - the `generate_*_name` macros are another special case (non-core dependency packages are ignored)
 - generating the macro execution context now uses the concept of an optional search_package_name
 - macro execution now binds these two together

Unify the lookup for models/docs/sources
 - added a search_name property to those three types
 - create a 'Searchable' protocol, have the node search code accept that
 - simplify matching logic/push it into the correct types accordingly

Rename get_materialization_macro to find_materialization_macro_by_name (consistency)

context namespacing behavior:
 - dbt run-operation now passes the named package along to macro execution if a package name is specified
 - so `dbt run-operation dependency.ad` runs with the dependency namespace as local, overriding globals
 - but `dbt run-operation my_macro` runs in the current package namespace as local, even if it ultimately runs the dependency's my_macro()
 - the current package namespace is always treated as "global", overriding core macros

Tons of tests
  • Loading branch information
Jacob Beck committed Jan 29, 2020
1 parent e570d22 commit 62755fe
Show file tree
Hide file tree
Showing 18 changed files with 1,008 additions and 229 deletions.
21 changes: 14 additions & 7 deletions core/dbt/adapters/base/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,9 @@ def execute_macro(
if manifest is None:
manifest = self._internal_manifest

macro = manifest.find_macro_by_name(macro_name, project)
macro = manifest.find_macro_by_name(
macro_name, self.config.project_name, project
)
if macro is None:
if project is None:
package_name = 'any package'
Expand All @@ -982,9 +984,10 @@ def execute_macro(
# ends up calling get_adapter, so the import has to be here.
import dbt.context.operation
macro_context = dbt.context.operation.generate(
macro,
self.config,
manifest
model=macro,
runtime_config=self.config,
manifest=manifest,
package_name=project
)
macro_context.update(context_override)

Expand Down Expand Up @@ -1018,9 +1021,13 @@ def get_catalog(self, manifest: Manifest) -> agate.Table:
information_schemas = self._get_catalog_information_schemas(manifest)
# make it a list so macros can index into it.
kwargs = {'information_schemas': information_schemas}
table = self.execute_macro(GET_CATALOG_MACRO_NAME,
kwargs=kwargs,
release=True)
table = self.execute_macro(
GET_CATALOG_MACRO_NAME,
kwargs=kwargs,
release=True,
# pass in the full manifest so we get any local project overrides
manifest=manifest,
)

results = self._catalog_filter_table(table, manifest)
return results
Expand Down
8 changes: 4 additions & 4 deletions core/dbt/context/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ def add_macros_from(
# adapter packages are part of the global project space
_add_macro_map(context, package_name, macro_map)

if package_name == self.config.project_name:
# If we're in the root project, allow global override
global_macros.append(macro_map)
elif package_name == self.search_package_name:
if package_name == self.search_package_name:
# If we're in the current project, allow local override
local_macros.append(macro_map)
elif package_name == self.config.project_name:
# If we're in the root project, allow global override
global_macros.append(macro_map)
elif package_name in PACKAGES:
# If it comes from a dbt package, allow global override
global_macros.append(macro_map)
Expand Down
43 changes: 36 additions & 7 deletions core/dbt/context/common.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import agate
import os
from typing_extensions import Protocol
from typing import Union, Callable, Any, Dict, TypeVar, Type
from typing import Union, Callable, Any, Dict, TypeVar, Type, Optional

from dbt.clients import agate_helper
from dbt.contracts.graph.compiled import CompiledSeedNode
from dbt.contracts.graph.parsed import ParsedSeedNode
from dbt.contracts.graph.compiled import CompiledSeedNode, CompileResultNode
from dbt.contracts.graph.parsed import ParsedSeedNode, ParsedMacro
import dbt.exceptions
import dbt.flags
import dbt.tracking
Expand All @@ -14,6 +14,7 @@
from dbt.adapters.factory import get_adapter
from dbt.node_types import NodeType
from dbt.clients.jinja import get_rendered
from dbt.config import RuntimeConfig
from dbt.context.base import Var, HasCredentialsContext
from dbt.contracts.graph.manifest import Manifest

Expand Down Expand Up @@ -300,9 +301,27 @@ class ExecuteMacroContext(ProviderContext):
- 'this', 'pre_hooks', 'post_hooks', and 'sql' are missing
- 'schema' does not use any 'model' information
- they can't be configured with config() directives
- the search packge is the root project, unless the macro was executed by
fully-qualified name, in which case it's the chosen package.
"""
def __init__(self, model, config, manifest: Manifest, provider) -> None:
def __init__(
self,
model: ParsedMacro,
config: RuntimeConfig,
manifest: Manifest,
provider,
search_package_name: Optional[str]
) -> None:
super().__init__(model, config, manifest, provider, None)
if search_package_name is None:
# if the search package name isn't specified, use the root project
self._search_package_name = config.project_name
else:
self._search_package_name = search_package_name

@property
def search_package_name(self):
return self._search_package_name


class ModelContext(ProviderContext):
Expand Down Expand Up @@ -330,7 +349,11 @@ def insert_model_information(self, context):


def generate_execute_macro(
model, config, manifest: Manifest, provider
model: ParsedMacro,
config: RuntimeConfig,
manifest: Manifest,
provider: Provider,
package_name: Optional[str],
) -> Dict[str, Any]:
"""Internally, macros can be executed like nodes, with some restrictions:
Expand All @@ -339,12 +362,18 @@ def generate_execute_macro(
- 'schema' does not use any 'model' information
- they can't be configured with config() directives
"""
ctx = ExecuteMacroContext(model, config, manifest, provider)
ctx = ExecuteMacroContext(
model, config, manifest, provider, package_name
)
return ctx.to_dict()


def generate(
model, config, manifest: Manifest, provider, source_config=None
model: CompileResultNode,
config: RuntimeConfig,
manifest: Manifest,
provider: Provider,
source_config=None,
) -> Dict[str, Any]:
"""
Not meant to be called directly. Call with either:
Expand Down
18 changes: 14 additions & 4 deletions core/dbt/context/operation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import dbt.context.common
from typing import Optional, Dict, Any

from dbt.context import runtime
from dbt.context.common import generate_execute_macro
from dbt.exceptions import raise_compiler_error
from dbt.config import RuntimeConfig
from dbt.contracts.graph.manifest import Manifest
from dbt.contracts.graph.parsed import ParsedMacro


class RefResolver(runtime.RefResolver):
Expand All @@ -23,7 +28,12 @@ class Provider(runtime.Provider):
ref = RefResolver


def generate(model, runtime_config, manifest):
return dbt.context.common.generate_execute_macro(
model, runtime_config, manifest, Provider()
def generate(
model: ParsedMacro,
runtime_config: RuntimeConfig,
manifest: Manifest,
package_name: Optional[str]
) -> Dict[str, Any]:
return generate_execute_macro(
model, runtime_config, manifest, Provider(), package_name
)
4 changes: 2 additions & 2 deletions core/dbt/context/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ def generate(model, runtime_config, manifest, source_config):
)


def generate_macro(model, runtime_config, manifest):
def generate_macro(model, runtime_config, manifest, package_name):
# parser.generate_macro is called by the get_${attr}_func family of Parser
# methods, which preparse and cache the generate_${attr}_name family of
# macros for use during parsing
return dbt.context.common.generate_execute_macro(
model, runtime_config, manifest, Provider()
model, runtime_config, manifest, Provider(), package_name
)
13 changes: 10 additions & 3 deletions core/dbt/context/runtime.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from dbt.utils import get_materialization, add_ephemeral_model_prefix
from typing import Dict, Any


import dbt.clients.jinja
import dbt.context.base
import dbt.context.common
import dbt.flags
from dbt.parser.util import ParserUtils

from dbt.config import RuntimeConfig
from dbt.contracts.graph.compiled import CompileResultNode
from dbt.contracts.graph.manifest import Manifest
from dbt.logger import GLOBAL_LOGGER as logger # noqa
from dbt.parser.util import ParserUtils
from dbt.utils import get_materialization, add_ephemeral_model_prefix


class RefResolver(dbt.context.common.BaseResolver):
Expand Down Expand Up @@ -156,7 +161,9 @@ class Provider(dbt.context.common.Provider):
source = SourceResolver


def generate(model, runtime_config, manifest):
def generate(
model: CompileResultNode, runtime_config: RuntimeConfig, manifest: Manifest
) -> Dict[str, Any]:
return dbt.context.common.generate(
model, runtime_config, manifest, Provider(), None
)
Loading

0 comments on commit 62755fe

Please sign in to comment.