如何解决在 Python 中使用入口点时,区分导入的包和在 CLI 上运行的包
我有一个最常用作 CLI 工具的 python 包,但有时我会出于自己的目的将它作为库运行。 (例如,将其转换为网络应用或用于单元测试)
例如,当用作 CLI 命令时,我想 sys.exit(1)
在错误时向最终用户提供有关异常的很好的错误消息,但是 raise
在用作 CLI 命令时为异常导入的库。
我在 entry_points
中使用了 setup.py
:
entry_points={
'console_scripts': [
'jello=jello.cli:main'
]
}
这很好用,但我无法轻易区分包是在 CLI 中运行还是导入,因为 __name__
始终是 jello.cli
。这是因为入口点基本上是照常导入包。
我尝试创建一个 __main__.py
文件并将我的入口点指向那里,但这似乎没有什么区别。
我正在考虑检查 sys.argv[0]
以查看我的程序名称是否存在,但这似乎是一个脆弱的黑客。 (万一用户给命令或其他东西起了别名)还有其他想法还是我做错了?目前,我一直在向我的函数传递一个 as_lib
参数,因此它们的行为会根据它们是作为模块加载还是从 CLI 运行而有所不同,但我想摆脱这种情况。
解决方法
我相信你想要的在 Python 中被称为“主守卫”。该模块在任何给定时间都知道其名称。如果模块是从 CLI 执行的,则其名称为 __main__
。因此,您可以做的是将您想要的所有功能放在模块级别的某个函数中,然后您可以在“主守卫”中以不同的方式调用它,而不是将其称为库。这是“主卫”的样子:
def myfunc(thing,stuff):
if not stuff:
raise MyExc
if __name__ == '__main__':
try:
myfunc(x,y)
except MyExc:
sys.exit(1)
这里,只有在模块作为脚本从命令行执行时,才会在出错时调用 sys.exit。
,这是可同时用作 cli
和库的包结构的最小示例。
这是目录结构:
egpkg/
├── setup.py
└── egpkg/
├── __init__.py
├── lib.py
└── cli.py
这是 entry_points
中的 setup.py
。它与您的相同:
entry_points={
"console_scripts": [
"egpkg_cli=egpkg.cli:main",],},
__init__.py
:
from .lib import func
cli.py
您将在此处定义 CLI 并处理您在其他 Python 文件中定义的函数引发的任何问题。
import sys
import argparse
from egpkg import func
def main():
p = argparse.ArgumentParser()
p.add_argument("a",type=int)
args = vars(p.parse_args())
try:
result = func(**args)
except Exception as e:
sys.exit(str(e))
print(f"Got result: {result}",file=sys.stdout)
lib.py
这是定义库的核心的地方,您应该以您期望用户使用它的方式使用该库。当您获得不起作用的值/输入时,您可以raise
它。
def func(a):
if a == 0:
raise ValueError("Supplied value can't be 0")
return 10 / a
然后在 python 控制台或脚本中,您可以:
In [1]: from egpkg import func
In [2]: func(2)
Out[2]: 5.0
In [3]: func(0)
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
File "/tmp/egpkg/egpkg/lib.py",line 3,in func
raise ValueError("Supplied value can't be 0")
ValueError: Supplied value can't be 0
Supplied value can't be 0
来自 CLI:
(venv) ~ egpkg_cli 2
Got result: 5.0
(venv) ~ egpkg_cli 0
Supplied value can't be 0
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。