85 lines
2.1 KiB
Python
85 lines
2.1 KiB
Python
|
|
"""
|
|
Publication helps you maintain public-api-friendly modules by preventing \
|
|
unintentional access to private implementation details via introspection.
|
|
|
|
It's easy to use::
|
|
|
|
# yourmodule.py
|
|
import dependency1
|
|
import dependency2
|
|
|
|
from publication import publish
|
|
|
|
def implementation_detail():
|
|
...
|
|
|
|
def stuff():
|
|
...
|
|
implementation_detail()
|
|
...
|
|
|
|
__all__ = [
|
|
'stuff'
|
|
]
|
|
|
|
publish()
|
|
|
|
Now, C{from yourmodule import dependency1} just raises an C{ImportError} - as
|
|
you would want; C{dependency1} isn't part of yourmodule! So does C{from
|
|
yourmodule import dependency1} Only C{stuff} is I{supposed} to be in the public
|
|
interface you're trying to support, so only it can be imported.
|
|
|
|
All your implementation details are still accessible in a namespace called
|
|
C{_private}, which you can still use via C{from yourmodule._private import
|
|
dependency1}, for white-box testing and similar use-cases.
|
|
"""
|
|
|
|
from types import ModuleType
|
|
import sys
|
|
|
|
PRIVATE_NAME = "_private"
|
|
|
|
_nothing = object()
|
|
|
|
|
|
def publish():
|
|
# type: () -> None
|
|
"""
|
|
Publish the interface of the calling module as defined in C{__all__};
|
|
relegate the rest of it to a C{_private} API module.
|
|
|
|
Call it at the top level of your module after C{__all__} and all the names
|
|
described in it are defined; usually the best place to do this is as the
|
|
module's last line.
|
|
"""
|
|
localvars = sys._getframe(1).f_locals
|
|
name = localvars["__name__"]
|
|
all = localvars["__all__"]
|
|
public = ModuleType(name)
|
|
private = sys.modules[name]
|
|
sys.modules[name] = public
|
|
names = all + [
|
|
"__all__",
|
|
"__cached__",
|
|
"__doc__",
|
|
"__file__",
|
|
"__loader__",
|
|
"__name__",
|
|
"__package__",
|
|
"__path__",
|
|
"__spec__",
|
|
]
|
|
for published in names:
|
|
value = getattr(private, published, _nothing)
|
|
if value is not _nothing:
|
|
setattr(public, published, value)
|
|
setattr(public, PRIVATE_NAME, private)
|
|
sys.modules[".".join([name, PRIVATE_NAME])] = private
|
|
|
|
|
|
__version__ = "0.0.3"
|
|
|
|
__all__ = ["publish", "__version__"]
|
|
publish()
|