/django/contrib/gis/geos/mutable_list.py

https://code.google.com/p/mango-py/ · Python · 309 lines · 271 code · 16 blank · 22 comment · 20 complexity · 9c155a33376588661aecc4019121154d MD5 · raw file

  1. # Copyright (c) 2008-2009 Aryeh Leib Taurog, all rights reserved.
  2. # Released under the New BSD license.
  3. """
  4. This module contains a base type which provides list-style mutations
  5. without specific data storage methods.
  6. See also http://www.aryehleib.com/MutableLists.html
  7. Author: Aryeh Leib Taurog.
  8. """
  9. class ListMixin(object):
  10. """
  11. A base class which provides complete list interface.
  12. Derived classes must call ListMixin's __init__() function
  13. and implement the following:
  14. function _get_single_external(self, i):
  15. Return single item with index i for general use.
  16. The index i will always satisfy 0 <= i < len(self).
  17. function _get_single_internal(self, i):
  18. Same as above, but for use within the class [Optional]
  19. Note that if _get_single_internal and _get_single_internal return
  20. different types of objects, _set_list must distinguish
  21. between the two and handle each appropriately.
  22. function _set_list(self, length, items):
  23. Recreate the entire object.
  24. NOTE: items may be a generator which calls _get_single_internal.
  25. Therefore, it is necessary to cache the values in a temporary:
  26. temp = list(items)
  27. before clobbering the original storage.
  28. function _set_single(self, i, value):
  29. Set the single item at index i to value [Optional]
  30. If left undefined, all mutations will result in rebuilding
  31. the object using _set_list.
  32. function __len__(self):
  33. Return the length
  34. int _minlength:
  35. The minimum legal length [Optional]
  36. int _maxlength:
  37. The maximum legal length [Optional]
  38. type or tuple _allowed:
  39. A type or tuple of allowed item types [Optional]
  40. class _IndexError:
  41. The type of exception to be raise on invalid index [Optional]
  42. """
  43. _minlength = 0
  44. _maxlength = None
  45. _IndexError = IndexError
  46. ### Python initialization and special list interface methods ###
  47. def __init__(self, *args, **kwargs):
  48. if not hasattr(self, '_get_single_internal'):
  49. self._get_single_internal = self._get_single_external
  50. if not hasattr(self, '_set_single'):
  51. self._set_single = self._set_single_rebuild
  52. self._assign_extended_slice = self._assign_extended_slice_rebuild
  53. super(ListMixin, self).__init__(*args, **kwargs)
  54. def __getitem__(self, index):
  55. "Get the item(s) at the specified index/slice."
  56. if isinstance(index, slice):
  57. return [self._get_single_external(i) for i in xrange(*index.indices(len(self)))]
  58. else:
  59. index = self._checkindex(index)
  60. return self._get_single_external(index)
  61. def __delitem__(self, index):
  62. "Delete the item(s) at the specified index/slice."
  63. if not isinstance(index, (int, long, slice)):
  64. raise TypeError("%s is not a legal index" % index)
  65. # calculate new length and dimensions
  66. origLen = len(self)
  67. if isinstance(index, (int, long)):
  68. index = self._checkindex(index)
  69. indexRange = [index]
  70. else:
  71. indexRange = range(*index.indices(origLen))
  72. newLen = origLen - len(indexRange)
  73. newItems = ( self._get_single_internal(i)
  74. for i in xrange(origLen)
  75. if i not in indexRange )
  76. self._rebuild(newLen, newItems)
  77. def __setitem__(self, index, val):
  78. "Set the item(s) at the specified index/slice."
  79. if isinstance(index, slice):
  80. self._set_slice(index, val)
  81. else:
  82. index = self._checkindex(index)
  83. self._check_allowed((val,))
  84. self._set_single(index, val)
  85. def __iter__(self):
  86. "Iterate over the items in the list"
  87. for i in xrange(len(self)):
  88. yield self[i]
  89. ### Special methods for arithmetic operations ###
  90. def __add__(self, other):
  91. 'add another list-like object'
  92. return self.__class__(list(self) + list(other))
  93. def __radd__(self, other):
  94. 'add to another list-like object'
  95. return other.__class__(list(other) + list(self))
  96. def __iadd__(self, other):
  97. 'add another list-like object to self'
  98. self.extend(list(other))
  99. return self
  100. def __mul__(self, n):
  101. 'multiply'
  102. return self.__class__(list(self) * n)
  103. def __rmul__(self, n):
  104. 'multiply'
  105. return self.__class__(list(self) * n)
  106. def __imul__(self, n):
  107. 'multiply'
  108. if n <= 0:
  109. del self[:]
  110. else:
  111. cache = list(self)
  112. for i in range(n-1):
  113. self.extend(cache)
  114. return self
  115. def __cmp__(self, other):
  116. 'cmp'
  117. slen = len(self)
  118. for i in range(slen):
  119. try:
  120. c = cmp(self[i], other[i])
  121. except IndexError:
  122. # must be other is shorter
  123. return 1
  124. else:
  125. # elements not equal
  126. if c: return c
  127. return cmp(slen, len(other))
  128. ### Public list interface Methods ###
  129. ## Non-mutating ##
  130. def count(self, val):
  131. "Standard list count method"
  132. count = 0
  133. for i in self:
  134. if val == i: count += 1
  135. return count
  136. def index(self, val):
  137. "Standard list index method"
  138. for i in xrange(0, len(self)):
  139. if self[i] == val: return i
  140. raise ValueError('%s not found in object' % str(val))
  141. ## Mutating ##
  142. def append(self, val):
  143. "Standard list append method"
  144. self[len(self):] = [val]
  145. def extend(self, vals):
  146. "Standard list extend method"
  147. self[len(self):] = vals
  148. def insert(self, index, val):
  149. "Standard list insert method"
  150. if not isinstance(index, (int, long)):
  151. raise TypeError("%s is not a legal index" % index)
  152. self[index:index] = [val]
  153. def pop(self, index=-1):
  154. "Standard list pop method"
  155. result = self[index]
  156. del self[index]
  157. return result
  158. def remove(self, val):
  159. "Standard list remove method"
  160. del self[self.index(val)]
  161. def reverse(self):
  162. "Standard list reverse method"
  163. self[:] = self[-1::-1]
  164. def sort(self, cmp=cmp, key=None, reverse=False):
  165. "Standard list sort method"
  166. if key:
  167. temp = [(key(v),v) for v in self]
  168. temp.sort(cmp=cmp, key=lambda x: x[0], reverse=reverse)
  169. self[:] = [v[1] for v in temp]
  170. else:
  171. temp = list(self)
  172. temp.sort(cmp=cmp, reverse=reverse)
  173. self[:] = temp
  174. ### Private routines ###
  175. def _rebuild(self, newLen, newItems):
  176. if newLen < self._minlength:
  177. raise ValueError('Must have at least %d items' % self._minlength)
  178. if self._maxlength is not None and newLen > self._maxlength:
  179. raise ValueError('Cannot have more than %d items' % self._maxlength)
  180. self._set_list(newLen, newItems)
  181. def _set_single_rebuild(self, index, value):
  182. self._set_slice(slice(index, index + 1, 1), [value])
  183. def _checkindex(self, index, correct=True):
  184. length = len(self)
  185. if 0 <= index < length:
  186. return index
  187. if correct and -length <= index < 0:
  188. return index + length
  189. raise self._IndexError('invalid index: %s' % str(index))
  190. def _check_allowed(self, items):
  191. if hasattr(self, '_allowed'):
  192. if False in [isinstance(val, self._allowed) for val in items]:
  193. raise TypeError('Invalid type encountered in the arguments.')
  194. def _set_slice(self, index, values):
  195. "Assign values to a slice of the object"
  196. try:
  197. iter(values)
  198. except TypeError:
  199. raise TypeError('can only assign an iterable to a slice')
  200. self._check_allowed(values)
  201. origLen = len(self)
  202. valueList = list(values)
  203. start, stop, step = index.indices(origLen)
  204. # CAREFUL: index.step and step are not the same!
  205. # step will never be None
  206. if index.step is None:
  207. self._assign_simple_slice(start, stop, valueList)
  208. else:
  209. self._assign_extended_slice(start, stop, step, valueList)
  210. def _assign_extended_slice_rebuild(self, start, stop, step, valueList):
  211. 'Assign an extended slice by rebuilding entire list'
  212. indexList = range(start, stop, step)
  213. # extended slice, only allow assigning slice of same size
  214. if len(valueList) != len(indexList):
  215. raise ValueError('attempt to assign sequence of size %d '
  216. 'to extended slice of size %d'
  217. % (len(valueList), len(indexList)))
  218. # we're not changing the length of the sequence
  219. newLen = len(self)
  220. newVals = dict(zip(indexList, valueList))
  221. def newItems():
  222. for i in xrange(newLen):
  223. if i in newVals:
  224. yield newVals[i]
  225. else:
  226. yield self._get_single_internal(i)
  227. self._rebuild(newLen, newItems())
  228. def _assign_extended_slice(self, start, stop, step, valueList):
  229. 'Assign an extended slice by re-assigning individual items'
  230. indexList = range(start, stop, step)
  231. # extended slice, only allow assigning slice of same size
  232. if len(valueList) != len(indexList):
  233. raise ValueError('attempt to assign sequence of size %d '
  234. 'to extended slice of size %d'
  235. % (len(valueList), len(indexList)))
  236. for i, val in zip(indexList, valueList):
  237. self._set_single(i, val)
  238. def _assign_simple_slice(self, start, stop, valueList):
  239. 'Assign a simple slice; Can assign slice of any length'
  240. origLen = len(self)
  241. stop = max(start, stop)
  242. newLen = origLen - stop + start + len(valueList)
  243. def newItems():
  244. for i in xrange(origLen + 1):
  245. if i == start:
  246. for val in valueList:
  247. yield val
  248. if i < origLen:
  249. if i < start or i >= stop:
  250. yield self._get_single_internal(i)
  251. self._rebuild(newLen, newItems())