0
# Publication
1
2
A Python library that helps maintain clear public APIs by preventing unintentional access to private implementation details through introspection. Publication uses the existing convention of `__all__` and runtime module manipulation to hide everything that has not been marked as explicitly public, solving the problem where users accidentally depend on internal implementation details.
3
4
## Package Information
5
6
- **Package Name**: publication
7
- **Language**: Python
8
- **Python Compatibility**: Python 2.7+ and Python 3.x
9
- **Installation**: `pip install publication`
10
11
## Core Imports
12
13
```python
14
from publication import publish
15
```
16
17
To access version information:
18
19
```python
20
from publication import __version__
21
```
22
23
## Basic Usage
24
25
```python
26
# yourmodule.py
27
import dependency1
28
import dependency2
29
30
from publication import publish
31
32
def implementation_detail():
33
"""Internal function not intended for public use."""
34
...
35
36
def stuff():
37
"""Public function that users should call."""
38
...
39
implementation_detail()
40
...
41
42
__all__ = [
43
'stuff'
44
]
45
46
publish()
47
```
48
49
After calling `publish()`, only the names listed in `__all__` are accessible through normal imports:
50
51
```python
52
# This works - stuff is in __all__
53
from yourmodule import stuff
54
55
# This raises ImportError - implementation_detail is hidden
56
from yourmodule import implementation_detail
57
58
# This raises ImportError - dependency1 is hidden
59
from yourmodule import dependency1
60
61
# But implementation details are still accessible via _private namespace
62
from yourmodule._private import implementation_detail, dependency1
63
```
64
65
## Capabilities
66
67
### Module Publishing
68
69
Transforms a module's public interface by hiding all names not listed in `__all__`, while preserving access to private implementation details through a `_private` namespace.
70
71
```python { .api }
72
def publish():
73
"""
74
Publish the interface of the calling module as defined in __all__;
75
relegate the rest of it to a _private API module.
76
77
Call it at the top level of your module after __all__ and all the names
78
described in it are defined; usually the best place to do this is as the
79
module's last line.
80
81
The function uses frame introspection to access the calling module's
82
namespace and performs the following operations:
83
1. Creates a new public module containing only names from __all__
84
2. Moves the original module to a _private namespace
85
3. Updates sys.modules to use the new public module
86
4. Preserves essential module attributes (__doc__, __file__, etc.)
87
88
Parameters:
89
None (uses frame introspection to access caller's module)
90
91
Returns:
92
None
93
94
Side Effects:
95
- Modifies sys.modules to replace the calling module
96
- Creates a _private submodule with original implementation
97
- Hides non-public names from direct import access
98
"""
99
```
100
101
### Version Information
102
103
Package version identifier for compatibility and dependency management.
104
105
```python { .api }
106
__version__: str
107
# Current value: "0.0.3"
108
```
109
110
## Implementation Details
111
112
### Private Namespace Access
113
114
After `publish()` is called, the original module with all its implementation details becomes available as `<module_name>._private`:
115
116
```python
117
# If yourmodule.py called publish()
118
from yourmodule._private import implementation_detail
119
from yourmodule._private import dependency1
120
121
# The _private module is also accessible in sys.modules
122
import sys
123
private_module = sys.modules['yourmodule._private']
124
```
125
126
### Module Attributes Preserved
127
128
The following standard module attributes are automatically preserved in the public interface:
129
130
- `__all__` - The public interface definition
131
- `__cached__` - Bytecode cache file path
132
- `__doc__` - Module documentation string
133
- `__file__` - Module source file path
134
- `__loader__` - Module loader object
135
- `__name__` - Module name
136
- `__package__` - Parent package name
137
- `__path__` - Package search path (for packages)
138
- `__spec__` - Module specification object
139
140
### Type Checking Compatibility
141
142
For static type checkers like mypy, use conditional imports:
143
144
```python
145
from typing import TYPE_CHECKING
146
if TYPE_CHECKING:
147
from something import T
148
else:
149
from something._private import T
150
151
def returns_t() -> T:
152
...
153
```
154
155
### Error Handling
156
157
- **ImportError**: Raised when attempting to import non-public names after `publish()` is called
158
- **AttributeError**: May be raised if `__all__` is not defined in the calling module
159
- **Runtime errors**: Frame introspection failures if called from unexpected contexts (e.g., not called at module level)
160
- **KeyError**: Potential errors if module attributes are missing during the publishing process
161
162