首页 > 其他分享 >dbt macro 的执行简单说明

dbt macro 的执行简单说明

时间:2024-04-01 09:04:02浏览次数:26  
标签:None name macro self context 简单 dbt

BaseAdapter 中包含了一个adapter 实际运行依赖的转换,链接处理,当然也包含了macro 的执行,具体方法有直接的execute_macro
ModelRunner 中的materialization_macro(run 命令)还有run-operation 中RunOperationTask 的_run_unsafe 方法

ModelRunner call_macro 处理

  • 参考调用
 def execute(self, model, manifest):
        context = generate_runtime_model_context(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:
            raise MissingMaterializationError(
                materialization=model.get_materialization(), adapter_type=self.adapter.type()
            )
 
        if "config" not in context:
            raise DbtInternalError(
                "Invalid materialization context generated, missing config: {}".format(context)
            )
        context_config = context["config"]
 
        mat_has_supported_langs = hasattr(materialization_macro, "supported_languages")
        model_lang_supported = model.language in materialization_macro.supported_languages
        if mat_has_supported_langs and not model_lang_supported:
            str_langs = [str(lang) for lang in materialization_macro.supported_languages]
            raise DbtValidationError(
                f'Materialization "{materialization_macro.name}" only supports languages {str_langs}; '
                f'got "{model.language}"'
            )
 
        hook_ctx = self.adapter.pre_model_hook(context_config)
        try:
           # 此处主要处理了materialization_macro 相关的
            result = MacroGenerator(
                materialization_macro, context, stack=context["context_macro_stack"]
            )()
        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)
  • MacroGenerator 处理
def __call__(self, *args, **kwargs):
    with self.track_call():
        return self.call_macro(*args, **kwargs)
  • call_macro 处理
def call_macro(self, *args, **kwargs):
    # called from __call__ methods
    if self.context is None:
        raise DbtInternalError("Context is still None in call_macro!")
    assert self.context is not None
   # 先获取macro,使用动态创建macro 模块
    macro = self.get_macro()
    with self.exception_handler():
        try:
            return macro(*args, **kwargs)
        except MacroReturn as e:
            return e.value

RunOperationTask 调用

实际上就是execute_macro 参考处理

  • 参考代码
    dbt/adapters/base/impl.py
def execute_macro(
    self,
    macro_name: str,
    macro_resolver: Optional[MacroResolverProtocol] = None,
    project: Optional[str] = None,
    context_override: Optional[Dict[str, Any]] = None,
    kwargs: Optional[Dict[str, Any]] = None,
) -> AttrDict:
    """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.
    """
 
    if kwargs is None:
        kwargs = {}
    if context_override is None:
        context_override = {}
    # 会基于dbt 实现的macro_resolver 
    resolver = macro_resolver or self._macro_resolver
    if resolver is None:
        raise DbtInternalError("Macro resolver was None when calling execute_macro!")
   # 同时dbt 还包装了一个MacroContextGeneratorCallable
    if self._macro_context_generator is None:
        raise DbtInternalError("Macro context generator was None when calling execute_macro!")
   # 首先通过resolver查找macro 
    macro = resolver.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 DbtRuntimeError(
            'dbt could not find a macro with the name "{}" in {}'.format(
                macro_name, package_name
            )
        )
 
    macro_context = self._macro_context_generator(macro, self.config, resolver, project)
    macro_context.update(context_override)
    #  dbt_common/clients/jinja.py 中的CallableMacroGenerator 类进行macro 函数的包装,通过__call__ 进行处理的
    # 实际上此处MacroGenerator是CallableMacroGenerator 的子类,实际处理与上边的是类似的
    macro_function = CallableMacroGenerator(macro, macro_context)
 
    with self.connections.exception_handler(f"macro {macro_name}"):
       # 执行macro
        result = macro_function(**kwargs)
    return result
  • get_macro 处理
    dbt_common/clients/jinja.py 中,此处有一个比较有意思的地方,因为默认macro 是不带dbt_macro__的,但是get_dbt_macro_name 会包含一个前缀,实际上是dbt 自己开发了一个MacroFuzzParser,对于macro 添加了一个前缀
def get_macro(self):
    name = self.get_name()
    template = self.get_template()
    # make the module. previously we set both vars and local, but that's
    # redundant: They both end up in the same place
    # make_module is in jinja2.environment. It returns a TemplateModule
    module = template.make_module(vars=self.context, shared=False)
    macro = module.__dict__[get_dbt_macro_name(name)]
 
    return macro
  • MacroFuzzParser 处理
class MacroFuzzParser(jinja2.parser.Parser):
    def parse_macro(self):
        node = jinja2.nodes.Macro(lineno=next(self.stream).lineno)
 
        # modified to fuzz macros defined in the same file. this way
        # dbt can understand the stack of macros being called.
        #  - @cmcarthur
        # 此处添加了自己的prefix  dbt_macro__
        node.name = get_dbt_macro_name(self.parse_assign_target(name_only=True).name)
 
        self.parse_signature(node)
        node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
        return node
  • MacroFuzzParser 的使用
    MacroFuzzEnvironment 扩展类中,默认dbt 使用的是MacroFuzzEnvironment 这个env
class MacroFuzzEnvironment(jinja2.sandbox.SandboxedEnvironment):
    def _parse(self, source, name, filename):
        return MacroFuzzParser(self, source, name, filename).parse()

说明

dbt 对于macro 的处理直接使用的是文字符串模版模式,同时对于macro 的解析添加了自己的实现,灵活性上也很方便,同时对于项目的macro 会在之前实际命令之前先生成解析好(包含了依赖处理),以上只是简单说明关于自行,后边会说明下dbt 对于jinja2的包装,同时
还有macrocontext macro resovler

参考资料

dbt/adapters/base/impl.py (adapters 包)
dbt_common/clients/jinja.py (common 包)

标签:None,name,macro,self,context,简单,dbt
From: https://www.cnblogs.com/rongfengliang/p/18081279

相关文章

  • 渲染农场最简单三个步骤是什么?
    ​在涉及三维图像渲染时,渲染农场是设计师经常围绕的一个话题。通过渲染农场可实现一个高效的渲图速度,帮助设计师节省大量的时间。渲染农场又分为本地渲染与云渲染农场,那么渲染农场使用过程简单的操作是什么一起来看看吧!本地渲染农场搭建步骤用户如何多余的闲置电脑,可自行搭建一......
  • CompletableFuture 异步编排的简单使用
    目录1、创建异步对象2、计算完成时回调方法3、handle方法4、线程串行化方法5、两任务组合-都要完成6、两任务组合-一个完成7、多任务组合如果在我们的业务中某些功能需要其他一些功能执行完成之后才能开始执行(比如获取其他功能的返回结果),这样就需要用到异步编排......
  • 简单的OCR光学字符识别(可用于毕业设计)
    OCR作用就是提取图片中的文本转化成文本形式,主要分为两个部分,第一个部分:检测文字所在的位置,第二个部分:识别文本区域内容。代码简介其中test_images用于存放你想要识别的图像test_result用于存放识别的结果结果展示三张图分别为,需要识别的图片,识别图片的准确率,以及识别......
  • C语言----简单讲解编译与链接
        大家好,这次我们来讲讲我们写下代码后,源代码是变为执行文件的,这里我们将会使用用另外一种编译器(gcc),但是嘞因为鄙人对电脑的理解还是比较少的,所以对于我们进行对比的编译器(gcc)鄙人只能提供代码,以及一些网络上其他博主的图文,希望大家理解这样更加方便大家了解。(如果大......
  • ElasticSearch 简单认识
    概念elastic的集群相当于mysql的数据库elastic的索引相当于mysql的表elastic的文档相当于mysql的数据行elastic的字段相当于mysql的列下列操作是在kibana中执行的。我的腾讯云中的用docker拉了elasticsearch和kibana了,通过http://43.143.182.32:9200/访问el......
  • dbt this macro 处理简单说明
    dbtthismacro提供了一种方便的对于当前模型展现的方法,可以使用在增量模型以及pre&posthooks中this实际是就类似ref('<the_current_model>')是一个relation包含了database,schema以及模型标识使用示例一个增量处理的,基于this可以方便的引用模型{{config(mater......
  • 使用Python清理重复音乐文件:一个简单的解决方案
    在日常生活中,我们经常会从各种渠道获取音乐资源,例如购买、下载或者从朋友那里借来。然而,有时候我们可能会发现自己的音乐库里存在着大量的重复音乐文件,这不仅浪费了存储空间,而且在听歌的时候也会带来不便。针对这个问题,我编写了一个简单的Python程序来帮助清理重复的音乐文件。为......
  • 简单了解组策略
    实验介绍:组策略在部分意义上是控制用户可以或不能在计算机上做什么,例如:施行密码复杂性策略避免用户选择过于简单的密码。一:基于本地的组策略在dns1上win+r打开运行对话框,输入命令gpedit.msc这样就能打开本地组策略编辑器这里可以看到计算机设置和用户设置这里的配置只对本......
  • STM32中RFID模块(MFRC522)简单应用
    1.前言​ 此篇只是对RFID模块的简单概述以及应用,没有原理,对提供的店家提供的代码,进行注释,以及简单使用流程2.函数//功能:寻卡//参数说明:req_code[IN]:寻卡方式//0x52=寻感应区内所有符合14443A标准的卡//0x26=寻未进入休眠状......
  • linux---简单模拟实现shell(内置命令的解析)
    准备工作的知识我们要模拟实现一个命令行解释器的话,需要运用进程替换的知识。我们用我,如花,王婆,实习生的例子来说:这里的“我”就是程序员,如花是操作系统,王婆是命令行解释器bash,实习生则是子进程,我们用户想要和操作系统交流的话,就需要通过bash,而命令行解释器(王婆)不会自己去执行......