Source code for meshed.caching

"""Caching meshes"""

from functools import cached_property
from inspect import signature

from meshed.util import func_name, LiteralVal


[docs] def set_cached_property_attr(obj, name, value): """ Helper to set cached properties. Reason: When adding cached_property dynamically (not just with the @cached_property) the name is not set correctly. This solves that. """ cached_value = cached_property(value) cached_value.__set_name__(obj, name) setattr(obj, name, cached_value)
[docs] class LazyProps: """ A class that makes all its attributes cached_property properties. Example: >>> class Klass(LazyProps): ... a = 1 ... b = 2 ... ... # methods with one argument are cached ... def c(self): ... print("computing c...") ... return self.a + self.b ... ... d = lambda x: 4 ... e = LazyProps.Literal(lambda x: 4) ... ... @LazyProps.Literal # to mark that this method should not be cached ... def method1(self): ... return self.a * 7 ... ... # Methods with more than one argument are not cached ... def method2(self, x): ... return x + 1 ... ... >>> k = Klass() >>> k.b 2 >>> k.c computing c... 3 >>> k.c # note that c is not recomputed 3 >>> k.d # d, a lambda with one argument, is treated as a cached property 4 >>> k.e() # e is marked as a literal so is not a cached property, so need to call 4 >>> k.method1() # method1 has one argument, but marked as a literal 7 >>> k.method2(10) # method2 has more than one argument, so is not a cached property 11 """ def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) for attr_name in (a for a in dir(cls) if not a.startswith('__')): attr_obj = getattr(cls, attr_name) if isinstance(attr_obj, LiteralVal): setattr(cls, attr_name, attr_obj.val) elif callable(attr_obj) and len(signature(attr_obj).parameters) == 1: set_cached_property_attr(cls, attr_name, attr_obj) Literal = LiteralVal # just to have Literal available as LazyProps.Literal
[docs] def add_cached_property(cls, method, attr_name=None): """ Add a method as a cached property to a class. """ attr_name = attr_name or func_name(method) set_cached_property_attr(cls, attr_name, method) return cls
[docs] def add_cached_property_from_func(cls, func, attr_name=None): """ Add a function cached property to a class. """ params = list(signature(func).parameters) def method(self): return func(**{k: getattr(self, k) for k in params}) method.__name__ = func.__name__ method.__doc__ = func.__doc__ return add_cached_property(cls, method, attr_name)
[docs] def with_cached_properties(funcs): """ A decorator to add cached properties to a class. """ def add_cached_properties(cls): for func in funcs: if not callable(func): func, attr_name = func # assume it's a (func, attr_name) pair else: attr_name = None add_cached_property_from_func(cls, func, attr_name) return cls return add_cached_properties