32

I am trying to set a package with sub-packages in python. Here is the tree structure that I have at the moment:

myPackage
├── __init__.py
├── mySubPackage1
│   ├── foo2.py
│   ├── foo.py
│   └── __init__.py
├── mySubPackage2
│   ├── bar2.py
│   ├── bar.py
│   └── __init__.py
└── setup.py

All __init__.py are empty. Here is my setup.py:

from distutils.core import setup

if __name__ == "__main__":
    setup(
        name='myPackage',
        package_dir = {
            'mySubPackage1': 'mySubPackage1',
            'mySubPackage2': 'mySubPackage2'},
        packages=['mySubPackage1', 'mySubPackage2'],
    )

The problem is that, when I run python setup.py install from myPackage, the sub packages are installed into dist-packages:

/usr/local/lib/python2.7/dist-packages/mySubPackage1
/usr/local/lib/python2.7/dist-packages/mySubPackage2

I guess the problem is my setup.py, but I don't know how to fix it? Should it be in the parent directory of myPackage? If so, then how does it work when I pack the package into a zip using python setup.py sdist?

Max Malysh
  • 29,384
  • 19
  • 111
  • 115
Dror
  • 12,174
  • 21
  • 90
  • 160

2 Answers2

50

Just use setuptools instead of distutils, it has find_packages exactly for that purpose:

from setuptools import setup, find_packages

setup(
    name='myPackage',
    packages=find_packages(),
)
Max Malysh
  • 29,384
  • 19
  • 111
  • 115
18

TL;DR: Nest the package in another package having the same name.

I nested the super-package myPackage inside a directory (having the same name) as follow:

myPackage
├── myPackage
│   ├── __init__.py
│   ├── mySubPackage1
│   │   ├── foo1.py
│   │   ├── foo2.py
│   │   └── __init__.py
│   └── mySubPackage2
│       ├── bar1.py
│       ├── bar2.py
│       └── __init__.py
└── setup.py

Then, I updated the setup.py:

from distutils.core import setup
if __name__ == "__main__":
    setup(
        name='myPackage',
        package_dir = {
            'myPackage': 'myPackage',
            'myPackage.mySubPackage1': 'myPackage/mySubPackage1',
            'myPackage.mySubPackage2': 'myPackage/mySubPackage2'},
        packages=['myPackage', 'myPackage.mySubPackage1',
                  'myPackage.mySubPackage2']
    )

Now, sudo python setup.py install behaves as I expect and in dist-packages I have the following structure:

myPackage
├── __init__.py
├── __init__.pyc
├── mySubPackage1
│   ├── foo1.py
│   ├── foo1.pyc
│   ├── foo2.py
│   ├── foo2.pyc
│   ├── __init__.py
│   └── __init__.pyc
└── mySubPackage2
    ├── bar1.py
    ├── bar1.pyc
    ├── bar2.py
    ├── bar2.pyc
    ├── __init__.py
    └── __init__.pyc

and an egg file.

This is almost good. Now it is not platform independent because of the usage of /. To fix this, I edited setup.py as follow:

from distutils.core import setup
from distutils import util
if __name__ == "__main__":
    pathMySubPackage1 = util.convert_path('myPackage/mySubPackage1')
    pathMySubPackage2 = util.convert_path('myPackage/mySubPackage2')
    setup(
        name='myPackage',
        package_dir = {
            'myPackage': 'myPackage',
            'myPackage.mySubPackage1': pathMySubPackage1,
            'myPackage.mySubPackage2': pathMySubPackage2},
        packages=['myPackage', 'myPackage.mySubPackage1',
                  'myPackage.mySubPackage2']
    )
Dror
  • 12,174
  • 21
  • 90
  • 160
  • 4
    Copying FoxDot's comment: You were right to nest the package like you did in the reply but you don't need to specify paths using the package_dir keyword argument if your folder names already correspond to the subpackages etc. It's much better explained [here](https://docs.python.org/2/distutils/examples.html#pure-python-distribution-by-package). – Richard Aug 17 '17 at 01:33