Search code examples
pythonpackagenamespaces

Can regular python packages contain namespace packages?


I have read https://peps.python.org/pep-0420/ but it does not explicitly declare that namespace packages are strictly only allowed on top-level. All examples show namespace packages as top-level packages.

Would this work (package1 and package2 are distributed in separate packages)?

package1/
+-- foo/
    +-- __init__.py
    +-- bar/
        +-- baz.py
package2/
+-- foo/
    +-- bar/
        +-- zoq.py

In the above example, "foo" is a regular package and "foo/bar" is a namespace package. I assume that the answer should be "no" since "foo" would have 2 different roles, but I could be wrong.

(A reason for this question would be if foo/__init__.py is in extensive use, and converting it to a namespace package would cause a major headache.)


Solution

  • Regular packages can contain namespace packages, but there's little point. Your example will not work.

    A namespace package can be split among multiple directories, but each of those must be a subdirectory of a directory listed in its "parent path". When a namespace package is a subpackage of another package, the parent path is the parent package's __path__.

    When the parent package is a regular package, its __path__ only has one entry. The namespace package is allowed to be "split" across... exactly one location, completely negating any benefit.

    It's not clear from your example whether foo is a top-level package, or whether you actually have package1.foo and package2.foo packages. If you have a single foo top-level package, then the import system will recognize the first foo directory as the location of that package, and completely ignore the second foo directory and anything inside it.

    If you have package1.foo and package2.foo packages, then these are separate packages that have nothing to do with each other. package2.foo and package2.foo.bar will be namespace packages, but package2.foo.bar will have no connection with package1.foo.bar - it will not be treated as a single foo.bar namespace package split across two directories.