On 31 Mrz., 18:48, s4g <rafals...@gmail.com> wrote: > 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 > ...
This and similar solutions ( see Istvan Alberts ) point me to a fundamental problem of the current import architecture. Suppose you really want to run a module as a script without a prior import from a module path: ...A\B\C> python my_module.py then the current working directory C is added to sys.path which means that the module finder searches in C but C isn't a known package. There is no C package in sys.modules even if the C directory is "declared" as a package by placing an __init__.py file in it. Same goes of course with B and A. Although the ceremony has been performed basically correct the interpreter god is not pacified and doesn't respond. But why not? Because it looks up for *living* imported packages in the module cache ( in sys.modules ). I don't think there is any particular design idea behind it. The module cache is just a simple flat dictionary; a no-brainer to implement and efficient for look ups. But it counteracts a domain model. All you are left with is those Finders, Loaders and Importers in Brett Cannons importlib. Everything remains deeply mysterious and I don't wonder that it took long for him to work this out. -- http://mail.python.org/mailman/listinfo/python-list