summaryrefslogtreecommitdiffstats
path: root/ipalib/util.py
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2011-11-01 08:58:05 -0400
committerAlexander Bokovoy <abokovoy@redhat.com>2012-01-02 11:51:26 +0300
commit9beb467d98cb16e09fcda5ebbeb27056dfff3a2d (patch)
treed374273454f5fa5627eb1fe83782c437cdbddde2 /ipalib/util.py
parent46d3abc450db20c3e4c0854dbf9e711f59db3bff (diff)
downloadfreeipa-9beb467d98cb16e09fcda5ebbeb27056dfff3a2d.tar.gz
freeipa-9beb467d98cb16e09fcda5ebbeb27056dfff3a2d.tar.xz
freeipa-9beb467d98cb16e09fcda5ebbeb27056dfff3a2d.zip
Fix attempted write to attribute of read-only object.
Add new class "cachedproperty" for creating property-like attributes that cache the return value of a method call. Also fix few issues in the unit tests to enable them to succeed. ticket 1959
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")