Example #1
0
    def execute(self, model, manifest):
        context = generate_runtime_model(model, self.config, manifest)

        materialization_macro = manifest.find_materialization_macro_by_name(
            self.config.project_name, model.get_materialization(),
            self.adapter.type())

        if materialization_macro is None:
            missing_materialization(model, self.adapter.type())

        if 'config' not in context:
            raise InternalException(
                'Invalid materialization context generated, missing config: {}'
                .format(context))
        context_config = context['config']

        hook_ctx = self.adapter.pre_model_hook(context_config)
        try:
            result = MacroGenerator(materialization_macro, context)()
        finally:
            self.adapter.post_model_hook(context_config, hook_ctx)

        for relation in self._materialization_relations(result, model):
            self.adapter.cache_added(relation.incorporate(dbt_created=True))

        return self._build_run_model_result(model, context)
Example #2
0
    def execute_macro(
        self,
        macro_name: str,
        manifest: Optional[Manifest] = None,
        project: Optional[str] = None,
        context_override: Optional[Dict[str, Any]] = None,
        kwargs: Dict[str, Any] = None,
        release: bool = False,
        text_only_columns: Optional[Iterable[str]] = None,
    ) -> agate.Table:
        """Look macro_name up in the manifest and execute its results.

        :param macro_name: The name of the macro to execute.
        :param manifest: The manifest to use for generating the base macro
            execution context. If none is provided, use the internal manifest.
        :param project: The name of the project to search in, or None for the
            first match.
        :param context_override: An optional dict to update() the macro
            execution context.
        :param kwargs: An optional dict of keyword args used to pass to the
            macro.
        :param release: If True, release the connection after executing.
        """
        if kwargs is None:
            kwargs = {}
        if context_override is None:
            context_override = {}

        if manifest is None:
            manifest = self._internal_manifest

        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'
            else:
                package_name = 'the "{}" package'.format(project)

            raise RuntimeException(
                'dbt could not find a macro with the name "{}" in {}'.format(
                    macro_name, package_name))
        # This causes a reference cycle, as generate_runtime_macro()
        # ends up calling get_adapter, so the import has to be here.
        from dbt.context.providers import generate_runtime_macro
        macro_context = generate_runtime_macro(macro=macro,
                                               config=self.config,
                                               manifest=manifest,
                                               package_name=project)
        macro_context.update(context_override)

        macro_function = MacroGenerator(macro, macro_context)

        with self.connections.exception_handler(f'macro {macro_name}'):
            try:
                result = macro_function(**kwargs)
            finally:
                if release:
                    self.release_connection()
        return result
Example #3
0
    def __init__(self, config: RuntimeConfig, macro_manifest: MacroManifest,
                 component: str) -> None:
        macro = macro_manifest.find_generate_macro_by_name(
            component=component,
            root_project_name=config.project_name,
        )
        if macro is None:
            raise InternalException(
                f'No macro with name generate_{component}_name found')

        root_context = generate_generate_component_name_macro(
            macro, config, macro_manifest)
        self.updater = MacroGenerator(macro, root_context)
        self.component = component
Example #4
0
 def get_from_package(self, package_name: Optional[str],
                      name: str) -> Optional[MacroGenerator]:
     macro = None
     if package_name is None:
         macro = self.macro_resolver.macros_by_name.get(name)
     elif package_name == GLOBAL_PROJECT_NAME:
         macro = self.macro_resolver.internal_packages_namespace.get(name)
     elif package_name in self.resolver.packages:
         macro = self.macro_resolver.packages[package_name].get(name)
     else:
         raise_compiler_error(f"Could not find package '{package_name}'")
     macro_func = MacroGenerator(macro, self.ctx, self.node,
                                 self.thread_ctx)
     return macro_func
Example #5
0
 def __init__(self, macro_resolver, ctx, node, thread_ctx,
              depends_on_macros):
     self.macro_resolver = macro_resolver
     self.ctx = ctx
     self.node = node
     self.thread_ctx = thread_ctx
     local_namespace = {}
     if depends_on_macros:
         for macro_unique_id in depends_on_macros:
             macro = self.manifest.macros[macro_unique_id]
             local_namespace[macro.name] = MacroGenerator(
                 macro,
                 self.ctx,
                 self.node,
                 self.thread_ctx,
             )
     self.local_namespace = local_namespace
Example #6
0
    def add_macro(self, macro: ParsedMacro, ctx: Dict[str, Any]):
        macro_name: str = macro.name

        macro_func: MacroGenerator = MacroGenerator(
            macro, ctx, self.node, self.thread_ctx
        )

        # internal macros (from plugins) will be processed separately from
        # project macros, so store them in a different place
        if macro.package_name in self.internal_package_names:
            self._add_macro_to(self.internal_packages, macro, macro_func)
        else:
            self._add_macro_to(self.packages, macro, macro_func)

            if macro.package_name == self.search_package:
                self.locals[macro_name] = macro_func
            elif macro.package_name == self.root_package:
                self.globals[macro_name] = macro_func
Example #7
0
    def add_macro(self, macro: ParsedMacro, ctx: Dict[str, Any]):
        macro_name: str = macro.name

        # MacroGenerator is in clients/jinja.py
        # a MacroGenerator object is a callable object that will
        # execute the MacroGenerator.__call__ function
        macro_func: MacroGenerator = MacroGenerator(macro, ctx, self.node,
                                                    self.thread_ctx)

        # internal macros (from plugins) will be processed separately from
        # project macros, so store them in a different place
        if macro.package_name in self.internal_package_names:
            self._add_macro_to(self.internal_packages, macro, macro_func)
        else:
            # if it's not an internal package
            self._add_macro_to(self.packages, macro, macro_func)
            # add to locals if it's the package this node is in
            if macro.package_name == self.search_package:
                self.locals[macro_name] = macro_func
            # add to globals if it's in the root package
            elif macro.package_name == self.root_package:
                self.globals[macro_name] = macro_func
Example #8
0
    def add_macro(self, macro: ParsedMacro, ctx: Dict[str, Any]):
        macro_name: str = macro.name
        macro_func: MacroGenerator = MacroGenerator(macro, ctx, self.node,
                                                    self.thread_ctx)

        # put plugin macros into the root namespace
        if macro.package_name in PACKAGES:
            namespace: str = GLOBAL_PROJECT_NAME
        else:
            namespace = macro.package_name

        if namespace not in self.packages:
            value: Dict[str, MacroGenerator] = {}
            self.packages[namespace] = value

        if macro_name in self.packages[namespace]:
            raise_duplicate_macro_name(macro_func.macro, macro, namespace)
        self.packages[namespace][macro_name] = macro_func

        if namespace == self.search_package:
            self.locals[macro_name] = macro_func
        elif namespace in {self.root_package, GLOBAL_PROJECT_NAME}:
            self.globals[macro_name] = macro_func
Example #9
0
    def execute_test(self, test: Union[CompiledDataTestNode,
                                       CompiledSchemaTestNode],
                     manifest: Manifest) -> int:
        context = generate_runtime_model(test, self.config, manifest)

        materialization_macro = manifest.find_materialization_macro_by_name(
            self.config.project_name, test.get_materialization(),
            self.adapter.type())

        if materialization_macro is None:
            missing_materialization(test, self.adapter.type())

        if 'config' not in context:
            raise InternalException(
                'Invalid materialization context generated, missing config: {}'
                .format(context))

        # generate materialization macro
        # simple `select(*)` of the compiled test node
        macro_func = MacroGenerator(materialization_macro, context)
        # execute materialization macro
        macro_func()
        # load results from context
        # could eventually be returned directly by materialization
        result = context['load_result']('main')
        table = result['table']
        num_rows = len(table.rows)
        if num_rows != 1:
            num_cols = len(table.columns)
            # since we just wrapped our query in `select count(*)`, we are in
            # big trouble!
            raise InternalException(
                f"dbt internally failed to execute {test.unique_id}: "
                f"Returned {num_rows} rows and {num_cols} cols, but expected "
                f"1 row and 1 column")
        return int(table[0][0])
Example #10
0
 def generator(self) -> Callable[[Dict[str, Any]], Callable]:
     """
     Returns a function that can be called to render the macro results.
     """
     return MacroGenerator(self)