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

28

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

python -m somepackage.somemodule

在存放somepackage的目录中运行somemodule.py,就好像子模块是__main__一样。如果包使用显式相对导入(如此处所述),使用这种调用语法尤其重要。

同样地,使用-m选项调试脚本也非常方便,如下:

python -m pdb somescript.py

有没有办法同时做到这两个?也就是说,我能否像调用脚本一样调用模块,并同时进入调试器?我知道我可以进入代码本身并在想要中断的位置插入import pdb; pdb.set_trace(),但我正在尝试避免这样做。

5个回答

25

许多 努力 正在进行,以解决 Python 本身的问题。看起来,使用 Python 3.7,您可以执行以下操作:

python -m pdb -m somepackage.somemodule

同时,我还为旧版Python(2.7+)提供了一个后移版本

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

2
python -m pdb -m path.to.module 在 Python 3.9.5 中对我来说运行得非常完美。 - jlhasson

10

在经过相当一段时间的尝试后,事实证明这种方法确实可行:

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

由于某些原因,使用pdb.runcallpdb.run更为重要。


1
pdb.run 期望的是一个字符串,而不是可调用对象。 python -c "import runpy; import pdb; pdb.run(\"runpy.run_module( 'somepackage.somemodule', run_name='__main__')\")"同样可以工作,但更加繁琐。 - petre

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

0

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

我创建了一个草稿

import runpy

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

灵感来自:Intellij/Pycharm 无法调试 Python 模块


0

这里还有另一种选项,它也可以与命令行参数一起使用。

通常将脚本的逻辑封装在一个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 函数时,您可以以相同的方式编写单元测试 =)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接