Python命令行应用pip安装正常但直接执行脚本报错的解决求助
解决Click CLI项目中直接运行脚本与entry_points共存的问题
我之前也碰到过这个一模一样的头疼问题,本质是Python直接运行单个脚本时的路径处理逻辑,和把代码作为包导入时的逻辑不一样导致的。咱们一步步来解决:
问题根源拆解
- 当你用
pip install -e .安装后,entry_points是从系统包路径里导入mycli.cli,这时候from mycli import __application__能正常找到mycli包的__init__.py。 - 但直接运行
python mycli/cli.py时,Python会把cli.py所在的mycli/mycli/目录当作顶层,不会把外层的mycli/加入包搜索路径,所以from mycli import ...会去系统路径找,自然找不到你项目里的__application__。 - 你改成
from .mycli import __application__是找错地方了——__application__是在同目录的__init__.py里,不是mycli.py里,而且就算改成正确的相对导入from . import __application__,直接运行脚本时Python会认为__main__不是一个包,照样报错。
方案一:让cli.py兼容两种运行方式
修改mycli/mycli/cli.py的导入部分,加入路径兼容逻辑:
# 先尝试正常的包导入(用于entry_points或python -m运行) try: from mycli import __application__ except ImportError: # 直接运行脚本时,把外层mycli目录加入包搜索路径 import sys from pathlib import Path # 获取当前脚本的父目录的父目录(也就是外层mycli/) sys.path.append(str(Path(__file__).resolve().parent.parent)) from mycli import __application__ import click import sys @click.group() def my_cli(): """ rest of my code """ if __name__ == "__main__": sys.exit(my_cli())
这样调整后:
- 用
my-cli命令(entry_points)运行时,正常导入没问题 - 直接运行
python mycli/cli.py时,会自动把项目根目录加入路径,也能正确导入__application__
方案二:优化项目结构,符合Python包规范(推荐)
更优雅的方式是调整结构,支持用python -m运行,同时保留entry_points:
1. 调整目录结构(可以删掉多余的mycli.py,如果它没用的话)
mycli ├── mycli │ ├── __init__.py │ ├── cli.py │ └── __main__.py # 新增这个文件 └── setup.py
2. 编写__main__.py
在mycli/mycli/__main__.py里写入:
from mycli.cli import my_cli import sys if __name__ == "__main__": sys.exit(my_cli())
3. 保留cli.py的原导入
cli.py里还是用原来的from mycli import __application__就行。
这样你可以:
- 用
my-cli命令正常运行(entry_points不受影响) - 用
python -m mycli从项目根目录运行(符合Python包的标准运行方式) - 如果还是想支持直接运行
cli.py,可以把方案一的导入逻辑也加上
额外提示
如果你那个mycli/mycli/mycli.py没有特殊用途,建议删掉它,避免和包名重名导致混淆。
内容的提问来源于stack exchange,提问作者DazedAndConfused
相关产品推荐
相关产品推荐

