with tutorial the para latest framework español desde cero applications python debugging python-module pdb

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



the django project (5)

Sé que una secuencia de comandos 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


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 primero mira el directorio de trabajo actual, de modo que siempre que .py esté depurando esté en su cwd, python -m module y python module.py equivalente.


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


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 resto de la lista de argumentos y este comportamiento depende completamente de cómo se diseñe internamente y de si es compatible con otro -m

Echemos un vistazo a lo que está pasando 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/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)

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 merged 5 días. ¡Qué misteriosa coincidencia! Aquí está el code

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


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 a.x is b.x

Ejecutando esto saldrá

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

Y te deja usar el depurador de Python.


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.