summaryrefslogtreecommitdiffstats
path: root/ipalib/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipalib/util.py')
-rw-r--r--ipalib/util.py34
1 files changed, 34 insertions, 0 deletions
diff --git a/ipalib/util.py b/ipalib/util.py
index ffa275942..d575329e7 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -27,6 +27,7 @@ import time
import socket
import re
from types import NoneType
+from weakref import WeakKeyDictionary
from ipalib import errors
from ipalib.text import _
@@ -272,3 +273,36 @@ def validate_hostname(hostname):
if not all(regex_name.match(part) for part in hostname.split(".")):
raise ValueError(_('hostname parts may only include letters, numbers, and - ' \
'(which is not allowed as the last character)'))
+
+class cachedproperty(object):
+ """
+ A property-like attribute that caches the return value of a method call.
+
+ When the attribute is first read, the method is called and its return
+ value is saved and returned. On subsequent reads, the saved value is
+ returned.
+
+ Typical usage:
+ class C(object):
+ @cachedproperty
+ def attr(self):
+ return 'value'
+ """
+ __slots__ = ('getter', 'store')
+
+ def __init__(self, getter):
+ self.getter = getter
+ self.store = WeakKeyDictionary()
+
+ def __get__(self, obj, cls):
+ if obj is None:
+ return None
+ if obj not in self.store:
+ self.store[obj] = self.getter(obj)
+ return self.store[obj]
+
+ def __set__(self, obj, value):
+ raise AttributeError("can't set attribute")
+
+ def __delete__(self, obj):
+ raise AttributeError("can't delete attribute")