如何从命令行使用 python -m 调试 Python 模块 运行?
How to debug a Python module run with python -m from the command line?
我知道可以使用
从命令行调试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
您可以在代码中添加 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 标志执行以下操作:
Searches sys.path for the named module and runs the corresponding .py file as a script.
鉴于此,我有信心根据您的第一个示例通过 运行 .py 文件进行调试。要记住的一件事是 -m 搜索 sys.path
。幸运的是,python 首先查看当前工作目录,所以只要你正在调试的 .py 在你的 cwd 中,python -m module
和 python module.py
等价。
你现在不能这样做,因为-m
终止选项列表
python -h
...
-m mod : run library module as a script (terminates option list)
...
这意味着 mod 的 工作是解释参数列表的其余部分,此行为完全取决于 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)
的当前发布版本相同
好消息
允许执行您要求的请求的拉取请求已 merged 5 days ago. What a mysterious coincidence! Here's the code
所以稍等一下,等待即将推出的 python 3.x 版本解决这个问题)
以下脚本将 运行 一个模块,如果在 运行 安装该模块时发生异常,则进入 post-mortem 调试。它应该适用于 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:
上开始工作
New in version 3.7: pdb.py now accepts a -m option that execute modules similar to the way python3 -m does. As with a script, the debugger will pause execution just before the first line of the module.
正如其他人所说,此功能是在 Python 3.7 中添加的。但是,人们仍在使用旧版本,因此希望下面的解决方案可以帮助那些人!
基本上,您可以创建一个 运行 模块的脚本,只需导入包的 __main__.py
文件即可:
# runner.py
import path.to.my.module.__main__
然后简单地 运行 pdb 下的那个脚本:python -m pdb runner.py [args]
.
此解决方案适用于相对导入(因为 __main__
在包路径下 运行ning 而不是作为脚本调用)。
之所以只需要导入 __main__
模块是因为 Python 导入会触发要执行的顶层代码,而在 __main__
中,逻辑在顶级。
我知道可以使用
从命令行调试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
您可以在代码中添加 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 标志执行以下操作:
Searches sys.path for the named module and runs the corresponding .py file as a script.
鉴于此,我有信心根据您的第一个示例通过 运行 .py 文件进行调试。要记住的一件事是 -m 搜索 sys.path
。幸运的是,python 首先查看当前工作目录,所以只要你正在调试的 .py 在你的 cwd 中,python -m module
和 python module.py
等价。
你现在不能这样做,因为-m
终止选项列表
python -h
...
-m mod : run library module as a script (terminates option list)
...
这意味着 mod 的 工作是解释参数列表的其余部分,此行为完全取决于 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)
的当前发布版本相同
好消息
允许执行您要求的请求的拉取请求已 merged 5 days ago. What a mysterious coincidence! Here's the code
所以稍等一下,等待即将推出的 python 3.x 版本解决这个问题)
以下脚本将 运行 一个模块,如果在 运行 安装该模块时发生异常,则进入 post-mortem 调试。它应该适用于 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:
上开始工作New in version 3.7: pdb.py now accepts a -m option that execute modules similar to the way python3 -m does. As with a script, the debugger will pause execution just before the first line of the module.
正如其他人所说,此功能是在 Python 3.7 中添加的。但是,人们仍在使用旧版本,因此希望下面的解决方案可以帮助那些人!
基本上,您可以创建一个 运行 模块的脚本,只需导入包的 __main__.py
文件即可:
# runner.py
import path.to.my.module.__main__
然后简单地 运行 pdb 下的那个脚本:python -m pdb runner.py [args]
.
此解决方案适用于相对导入(因为 __main__
在包路径下 运行ning 而不是作为脚本调用)。
之所以只需要导入 __main__
模块是因为 Python 导入会触发要执行的顶层代码,而在 __main__
中,逻辑在顶级。