From 4350decf00a1036842083b6d169a4994f257714f 2013-06-27 18:14:06 From: Fernando Perez Date: 2013-06-27 18:14:06 Subject: [PATCH] Replace exec/eval with proper __import__. Unfortunately for some very weird reason, this code can't be called as a function, so I inlined a verbatim copy of importstring.import_item. --- diff --git a/IPython/frontend.py b/IPython/frontend.py index a076ced..edce202 100644 --- a/IPython/frontend.py +++ b/IPython/frontend.py @@ -19,9 +19,20 @@ printed. # Imports #----------------------------------------------------------------------------- from __future__ import print_function + +# Stdlib import sys import types +m = """\ +*** WARNING*** : The top-level `frontend` package has been deprecated. +All its subpackages have been moved to the top `IPython` level.""" + +print(m, file=sys.stderr) + +# FIXME: turn this into a Warning once we've fixed all our own imports. +#raise DeprecationWarning(m) + #----------------------------------------------------------------------------- # Class declarations #----------------------------------------------------------------------------- @@ -29,20 +40,35 @@ import types class ShimModule(types.ModuleType): def __getattribute__(self, key): - m = ("*** WARNING*** : The top-level `frontend` module has been deprecated.\n" - "Please import %s directly from the `IPython` level." % key) - - # FIXME: I don't understand why, but if the print statement below is - # redirected to stderr, this shim module stops working. It seems the - # Python import machinery has problem with redirected prints happening - # during the import process. If we can't figure out a solution, we may - # need to leave it to print to default stdout. - print(m) + # Use the equivalent of import_item(name), see below + name = 'IPython.' + key + + # NOTE: the code below is copied *verbatim* from + # importstring.import_item. For some very strange reason that makes no + # sense to me, if we call it *as a function*, it doesn't work. This + # has something to do with the deep bowels of the import machinery and + # I couldn't find a way to make the code work as a standard function + # call. But at least since it's an unmodified copy of import_item, + # which is used extensively and has a test suite, we can be reasonably + # confident this is OK. If anyone finds how to call the function, all + # the below could be replaced simply with: + # + # from IPython.utils.importstring import import_item + # return import_item('IPython.' + key) - # FIXME: this seems to work fine, but we should replace it with an - # __import__ call instead of using exec/eval. - exec 'from IPython import %s' % key - return eval(key) + parts = name.rsplit('.', 1) + if len(parts) == 2: + # called with 'foo.bar....' + package, obj = parts + module = __import__(package, fromlist=[obj]) + try: + pak = module.__dict__[obj] + except KeyError: + raise ImportError('No module named %s' % obj) + return pak + else: + # called with un-dotted string + return __import__(parts[0]) # Unconditionally insert the shim into sys.modules so that further import calls