-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpublication.py
84 lines (65 loc) · 2.11 KB
/
publication.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""
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()