Open
Description
Consider a library like this:
# lib/__init__.py
from .exceptions import LibError
from .client import Client
__all__ = [
"Client",
"LibError",
]
# lib/exceptions.py
class LibError(Exception): ...
# lib/client.py
from .exceptions import LibError
class Client:
def some_method(self):
if something.bad:
raise LibError("thou shalt not pass")
Then the user code imports these names:
from lib import LibError # OK, explicitly re-exported
from lib.exceptions import LibError # OK, that's where it's defined
from lib.client import LibError # WARN: lib.exceptions.LibError is re-exported via lib.client
from lib.client import Client # OK
The reason to warn is that lib.client can change, for example to raise exception.MoreSpecificError
instead, which would not be a breaking change is MoreSpecificError inherits from LibError.
However, in that case, LibError may no longer be re-exported via lib.client.
Thus user code that depends on LibError name being present on lib.client is mistaken.
Ideas how this could be implemented:
- get the
__qualname__
for the imported name - check if the import path is different from qualname
- check if the imported name is also available at lib top level or
- check if the imported name is available at some intermediate level between lib and qualname
- suggest a more direct import