Imported Upstream version 2008.1+svn1553
[opeanno-debian-packaging.git] / game / util / weaklist.py
blobe90d75b8889a9b94cf3abda4b5900cdb15fe651d
1 # ###################################################
2 # Copyright (C) 2008 The OpenAnno Team
3 # team@openanno.org
4 # This file is part of OpenAnno.
6 # OpenAnno is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the
18 # Free Software Foundation, Inc.,
19 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 # ###################################################
22 # This file was stolen from http://home.gna.org/meals/ at 2008-07-24
24 """
25 weaklist - list implementation that store objects with weakref
26 instead of strong ref
27 """
29 import weakref
31 class _CopyDocFromParentClass(type):
32 """
33 metaclass that copy, for a given class,
34 all the docstring from their parents if there are not set
35 """
37 def __init__(cls, name, bases, dict):
38 for name, method in dict.iteritems():
39 try:
40 if not method.__doc__:
41 method.__doc__ = getattr(bases[0], name).__doc__
42 except AttributeError:
43 pass
45 class WeakList(list):
46 """
47 A Weak_list can store objects but without keeping them
48 alive with references couting incrementation.
50 When objects are deleted or garbage_collected, they disapear from
51 the list.
53 ! WARNING: du to the *magic* deletion of item, some method here
54 are not guaranted to give the right result or even to work properly.
56 This class is NOT thread safe and NOT GC safe.
58 You can have problem with:
60 - extend can add broken weakref in the list
61 - sort can crash
62 - __iter__, __str__, __repr__ and __reversed can return some None
63 - all the rich comparison method
64 - count can return wrong values or outdated
65 - index can return too high values or forget to raise exceptions
66 - __get_item__ and __set_item__ are useless
68 Be also carrfull that your work with weakref, so some usual
69 tips don't work:
71 >>> weak = weaklist.WeakList(weakable_class())
72 >>> len(a)
75 """
77 # This copy all the list's doctstring into this class's method
78 # So even if the class look undocumented, it is ! (use pydoc)
79 __metaclass__ = _CopyDocFromParentClass
82 ## Basic custom
84 def __init__(self, items=None):
85 if items:
86 list.__init__(self, self.__iter_over_weakref(items))
87 else:
88 list.__init__(self)
90 def __str__(self):
91 return '[' + ', '.join((repr(i) for i in self)) + ']'
93 def __repr__(self):
94 return 'Weak_list((' + ', '.join((repr(i) for i in self)) + '))'
97 ## Special method
99 def __new_weekref(self, item):
100 """Create a weakref with the good callback"""
101 return weakref.ref(item, self.__remove_ref)
103 def __iter_over_weakref(self, iterable):
104 """For a given iterable, return an iterable generator over all weakref"""
105 return (self.__new_weekref(i) for i in iterable)
107 def __remove_ref(self, ref):
109 When an object from the list is destroy, this
110 method is call to remove it from list
113 list.remove(self, ref)
116 ## list method
118 def extend(self, iterable):
119 iterable = self.__iter_over_weakref(list(iterable))
120 list.extend(self, iterable)
122 def append(self, object):
123 list.append(self, weakref.ref(object, self.__remove_ref))
125 def remove(self, object):
126 list.remove(self, weakref.ref(object))
128 def count(self, value):
129 return list.count(self, weakref.ref(value))
131 def index(self, value, *args):
132 return list.index(self, weakref.ref(value), *args)
134 def pop(self, index=-1):
135 return list.pop(self,index)()
137 def sort(self, cmp=None, key=None, reverse=False):
138 sortable = list(self)
139 sortable.sort(cmp,key,reverse)
140 del self[:]
141 self.extend(sortable)
143 def insert(self, index, object):
144 list.insert(self, index, self.__new_weekref(object))
147 ## Emulating container types
149 def __getitem__(self, index):
150 return list.__getitem__(self, index)()
152 def __setitem__(self, index, value):
153 if isinstance(index,slice):
154 list.__setitem__(self, index, self.__iter_over_weakref(value))
155 else:
156 list.__setitem__(self, index, self.__new_weekref(value))
157 def __iter__(self):
158 return iter([i() for i in list.__iter__(self)])
160 def __contains__(self, item):
161 return list.__contains__(self, weakref.ref(item))
163 def __getslice__(self,i,j):
164 return WeakList(list(self)[i:j])
166 def __setslice__(self, i, j, iterable):
167 list.__setslice__(self, i, j, self.__iter_over_weakref(iterable))
169 def __reversed__(self):
170 return iter([i() for i in list.__reversed__(self)])
173 ## Emulating numeric types
175 def __iadd__(self, other):
176 self.extend(other)
177 return self
179 def __add__(self, other):
180 return self.__class__(list(self) + list(other))
183 ## Rich comparison
185 def __eq__(self, other):
186 if isinstance(other,WeakList):
187 other = list(other)
188 return list.__eq__(list(self), other)
190 def __ge__(self, other):
191 if isinstance(other,WeakList):
192 other = list(other)
193 return list.__ge__(list(self), other)
195 def __le__(self, other):
196 if isinstance(other,WeakList):
197 other = list(other)
199 return list.__le__(list(self), other)
201 def __gt__(self, other):
202 if isinstance(other,WeakList):
203 other = list(other)
205 return list.__gt__(list(self), other)
207 def __ne__(self, other):
208 if isinstance(other,WeakList):
209 other = list(other)
211 return list.__ne__(list(self), other)
213 def __lt__(self, other):
214 if isinstance(other,WeakList):
215 other = list(other)
217 return list.__lt__(list(self), other)
219 ### End of WeakList class