""" Module level property and cached property decorator """ import sys import types import functools def update_module_class(mod): class CachingModule(types.ModuleType): pass mod.__class__ = CachingModule def mod_property(func, cached=False): func_name = func.__name__ if '.' in func_name: raise ValueError('mod_property only applicable to top-level module functions') func_mod = sys.modules[func.__module__] if func_mod.__class__ == types.ModuleType: update_module_class(func_mod) elif func_mod.__class__.__name__ != 'CachingModule': raise RuntimeError(f'mod_property incompatible with module type: {func_mod.__name__}({func_mod.__class__.__qualname__})') @functools.wraps(func) def wrapper(mod): value = func() if cached: setattr(func_mod.__class__, func_name, value) delattr(func_mod, func_name) return value wrapper.__name__ = func_name setattr(func_mod.__class__, func_name, property(wrapper)) return wrapper def cached_mod_property(func): return mod_property(func, cached=True)