How do imports work in IPython
Question: I'm a little bewildered by exactly how import statements work in IPython. I've
turned up nothing through web searches.

Implicit relative imports work with Python 2, but I don't know if that's still
the case with IPython for Python 3.

Relative imports using the dot syntax dont seem to work at all:

    
    
    In [6]: ls 
    dsp/  __init__.py  __init__.pyc  utils/
    
    In [7]: from .utils import capture
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-7-e7d50007bdd1> in <module>()
    ----> 1 from .utils import capture
    
    ValueError: Attempted relative import in non-package
    

importing modules that use the dot syntax seems impossible:

    
    
    In [8]: cd utils
    /home/user/workspace/mypkg/mypkg/utils
    
    In [9]: ls
    capture/  capture.py  capture.pyc  cext/  __init__.py  __init__.pyc
    
    In [10]: from capture import Capture
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-10-8c31c76d052d> in <module>()
    ----> 1 from capture import Capture
    
    /home/user/workspace/mypkg/mypkg/utils/capture.py in <module>()
         17 import tarfile
         18 import re
    ---> 19 from .. import utils
         20 from . import flprint
         21 from select import poll
    
    ValueError: Attempted relative import in non-package
    

Is there some concise documentation on this somewhere?


Answer: The problem is I was importing the module from a lower position in the package
hierarchy than is used in the module's import statement. So if I cd into the
utils directory and run

    
    
    from capture import Capture
    

then capture becomes the top level of the hierarchy. So the import statement
in the capture module

    
    
    from .. import utils
    

goes beyond the top level. Python doesn't know what ".." refers to, because
modules aren't self-aware of what package they belong to. If I change back up
to the mypkg directory, I get the same problem

    
    
    In [13]: cd ..
    /home/user/workspace/myproj/mypkg
    
    In [14]: from utils import capture
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-14-c87f26b2171d> in <module>()
    ----> 1 from utils import capture
    
    /home/user/workspace/myproj/mypkg/utils/capture.py in <module>()
        18 import re
        19 import zmq
    ---> 20 from .. import utils
        21 from . import flprint
        22 from select import poll
    
    ValueError: Attempted relative import beyond toplevel package
    

In this case, utils is the top level, so

    
    
    from . import flprint
    

will work, but

    
    
    from .. import utils
    

won't work.

I have to move one more directory up:

    
    
    In [19]: cd ..
    /home/user/workspace/myproj
    
    In [20]: from mypkg.utils import capture
    
    In [21]: cap = capture.Capture
    

IPython can import packages and modules located in the current working
directory, or from directories in the import path. I can add the package to
the import path to be able to import from any working directory.

    
    
    In [23]: import sys
    
    In [24]: sys.path.append('/home/user/workspace/myproj')
    
    In [25]: cd
    /home/user
    
    In [26]: from mypkg.utils import capture
    

Using sys.path.append is probably the most robust method for controlling the
import path in Python generally, and much less error-prone than using relative
import statements. You can use it inside a module to essentially make the
module self-aware.

