You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 01:18:12