2010-11-20 17 views
36

Czy istnieje sposób uruchomienia powłoki lub monitu IPython, gdy mój program uruchamia linię, która zgłasza wyjątek?Uruchamianie powłoki protokołu IPython na wyjątku

Najbardziej interesuje mnie kontekst, zmienne, w zakresie (i podskopach), w których wyjątek został podniesiony. Coś takiego jak debugowanie Visual Studio, gdy wyjątek jest rzucany, ale nie jest przechwytywany przez nikogo, Visual Studio zatrzyma się i da mi stos wywołań i zmienne obecne na każdym poziomie.

Czy sądzisz, że istnieje sposób na uzyskanie czegoś podobnego za pomocą IPython?

EDIT: Opcja -pdb przy uruchamianiu ipython nie wydaje się robić to, co chcę (albo nie wiem jak go używać prawidłowo, co jest całkiem możliwe). I uruchom następujący skrypt:

def func(): 
    z = 2 
    g = 'b' 
    raise NameError("This error will not be caught, but IPython still" 
        "won't summon pdb, and I won't be able to consult" 
        "the z or g variables.") 

x = 1 
y = 'a' 

func() 

Używając polecenia:

ipython -pdb exceptionTest.py 

który zatrzymuje wykonanie gdy błąd zostanie podniesiony, ale przynosi mi wiersz ipython gdzie mam dostęp do zmiennych globalnych skryptu , ale nie lokalne zmienne funkcji func. pdb jest wywoływane tylko wtedy, gdy bezpośrednio wpiszę polecenie w ipython, które powoduje błąd, tj. raise NameError("This, sent from the IPython prompt, will trigger pdb.").

Nie muszę koniecznie używać pdb, chciałbym tylko mieć dostęp do zmiennych wewnątrz func.

EDYTUJ 2: Minęło trochę czasu, opcja IPython's -pdb działa teraz tak, jak tego chcę. Oznacza to, że gdy zgłoszę wyjątek, mogę cofnąć się w zakresie func i bez problemu odczytać jego zmienne z i g. Nawet bez ustawienia opcji -pdb, można uruchomić IPython w trybie interaktywnym, a następnie wywołać funkcję magiczną %debug po wyjściu programu z błędem - spowoduje to również przejście do interaktywnego pytania ipdb z dostępem do wszystkich zakresów.

+1

Podczas tego rodzaju hacki, należy pamiętać, że skrypt może zawiesić cokolwiek to nazywa, czy jest to część anoth er program. Moja sugestia polega na sprawdzeniu, czy sys.stdin.isatty() przed wykonaniem tego. – d33tah

Odpowiedz

20

Aktualizacja IPython v0.13:

import sys 
from IPython.core import ultratb 
sys.excepthook = ultratb.FormattedTB(mode='Verbose', 
    color_scheme='Linux', call_pdb=1) 
2

Ten man page mówi, że iPython ma opcję --[no]pdb do przekazania w wierszu poleceń, aby uruchomić iPython dla niezatrzymanych wyjątków. Szukasz więcej?

EDYTOWANIE: python -m pdb pythonscript.py może uruchomić pdb. Jednak nie jestem pewien co do podobnego problemu z iPythonem. Jeśli szukasz śladu stosu i ogólnej sekcji zwłok wyjścia programu, powinno to zadziałać.

+0

-1 Ta operacja jest przeznaczona dla nieprzechwyconych wyjątków, gdy coś jest już uruchomione w ipythonie, a nie dla uruchomienia ipython, gdy jeszcze nie jest uruchomiony. – snapshoe

4

można zrobić coś jak poniżej:

import sys 
from IPython.Shell import IPShellEmbed 
ipshell = IPShellEmbed() 

def excepthook(type, value, traceback): 
    ipshell() 

sys.excepthook = excepthook 

Zobacz sys.excepthook i Embedding IPython.

+0

Uwielbiam ten pomysł, ale czytam [tutaj] (http://stackoverflow.com/questions/1261668/cannot-override-sys-excepthook/1262091#1262091), że ipython nie * używa * sys.excepthook. – levesque

+0

Spróbuj dodać te linie do początku skryptu, a następnie uruchom go poza biblioteką ipython i sprawdź, czy nie przeniesie Cię do sesji opartej na pythonach. Jeśli uruchomiłeś skrypt za pomocą 'ipython

9

ipdb integruje funkcje IPython w pdb. Poniższy kod służy do wrzucania aplikacji do debuggera IPython po nieobsługiwanym wyjątku.

import sys, ipdb, traceback 

def info(type, value, tb): 
    traceback.print_exception(type, value, tb) 
    ipdb.pm() 

sys.excepthook = info 
+4

ipdb ma również poręczny menedżer kontekstu: 'launch_ipdb_on_exception()' – scribu

5

@ odpowiedź snapshoe nie działa w nowszych wersjach ipython.

to robi jednak:

import sys 
from IPython import embed 

def excepthook(type, value, traceback): 
    embed() 

sys.excepthook = excepthook 
+0

To jest ten, którego użyłem do uruchomienia powłoki w pewnym momencie w skrypcie –

2

@ dzieł Adama jak czar tą różnicą, że ipython ładuje się trochę wolniej (800ms na moim komputerze). Tutaj mam sztuczkę, która sprawia, że ​​ładunek jest leniwy.

class ExceptionHook: 
    instance = None 

    def __call__(self, *args, **kwargs): 
     if self.instance is None: 
      from IPython.core import ultratb 
      self.instance = ultratb.FormattedTB(mode='Verbose', 
       color_scheme='Linux', call_pdb=1) 
     return self.instance(*args, **kwargs) 
sys.excepthook = ExceptionHook() 

Teraz nie musimy czekać na samym początku. Dopiero gdy program się zawiesi, zostanie zaimportowany program IPython.

1

Jeśli chcesz zarówno uzyskać traceback i otworzyć skorupę ipython z otoczeniem w miejscu wyjątkiem:

def exceptHook(*args): 
    '''A routine to be called when an exception occurs. It prints the traceback 
    with fancy formatting and then calls an IPython shell with the environment 
    of the exception location. 
    ''' 
    from IPython.core import ultratb 
    ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args) 
    from IPython.terminal.embed import InteractiveShellEmbed 
    import inspect 
    frame = inspect.getinnerframes(args[2])[-1][0] 
    msg = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame) 
    savehook = sys.excepthook # save the exception hook 
    InteractiveShellEmbed()(msg,local_ns=frame.f_locals,global_ns=frame.f_globals) 
    sys.excepthook = savehook # reset IPython's change to the exception hook 

import sys 
sys.excepthook = exceptHook 

pamiętać, że jest to konieczne, aby wyciągnąć od informacji namespace od ostatniej klatki odwołuje ślad błędu (arg [2])

+0

Jeśli ktokolwiek nadal używa IPython 0.12 (EPD), import musi być '' 'from IPython.frontend.terminal.embed importuj InteractiveShellEmbed'''' – bht

2

można spróbować:

from ipdb import launch_ipdb_on_exception 

def main(): 
    with launch_ipdb_on_exception(): 
     # The rest of the code goes here. 
     [...] 
Powiązane problemy