abnowack
abnowack

Reputation: 380

Directory Structure for Importing Python Package using __init__.py

I've got a python project (projectA), which I've included as a git submodule in a separate project (projectB) as a subfolder. The structure is laid out as

projectB/
  projectB_file.py
  projectA/        (repository)
    projectA/      (source code)
      module1/
        file1.py   (contains Class1)
      file2.py     (contains Class2)
    tests/
      test_file1.py

I'm trying to figure out how to layout __init__.py files so in projectB_file.py I can import Class1 and Class2 as

from projectA.module1 import Class1
from projectA import Class2

Upvotes: 0

Views: 590

Answers (3)

justengel
justengel

Reputation: 6320

This is an annoying issue. The main approach I use is to edit the PYTHONPATH. This is essentially how I do it.

ProjectB/                   # Main Repository
    projectb/               # Package/library
        __init__.py
        projectB_file.py
    docs/
    tests/
    setup.py                # Setup file to distribute the library
    freeze.py               # CX_Freeze file to make executables

    ProjectA/               # Subrepository
        projecta/           # Package/library
            __init__.py
            projectA_file.py
            file2.py
            submodule/
                __init__.py
                file3.py
        pa_module1/         # Additional package/library in 1 project
            __init__.py
            file1.py
        docs/
        tests/
        setup.py

With this setup I have to edit the python path before running ProjectB's code. I use this structure, because it is easier for deployment and distribution. The subrepository helps track the version of ProjectA for each release of ProjectB.

cd ProjectB
export PYTHONPATH=${PWD}:${PWD}/ProjectA
python projectb/projectB_file.py

projectB_file.py

from projecta import projectA_file

This is for my development environment. For a release environment someone would install with the below code.

# Need a correct setup.py to handle 2 packages for pa_module1 and projecta
pip install ProjectA (install projecta to site-packages) 
cd ..
pip install ProjectB (install projectb to site-packages)

This means projectb and projecta are in site packages. From there any file can simply

from projectb import projectB_file
from projecta import projectA_file, file2
from pa_module1 import file1

# Personally I don't like imports that use project.sub.sub.sub ...
# I have seen it cause import confusion and problems, but it is useful in some situations.
from projecta.submodule import file3

#import projecta.projectA_file
#import projecta # if __init__.py has import code

file1.Class1()
file2.Class2()
file3.Class3()

Additionally with pip you can install a library as a developer environment which links to the real project directory instead of copying files to site-packages.

pip install -e ProjectA

Upvotes: 0

Blckknght
Blckknght

Reputation: 104712

I think having the top level projectA part of the import will be a mistake. That will require you to write your imports with projectA duplicated (e.g. import projectA.projectA.module1.file1).

Instead, you should add the top projectA folder to the module search path in some way (either as part of an install script for projectB, or with a setting in your IDE). That way, projectA as a top-level name will refer to the inner folder, which you actually intend to be the projectA package.

Upvotes: 1

Ethan Furman
Ethan Furman

Reputation: 69041

You'll need an __init__.py in each subdirectory you want to treat as a package. Which in your case means one in:

  • projectA
  • projectA/projectA
  • projectA/projectA/module1
  • projectA/projectA/tests

It would definitely be better you could lose that first projectA folder.

Upvotes: 0

Related Questions