Categories
python

Python Implicit Namespace Packages

A very confusing topic is python imports and paths.

One area that makes it more confusing was the introductions of implicit namespace packages.

https://peps.python.org/pep-0420/#differences-between-namespace-packages-and-regular-packages

These are packages that are found even without an __init__.py.

A folder can be created on the python path and that folder automatically becomes a python package. Not sure why or if this was intended but it is a fact of life in python 3.3 and later. Example:

$ mkdir holymoly
$ python
Python 3.10.6
>>> import holymoly
>>> holymoly
)>
>>> print(holymoly.__file__)
None

How to Know if a Package is An Explicit Namespace Package

  1. Import it

    import fixes_package
  2. Check the __file__ attribute

    print(fixes_package.__file__)

If it prints None then it is an implicit namespace package. If it does not – and prints out the location of the __init__.py it is a regular package

Another way is to import and repl it:

>>> import fixes_package
>>> fixes_package

Implicit namespace prints:

<module 'fixes_package' (<_frozen_importlib_external._NamespaceLoader object at 0x10683bd00>)>

If would print <module 'fixes_package' (namespace)> in older python versions

Regular package:

<module 'fixes_package' from '~/projects/playground/implicit_namespace/fixes_package/__init__.py'>

Packaging won’t find the Namespace Packages by default

When packaging the package, the package doesn’t contain an __init__.py sosetuptools.find_packages() won’t find the sub-package. You must use setuptools.find_namespace_packages() instead or explicitly list all packages in your setup.py. Source: packaging_namespace_packages

Anthonywritescode has a good explanation of namespace packages and their caveats.

Pyproject.toml

Using pyproject.toml and the setuptools build system backend – did pick up the implicit namespaced package from testing.

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

It appears that using setuptools.find_packages() directly to specify the packages is the root of the namespaced packages not being packaged.

Sources