以下脚本将运行一个模块,如果在运行该模块时发生异常,则会进入验尸调试。它应同时适用于Python 2.7和3.x。
我知道可以使用以下命令从命令行调试Python脚本
python -m pdb my_script.py
如果my_script.py
是打算与python my_script.py
一起运行的脚本。
但是,python模块my_module.py
应该与python -m my_module
一起运行。即使包含相对导入的脚本也应使用python -m
运行。如何在python -m my_module
的控制下运行pdb
?以下无效:
python -m pdb -m my_module
您现在不能这样做,因为-m
终止了选项列表
python -h
...
-m mod : run library module as a script (terminates option list)
...
这意味着要解释其余参数列表是mod's >>工作,并且此行为完全取决于mod在内部的设计方式以及是否支持其他-m
让我们检查python 2.x
的pdb内部发生了什么。实际上,没有什么可解释的,它只希望提供一个脚本名称:的版本相同>>if not sys.argv[1:] or sys.argv[1] in ("--help", "-h"): print "usage: pdb.py scriptfile [arg] ..." sys.exit(2) mainpyfile = sys.argv[1] # Get script filename if not os.path.exists(mainpyfile): print 'Error:', mainpyfile, 'does not exist' sys.exit(1) del sys.argv[0] # Hide "pdb.py" from argument list # Replace pdb's dir with script's dir in front of module search path. sys.path[0] = os.path.dirname(mainpyfile) # Note on saving/restoring sys.argv: it's a good idea when sys.argv was # modified by the script being debugged. It's a bad idea when it was # changed by the user from the command line. There is a "restart" command # which allows explicit specification of command line arguments. pdb = Pdb() while True: try: pdb._runscript(mainpyfile)
与当前发布的python 3.x
允许执行您要问的请求的拉取请求已经在merged于5天之前了。多么神秘的巧合!这是code
因此,请稍等一下即将到来的python 3.x版本,以解决此问题)
以下脚本将运行一个模块,如果在运行该模块时发生异常,则会进入验尸调试。它应同时适用于Python 2.7和3.x。
用法
mdb.py module_name [args ...]
已知限制
:
sys.argv[0]
被保留为模块名称,而不是解析为模块的文件路径。mdb.py
#!/usr/bin/env python from __future__ import print_function import pdb import runpy import sys import traceback if len(sys.argv) == 0: print("Usage: mdb.py module_name [args ...]") exit(1) modulename = sys.argv[1] del sys.argv[0] try: runpy.run_module(modulename, run_name='__main__') except: traceback.print_exception(*sys.exc_info()) print("") print("-" * 40) print("mdb: An exception occurred while executing module ", modulename) print("mdb: See the traceback above.") print("mdb: Entering post-mortem debugging.") print("-" * 40) pdb.post_mortem(sys.exc_info()[2])
示范:
$ tree . ├── mdb.py └── mypackage ├── __init__.py ├── __main__.py └── mymodule.py 1 directory, 4 files $ ###################### Examine the module code ################### $ cat mypackage/mymodule.py from __future__ import print_function import sys print("mymodule loaded") if __name__ == "__main__": print("mymodule executed") print("args:", sys.argv) $ #################### Run the module through python ############### $ python -m mypackage.mymodule abc defgh mymodule loaded mymodule executed args: ['/home/leon/playground/mdb/mypackage/mymodule.py', 'abc', 'defgh'] $ #################### Run the module through mdb ################## $ ./mdb.py mypackage.mymodule abc defgh mymodule loaded mymodule executed args: ['mypackage.mymodule', 'abc', 'defgh'] $ ### ^^^^^^^^^^^^^^^^^^ $ ### Note that sys.argv[0] is not resolved to the file path $ ###################### Examine the module code ################### $ cat mypackage/__main__.py from __future__ import print_function import sys print("mypackage loaded") if __name__ == "__main__": print("mypackage executed") print("args:", sys.argv) print(x + y) $ #################### Run the module through python ############### $ python -m mypackage mypackage loaded mypackage executed args: ['/home/leon/playground/mdb/mypackage/__main__.py'] Traceback (most recent call last): File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main "__main__", fname, loader, pkg_name) File "/usr/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals File "/home/leon/playground/mdb/mypackage/__main__.py", line 9, in <module> print(x + y) NameError: name 'x' is not defined $ #################### Run the module through mdb ################## $ ./mdb.py mypackage mypackage loaded mypackage executed args: ['mypackage'] Traceback (most recent call last): File "./mdb.py", line 17, in <module> runpy.run_module(modulename, run_name='__main__') File "/usr/lib/python2.7/runpy.py", line 192, in run_module fname, loader, pkg_name) File "/usr/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals File "/home/leon/playground/mdb/mypackage/__main__.py", line 9, in <module> print(x + y) NameError: name 'x' is not defined ---------------------------------------- mdb: An exception occurred while executing module mypackage mdb: See the traceback above. mdb: Entering post-mortem debugging. ---------------------------------------- > /home/leon/playground/mdb/mypackage/__main__.py(9)<module>() -> print(x + y) (Pdb) q
Python 3.7添加了该功能
从the docs,看起来您的命令:
python -m pdb -m my_module
将开始在Python 3.7上工作:
版本3.7中的新增功能:pdb.py现在接受-m选项,该选项执行类似于python3 -m的模块。与脚本一样,调试器将在模块第一行之前暂停执行。
您可以在要调试的代码之前,在代码中添加
pdb.set_trace()
以进行交互式调试。class C: def __init__(self, x): self.x = x def inst_f(self): pass a = C('this is a') import pdb pdb.set_trace() b = C('this is b') print a.x is b.x
运行此将输出
> c:\python27\tests\test.py(11)<module>() -> b = C('this is b') (Pdb)
并且让您使用python调试器。
根据python
命令行帮助页,-m标志执行以下操作:
在sys.path中搜索指定的模块,并将相应的.py文件作为脚本运行。
鉴于此,按照您的第一个示例,通过运行.py文件,我将充满信心地进行调试。要记住的一件事是-m搜索sys.path
。幸运的是,python首先会查看当前的工作目录,因此,只要要调试的.py位于cwd中,就相当于python -m module
和python module.py
。
正如其他人所说,此功能是在Python 3.7中添加的。但是,人们仍在使用旧版本,因此希望以下解决方案能帮助那些人!
基本上,您可以通过导入包的__main__.py
文件来创建运行该模块的脚本:
# runner.py
import path.to.my.module.__main__
然后只需在pdb下运行该脚本:python -m pdb runner.py [args]
。
此解决方案适用于相对导入(因为__main__
在程序包路径下运行,而不是被称为脚本)。
您只需要导入__main__
模块的原因是,Python导入会触发要执行的顶层代码,而在__main__
中,逻辑是在顶层执行的。
以下脚本将运行一个模块,如果在运行该模块时发生异常,则会进入验尸调试。它应同时适用于Python 2.7和3.x。
Python 3.7添加了该功能
您可以在要调试的代码之前,在代码中添加pdb.set_trace()
以进行交互式调试。
class C:
def __init__(self, x):
self.x = x
def inst_f(self):
pass
a = C('this is a')
import pdb
pdb.set_trace()
b = C('this is b')
print a.x is b.x
根据python
命令行帮助页,-m标志执行以下操作:
在sys.path中搜索指定的模块,并将相应的.py文件作为脚本运行。
正如其他人所说,此功能是在Python 3.7中添加的。但是,人们仍在使用旧版本,因此希望以下解决方案能帮助那些人!
基本上,您可以通过导入包的__main__.py
文件来创建运行该模块的脚本: