Search code examples
pythonpipdistutils

Is it really possible to use a different convention to lay out source directory without breaking intra-package references?


Suppose you are working on a python package. Here is the structure of the package (expressed in terms of a hierarchical file system):

/PackageName
    /src
        __init__.py
        /subpackage1
            __init__.py
            module1a.py
            module1b.py
        /subpackage2
            __init__.py
            module2a.py
            module2b.py
    /tests
    INSTALL
    LICENSE
    README
    setup.py

Distutils is used to build, distribute and install the package. In the setup script it is possible to tell Distutils about my convention to lay out my source directory (see here). In short I would put:

package_dir = {'packagename', 'src'}

However there is an issue when for example module1a needs to import module2a with an absolute import (see here). In short I would put in module1a:

import src.module2a

Once the package distributed and installed with pip a simple:

import packagename

raises:

ImportError: No module names src.module2a

A simple solution will be to rename src directory to packagename but (as my question clearly states) is there a solution to use a different convention to lay out source directory (perhaps a distutils or pip option I missed).

Thank you in advance.


Solution

  • Register your package with:

    package_dir = {'': 'src'}
    

    and create a packagename directory in src. You want to import packagename, not src. src is not meant to be a package itself:

    /PackageName
        /src
            /packagename
                __init__.py
                /subpackage1
                    __init__.py
                    module1a.py
                    module1b.py
                /subpackage2
                    __init__.py
                    module2a.py
                    module2b.py
        /tests
        INSTALL
        LICENSE
        README
        setup.py
    

    You can use relative imports between the modules anyway, but an absolute import is now

    from package.subpackage2 import module2b
    

    or you could use relative imports:

    from ..subpackage2 import module2b
    

    Sample real-life project: https://github.com/mjpieters/collective.transmogrifier