Python 气流/组合器-在压缩打包的DAG中找不到模板

Python 气流/组合器-在压缩打包的DAG中找不到模板,python,jinja2,airflow,google-cloud-composer,Python,Jinja2,Airflow,Google Cloud Composer,我在让模板化SQL文件在Composer中工作时遇到问题。我认为问题与我将DAG打包为zip文件以便包含额外代码的事实有关 我从这里开始(只是展示相关部分): 文件结构如下所示: /dags/my_dag_file.py /dags/sql/query_file.sql /dags/my_pkg/ /dags/my_pkg/__init__.py /dags/my_pkg/extra_module.py 我像这样压缩它并将其复制到Composer dags文件夹: zip -r my_zip_

我在让模板化SQL文件在Composer中工作时遇到问题。我认为问题与我将DAG打包为zip文件以便包含额外代码的事实有关

我从这里开始(只是展示相关部分):

文件结构如下所示:

/dags/my_dag_file.py
/dags/sql/query_file.sql
/dags/my_pkg/
/dags/my_pkg/__init__.py
/dags/my_pkg/extra_module.py
我像这样压缩它并将其复制到Composer dags文件夹:

zip -r my_zip_file.zip *.py my_pkg/ sql/
这在本地工作,但在Composer上部署时出现错误:

TemplateNotFound: sql/query_file.sql
我确信我在zip中包含了SQL文件。我还尝试将其移动到根文件夹(没有sql/子目录),但得到了相同的结果

我在某个地方读到,在实例化DAG对象时,需要设置
模板\u searchpath
。我没能成功地做到这一点。当我尝试一个相对路径(
sql
)时,我会得到更多的
TemplateNotFound
错误。当我尝试下面的绝对路径时,得到的是
而不是目录

以下是我尝试过的:

dag = DAG('my_dag',
      default_args=default_args,
      schedule_interval=schedule_interval,
      template_searchpath = os.path.dirname(__file__) + "/sql"
)

task0 = BigQueryOperator(
     task_id='task0',
     use_legacy_sql=False,
     bql='query_file.sql',
     bigquery_conn_id=bigquery_conn_id,
     dag=dag)
我还尝试将“sql”作为任务路径的一部分,而不是模板搜索路径,并且再次尝试将所有内容移动到根级别,并得到相同的“not a directory”错误

据我所知,问题与文件包含在zip中这一事实有关
\uuuu file\uuuu
返回
/home/aiffair/gcs/dags/my\u zip\u file.zip/my\u dag\u file.py
。但是,
os.listdir(os.path.dirname(_文件__))
抛出相同的
而不是目录
错误。因此,可能因为我们在zip存档中执行,所以不能以相同的方式使用文件夹和路径。也许Jinja在这件事上被绊倒了。。。?或者在打包zip文件时,可能还有更多的事情要做

[2018-06-20 15:35:34,837] {base_task_runner.py:98} INFO - Subtask: Traceback (most recent call last):
[2018-06-20 15:35:34,838] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/bin/airflow", line 27, in <module>
[2018-06-20 15:35:34,840] {base_task_runner.py:98} INFO - Subtask:     args.func(args)
[2018-06-20 15:35:34,841] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/airflow/bin/cli.py", line 392, in run
[2018-06-20 15:35:34,841] {base_task_runner.py:98} INFO - Subtask:     pool=args.pool,
[2018-06-20 15:35:34,842] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/airflow/utils/db.py", line 50, in wrapper
[2018-06-20 15:35:34,843] {base_task_runner.py:98} INFO - Subtask:     result = func(*args, **kwargs)
[2018-06-20 15:35:34,843] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/airflow/models.py", line 1477, in _run_raw_task
[2018-06-20 15:35:34,844] {base_task_runner.py:98} INFO - Subtask:     self.render_templates()
[2018-06-20 15:35:34,844] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/airflow/models.py", line 1760, in render_templates
[2018-06-20 15:35:34,845] {base_task_runner.py:98} INFO - Subtask:     rendered_content = rt(attr, content, jinja_context)
[2018-06-20 15:35:34,847] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/airflow/models.py", line 2481, in render_template
[2018-06-20 15:35:34,848] {base_task_runner.py:98} INFO - Subtask:     return jinja_env.get_template(content).render(**context)
[2018-06-20 15:35:34,849] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/jinja2/environment.py", line 812, in get_template
[2018-06-20 15:35:34,849] {base_task_runner.py:98} INFO - Subtask:     return self._load_template(name, self.make_globals(globals))
[2018-06-20 15:35:34,850] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/jinja2/environment.py", line 774, in _load_template
[2018-06-20 15:35:34,851] {base_task_runner.py:98} INFO - Subtask:     cache_key = self.loader.get_source(self, name)[1]
[2018-06-20 15:35:34,852] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/jinja2/loaders.py", line 171, in get_source
[2018-06-20 15:35:34,854] {base_task_runner.py:98} INFO - Subtask:     f = open_if_exists(filename)
[2018-06-20 15:35:34,855] {base_task_runner.py:98} INFO - Subtask:   File "/usr/local/lib/python2.7/site-packages/jinja2/utils.py", line 151, in open_if_exists
[2018-06-20 15:35:34,856] {base_task_runner.py:98} INFO - Subtask:     return open(filename, mode)
[2018-06-20 15:35:34,856] {base_task_runner.py:98} INFO - Subtask: IOError: [Errno 20] Not a directory: '/home/airflow/gcs/dags/my_zip_file.zip/sql/query_file.sql'
[2018-06-20 15:35:34837]{base_task_runner.py:98}信息-子任务:回溯(最近一次调用):
[2018-06-20 15:35:34838]{base_task_runner.py:98}信息-子任务:文件“/usr/local/bin/aiffair”,第27行,in
[2018-06-20 15:35:34840]{base_task_runner.py:98}信息-子任务:args.func(args)
[2018-06-20 15:35:34841]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/afflow/bin/cli.py”,第392行,运行中
[2018-06-20 15:35:34841]{base_task_runner.py:98}INFO-子任务:pool=args.pool,
[2018-06-20 15:35:34842]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/afflow/utils/db.py”,第50行,在包装器中
[2018-06-20 15:35:34843]{base_task_runner.py:98}信息-子任务:result=func(*args,**kwargs)
[2018-06-20 15:35:34843]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/afflow/models.py”,第1477行,在_run_raw_task中
[2018-06-20 15:35:34844]{base_task_runner.py:98}INFO-子任务:self.render_templates()
[2018-06-20 15:35:34844]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/afflow/models.py”,第1760行,在渲染模板中
[2018-06-20 15:35:34845]{base_task_runner.py:98}INFO-子任务:rendered_content=rt(attr,content,jinja_上下文)
[2018-06-20 15:35:34847]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/afflow/models.py”,第2481行,在渲染模板中
[2018-06-20 15:35:34848]{base_task_runner.py:98}信息-子任务:返回jinja_环境获取模板(内容).render(**上下文)
[2018-06-20 15:35:34849]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/jinja2/environment.py”,第812行,在get_模板中
[2018-06-20 15:35:34849]{base_task_runner.py:98}信息-子任务:返回self.\u加载模板(名称,self.make_globals(全局))
[2018-06-20 15:35:34850]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/jinja2/environment.py”,第774行,在加载模板中
[2018-06-20 15:35:34851]{base_task_runner.py:98}INFO-子任务:cache_key=self.loader.get_source(self,name)[1]
[2018-06-20 15:35:34852]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/jinja2/loaders.py”,第171行,在get_source中
[2018-06-20 15:35:34854]{base_task_runner.py:98}INFO-子任务:f=open_如果存在(文件名)
[2018-06-20 15:35:34855]{base_task_runner.py:98}信息-子任务:文件“/usr/local/lib/python2.7/site packages/jinja2/utils.py”,第151行,如果存在
[2018-06-20 15:35:34856]{base_task_runner.py:98}信息-子任务:返回打开状态(文件名,模式)
[2018-06-20 15:35:34856]{base_task_runner.py:98}信息-子任务:IOError:[Errno 20]不是目录:'/home/aiffort/gcs/dags/my_zip_file.zip/sql/query_file.sql'

首先,确认ZIP中的文件结构符合预期

然后,尝试获取路径:

os.path.join(os.path.dirname(os.path.realpath(__file__)),"sql","query_file.sql")

这就是我们在Airflow部署中获取查询路径的方式。

使用文件的绝对路径更安全,如下所示
sql=os.path.abspath(os.path.join(os.path.dirname(\uuuuu file\uuuu),“sql/query\u file.sql”)


因为操作员/任务可能会在新创建的临时目录下运行命令/方法,该临时目录不会复制依赖项。勾选a,您就会明白。

看起来气流当前(从1.10版本开始)不支持从压缩DAG加载模板,因为它只使用
jinja2.FileSystemLoader
加载模板(请参阅)

os.path.join(os.path.dirname(os.path.realpath(__file__)),"sql","query_file.sql")