启动 Python 调试器,同时将模块作为脚本执行

Posted

技术标签:

【中文标题】启动 Python 调试器,同时将模块作为脚本执行【英文标题】:Launch Python debugger while simultaneously executing module as script 【发布时间】:2013-08-10 21:08:52 【问题描述】:

在开发 Python 包时,使用-m 选项将包内的模块作为脚本运行以进行快速测试非常方便。例如,对于 somepackage 内部有模块 somemodule.py,调用

python -m somepackage.somemodule

somepackage 所在的目录运行somemodule.py,就好像子模块是__main__。如果包使用如here 所述的显式相对导入,则使用此调用语法尤其重要。

同样,使用-m选项调试脚本也很方便,如

python -m pdb somescript.py

有没有办法同时做这两个?也就是说,我可以像调用脚本一样调用模块并同时启动到调试器中吗?我意识到我可以进入代码本身并在我想要中断的地方插入import pdb; pdb.set_trace(),但我试图避免这种情况。

【问题讨论】:

【参考方案1】:

有effortsunderway 可以在Python 本身中解决这个问题。看起来像 Python 3.7,你可以这样做:

python -m pdb -m somepackage.somemodule

我已经为较旧的 Python 版本(2.7+)提供了a backport:

pip install backports.pdb
python -m backports.pdb -m somepackage.somemodule

【讨论】:

python -m pdb -m path.to.module 在 python 3.9.5 中非常适合我【参考方案2】:

经过一段时间的试验,结果证明这种方法确实有效:

python -c "import runpy; import pdb; pdb.runcall(runpy.run_module, 'somepackage.somemodule', run_name='__main__')"

出于某种原因,使用pdb.runcall 而非pdb.run 很重要。

【讨论】:

pdb.run 需要一个字符串,而不是可调用的。 python -c "import runpy; import pdb; pdb.run(\"runpy.run_module( 'somepackage.somemodule', run_name='__main__')\")" 也可以,但是比较麻烦【参考方案3】:

基于@jed 的回答,我构建了这个模块:

import pdb
import runpy
import sys


def main():
    module = sys.argv[1]
    sys.argv[1:] = sys.argv[2:]
    pdb.runcall(runpy.run_module, module, run_name='__main__')


__name__ == '__main__' and main()

将该模块作为 mpdb.py 放在 Python 路径中的任何位置(当前目录有效),然后您可以调用:

python -m mpdb somepackage.somemodule even with args

【讨论】:

【参考方案4】:

这是另一个也适用于命令行参数的选项。

将脚本的逻辑包装在main 函数中通常是个好主意。然后你可以让main 接受一个可选的参数列表来覆盖sys.argv。这是一个名为argdemo.py的示例:

def main(cmd_line_args=None):
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("number", help="a number", type=int)

    # allow cmd_line_args to override sys.argv
    if cmd_line_args is None:
        args = parser.parse_args()
    else:
        args = parser.parse_args(cmd_line_args)

    print("The number is ".format(args.number))

if __name__ == '__main__':
    main()

这个模块可以照常运行:

$ python -m argdemo 2
> The number is 2

或者可以直接调用main(),使用pdb运行:

$ python -c "import pdb; import argdemo; pdb.runcall(argdemo.main, ['2'])"
(Pdb) continue
> The number is 2

(注意cmd_line_args 必须是字符串列表,就像argv 一样)。

作为额外的奖励,当您的模块具有可导入的 main 函数时,您可以以相同的方式为其编写单元测试 =)

【讨论】:

【参考方案5】:

这对我有用(使用 -m 选项将 python 模块作为脚本调试)

我创建了一个划痕

import runpy

if __name__ == '__main__':
    runpy.run_module('somepackage.somemodule', run_name="__main__", alter_sys=True)

想法来自:Intellij/Pycharm can't debug Python modules

【讨论】:

以上是关于启动 Python 调试器,同时将模块作为脚本执行的主要内容,如果未能解决你的问题,请参考以下文章

调试htcondor运行python脚本的问题

python scrapy 调试模式

nodemon :作为必需模块使用时将参数传递给可执行文件

根据要求触发VS Code python调试器

多线程 python 脚本静默死亡 - 如何调试

模块作为Python中没有.py的脚本?