Relative Imports, why the hell is it so hard?

s4g rafalskiy at gmail.com
Tue Mar 31 12:48:19 EDT 2009


Hi,

I was looking for a nice idiom for interpackage imports as I found
this thread.
Here come a couple of solutions I came up with. Any discussion is
welcome.

I assume the same file structure

\ App
| main.py
+--\subpack1
| | __init__.py
| | module1.py
|
+--\subpack2
| | __init__.py
| | module2.py


When you run main.py all imports relative to \App work fine, so the
only problem is running a module from within a subpackage as a script.
I therefore assume we want to run module1.py as a script, which wants
to import module2.

I hope the following solutions are self-evident

================= solution 1
--> in module1.py
import sys, os
if __name__ == '__main__':
    sys.path.append(os.path.normpath(__file__+'/../..'))

import subpack2.module2

================= solution 2
--> in subpack1/__init__.py
import sys, os

_top_package_level = 1   # with current package being level 0

_top_package = os.path.normpath(__file__ + '/..'*(_top_package_level
+1))
if _top_package not in sys.path:
    sys.path.append(_top_package)

--> in module1 or any module in the package, which requires import
relative to the package top
import __init__
import subpack2.module2


================= solution 3
--> in package_import.py, somewhere on the PYTHONPATH ( perhaps in
standard lib ;)

def set_top_package(module, level):
    _top_package = os.path.normpath(module + '/..'*(level+1))
    if _top_package not in sys.path:
        sys.path.append(_top_package)

class absolute_import(object):
    def __init__(self, module, level):
        self.level = level
        self.module = module

    def __enter__(self):
        sys.path.insert( 0,
            os.path.normpath(self.module + '/..'*(self.level+1))
            )

    def __exit__(self, exc_type, exc_val, exc_tb):
        del sys.path[0]

--> in module1
import package_import
package_import.set_top_package(__file__, 1)
import subpack2.module2

--> or in module1
import package_import
with package_import.absolute_import(__file__, 1):
    import subpack2.module2
    ...





More information about the Python-list mailing list