Search code examples
pythonpython-2.7project-structure

Project structure leads to redundant dot notation


I have created a Python package which builds on the structure indicated in Kenneth Reitz' "Repository Structure and Python" (1). The main package path is:

/projects-folder (not site-packages)
    /package
        /package
            __init__.py
            Datasets.py
            Draw.py
            Gmaps.py
            ShapeSVG.py
            project.py
        __init__.py
        setup.py

With the current structure, I must use the following module import syntax:

import package.package.Datasets

I would prefer to type the following:

import package.Datasets

I am capable of typing the same word twice, of course, but it feels wrong in a deeper sense, i.e., I am structuring my package incorrectly or misunderstanding how Python interprets that structure.

The outer __init__.py is required for Python to detect this package at all, per the docs (2). But that sets up /package/ as the top level of the package and /package/package/ as a sub-package, forcing me into the unwieldy import syntax above.

To avoid this, it seems that my options are to:

  • Create a package in which the outer folder contains the top level of package modules.
  • Add the inner folder to my PYTHONPATH environment variable.

Yet both of these seem like suboptimal workarounds for something that shouldn't be an issue in the first place. What should I do?


Solution

  • You've misunderstood. You have two package packages for some reason, but the source you cite never said to do that. The outer folder, with setup.py, is not supposed to be a package.

    It sounds like you're running Python in projects-folder and trying to import your package from there. That's not what you should be doing. You have several options to get your package into the import system. (I'll refer to the folder with setup.py in it as setupfolder, to distinguish it from the inner folder):

    • Build your package with setup.py, for example, python setup.py bdist-wheel --universal, and install the built package with pip.
    • Skip the build step and just run pip install path/to/setupfolder. Building the package produces an installer useful if you want to distribute your package, but maybe you don't want to do that.
    • "Install" the package's source tree in development mode with pip install -e path/to/setupfolder, so the Python import system will locate the package's source tree when performing imports. This is handy because you don't have to rebuild and reinstall if you edit the source repository, although you'll still want to restart any running Python processes that are using the package.
    • Run Python from directly inside the setupfolder.

    Any of these options will cause your package to be importable directly as package instead of package.package, as it should be.