2013-08-10 6 views
8

Podczas opracowywania pakietu Python bardzo wygodne jest użycie opcji -m do uruchamiania modułów wewnątrz pakietu jako skrypty do szybkiego testowania. Na przykład, dla somepackage z modułem somemodule.py wewnątrz niego powołującUruchomienie debuggera Python przy jednoczesnym wykonywaniu modułu jako skryptu

python -m somepackage.somemodule 

z katalogu, w którym zamieszkuje somepackage będzie działać somemodule.py jakby modułem były __main__. Używanie tej składni wywołania jest szczególnie ważne, jeśli pakiet korzysta z bezpośrednich importów względnych, jak opisano w here.

Podobnie jest także wygodny w użyciu opcję -m debugowanie skryptu, tak jak w

python -m pdb somescript.py 

Czy istnieje jakiś sposób, aby zrobić zarówno w tym samym czasie? To znaczy, czy mogę wywołać moduł tak, jakby był skryptem i jednocześnie uruchamiać w debugerze? Zdaję sobie sprawę, że mogę przejść do samego kodu i wstawić import pdb; pdb.set_trace(), gdzie chcę przerwać, ale staram się tego uniknąć.

Odpowiedz

7

Po eksperymentach z tym od dłuższego czasu, okazuje się, że takie podejście rzeczywiście działa:

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

Z jakiegoś powodu, stosowanie pdb.runcall nad pdb.run jest ważne.

+0

pdb.run spodziewałbym ciąg, a nie wpłacone. 'python -c" importuj runpy; importuj pdb; pdb.run (\ "runpy.run_module (" somepackage.somemodule ", run_name = '__ main __') \") "' działa równie dobrze, ale jest bardziej uciążliwy – petre

0

Oto kolejna opcja, która działa również z argumentami wiersza poleceń.

Generalnie dobrze jest zawrzeć logikę skryptu w funkcji main. Możesz następnie main wziąć opcjonalną listę argumentów, aby zastąpić sys.argv. Oto przykład nazywa 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() 

Moduł ten może być prowadzony jak zwykle:

$ python -m argdemo 2 
> The number is 2 

Albo można go uruchomić z pdb wywołując main() bezpośrednio:

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

(Zauważ, że cmd_line_args musi być listą ciągów znaków, podobnie jak argv).

Jako dodatkowy bonus, gdy moduł ma main funkcji importu-stanie, można pisać testy jednostkowe dla niego w taki sam sposób =)

0

budynku na odpowiedź @ Jeda, zbudowałem ten moduł:

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

umieścić ten moduł jako mpdb.py gdziekolwiek w ścieżce Pythona (bieżących pracach katalogów), to może wywołać:

python -m mpdb somepackage.somemodule even with args 
0

Istnieją effortsunderway rozwiązać ten problem w samym Pythonie. Wygląda jak w Pythonie 3.7, można zrobić:

python -m pdb -m somepackage.somemodule 

A ja pod warunkiem a backport dla starszych wersji Pythona (2.7+):

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