7

我想修改 IPython 默认处理导入错误的方式。当我在 IPython shell 中对某些东西进行原型制作时,我通常会忘记首先 importosre任何我需要的东西。前几个语句通常遵循这种模式:

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

当然,这是我有坏习惯的错,当然,在一个有意义的脚本或真实程序中,但在 shell 中,我宁愿 IPython 遵循 DWIM 原则,至少尝试导入我试图使用的内容.

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

如果使用香草 IPython 无法做到这一点,我该怎么做才能完成这项工作?包装内核是最简单的方法吗?还是应该使用魔术命令直接在核心中实现?

请注意,这与有人希望始终加载预定义模块的那种问题不同。我不。因为我不知道我会做什么,而且我不想加载所有内容(我也不想更新所有内容的列表。

4

1 回答 1

11

注意:这现在正在Github上维护。从那里下载最新版本的脚本!

我开发了一个脚本,它通过set_custom_exc. 如果有NameError,它会使用正则表达式来查找您尝试使用的模块,然后尝试导入它。然后它运行您尝试再次调用的函数。这是代码:

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)

您可以在启动 IPython 提示时自动运行它,方法是将其保存在某个位置,然后设置一个调用PYTHONSTARTUP该文件路径的环境变量。根据您的操作系统设置不同的环境变量(请记住更改路径):

  • Windows:setx PYTHONSTARTUP C:\startup.py在命令提示符下
  • Mac/Linux (bash):放入export PYTHONSTARTUP=$HOME/startup.py您的~/.bashrc

以下是实际脚本的演示:

演示

于 2016-03-20T16:12:51.267 回答