return d
-def lightweight_named_tuple(name, fields):
-
- tp_cls = type(
- name, (_LW,),
- dict([
- (field, _property_getters[idx])
- for idx, field in enumerate(fields) if field is not None
- ])
- )
-
- tp_cls._real_fields = fields
- tp_cls._fields = tuple([f for f in fields if f is not None])
-
- return tp_cls
-
-
class ImmutableContainer(object):
def _immutable(self, *arg, **kw):
raise TypeError("%s object is immutable" % self.__class__.__name__)
set.__init__(self)
self._list = []
if d is not None:
- self.update(d)
+ self._list = unique_list(d)
+ set.update(self, self._list)
+ else:
+ self._list = []
def add(self, element):
if element not in self:
"""Dictionary with 'squishy' removal of least
recently used items.
+ Note that either get() or [] should be used here, but
+ generally its not safe to do an "in" check first as the dictionary
+ can change subsequent to that call.
+
"""
def __init__(self, capacity=100, threshold=.5):
self.capacity = capacity
self.threshold = threshold
self._counter = 0
+ self._mutex = threading.Lock()
def _inc_counter(self):
self._counter += 1
return self._counter
+ def get(self, key, default=None):
+ item = dict.get(self, key, default)
+ if item is not default:
+ item[2] = self._inc_counter()
+ return item[1]
+ else:
+ return default
+
def __getitem__(self, key):
item = dict.__getitem__(self, key)
item[2] = self._inc_counter()
self._manage_size()
def _manage_size(self):
- while len(self) > self.capacity + self.capacity * self.threshold:
- by_counter = sorted(dict.values(self),
- key=operator.itemgetter(2),
- reverse=True)
- for item in by_counter[self.capacity:]:
- try:
- del self[item[0]]
- except KeyError:
- # if we couldn't find a key, most
- # likely some other thread broke in
- # on us. loop around and try again
- break
+ if not self._mutex.acquire(False):
+ return
+ try:
+ while len(self) > self.capacity + self.capacity * self.threshold:
+ by_counter = sorted(dict.values(self),
+ key=operator.itemgetter(2),
+ reverse=True)
+ for item in by_counter[self.capacity:]:
+ try:
+ del self[item[0]]
+ except KeyError:
+ # deleted elsewhere; skip
+ continue
+ finally:
+ self._mutex.release()
+
+
+_lw_tuples = LRUCache(1000)
+
+
+def lightweight_named_tuple(name, fields):
+ hash_ = (name, ) + tuple(fields)
+ tp_cls = _lw_tuples.get(hash_)
+ if tp_cls:
+ return tp_cls
+
+ tp_cls = type(
+ name, (_LW,),
+ dict([
+ (field, _property_getters[idx])
+ for idx, field in enumerate(fields) if field is not None
+ ] + [('__slots__', ())])
+ )
+
+ tp_cls._real_fields = fields
+ tp_cls._fields = tuple([f for f in fields if f is not None])
+
+ _lw_tuples[hash_] = tp_cls
+ return tp_cls
class ScopedRegistry(object):