Как отладить модуль Python, запущенный с python -m из командной строки?
Я знаю, что Python script можно отлаживать из командной строки с помощью
python -m pdb my_script.py
если my_script.py
является script, предназначенным для запуска с python my_script.py
.
Однако, python module my_module.py
должен запускаться с python -m my_module
. Даже сценарии, содержащие относительный импорт, должны выполняться с python -m
. Как я могу запустить python -m my_module
под управлением pdb
? Следующая не работает:
python -m pdb -m my_module
Ответы
Ответ 1
Вы не можете сделать это сейчас, потому что -m
завершает список опций
python -h
...
-m mod : run library module as a script (terminates option list)
...
Это означает, что это mod задание для интерпретации остальной части списка аргументов, и это поведение полностью зависит от того, как mod разработан внутри и поддерживает ли он другой м
Давайте посмотрим, что происходит внутри pdb python 2.x. На самом деле, ничего интересного, он ожидает только script name:
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 dir with script dir in front of module search path.
sys.path[0] = os.path.dirname(mainpyfile)
# Note on saving/restoring sys.argv: it a good idea when sys.argv was
# modified by the script being debugged. It 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
Хорошие новости
Запрос на pull, который позволяет делать то, что вы просите, был слит 5 дней назад. Какое таинственное совпадение! Здесь code
Так что просто подождите немного для предстоящих версий python 3.x, чтобы решить эту проблему.
Ответ 2
Следующий script будет запускать модуль и разбиваться на посмертную отладку, если во время работы модуля возникает исключение. Он должен работать как с 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
Ответ 3
Вы можете добавить 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.
Ответ 4
В соответствии с man-страницей командной строки python
флаг -m выполняет следующие действия:
Ищет sys.path для именованного модуля и запускает соответствующий .py файл как script.
Учитывая это, я бы чувствовал уверенную отладку, запустив файл .py в соответствии с вашим первым примером. Следует иметь в виду, что -m ищет sys.path
. К счастью, python сначала обращается к текущему рабочему каталогу, поэтому до тех пор, пока вы отлаживаете .py, вы используете эквивалент cwd, python -m module
и python module.py
.
Ответ 5
Python 3.7 добавляет эту функцию
Из документации видно, что ваша команда:
python -m pdb -m my_module
начну работать на Python 3.7:
Новое в версии 3.7: теперь pdb.py принимает опцию -m, которая выполняет модули, аналогично тому, как это делает python3 -m. Как и в случае со скриптом, отладчик приостанавливает выполнение непосредственно перед первой строкой модуля.