Invoke 2.2.0版本无法导入同级scripts目录的Python技术求助
Invoke 2.x版本中同级scripts目录导入失败的兼容方案
问题概述
我们使用invoke模块管理大量Python脚本,invoke从tasks子目录加载任务脚本并支持结构化调用。之前在任务脚本中通过from scripts import useful_script_1导入同级scripts目录下的通用脚本,在invoke 2.0.0版本可正常运行,但升级到2.2.0版本后,scripts目录无法被识别,触发导入错误。
目录结构
-- scripts -- __init__.py -- useful_script_1.py -- useful_script_2.py -- ... -- tasks -- __init__.py -- task_1.py -- task_2.py
报错信息
Traceback (most recent call last): File "c:\program files\python39\lib\runpy.py", line 197, in _run_module_as_main return _run_code(code, main_globals, None, File "c:\program files\python39\lib\runpy.py", line 87, in _run_code exec(code, run_globals) File "C:\Program Files\Python39\Scripts\inv.exe\__main__.py", line 7, in <module> File "c:\program files\python39\lib\site-packages\invoke\program.py", line 387, in run self.parse_collection() File "c:\program files\python39\lib\site-packages\invoke\program.py", line 479, in parse_collection self.load_collection() File "c:\program files\python39\lib\site-packages\invoke\program.py", line 716, in load_collection module, parent = loader.load(coll_name) File "c:\program files\python39\lib\site-packages\invoke\loader.py", line 91, in load spec.loader.exec_module(module) File "<frozen importlib._bootstrap_external>", line 855, in exec_module File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed File "c:\projects\my_project\tasks\__init__.py", line 2, in <module> from scripts import useful_script_1 ImportError: cannot import name 'useful_script_1' from 'scripts' (unknown location)
调用方式
两种调用方式均触发错误:
- 任意路径调用:
inv -r <tasks父目录路径> function parameters - 在tasks父目录直接调用:
inv function parameters
需求
不愿长期停留在旧版本,无法更换invoke或调整现有目录结构(已提交GitHub issue但无回应),寻求无需大幅改动代码的兼容方案。
兼容方案
方案1:手动修改sys.path(推荐)
在tasks/__init__.py的开头添加代码,将scripts所在的父目录加入Python模块搜索路径:
import sys from pathlib import Path # 获取当前tasks目录的父目录(即scripts所在的目录) root_dir = Path(__file__).resolve().parent.parent # 仅当目录不在sys.path中时添加,避免重复 if str(root_dir) not in sys.path: sys.path.append(str(root_dir)) # 正常导入scripts模块 from scripts import useful_script_1
这种方式无需修改调用命令,且对现有代码侵入极小,仅需在tasks的初始化文件中添加几行代码。
方案2:使用相对导入
如果tasks和scripts的父目录可作为Python包(即父目录下添加__init__.py),可使用相对导入语句替换原有导入:
from ..scripts import useful_script_1
注意:这种方式依赖Python的包导入机制,需确保invoke将tasks作为包的一部分加载,若父目录原本没有__init__.py,需新增一个空文件。
方案3:设置PYTHONPATH环境变量
在调用invoke前,先将tasks的父目录设置为PYTHONPATH:
- Windows(命令提示符):
set PYTHONPATH=<tasks父目录的绝对路径> && inv function parameters - Linux/macOS(终端):
PYTHONPATH=<tasks父目录的绝对路径> inv function parameters
这种方式无需修改代码,但每次调用都需设置环境变量,适合临时测试或封装到批处理/Shell脚本中统一调用。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

