Python “巨蟒狮身人面像”;模块执行模块级语句,它可能会调用sys.exit();

Python “巨蟒狮身人面像”;模块执行模块级语句,它可能会调用sys.exit();,python,python-sphinx,argparse,Python,Python Sphinx,Argparse,我尝试使用Sphinx来记录我的代码。但我看到了错误: 模块执行模块级语句,并可能调用sys.exit() 我发现此错误与以下代码有关: import argparse # parse command line arguments parser = argparse.ArgumentParser(description='AWS VPN status checker.') parser.add_argument('account', type=str, help='AWS account nam

我尝试使用Sphinx来记录我的代码。但我看到了错误:

模块执行模块级语句,并可能调用sys.exit()

我发现此错误与以下代码有关:

import argparse
# parse command line arguments
parser = argparse.ArgumentParser(description='AWS VPN status checker.')
parser.add_argument('account', type=str, help='AWS account name.')
parser.add_argument('region', type=str, help='region of VPN tunnel.')
parser.add_argument('ipaddress', type=str, help='Tunnel IP address.')
parser.add_argument("-d", "--debug", help="debug", action="store_true")
args = parser.parse_args()
我认为这与导入模块时的“副作用”有关


为什么不好?我该如何解决这个问题?

在我的例子中,我有一个第三方库导入的子模块,该库是问题的根源(
pyautogui
)。 但我花了几个小时试图找出原因,因为错误如下:

FOO.a import error the module executes module level statement and it might call sys.exit()
FOO.b import error the module executes module level statement and it might call sys.exit()
FOO.d.foo import error the module executes module level statement and it might call sys.exit()
FOO.d.bar import error the module executes module level statement and it might call sys.exit()
FOO.d.baz import error the module executes module level statement and it might call sys.exit()
FOO.d import error the module executes module level statement and it might call sys.exit()
FOO import error the module executes module level statement and it might call sys.exit()
虽然我的包结构与此类似:

FOO
├── a
├── b
│   ├── ci
|   └── __init__.py|
└── d
    ├── foo
    ├── bar
    ├── baz
    └── __init__.py

其中
a
b
中有
import d
字符串。并且
import pyautogui
位于
FOO.d.bar
子模块中。

Sphinx警告是由前面的
parse_args()
错误引起的效果。调用
arg\u parse()
函数,在预期要分析的参数中找到一个正常错误,并且该函数存在

在分析命令行时,parse_args()检查各种错误,包括不明确的选项、无效的类型、无效的选项、错误数量的位置参数等。遇到此类错误时,它会退出并打印错误以及用法消息:

在生成Sphinx文档时,最可能的原因是
parse_args()
退出,因为您真正调用的是
Sphinx build
生成html
。因此,在python shell上执行的是以下签名:

概要

sphinx构建[选项][filenames…]

这意味着您可能没有使用编码为
ArgumentParser
所需的参数执行脚本。运行
sphinx build
make html
,包括
ArgumentParser()
中所需的命令行参数
argumentparse()
,或者在生成文档时不调用
arg\u parse()

如何解决此问题?

一种可能的方法是:

entry\u script.py

从系统导入argv
从pathlib导入路径
导入命令行模块
#检查命令行包含的内容可能很有用。
打印(argv)
示例_ARGS=['-i','../in_dir_test','-o','out_dir_test']
#剧本。
如果名称=“\uuuuu main\uuuuuuuu”:
#默认名称空间
打印(命令行参数参数参数)
#命令行
cmd_line_module.set_args()
打印(命令行参数参数参数)
#测试用例
cmd_line_module.set_args(示例_args)
打印(命令行参数参数参数)
#斯芬克斯建造或制造。
elif路径(argv[0])。名称==“sphinx构建”或路径(argv[0])。名称==“build.py”:
cmd_line_module.set_args(示例_args)
#仅限模块。
其他:
cmd_line_module.set_args(示例_args)
cmd\u line\u module.py

import argparse
_DEFAULT=argparse.Namespace(in\u dir=None,out\u dir=None)
args=\u默认值
def命令行参数()
parser=argparse.ArgumentParser(prog='entry\u script',description='Does magic:')。)
parser.add_参数(“-i”,”--in_dir”,help=“输入目录/文件。使用绝对或相对路径。”)
parser.add_参数(“-o”,“--out_dir”,help=“输出目录。使用绝对或相对路径。”)
返回解析器
def set_参数(命令行=无):
解析器=命令行参数()
全局args
args=parser.parse_args(cmd_行)
关于解决方案的一些注释可能对读者有用:

1.cmd\u line\u module.py将
args
作为模块级变量进行维护,以尽可能类似于示例。可以找到
argparse
的特定Sphinx扩展

2.
args
使用默认值可能比较方便,这是一个建议。(预期的默认值有助于导入模块中的测试)

3.测试
\uuuuu main\uuuuuu
sphinx build
可能没有必要,这取决于3
if
测试仅用于为问题添加上下文

4.使用
DEFAULT_ARGS
演示如何使用
parse_ARGS()
而无需读取
sys.argv
,以及如何运行
sphinx build
如果uuuuu name==“uuuu main”:

5.sphinx构建脚本的名称和路径可能因操作系统而异

最后一点注意:如果您喜欢编写自初始化其变量的模块(如我),请特别注意在导入可能具有依赖于它的变量的模块之前运行
parse_args()

6.1

模块可以包含可执行语句以及函数定义。这些语句用于初始化模块。只有在import语句中第一次遇到模块名时,才会执行这些命令。(如果文件作为脚本执行,它们也会运行。)


我也有这个问题。我的解决方案是在argparse代码之前向脚本中添加以下if语句:

if __name__ == "__main__":
   parser = argparse.ArgumentParser(description="some description", formatter_class=RawTextHelpFormatter)
   parser.add_argument(....)
   args = parser.parse_args()
   ......

“为什么不好”-因为Sphinx导入您的代码来分析它,如果有代码在模块的顶层运行,那么根据消息,它可以在Sphinx完成之前退出。“如何修复此问题?”-没有在顶层运行代码。将它移动到一个函数中,并添加
if uuuuu name_uuu=='\uuuu main\uuuu'
来调用它(请参阅)。我去掉了导致问题的第三方库。