5

How can I import a file that is in a parent directory within a python package (that is not on the path) into a file in a child dir?

I'm not totally clear on the vocabulary of python packaging so by way of example:

dir1/
    __init__.py
    runner.py
    in_dir1.py
    dir2/
        __init__.py
        in_dir2.py

dir1/in_dir1.py:

def example():
    print "Hello from dir1/in_dir1.example()"

dir1/dir2/in_dir2.py

import in_dir1   #or whatever this should be to make this work
print "Inside in_dir2.py, calling in_dir1.example()"
print in_dir1.example()

Given that dir1 is not on the python path I'm looking for the best way to import in_dir1 into in_dir2.

I tried from .. import in_dir1 and from ..dir1 import in_dir1 based on this Q/A but neither works. What is the correct way of executing that intent? This Q/A seems to contain the answer; however, I'm not quite sure what to make of it / how to actually solve my problem using PEP 366

Both __init__.py files are empty and I am on v2.6.

I'm attempting to do this without using any of the path hacks that Google keeps turning up.

Community
  • 1
  • 1
Finn
  • 1,823
  • 2
  • 15
  • 31

2 Answers2

3

The answer is in the link you gave:

Relative imports use a module's __name__ attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to 'main') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

You cannot do relative imports in __main__ scripts (i.e. if you directly run python in_dir2.py).

To solve this, what PEP 366 allows you to do is set the global __package__:

import dir1
if __name__ == '__main__':
    __package__ = 'dir1.dir2'
    from .. import in_dir1

Note that the package dir1 still has to be on sys.path! You can manipulate sys.path to achieve this. But by then, what have you achieved over absolute imports?

Rob Wouters
  • 15,797
  • 3
  • 42
  • 36
  • "But by then, what have you achieved..." nothing. This really doesn't seem like all that much of an edge case. I really cannot import within a package without sticking the top level on the path? – Finn Jan 25 '12 at 23:12
  • 2
    @Finn, it is an edge case because you are running a submodule of a package directly. While the proper way to do it would be to create a separate script that imports the package/submodule and run that. – Rob Wouters Jan 25 '12 at 23:18
  • what would the requirements be on the location of the separate runner script as far as pythonpath / location in the dir tree to make it work? – Finn Jan 26 '12 at 04:26
  • 1
    @Finn: `python your_script.py` adds its directory to `sys.path` therefore if you use absolute imports everywhere and `dir1` is along-side `your_script.py` then you could import anything inside `dir1`. [Why are my imports broken?](http://www.python.org/dev/peps/pep-0395/#traps-for-the-unwary) – jfs Jan 26 '12 at 04:47
  • 1
    Finn, exactly what @J.F. Sebastian says. And then you *can* use relative imports in the modules inside your package. – Rob Wouters Jan 26 '12 at 05:28
  • relative imports would require `__package__` shenanigans – jfs Jan 26 '12 at 05:54
  • 1
    @J.F.Sebastian, not in a module inside a package. – Rob Wouters Jan 26 '12 at 06:08
0

You can actually do this:

import sys
sys.path.append('..')

and that will work. But don't do that. It could break other modules.

I guess you could remove it directly after the import, but don't.

EDIT:

Actually, this also works and I think there's no reason it's not safe:

inside in_dir2.py you can do:

import sys
import os
current_module = sys.modules[__name__]
indir2file=current_module.__file__
sys.path.append(os.path.dirname(os.path.abspath(indir2file))+os.sep+".."+os.sep)
import in_dir1

Try hard to restructure your code instead.

Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
  • 1
    Yeah, I've seen lots of people suggest run-time path hacks elsewhere (that's actually what I've used in the past) but everyone always follows up the sys path hack by saying "don't do it" so... – Finn Jan 25 '12 at 23:11