__all__ is supposed to define a module's API. This class lets you know when that contract is violated by raising a warning. As an alternative, raise AttributeError() instead to __all__ with an iron fist.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import sys
import types
import warnings
class EncapsulationWarning(RuntimeWarning): pass
class ModuleWrapper(types.ModuleType):
def __init__(self, context):
self.context = context
super(ModuleWrapper, self).__init__(
context.__name__,
context.__doc__)
def __getattribute__(self, key):
context = object.__getattribute__(self, 'context')
if key not in context.__all__:
warnings.warn('%s not in %s.__all__' % (key, context.__name__),
EncapsulationWarning,
2)
return context.__getattribute__(key)
import example
sys.modules['example'] = ModuleWrapper(example)
|
I would like Python programmers to put more thought into the API of their modules. This class makes it possible to get a warning or an error when names outside of __all__ are referenced from other code.
This recipe should be combined with its own import hook.