如何解决Airflow PythonVirtualEnvOperator无法导入外部类的问题
PythonVirtualenvOperator运行时会创建和Airflow主环境完全隔离的全新虚拟环境,默认不会将Airflow DAG目录、本地自定义脚本存放路径加入虚拟环境的Python模块搜索路径,也不会自动同步本地自定义.py文件到虚拟环境运行上下文,因此找不到你写的modelsFile模块。而PythonOperator直接复用Airflow Worker进程的Python环境运行,DAG目录默认就在Python搜索路径中,所以导包不会报错。
手动追加模块搜索路径
最简便的方式是在调用函数内手动将存放modelsFile.py的目录加入系统路径,注意要保证虚拟环境运行时能访问到这个路径(Airflow Worker节点上该路径真实存在、权限足够):import os import sys def get_info(): # 替换为你实际存放modelsFile.py的目录绝对路径,一般是Airflow的DAG根目录,比如/opt/airflow/dags dag_dir = "/你的实际DAG存放目录绝对路径" if dag_dir not in sys.path: sys.path.append(dag_dir) from modelsFile import model_config print("version: ")如果是Airflow 2.0以上版本,也可以直接给算子传
python_path参数,不用改函数内部逻辑,同时开启dill序列化保证依赖文件能正常传递到虚拟环境:import os DAG_DIR = os.path.abspath(os.path.dirname(__file__)) get_info_operator = PythonVirtualenvOperator( task_id='get_info_task', python_callable=get_info, python_path=[DAG_DIR], use_dill=True, system_site_packages=False, dag=dag )注意如果
modelsFile.py存放在子文件夹中,需要给对应子文件夹添加__init__.py空文件,让Python能识别为合法包;同时Linux环境下文件名大小写严格敏感,导入名要和实际文件名完全一致,避免因大小写不匹配报错。把自定义模块作为依赖安装到虚拟环境
如果自定义模块需要在多个任务复用,可以将modelsFile相关代码打成标准Python安装包,通过requirements参数让算子创建虚拟环境时自动安装,彻底避免路径问题:get_info_operator = PythonVirtualenvOperator( task_id='get_info_task', python_callable=get_info, # 支持写本地包路径、私有源包名、公网包名 requirements=["./libs/models_file-0.1.0.tar.gz"], dag=dag )替换为非隔离类算子
如果不需要强隔离的虚拟环境,直接使用PythonOperator,或者用ExternalPythonOperator指向提前装好所有依赖(包含自定义模块)的Python解释器路径即可,也不会出现这类导包问题。
内容的提问来源于stack exchange,提问作者Dharsini

