Skip to content

Instantly share code, notes, and snippets.

@pankajp
Created December 8, 2018 17:37

Revisions

  1. pankajp created this gist Dec 8, 2018.
    12 changes: 12 additions & 0 deletions caching_mod.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    from mod_prop import mod_property, cached_mod_property


    @mod_property
    def my_prop():
    print('my_prop called')
    return 42

    @cached_mod_property
    def my_cached_prop():
    print('my_cached_property called')
    return '24'
    13 changes: 13 additions & 0 deletions caching_mod_check.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    import caching_mod
    print(caching_mod)
    print('p', caching_mod.my_prop)
    print('q', caching_mod.my_prop)

    from caching_mod import my_prop
    print('r', caching_mod.my_prop)
    print('s', caching_mod.my_prop)

    from caching_mod import my_cached_prop
    print('t')
    print('u', my_cached_prop)
    print('v', caching_mod.my_cached_prop)
    33 changes: 33 additions & 0 deletions mod_prop.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    """ 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)