¿Cómo depurar un módulo de Python ejecutado con python -m desde la línea de comandos?

Sé que un script de Python se puede depurar desde la línea de comandos con

python -m pdb my_script.py 

si my_script.py es un script destinado a ejecutarse con python my_script.py .

Sin embargo, un módulo python my_module.py debe ejecutarse con python -m my_module . Incluso los scripts que contienen importaciones relativas deben ejecutarse con python -m . ¿Cómo puedo ejecutar python -m my_module bajo el control de pdb ? Lo siguiente no funciona :

 python -m pdb -m my_module 

No puedes hacerlo ahora, porque -m termina la lista de opciones

 python -h ... -m mod : run library module as a script (terminates option list) ... 

Eso significa que el trabajo de mod es interpretar el rest de la lista de argumentos y este comportamiento depende completamente de cómo se diseñe internamente y si admite otro -m

Echemos un vistazo a lo que está sucediendo dentro de pdb de python 2.x. En realidad, nada interesante, solo espera que se proporcione un nombre de script:

  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/restring 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) 

Lo mismo para las versiones lanzadas actualmente de python 3.x

Buenas noticias

La solicitud de extracción que permite hacer lo que está pidiendo se ha fusionado hace 5 días. ¡Qué misteriosa coincidencia! Aquí está el código

Así que solo espere un poco para que las próximas versiones de Python 3.x tengan este problema resuelto)

La siguiente secuencia de comandos ejecutará un módulo y se dividirá en la depuración post mortem si se produce una excepción al ejecutar el módulo. Debería funcionar tanto con Python 2.7 como con 3.x.

Uso

 mdb.py module_name [args ...] 

Limitaciones conocidas :

  • Mientras se ejecuta el código del módulo, sys.argv[0] se conserva como el nombre del módulo, en lugar de resolverse en la ruta del archivo del módulo.
  • Si no se encuentra el módulo de destino, el error no se reporta de manera diferente que si el error ocurrió durante la ejecución del módulo

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]) 

Demostración :

 $ 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  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  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  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)() -> print(x + y) (Pdb) q 

Puede agregar pdb.set_trace() en su código para la depuración interactiva, antes del código que desea depurar.

 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 ax is bx 

Ejecutando esto saldrá

 > c:\python27\tests\test.py(11)() -> b = C('this is b') (Pdb) 

Y te deja usar el depurador de Python.

De acuerdo con la página de manual de la línea de comandos de python , el indicador -m hace lo siguiente:

Busca en sys.path el módulo nombrado y ejecuta el archivo .py correspondiente como un script.

Dado esto, me sentiría confiado en la depuración ejecutando el archivo .py según su primer ejemplo. Una cosa a tener en cuenta es que -m busca en sys.path . Afortunadamente, python mira primero el directorio de trabajo actual, por lo tanto, siempre y cuando el .py que está depurando esté en su cwd, python -m module y python module.py equivalente.

Python 3.7 agrega esa característica

De los documentos , parece que su comando:

 python -m pdb -m my_module 

comenzará a trabajar en Python 3.7:

Nuevo en la versión 3.7: pdb.py ahora acepta una opción -m que ejecuta módulos de manera similar a como lo hace python3 -m. Al igual que con un script, el depurador pausará la ejecución justo antes de la primera línea del módulo.