Usage of __all__ in __init__.py

Hello,

I notice that some projects make use of the __all__ member in the __init__.py file to declare members that are part of the public API of a package.

I am wondering if this can be compared to module exports in JavaScript, for example.
And, if yes, if it would be a good thing if an inspection tool might show warnings whenever a client uses a member which is not listed in __all__?

Bye,
Jo

My understanding of __all__ was to control what’s included if say a * import took place and nothing else.

Yes, __all__ is just for star imports.

https://docs.python.org/3/tutorial/modules.html#importing-from-a-package


I do not use * imports. If I used them I would still not use __all__ because:

  • I do not like referring to Python identifiers by their names inside strings.
  • I still prefer to keep my __init__.py as clean as possible so everything defined there is probably OK for * import anyway and __all__ is redundant.

I guess that it is true that __all__ might be called a member of the module, but the normal terminology that we use in Python is:

  • __all__ is a global variable (remember that globals are per module and not per interpreter;
  • it lists the globals which are imported from that module by a star import.

Perhaps. You would have to explain module exports in Javascript first.

Python linters such as PyLint may choose to flag such uses, but they shouldn’t be a runtime warning.

  1. The use of __all__ is optional.
  2. It only affects what names are imported by star imports, not necessarily all public parts of the module API.
  3. For a package, it only lists the names from the top level module, not any submodules or subpackages.

For example, if you had this package structure:

starship/
+-- __init__.py
+-- engine/
>   +-- __init__.py
>   +-- impulse_drive.py
>   +-- warp_drive.py
+-- navigation.py
+-- shields.py
+-- weapons.py

then the __all__ inside ___init__.py only refers to imports using from starship import *, it says nothing about the starship.engine subpackage or starship.navigation, starship.shields and starship.weapons modules.

Each of those can have their own __all__. And remember that __all__ may not list all public names.

IIRC, exports in Javascript are necessary so that imports work. That’s different in Python, of course.

I also never use wildcard imports.
Still, I find the idea appealing to define my public API in __all__.

So, my question becomes:
Is it safe to assume that __all__ can be used to declare the public API of a package?

I read @steven.daprano 's answer as a yes.

No.

__all__ cannot be used to declare the public API of an entire package, unless that package contains only a single module.

__all__ can be used to declare the public API of a single module, but you cannot assume that it will be used that way.

You cannot assume that a module will have an __all__ attribute. If it does have one, you cannot assume that it includes the entire public API. Maybe it does, maybe it doesn’t.