I am wondering if there is a mechanism in python to fetch the "public" path to a class object in python (PEP8, __all__, "explicit reexport", ...).
To provide a minimal example, let's assume the following package structure:
|-- my_package
| |-- __init__.py
| |-- _my_module.py
Let this be the file contents of my_package.__my_module.py:
class MyObject: ...
Let this be the file contents of my_package.__init__.py:
from ._my_module import MyObject
__all__ = [
"MyObject"
]
Is there a 'canonical' way of fetching the public path to MyObject - which should be my_package.MyObject (rather than my_package._my_module.MyObject)?
The following snippet works in the above example, but obviously bears a high risk of error (especially if you might want to use the returned string to do a programmatic import later on)
from typing import Any
from typing import Type
def get_public_path(to: Type[Any]) -> str:
module = ".".join(list(filter(lambda k: not str(k).startswith("_"), to.__module__.split("."))))
name = to.__qualname__
return ".".join([module, name])
if __name__ == '__main__':
from my_package import MyObject
print(get_public_path(MyObject))
The example is a pretty common pattern, where the exact code location of MyObejct is considered an internal implementation detail of the package, which may change at any time without further note. Users of the package must import the object via from my_package import MyObject, which is considered the public api.
I would hope, that there is a clean and obvious way of getting the "public" class path without a huge bunch of meta-programming inspection (e.g. iterating the "private" module path, recursively looking for __all__ sections inside the module path etc.)
Presumably, and in the lack of a clearly specified standard (there are potentially multiple paths to a class), there is no one obvious way to achieve this.
One clean way of achieving this would be to pin this information, e.g. in form of an
enum.Enum:And add good test coverage
If that grows out of hand, e.g. because the amount of types simply becomes too large to maintain, a reflection approach might be used as well, where a back reference to the original import statement (
from my_package import MyObject) is used to generate the class path