2013-08-10 12 views
8

Quando si sviluppa un pacchetto Python, è molto conveniente utilizzare l'opzione per eseguire moduli all'interno del pacchetto come script per test rapidi. Ad esempio, per somepackage con modulo somemodule.py suo interno, invocandoAvvia il debugger Python mentre esegue contemporaneamente il modulo come script

python -m somepackage.somemodule 

dalla directory in cui risiede somepackage verranno eseguiti somemodule.py come se fosse sottomodulo __main__. L'utilizzo di questa sintassi di chiamata è particolarmente importante se il pacchetto utilizza importazioni relative esplicite come descritto in here.

Allo stesso modo, è anche comodo da usare l'opzione -m per eseguire il debug di uno script, come in

python -m pdb somescript.py 

Esiste un modo per fare entrambe le cose allo stesso tempo? Cioè, posso chiamare un modulo come se fosse uno script e contemporaneamente lanciarlo nel debugger? Mi rendo conto che posso inserire il codice stesso e inserire import pdb; pdb.set_trace() dove voglio rompere, ma sto cercando di evitarlo.

risposta

7

Dopo aver sperimentato questo per un bel po 'di tempo, si scopre che questo approccio funziona davvero:

python -c "import runpy; import pdb; pdb.runcall(runpy.run_module, 'somepackage.somemodule', run_name='__main__')" 

Per qualche ragione, l'uso di pdb.runcall sopra pdb.run è importante.

+0

pdb.run ci si aspetta una stringa, non un callable. 'python -c" importa runpy; importa pdb; pdb.run (\ "runpy.run_module ('somepackage.somemodule', run_name = '__ main __') \") "' funziona altrettanto bene, ma è più ingombrante – petre

0

Ecco un'altra opzione che funziona anche con gli argomenti della riga di comando.

E 'generalmente una buona idea per avvolgere la logica del vostro scritto in una funzione main. È quindi possibile avere main in un elenco di argomenti facoltativo da sostituire su sys.argv. Ecco un esempio chiama argdemo.py:

def main(cmd_line_args=None): 
    import argparse 

    parser = argparse.ArgumentParser() 
    parser.add_argument("number", help="a number", type=int) 

    # allow cmd_line_args to override sys.argv 
    if cmd_line_args is None: 
     args = parser.parse_args() 
    else: 
     args = parser.parse_args(cmd_line_args) 

    print("The number is {}".format(args.number)) 

if __name__ == '__main__': 
    main() 

Questo modulo può essere eseguito come al solito:

$ python -m argdemo 2 
> The number is 2 

Oppure può essere gestito con pdb chiamando main() direttamente:

$ python -c "import pdb; import argdemo; pdb.runcall(argdemo.main, ['2'])" 
(Pdb) continue 
> The number is 2 

(Si noti che cmd_line_args deve essere una lista di stringhe come sarebbe argv).

Come bonus aggiuntivo, quando il modulo ha una funzione di importazione-grado main, è possibile scrivere unit test per esso nello stesso modo =)

0

Sulla risposta @ di Jed, ho costruito questo modulo:

import pdb 
import runpy 
import sys 


def main(): 
    module = sys.argv[1] 
    sys.argv[1:] = sys.argv[2:] 
    pdb.runcall(runpy.run_module, module, run_name='__main__') 


__name__ == '__main__' and main() 

Metti che modulo come mpdb.py in qualsiasi punto del percorso Python (opere directory corrente), allora si può invocare:

python -m mpdb somepackage.somemodule even with args 
0

ci sono effortsunderway per risolvere questo problema in Python stesso. Sembra con Python 3.7, si può fare:

python -m pdb -m somepackage.somemodule 

E ho previsto a backport per le vecchie versioni di Python (2.7+):

pip install backports.pdb 
python -m backports.pdb -m somepackage.somemodule 
Problemi correlati