brandizzi
brandizzi

Reputation: 27050

Importing directly from a namespace package in setuptools

How to use a module as both a namespace package and as a container for classes in a specific subproject? That is, how can I import something directly from a namespace package instead of its subpackages?

An example can make the question clearer.

Three subpackages of calc

Suppose I want to create a namespace package called calc, and there are three projects on it (sscce: calcs.tar.gz). The first one, found at the calc-add directory, has the following structure:

calc-add/calc/
calc-add/calc/add.py
calc-add/calc/__init__.py

The content of calc-add/calc/__init__.py is just

__import__('pkg_resources').declare_namespace(__name__)

as required by namespace packages, and add.py has only the following function:

def op(n1, n2):
    return n1 + n2

There is another project, at the calc-sub directory, has the following structure:

calc-sub/calc/
calc-sub/calc/sub.py
calc-sub/calc/__init__.py

The __init__.py file is identical to the previous one and sub.py has only a simple function:

def op(n1, n2):
    return n1 - n2

Finally, I have a calc-main directory with the following content:

calc-main/calc/
calc-main/calc/main.py
calc-main/calc/__init__.py

Again, the __init__.py has only the mentioned line, yet main.py has the following code:

import calc.add, calc.sub

def apply(n1, n2, op):
    if op == "add":
        return calc.add.op(n1, n2)
    else:
        return calc.sub.op(n1, n2)

How do I call and how would I call the apply() function

If I invoke the Python interpreter with $PYTHONPATH set as below:

$ PYTHONPATH=$PYTHONPATH:../calc-add/:../calc-sub/ python

then I can call apply() this way:

>>> import calc.main
>>> calc.main.apply(2, 3, 'add')
5

However, I would like to call apply() directly from calc, as below:

>>> import calc
>>> calc.apply(2, 3, 'add')
5

It apparently works if I add the following line to calc-main/calc/__init__.py:

from main import apply

However, setuptools documenation is very clear:

You must NOT include any other code and data in a namespace package's __init__.py. Even though it may appear to work during development, or when projects are installed as .egg files, it will not work when the projects are installed using "system" packaging tools -- in such cases the __init__.py files will not be installed, let alone executed.

So how can I get what I want without breaking the restriction on __init__.py files? Is that possible?

Upvotes: 3

Views: 257

Answers (0)

Related Questions