Robert Wisner
Robert Wisner

Reputation: 155

Namespacing in Python imports

I have a rather complex python build project with a PyQT GUI interface. The builder is supposed to accept configuration for a list of projects, which may differ from user to user, and then customize the build process for a selected project. As a result, parts of the builder project are versioned with the project to be built (project specific UI elements and controller files), with the rest being located in the builders directory. The issue I am running into is an overlap in namespacing for imports. For example:

The builder directory might look like:

 Builder/
        Controllers/
            __init__.py
            BuilderController1.py
            BuilderController2.py
        UI/
            __init__.py
            BuilderUI_1.py
            BuilderUI_2.py
        .../
        __main__.py 

The project directory might look like:

Project/
    Project_Files/
    Build/
        Controllers/
            __init__.py
            ProjController1.py
            ProjController2.py
        UI/
            __init__.py
            ProjUI_1.py
            ProjUI_2.py
        .../
        __init__.py
        Project_setup.py        

With code in __main__.py such as:

...
sys.path.append("../path/to/Project/Build")
projSetup = __import__("Project_setup)
projSetup.run()    
...

And code in Project_setup.py such as:

...
from Controllers.ProjController1 import TestControl1
from Controllers.ProjController2 import TestControl2


def run():
    registerStage(name = 'TestControl1', controller = TestControl1(mainApp.getController(), displayName='TestControl1'), displayName = 'Test Control Page 1', parent = None)
    registerStage(name = 'TestControl2', controller = TestControl2(mainApp.getController(), displayName='TestControl2'), displayName = 'Test Control Page 2', parent = None)
...

The problem is that every time I run __main__.py, I get an error saying that:

ImportError: No module named Controllers.ProjController1

It seems that while searching the PYTHONPATH for the module ProjController1 the interpreter gets stranded in Builder/Controllers and then stops looking further down the path.

Is this reasonable behavior in python? Is there a method to obtain the same results that circumvents these issues?

I have tried using the various flavors of python importing ( import, __import__, imp, and importlib). Additionally it will work if I rename Project/Build/Controllers and Project/Build/UI, but given the possible complexity of these file structures I would rather not be stuck giving unique names to everything.

Upvotes: 1

Views: 127

Answers (1)

Dave Lasley
Dave Lasley

Reputation: 6242

Relative paths are reliant on your current working directory. Try the following for your sys path append:

import os
dir_ = os.path.dirname(__file__)
sys.path.append(os.path.join(dir_, "/path/to/Project/Build"))

It's really better to make a package, then import via the fully qualified path. In your root project dir, put a file setup.py with contents similar to:

#!/usr/bin/env python
from setuptools import setup
from setuptools import find_packages

setup(
    name='Name',
    version='1.0',
    packages=find_packages(exclude=('tests',)),
    cmdclass={

    },
    package_data={

    },
)

Then building and installing the package like so:

python setup.py build; python setup.py install

Perform the imports like so:

from project.hierarchy.module import Class

More information on creating packages is available in the Python docs.

Relative imports and modifying sys path have always caused me heartache.

Upvotes: 2

Related Questions