2016-03-20 9 views
5

Desidero modificare il modo in cui IPython gestisce gli errori di importazione per impostazione predefinita. Quando prototipo qualcosa nella shell IPython, di solito dimentico di importare prima os, re o qualsiasi altra cosa di cui ho bisogno. Le prime dichiarazioni spesso seguono questo schema:Imposta IPython Import Cosa intendo

In [1]: os.path.exists("~/myfile.txt") 
--------------------------------------------------------------------------- 
NameError         Traceback (most recent call last) 
<ipython-input-1-0ffb6014a804> in <module>() 
----> 1 os.path.exists("~/myfile.txt") 

NameError: name 'os' is not defined 

In [2]: import os 

In [3]: os.path.exists("~/myfile.txt") 
Out[3]: False 

Certo, è colpa mia per avere cattive abitudini e, sicuro, in uno script o un programma vero e proprio che abbia un senso, ma nel guscio Preferirei che IPython segue il principio DWIM , di almeno cercando per importare ciò che sto cercando di utilizzare.

In [1]: os.path.exists("~/myfile.txt") 
--------------------------------------------------------------------------- 
NameError         Traceback (most recent call last) 
<ipython-input-1-0ffb6014a804> in <module>() 
----> 1 os.path.exists("~/myfile.txt") 

NameError: name 'os' is not defined 

Catching this for you and trying to import "os" … success! 
Retrying … 
--------------------------------------------------------------------------- 
Out[1]: False 

Se ciò non è possibile con una vaniglia IPython, cosa avrei dovuto fare per fare questo lavoro? È un wrapper kernel il modo più semplice per avanzare? O dovrebbe essere implementato direttamente nel nucleo, con un comando magico?

Nota, questo è diverso da those kind of question dove qualcuno desidera caricare sempre moduli predefiniti. Io non. Cuz Io non so quello che io lavorerò, e io non voglio caricare tutto (né voglio mantenere l'elenco dei tutto aggiornato

risposta

10

NOTA:. Questo è ora il mantenimento on Github. Scarica l'ultima versione dello script da lì!

ho sviluppato uno script che si lega alla gestione attraverso set_custom_exc eccezione di IPython. Se c'è un NameError, utilizza una regex per trovare quale modulo si è tentato di utilizzare e poi tenta di importarlo, quindi esegue la funzione che hai provato a chiamare di nuovo. Ecco il codice:

import sys, IPython, colorama # <-- colorama must be "pip install"-ed 

colorama.init() 

def custom_exc(shell, etype, evalue, tb, tb_offset=None): 
    pre = colorama.Fore.CYAN + colorama.Style.BRIGHT + "AutoImport: " + colorama.Style.NORMAL + colorama.Fore.WHITE 
    if etype == NameError: 
     shell.showtraceback((etype, evalue, tb), tb_offset) # Show the normal traceback 
     import re 
     try: 
      # Get the name of the module you tried to import 
      results = re.match("name '(.*)' is not defined", str(evalue)) 
      name = results.group(1) 

      try: 
       __import__(name) 
      except: 
       print(pre + "{} isn't a module".format(name)) 
       return 

      # Import the module 
      IPython.get_ipython().run_code("import {}".format(name)) 
      print(pre + "Imported referenced module \"{}\", will retry".format(name)) 
     except Exception as e: 
      print(pre + "Attempted to import \"{}\" but an exception occured".format(name)) 

     try: 
      # Run the failed line again 
      res = IPython.get_ipython().run_cell(list(get_ipython().history_manager.get_range())[-1][-1]) 
     except Exception as e: 
      print(pre + "Another exception occured while retrying") 
      shell.showtraceback((type(e), e, None), None) 
    else: 
     shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset) 

# Bind the function we created to IPython's exception handler 
IPython.get_ipython().set_custom_exc((Exception,), custom_exc) 

È possibile effettuare automaticamente questo periodo, quando si avvia un prompt dei IPython salvandolo da qualche parte e quindi impostando una variabile d'ambiente chiamata PYTHONSTARTUP al percorso di questo file. È possibile impostare le variabili di ambiente in modo diverso a seconda del sistema operativo (ricordarsi di modificare i percorsi):

  • di Windows: setx PYTHONSTARTUP C:\startup.py nel prompt dei comandi
  • Mac/Linux (bash): Mettere export PYTHONSTARTUP=$HOME/startup.py nella vostra ~/.bashrc

Ecco una demo dello script in azione:

Demo

+0

_Currently, questo script infi nite-loop su alcuni errori_ - se i risultati dell'importazione in NameError e la routine di pulizia fanno la stessa importazione ... - sai già cosa succede. Devi verificare se il modulo che stai cercando di importare esiste. –

+0

@Rogalski Come potrei farlo? So che 'pip' ha dei metodi per farlo, ma qualcuno potrebbe importare qualcosa che si trova sulla loro macchina locale. –

+0

Esegui: 'prova: importa qualsiasi cosa tranne ImportError: oops_failed_to_import_handle_it()'? –