python - 无法从通过 pip 和 setuptools 安装的 entry_points 脚本中执行 Python 脚本
问题描述
我按照这些说明创建了一个setup.py
可以安装 Python“可执行”脚本的文件。这是我的项目结构:
pkgexec/
setup.py
pkgexec/
__init__.py
__main__.py
core.py
根据说明,__main__.py
'smain()
方法是一个入口点setup.py
:
from setuptools import setup, find_packages
setup(
name="pkgexec",
version="0.2.0",
packages=find_packages(),
entry_points={ "console_scripts": ["pkgexec = pkgexec.__main__:main"]},
)
pkgexec/
我通过运行从目录中安装了包pip install -e .
。
到目前为止,一切都按预期工作。
不起作用的是通过这个“可执行”入口点执行 Python 脚本。你看,这个包的全部目的是运行 Python 脚本,从包中导入一堆东西,例如script.py
使用包中的功能pkgexec
并通过pkgexec
“可执行文件”“运行”:
pkgexec script.py -v arg1 arg2
以下是 的简化版本__main__.py
:
import argparse
import sys
from pkgexec import some_stuff
def main(args=None):
if args is None:
args = sys.argv[1:]
parser = argparse.ArgumentParser()
parser.add_argument('script', help='script to run via pkgexec')
parser.add_argument(...)
cli_args = parser.parse_args()
print(f'{__name__}: Running script {cli_args.script}')
exec(open(cli_args.script).read(), globals(), globals()) # <-- ???
print(f'{__name__}: Done')
if __name__ == '__main__':
sys.exit(main())
问题:什么都没有发生exec(open(cli_args.script).read())
(尝试了和没有, globals(), globals()
)。该脚本未执行。我在这里做错了什么?
我不喜欢的解决方法:
exec()
如果我不“安装”入口点,我可以运行脚本。不是一个选择。- 如果我通过
importlib
. 但这对于应该编写main()
方法的包的用户来说太严格了。
解决方案
调用exec()
. _ _ 我无法弄清楚runpy
标准库中有什么不同,但它确实有效。在我的情况下,解决方案是将exec()
调用替换为调用runpy.run_path()
.
这是修改后的__main__.py
脚本进行比较:
import argparse
import os
import runpy
import sys
from pkgexec import some_stuff
def main(args=None):
if args is None:
args = sys.argv[1:]
parser = argparse.ArgumentParser()
parser.add_argument('script', help='script to run via pkgexec')
parser.add_argument(...)
cli_args = parser.parse_args()
print(f'{__name__}: Running script {cli_args.script}')
mod = argparse.Namespace(
**runpy.run_path(cli_args.script,
run_name=os.path.basename(cli_args.script)))
print(f'{__name__}: Done')
if __name__ == '__main__':
sys.exit(main())
我将文件名作为run_name
参数发送给run_path
(这样脚本“知道”它的实际值而不是由设置__name__
的默认值)。<run_path>
runpy
请注意,此解决方案仅适用于要运行的脚本不包含if __name__ == '__main__'
部分(这正是我想要的)。
更新:可以通过执行幕后操作来实现相同的效果runpy
:compile()
首先是代码,然后是代码exec()
:
# mod = argparse.Namespace(
# **runpy.run_path(cli_args.script,
# run_name=os.path.basename(cli_args.script)))
code = compile(open(cli_args.script).read(),
os.path.basename(cli_args.script),
'exec')
exec(code)
推荐阅读
- amazon-web-services - 如何管理认知令牌生命周期
- php - Wordpress Cron 作业未运行
- python - python 参数解析器。可执行文件和源代码文件作为参数
- php - 使用旧版本数据库的新版本 Laravel 项目
- wireshark - 将wireshark与ns3一起使用
- libgdx - 在 libgdx 中设置文本 alpha 的最佳方法
- python - 试图找到这种特殊情况的正则表达式?我也可以在不创建组的情况下解析它吗?
- php - 如何在(高级)自定义字段更新上添加订单注释?
- ip-camera - 在霍尼韦尔 HBL6GR2 上查找实时快照的 URL
- php - 如何在函数中使用动态变量与 PHP 和 MySQL 中的查询