Applied latest changes to `ListMixin` from Aryeh Leib Taurog and added him to AUTHORS; fixed memory leak introduced in r10174 -- no longer call `ListMixin.__init__` and set methods manually because it created references that prevented garbage collection; fixed several routines that had no need to be class methods.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@10494 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
ae7cb577dd
commit
5e58810e21
1
AUTHORS
1
AUTHORS
|
@ -408,6 +408,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Christian Tanzer <tanzer@swing.co.at>
|
Christian Tanzer <tanzer@swing.co.at>
|
||||||
Tyler Tarabula <tyler.tarabula@gmail.com>
|
Tyler Tarabula <tyler.tarabula@gmail.com>
|
||||||
Tyson Tate <tyson@fallingbullets.com>
|
Tyson Tate <tyson@fallingbullets.com>
|
||||||
|
Aryeh Leib Taurog <http://www.aryehleib.com/>
|
||||||
Frank Tegtmeyer <fte@fte.to>
|
Frank Tegtmeyer <fte@fte.to>
|
||||||
Marcel Telka <marcel@telka.sk>
|
Marcel Telka <marcel@telka.sk>
|
||||||
Terry Huang <terryh.tp@gmail.com>
|
Terry Huang <terryh.tp@gmail.com>
|
||||||
|
|
|
@ -49,8 +49,7 @@ class GeometryCollection(GEOSGeometry):
|
||||||
return self.num_geom
|
return self.num_geom
|
||||||
|
|
||||||
### Methods for compatibility with ListMixin ###
|
### Methods for compatibility with ListMixin ###
|
||||||
@classmethod
|
def _create_collection(self, length, items):
|
||||||
def _create_collection(cls, length, items):
|
|
||||||
# Creating the geometry pointer array.
|
# Creating the geometry pointer array.
|
||||||
geoms = get_pointer_arr(length)
|
geoms = get_pointer_arr(length)
|
||||||
for i, g in enumerate(items):
|
for i, g in enumerate(items):
|
||||||
|
@ -58,17 +57,17 @@ class GeometryCollection(GEOSGeometry):
|
||||||
# allow GEOSGeometry types (python wrappers) or pointer types
|
# allow GEOSGeometry types (python wrappers) or pointer types
|
||||||
geoms[i] = capi.geom_clone(getattr(g, 'ptr', g))
|
geoms[i] = capi.geom_clone(getattr(g, 'ptr', g))
|
||||||
|
|
||||||
return capi.create_collection(c_int(cls._typeid), byref(geoms), c_uint(length))
|
return capi.create_collection(c_int(self._typeid), byref(geoms), c_uint(length))
|
||||||
|
|
||||||
def _getitem_internal(self, index):
|
def _get_single_internal(self, index):
|
||||||
return capi.get_geomn(self.ptr, index)
|
return capi.get_geomn(self.ptr, index)
|
||||||
|
|
||||||
def _getitem_external(self, index):
|
def _get_single_external(self, index):
|
||||||
"Returns the Geometry from this Collection at the given index (0-based)."
|
"Returns the Geometry from this Collection at the given index (0-based)."
|
||||||
# Checking the index and returning the corresponding GEOS geometry.
|
# Checking the index and returning the corresponding GEOS geometry.
|
||||||
return GEOSGeometry(capi.geom_clone(self._getitem_internal(index)), srid=self.srid)
|
return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
|
||||||
|
|
||||||
def _set_collection(self, length, items):
|
def _set_list(self, length, items):
|
||||||
"Create a new collection, and destroy the contents of the previous pointer."
|
"Create a new collection, and destroy the contents of the previous pointer."
|
||||||
prev_ptr = self.ptr
|
prev_ptr = self.ptr
|
||||||
srid = self.srid
|
srid = self.srid
|
||||||
|
@ -76,6 +75,9 @@ class GeometryCollection(GEOSGeometry):
|
||||||
if srid: self.srid = srid
|
if srid: self.srid = srid
|
||||||
capi.destroy_geom(prev_ptr)
|
capi.destroy_geom(prev_ptr)
|
||||||
|
|
||||||
|
_set_single = GEOSGeometry._set_single_rebuild
|
||||||
|
_assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kml(self):
|
def kml(self):
|
||||||
"Returns the KML for this Geometry Collection."
|
"Returns the KML for this Geometry Collection."
|
||||||
|
|
|
@ -90,7 +90,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
|
|
||||||
# Post-initialization setup.
|
# Post-initialization setup.
|
||||||
self._post_init(srid)
|
self._post_init(srid)
|
||||||
super(GEOSGeometry, self).__init__()
|
|
||||||
|
|
||||||
def _post_init(self, srid):
|
def _post_init(self, srid):
|
||||||
"Helper routine for performing post-initialization setup."
|
"Helper routine for performing post-initialization setup."
|
||||||
|
|
|
@ -74,12 +74,12 @@ class LineString(GEOSGeometry):
|
||||||
"Returns the number of points in this LineString."
|
"Returns the number of points in this LineString."
|
||||||
return len(self._cs)
|
return len(self._cs)
|
||||||
|
|
||||||
def _getitem_external(self, index):
|
def _get_single_external(self, index):
|
||||||
self._checkindex(index)
|
|
||||||
return self._cs[index]
|
return self._cs[index]
|
||||||
_getitem_internal = _getitem_external
|
|
||||||
|
|
||||||
def _set_collection(self, length, items):
|
_get_single_internal = _get_single_external
|
||||||
|
|
||||||
|
def _set_list(self, length, items):
|
||||||
ndim = self._cs.dims #
|
ndim = self._cs.dims #
|
||||||
hasz = self._cs.hasz # I don't understand why these are different
|
hasz = self._cs.hasz # I don't understand why these are different
|
||||||
|
|
||||||
|
|
|
@ -2,45 +2,52 @@
|
||||||
# Released under the New BSD license.
|
# Released under the New BSD license.
|
||||||
"""
|
"""
|
||||||
This module contains a base type which provides list-style mutations
|
This module contains a base type which provides list-style mutations
|
||||||
This is akin to UserList, but without specific data storage methods.
|
without specific data storage methods.
|
||||||
Possible candidate for a more general position in the source tree,
|
|
||||||
perhaps django.utils
|
See also http://www.aryehleib.com/MutableLists.html
|
||||||
|
|
||||||
Author: Aryeh Leib Taurog.
|
Author: Aryeh Leib Taurog.
|
||||||
"""
|
"""
|
||||||
class ListMixin(object):
|
class ListMixin(object):
|
||||||
"""
|
"""
|
||||||
A base class which provides complete list interface
|
A base class which provides complete list interface.
|
||||||
derived classes should implement the following:
|
Derived classes must call ListMixin's __init__() function
|
||||||
|
and implement the following:
|
||||||
|
|
||||||
function _getitem_external(self, i):
|
function _get_single_external(self, i):
|
||||||
Return single item with index i for general use
|
Return single item with index i for general use.
|
||||||
|
The index i will always satisfy 0 <= i < len(self).
|
||||||
|
|
||||||
function _getitem_internal(self, i):
|
function _get_single_internal(self, i):
|
||||||
Same as above, but for use within the class [Optional]
|
Same as above, but for use within the class [Optional]
|
||||||
|
Note that if _get_single_internal and _get_single_internal return
|
||||||
|
different types of objects, _set_list must distinguish
|
||||||
|
between the two and handle each appropriately.
|
||||||
|
|
||||||
function _set_collection(self, length, items):
|
function _set_list(self, length, items):
|
||||||
Recreate the entire object
|
Recreate the entire object.
|
||||||
|
|
||||||
|
NOTE: items may be a generator which calls _get_single_internal.
|
||||||
|
Therefore, it is necessary to cache the values in a temporary:
|
||||||
|
temp = list(items)
|
||||||
|
before clobbering the original storage.
|
||||||
|
|
||||||
function _set_single(self, i, value):
|
function _set_single(self, i, value):
|
||||||
Set the single item at index i to value [Optional]
|
Set the single item at index i to value [Optional]
|
||||||
If left undefined, all mutations will result in rebuilding
|
If left undefined, all mutations will result in rebuilding
|
||||||
the object using _set_collection.
|
the object using _set_list.
|
||||||
|
|
||||||
function __len__(self):
|
function __len__(self):
|
||||||
Return the length
|
Return the length
|
||||||
|
|
||||||
function __iter__(self):
|
|
||||||
Return an iterator for the object
|
|
||||||
|
|
||||||
int _minlength:
|
int _minlength:
|
||||||
The minimum legal length [Optional]
|
The minimum legal length [Optional]
|
||||||
|
|
||||||
int _maxlength:
|
int _maxlength:
|
||||||
The maximum legal length [Optional]
|
The maximum legal length [Optional]
|
||||||
|
|
||||||
iterable _allowed:
|
type or tuple _allowed:
|
||||||
A list of allowed item types [Optional]
|
A type or tuple of allowed item types [Optional]
|
||||||
|
|
||||||
class _IndexError:
|
class _IndexError:
|
||||||
The type of exception to be raise on invalid index [Optional]
|
The type of exception to be raise on invalid index [Optional]
|
||||||
|
@ -50,11 +57,11 @@ class ListMixin(object):
|
||||||
_maxlength = None
|
_maxlength = None
|
||||||
_IndexError = IndexError
|
_IndexError = IndexError
|
||||||
|
|
||||||
### Python initialization and list interface methods ###
|
### Python initialization and special list interface methods ###
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
if not hasattr(self, '_getitem_internal'):
|
if not hasattr(self, '_get_single_internal'):
|
||||||
self._getitem_internal = self._getitem_external
|
self._get_single_internal = self._get_single_external
|
||||||
|
|
||||||
if not hasattr(self, '_set_single'):
|
if not hasattr(self, '_set_single'):
|
||||||
self._set_single = self._set_single_rebuild
|
self._set_single = self._set_single_rebuild
|
||||||
|
@ -63,15 +70,15 @@ class ListMixin(object):
|
||||||
super(ListMixin, self).__init__(*args, **kwargs)
|
super(ListMixin, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Gets the coordinates of the point(s) at the specified index/slice."
|
"Get the item(s) at the specified index/slice."
|
||||||
if isinstance(index, slice):
|
if isinstance(index, slice):
|
||||||
return [self._getitem_external(i) for i in xrange(*index.indices(len(self)))]
|
return [self._get_single_external(i) for i in xrange(*index.indices(len(self)))]
|
||||||
else:
|
else:
|
||||||
index = self._checkindex(index)
|
index = self._checkindex(index)
|
||||||
return self._getitem_external(index)
|
return self._get_single_external(index)
|
||||||
|
|
||||||
def __delitem__(self, index):
|
def __delitem__(self, index):
|
||||||
"Delete the point(s) at the specified index/slice."
|
"Delete the item(s) at the specified index/slice."
|
||||||
if not isinstance(index, (int, long, slice)):
|
if not isinstance(index, (int, long, slice)):
|
||||||
raise TypeError("%s is not a legal index" % index)
|
raise TypeError("%s is not a legal index" % index)
|
||||||
|
|
||||||
|
@ -84,14 +91,14 @@ class ListMixin(object):
|
||||||
indexRange = range(*index.indices(origLen))
|
indexRange = range(*index.indices(origLen))
|
||||||
|
|
||||||
newLen = origLen - len(indexRange)
|
newLen = origLen - len(indexRange)
|
||||||
newItems = ( self._getitem_internal(i)
|
newItems = ( self._get_single_internal(i)
|
||||||
for i in xrange(origLen)
|
for i in xrange(origLen)
|
||||||
if i not in indexRange )
|
if i not in indexRange )
|
||||||
|
|
||||||
self._rebuild(newLen, newItems)
|
self._rebuild(newLen, newItems)
|
||||||
|
|
||||||
def __setitem__(self, index, val):
|
def __setitem__(self, index, val):
|
||||||
"Sets the Geometry at the specified index."
|
"Set the item(s) at the specified index/slice."
|
||||||
if isinstance(index, slice):
|
if isinstance(index, slice):
|
||||||
self._set_slice(index, val)
|
self._set_slice(index, val)
|
||||||
else:
|
else:
|
||||||
|
@ -99,7 +106,74 @@ class ListMixin(object):
|
||||||
self._check_allowed((val,))
|
self._check_allowed((val,))
|
||||||
self._set_single(index, val)
|
self._set_single(index, val)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"Iterate over the items in the list"
|
||||||
|
for i in xrange(len(self)):
|
||||||
|
yield self[i]
|
||||||
|
|
||||||
|
### Special methods for arithmetic operations ###
|
||||||
|
def __add__(self, other):
|
||||||
|
'add another list-like object'
|
||||||
|
return self.__class__(list(self) + list(other))
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
'add to another list-like object'
|
||||||
|
return other.__class__(list(other) + list(self))
|
||||||
|
|
||||||
|
def __iadd__(self, other):
|
||||||
|
'add another list-like object to self'
|
||||||
|
self.extend(list(other))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __mul__(self, n):
|
||||||
|
'multiply'
|
||||||
|
return self.__class__(list(self) * n)
|
||||||
|
|
||||||
|
def __rmul__(self, n):
|
||||||
|
'multiply'
|
||||||
|
return self.__class__(list(self) * n)
|
||||||
|
|
||||||
|
def __imul__(self, n):
|
||||||
|
'multiply'
|
||||||
|
if n <= 0:
|
||||||
|
del self[:]
|
||||||
|
else:
|
||||||
|
cache = list(self)
|
||||||
|
for i in range(n-1):
|
||||||
|
self.extend(cache)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
'cmp'
|
||||||
|
slen = len(self)
|
||||||
|
for i in range(slen):
|
||||||
|
try:
|
||||||
|
c = cmp(self[i], other[i])
|
||||||
|
except IndexError:
|
||||||
|
# must be other is shorter
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
# elements not equal
|
||||||
|
if c: return c
|
||||||
|
|
||||||
|
return cmp(slen, len(other))
|
||||||
|
|
||||||
### Public list interface Methods ###
|
### Public list interface Methods ###
|
||||||
|
## Non-mutating ##
|
||||||
|
def count(self, val):
|
||||||
|
"Standard list count method"
|
||||||
|
count = 0
|
||||||
|
for i in self:
|
||||||
|
if val == i: count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
def index(self, val):
|
||||||
|
"Standard list index method"
|
||||||
|
for i in xrange(0, len(self)):
|
||||||
|
if self[i] == val: return i
|
||||||
|
raise ValueError('%s not found in object' % str(val))
|
||||||
|
|
||||||
|
## Mutating ##
|
||||||
def append(self, val):
|
def append(self, val):
|
||||||
"Standard list append method"
|
"Standard list append method"
|
||||||
self[len(self):] = [val]
|
self[len(self):] = [val]
|
||||||
|
@ -120,32 +194,33 @@ class ListMixin(object):
|
||||||
del self[index]
|
del self[index]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def index(self, val):
|
|
||||||
"Standard list index method"
|
|
||||||
for i in xrange(0, len(self)):
|
|
||||||
if self[i] == val: return i
|
|
||||||
raise ValueError('%s not found in object' % str(val))
|
|
||||||
|
|
||||||
def remove(self, val):
|
def remove(self, val):
|
||||||
"Standard list remove method"
|
"Standard list remove method"
|
||||||
del self[self.index(val)]
|
del self[self.index(val)]
|
||||||
|
|
||||||
def count(self, val):
|
def reverse(self):
|
||||||
"Standard list count method"
|
"Standard list reverse method"
|
||||||
count = 0
|
self[:] = self[-1::-1]
|
||||||
for i in self:
|
|
||||||
if val == i: count += 1
|
|
||||||
return count
|
|
||||||
|
|
||||||
### Private API routines unique to ListMixin ###
|
def sort(self, cmp=cmp, key=None, reverse=False):
|
||||||
|
"Standard list sort method"
|
||||||
|
if key:
|
||||||
|
temp = [(key(v),v) for v in self]
|
||||||
|
temp.sort(cmp=cmp, key=lambda x: x[0], reverse=reverse)
|
||||||
|
self[:] = [v[1] for v in temp]
|
||||||
|
else:
|
||||||
|
temp = list(self)
|
||||||
|
temp.sort(cmp=cmp, reverse=reverse)
|
||||||
|
self[:] = temp
|
||||||
|
|
||||||
|
### Private routines ###
|
||||||
def _rebuild(self, newLen, newItems):
|
def _rebuild(self, newLen, newItems):
|
||||||
if newLen < self._minlength:
|
if newLen < self._minlength:
|
||||||
raise ValueError('Must have at least %d items' % self._minlength)
|
raise ValueError('Must have at least %d items' % self._minlength)
|
||||||
if self._maxlength is not None and newLen > self._maxlength:
|
if self._maxlength is not None and newLen > self._maxlength:
|
||||||
raise ValueError('Cannot have more than %d items' % self._maxlength)
|
raise ValueError('Cannot have more than %d items' % self._maxlength)
|
||||||
|
|
||||||
self._set_collection(newLen, newItems)
|
self._set_list(newLen, newItems)
|
||||||
|
|
||||||
def _set_single_rebuild(self, index, value):
|
def _set_single_rebuild(self, index, value):
|
||||||
self._set_slice(slice(index, index + 1, 1), [value])
|
self._set_slice(slice(index, index + 1, 1), [value])
|
||||||
|
@ -200,7 +275,7 @@ class ListMixin(object):
|
||||||
if i in newVals:
|
if i in newVals:
|
||||||
yield newVals[i]
|
yield newVals[i]
|
||||||
else:
|
else:
|
||||||
yield self._getitem_internal(i)
|
yield self._get_single_internal(i)
|
||||||
|
|
||||||
self._rebuild(newLen, newItems())
|
self._rebuild(newLen, newItems())
|
||||||
|
|
||||||
|
@ -229,6 +304,6 @@ class ListMixin(object):
|
||||||
|
|
||||||
if i < origLen:
|
if i < origLen:
|
||||||
if i < start or i >= stop:
|
if i < start or i >= stop:
|
||||||
yield self._getitem_internal(i)
|
yield self._get_single_internal(i)
|
||||||
|
|
||||||
self._rebuild(newLen, newItems())
|
self._rebuild(newLen, newItems())
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.contrib.gis.geos import prototypes as capi
|
||||||
|
|
||||||
class Point(GEOSGeometry):
|
class Point(GEOSGeometry):
|
||||||
_minlength = 2
|
_minlength = 2
|
||||||
|
_maxlength = 3
|
||||||
|
|
||||||
def __init__(self, x, y=None, z=None, srid=None):
|
def __init__(self, x, y=None, z=None, srid=None):
|
||||||
"""
|
"""
|
||||||
|
@ -36,7 +37,6 @@ class Point(GEOSGeometry):
|
||||||
# createPoint factory.
|
# createPoint factory.
|
||||||
super(Point, self).__init__(point, srid=srid)
|
super(Point, self).__init__(point, srid=srid)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _create_point(self, ndim, coords):
|
def _create_point(self, ndim, coords):
|
||||||
"""
|
"""
|
||||||
Create a coordinate sequence, set X, Y, [Z], and create point
|
Create a coordinate sequence, set X, Y, [Z], and create point
|
||||||
|
@ -52,7 +52,7 @@ class Point(GEOSGeometry):
|
||||||
|
|
||||||
return capi.create_point(cs)
|
return capi.create_point(cs)
|
||||||
|
|
||||||
def _set_collection(self, length, items):
|
def _set_list(self, length, items):
|
||||||
ptr = self._create_point(length, items)
|
ptr = self._create_point(length, items)
|
||||||
if ptr:
|
if ptr:
|
||||||
capi.destroy_geom(self.ptr)
|
capi.destroy_geom(self.ptr)
|
||||||
|
@ -76,15 +76,15 @@ class Point(GEOSGeometry):
|
||||||
if self.hasz: return 3
|
if self.hasz: return 3
|
||||||
else: return 2
|
else: return 2
|
||||||
|
|
||||||
def _getitem_external(self, index):
|
def _get_single_external(self, index):
|
||||||
self._checkindex(index)
|
|
||||||
if index == 0:
|
if index == 0:
|
||||||
return self.x
|
return self.x
|
||||||
elif index == 1:
|
elif index == 1:
|
||||||
return self.y
|
return self.y
|
||||||
elif index == 2:
|
elif index == 2:
|
||||||
return self.z
|
return self.z
|
||||||
_getitem_internal = _getitem_external
|
|
||||||
|
_get_single_internal = _get_single_external
|
||||||
|
|
||||||
def get_x(self):
|
def get_x(self):
|
||||||
"Returns the X component of the Point."
|
"Returns the X component of the Point."
|
||||||
|
|
|
@ -59,9 +59,8 @@ class Polygon(GEOSGeometry):
|
||||||
return GEOSGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
|
return GEOSGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
|
||||||
x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
|
x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
|
||||||
|
|
||||||
### These classmethods and routines are needed for list-like operation w/ListMixin ###
|
### These routines are needed for list-like operation w/ListMixin ###
|
||||||
@classmethod
|
def _create_polygon(self, length, items):
|
||||||
def _create_polygon(cls, length, items):
|
|
||||||
# Instantiate LinearRing objects if necessary, but don't clone them yet
|
# Instantiate LinearRing objects if necessary, but don't clone them yet
|
||||||
# _construct_ring will throw a TypeError if a parameter isn't a valid ring
|
# _construct_ring will throw a TypeError if a parameter isn't a valid ring
|
||||||
# If we cloned the pointers here, we wouldn't be able to clean up
|
# If we cloned the pointers here, we wouldn't be able to clean up
|
||||||
|
@ -71,30 +70,28 @@ class Polygon(GEOSGeometry):
|
||||||
if isinstance(r, GEOM_PTR):
|
if isinstance(r, GEOM_PTR):
|
||||||
rings.append(r)
|
rings.append(r)
|
||||||
else:
|
else:
|
||||||
rings.append(cls._construct_ring(r))
|
rings.append(self._construct_ring(r))
|
||||||
|
|
||||||
shell = cls._clone(rings.pop(0))
|
shell = self._clone(rings.pop(0))
|
||||||
|
|
||||||
n_holes = length - 1
|
n_holes = length - 1
|
||||||
if n_holes:
|
if n_holes:
|
||||||
holes = get_pointer_arr(n_holes)
|
holes = get_pointer_arr(n_holes)
|
||||||
for i, r in enumerate(rings):
|
for i, r in enumerate(rings):
|
||||||
holes[i] = cls._clone(r)
|
holes[i] = self._clone(r)
|
||||||
holes_param = byref(holes)
|
holes_param = byref(holes)
|
||||||
else:
|
else:
|
||||||
holes_param = None
|
holes_param = None
|
||||||
|
|
||||||
return capi.create_polygon(shell, holes_param, c_uint(n_holes))
|
return capi.create_polygon(shell, holes_param, c_uint(n_holes))
|
||||||
|
|
||||||
@classmethod
|
def _clone(self, g):
|
||||||
def _clone(cls, g):
|
|
||||||
if isinstance(g, GEOM_PTR):
|
if isinstance(g, GEOM_PTR):
|
||||||
return capi.geom_clone(g)
|
return capi.geom_clone(g)
|
||||||
else:
|
else:
|
||||||
return capi.geom_clone(g.ptr)
|
return capi.geom_clone(g.ptr)
|
||||||
|
|
||||||
@classmethod
|
def _construct_ring(self, param, msg='Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings'):
|
||||||
def _construct_ring(cls, param, msg='Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings'):
|
|
||||||
"Helper routine for trying to construct a ring from the given parameter."
|
"Helper routine for trying to construct a ring from the given parameter."
|
||||||
if isinstance(param, LinearRing): return param
|
if isinstance(param, LinearRing): return param
|
||||||
try:
|
try:
|
||||||
|
@ -103,7 +100,7 @@ class Polygon(GEOSGeometry):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
||||||
def _set_collection(self, length, items):
|
def _set_list(self, length, items):
|
||||||
# Getting the current pointer, replacing with the newly constructed
|
# Getting the current pointer, replacing with the newly constructed
|
||||||
# geometry, and destroying the old geometry.
|
# geometry, and destroying the old geometry.
|
||||||
prev_ptr = self.ptr
|
prev_ptr = self.ptr
|
||||||
|
@ -112,7 +109,7 @@ class Polygon(GEOSGeometry):
|
||||||
if srid: self.srid = srid
|
if srid: self.srid = srid
|
||||||
capi.destroy_geom(prev_ptr)
|
capi.destroy_geom(prev_ptr)
|
||||||
|
|
||||||
def _getitem_internal(self, index):
|
def _get_single_internal(self, index):
|
||||||
"""
|
"""
|
||||||
Returns the ring at the specified index. The first index, 0, will
|
Returns the ring at the specified index. The first index, 0, will
|
||||||
always return the exterior ring. Indices > 0 will return the
|
always return the exterior ring. Indices > 0 will return the
|
||||||
|
@ -120,8 +117,8 @@ class Polygon(GEOSGeometry):
|
||||||
return the first and second interior ring, respectively).
|
return the first and second interior ring, respectively).
|
||||||
|
|
||||||
CAREFUL: Internal/External are not the same as Interior/Exterior!
|
CAREFUL: Internal/External are not the same as Interior/Exterior!
|
||||||
_getitem_internal returns a pointer from the existing geometries for use
|
_get_single_internal returns a pointer from the existing geometries for use
|
||||||
internally by the object's methods. _getitem_external returns a clone
|
internally by the object's methods. _get_single_external returns a clone
|
||||||
of the same geometry for use by external code.
|
of the same geometry for use by external code.
|
||||||
"""
|
"""
|
||||||
if index == 0:
|
if index == 0:
|
||||||
|
@ -130,8 +127,11 @@ class Polygon(GEOSGeometry):
|
||||||
# Getting the interior ring, have to subtract 1 from the index.
|
# Getting the interior ring, have to subtract 1 from the index.
|
||||||
return capi.get_intring(self.ptr, index-1)
|
return capi.get_intring(self.ptr, index-1)
|
||||||
|
|
||||||
def _getitem_external(self, index):
|
def _get_single_external(self, index):
|
||||||
return GEOSGeometry(capi.geom_clone(self._getitem_internal(index)), srid=self.srid)
|
return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
|
||||||
|
|
||||||
|
_set_single = GEOSGeometry._set_single_rebuild
|
||||||
|
_assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
|
||||||
|
|
||||||
#### Polygon Properties ####
|
#### Polygon Properties ####
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -45,15 +45,15 @@ class GEOSMutationTest(unittest.TestCase):
|
||||||
def test01_PointMutations(self):
|
def test01_PointMutations(self):
|
||||||
'Testing Point mutations'
|
'Testing Point mutations'
|
||||||
for p in (Point(1,2,3), fromstr('POINT (1 2 3)')):
|
for p in (Point(1,2,3), fromstr('POINT (1 2 3)')):
|
||||||
self.assertEqual(p._getitem_external(1), 2.0, 'Point _getitem_external')
|
self.assertEqual(p._get_single_external(1), 2.0, 'Point _get_single_external')
|
||||||
|
|
||||||
# _set_single
|
# _set_single
|
||||||
p._set_single(0,100)
|
p._set_single(0,100)
|
||||||
self.assertEqual(p.coords, (100.0,2.0,3.0), 'Point _set_single')
|
self.assertEqual(p.coords, (100.0,2.0,3.0), 'Point _set_single')
|
||||||
|
|
||||||
# _set_collection
|
# _set_list
|
||||||
p._set_collection(2,(50,3141))
|
p._set_list(2,(50,3141))
|
||||||
self.assertEqual(p.coords, (50.0,3141.0), 'Point _set_collection')
|
self.assertEqual(p.coords, (50.0,3141.0), 'Point _set_list')
|
||||||
|
|
||||||
def test02_PointExceptions(self):
|
def test02_PointExceptions(self):
|
||||||
'Testing Point exceptions'
|
'Testing Point exceptions'
|
||||||
|
@ -72,15 +72,15 @@ class GEOSMutationTest(unittest.TestCase):
|
||||||
'Testing LineString mutations'
|
'Testing LineString mutations'
|
||||||
for ls in (LineString((1,0),(4,1),(6,-1)),
|
for ls in (LineString((1,0),(4,1),(6,-1)),
|
||||||
fromstr('LINESTRING (1 0,4 1,6 -1)')):
|
fromstr('LINESTRING (1 0,4 1,6 -1)')):
|
||||||
self.assertEqual(ls._getitem_external(1), (4.0,1.0), 'LineString _getitem_external')
|
self.assertEqual(ls._get_single_external(1), (4.0,1.0), 'LineString _get_single_external')
|
||||||
|
|
||||||
# _set_single
|
# _set_single
|
||||||
ls._set_single(0,(-50,25))
|
ls._set_single(0,(-50,25))
|
||||||
self.assertEqual(ls.coords, ((-50.0,25.0),(4.0,1.0),(6.0,-1.0)), 'LineString _set_single')
|
self.assertEqual(ls.coords, ((-50.0,25.0),(4.0,1.0),(6.0,-1.0)), 'LineString _set_single')
|
||||||
|
|
||||||
# _set_collection
|
# _set_list
|
||||||
ls._set_collection(2, ((-50.0,25.0),(6.0,-1.0)))
|
ls._set_list(2, ((-50.0,25.0),(6.0,-1.0)))
|
||||||
self.assertEqual(ls.coords, ((-50.0,25.0),(6.0,-1.0)), 'LineString _set_collection')
|
self.assertEqual(ls.coords, ((-50.0,25.0),(6.0,-1.0)), 'LineString _set_list')
|
||||||
|
|
||||||
lsa = LineString(ls.coords)
|
lsa = LineString(ls.coords)
|
||||||
for f in geos_function_tests:
|
for f in geos_function_tests:
|
||||||
|
@ -91,20 +91,20 @@ class GEOSMutationTest(unittest.TestCase):
|
||||||
for pg in (Polygon(((1,0),(4,1),(6,-1),(8,10),(1,0)),
|
for pg in (Polygon(((1,0),(4,1),(6,-1),(8,10),(1,0)),
|
||||||
((5,4),(6,4),(6,3),(5,4))),
|
((5,4),(6,4),(6,3),(5,4))),
|
||||||
fromstr('POLYGON ((1 0,4 1,6 -1,8 10,1 0),(5 4,6 4,6 3,5 4))')):
|
fromstr('POLYGON ((1 0,4 1,6 -1,8 10,1 0),(5 4,6 4,6 3,5 4))')):
|
||||||
self.assertEqual(pg._getitem_external(0),
|
self.assertEqual(pg._get_single_external(0),
|
||||||
LinearRing((1,0),(4,1),(6,-1),(8,10),(1,0)),
|
LinearRing((1,0),(4,1),(6,-1),(8,10),(1,0)),
|
||||||
'Polygon _getitem_external(0)')
|
'Polygon _get_single_external(0)')
|
||||||
self.assertEqual(pg._getitem_external(1),
|
self.assertEqual(pg._get_single_external(1),
|
||||||
LinearRing((5,4),(6,4),(6,3),(5,4)),
|
LinearRing((5,4),(6,4),(6,3),(5,4)),
|
||||||
'Polygon _getitem_external(1)')
|
'Polygon _get_single_external(1)')
|
||||||
|
|
||||||
# _set_collection
|
# _set_list
|
||||||
pg._set_collection(2, (((1,2),(10,0),(12,9),(-1,15),(1,2)),
|
pg._set_list(2, (((1,2),(10,0),(12,9),(-1,15),(1,2)),
|
||||||
((4,2),(5,2),(5,3),(4,2))))
|
((4,2),(5,2),(5,3),(4,2))))
|
||||||
self.assertEqual(pg.coords,
|
self.assertEqual(pg.coords,
|
||||||
(((1.0,2.0),(10.0,0.0),(12.0,9.0),(-1.0,15.0),(1.0,2.0)),
|
(((1.0,2.0),(10.0,0.0),(12.0,9.0),(-1.0,15.0),(1.0,2.0)),
|
||||||
((4.0,2.0),(5.0,2.0),(5.0,3.0),(4.0,2.0))),
|
((4.0,2.0),(5.0,2.0),(5.0,3.0),(4.0,2.0))),
|
||||||
'Polygon _set_collection')
|
'Polygon _set_list')
|
||||||
|
|
||||||
lsa = Polygon(*pg.coords)
|
lsa = Polygon(*pg.coords)
|
||||||
for f in geos_function_tests:
|
for f in geos_function_tests:
|
||||||
|
@ -114,10 +114,10 @@ class GEOSMutationTest(unittest.TestCase):
|
||||||
'Testing Collection mutations'
|
'Testing Collection mutations'
|
||||||
for mp in (MultiPoint(*map(Point,((3,4),(-1,2),(5,-4),(2,8)))),
|
for mp in (MultiPoint(*map(Point,((3,4),(-1,2),(5,-4),(2,8)))),
|
||||||
fromstr('MULTIPOINT (3 4,-1 2,5 -4,2 8)')):
|
fromstr('MULTIPOINT (3 4,-1 2,5 -4,2 8)')):
|
||||||
self.assertEqual(mp._getitem_external(2), Point(5,-4), 'Collection _getitem_external')
|
self.assertEqual(mp._get_single_external(2), Point(5,-4), 'Collection _get_single_external')
|
||||||
|
|
||||||
mp._set_collection(3, map(Point,((5,5),(3,-2),(8,1))))
|
mp._set_list(3, map(Point,((5,5),(3,-2),(8,1))))
|
||||||
self.assertEqual(mp.coords, ((5.0,5.0),(3.0,-2.0),(8.0,1.0)), 'Collection _set_collection')
|
self.assertEqual(mp.coords, ((5.0,5.0),(3.0,-2.0),(8.0,1.0)), 'Collection _set_list')
|
||||||
|
|
||||||
lsa = MultiPoint(*map(Point,((5,5),(3,-2),(8,1))))
|
lsa = MultiPoint(*map(Point,((5,5),(3,-2),(8,1))))
|
||||||
for f in geos_function_tests:
|
for f in geos_function_tests:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# Copyright (c) 2008-2009 Aryeh Leib Taurog, all rights reserved.
|
# Copyright (c) 2008-2009 Aryeh Leib Taurog, http://www.aryehleib.com
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
# Modified from original contribution by Aryeh Leib Taurog, which was
|
# Modified from original contribution by Aryeh Leib Taurog, which was
|
||||||
# released under the New BSD license.
|
# released under the New BSD license.
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -12,13 +14,11 @@ class UserListA(ListMixin):
|
||||||
|
|
||||||
def __len__(self): return len(self._list)
|
def __len__(self): return len(self._list)
|
||||||
|
|
||||||
def __iter__(self): return iter(self._list)
|
|
||||||
|
|
||||||
def __str__(self): return str(self._list)
|
def __str__(self): return str(self._list)
|
||||||
|
|
||||||
def __repr__(self): return repr(self._list)
|
def __repr__(self): return repr(self._list)
|
||||||
|
|
||||||
def _set_collection(self, length, items):
|
def _set_list(self, length, items):
|
||||||
# this would work:
|
# this would work:
|
||||||
# self._list = self._mytype(items)
|
# self._list = self._mytype(items)
|
||||||
# but then we wouldn't be testing length parameter
|
# but then we wouldn't be testing length parameter
|
||||||
|
@ -28,13 +28,9 @@ class UserListA(ListMixin):
|
||||||
|
|
||||||
self._list = self._mytype(itemList)
|
self._list = self._mytype(itemList)
|
||||||
|
|
||||||
def _getitem_external(self, index):
|
def _get_single_external(self, index):
|
||||||
return self._list[index]
|
return self._list[index]
|
||||||
|
|
||||||
_getitem_internal = _getitem_external
|
|
||||||
_set_single = ListMixin._set_single_rebuild
|
|
||||||
_assign_extended_slice = ListMixin._assign_extended_slice_rebuild
|
|
||||||
|
|
||||||
class UserListB(UserListA):
|
class UserListB(UserListA):
|
||||||
_mytype = list
|
_mytype = list
|
||||||
|
|
||||||
|
@ -55,22 +51,19 @@ class ListMixinTest(unittest.TestCase):
|
||||||
limit = 3
|
limit = 3
|
||||||
listType = UserListA
|
listType = UserListA
|
||||||
|
|
||||||
@classmethod
|
def lists_of_len(self, length=None):
|
||||||
def lists_of_len(cls, length=None):
|
if length is None: length = self.limit
|
||||||
if length is None: length = cls.limit
|
|
||||||
pl = range(length)
|
pl = range(length)
|
||||||
return pl, cls.listType(pl)
|
return pl, self.listType(pl)
|
||||||
|
|
||||||
@classmethod
|
def limits_plus(self, b):
|
||||||
def limits_plus(cls, b):
|
return range(-self.limit - b, self.limit + b)
|
||||||
return range(-cls.limit - b, cls.limit + b)
|
|
||||||
|
|
||||||
@classmethod
|
def step_range(self):
|
||||||
def step_range(cls):
|
return range(-1 - self.limit, 0) + range(1, 1 + self.limit)
|
||||||
return range(-1 - cls.limit, 0) + range(1, 1 + cls.limit)
|
|
||||||
|
|
||||||
def test01_getslice(self):
|
def test01_getslice(self):
|
||||||
'Testing slice retrieval'
|
'Slice retrieval'
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
for i in self.limits_plus(1):
|
for i in self.limits_plus(1):
|
||||||
self.assertEqual(pl[i:], ul[i:], 'slice [%d:]' % (i))
|
self.assertEqual(pl[i:], ul[i:], 'slice [%d:]' % (i))
|
||||||
|
@ -89,7 +82,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertEqual(pl[::k], ul[::k], 'slice [::%d]' % (k))
|
self.assertEqual(pl[::k], ul[::k], 'slice [::%d]' % (k))
|
||||||
|
|
||||||
def test02_setslice(self):
|
def test02_setslice(self):
|
||||||
'Testing slice assignment'
|
'Slice assignment'
|
||||||
def setfcn(x,i,j,k,L): x[i:j:k] = range(L)
|
def setfcn(x,i,j,k,L): x[i:j:k] = range(L)
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
for slen in range(self.limit + 1):
|
for slen in range(self.limit + 1):
|
||||||
|
@ -145,7 +138,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
def test03_delslice(self):
|
def test03_delslice(self):
|
||||||
'Testing delete slice'
|
'Delete slice'
|
||||||
for Len in range(self.limit):
|
for Len in range(self.limit):
|
||||||
pl, ul = self.lists_of_len(Len)
|
pl, ul = self.lists_of_len(Len)
|
||||||
del pl[:]
|
del pl[:]
|
||||||
|
@ -189,7 +182,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertEqual(pl[:], ul[:], 'del slice [::%d]' % (k))
|
self.assertEqual(pl[:], ul[:], 'del slice [::%d]' % (k))
|
||||||
|
|
||||||
def test04_get_set_del_single(self):
|
def test04_get_set_del_single(self):
|
||||||
'Testing get/set/delete single item'
|
'Get/set/delete single item'
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
for i in self.limits_plus(0):
|
for i in self.limits_plus(0):
|
||||||
self.assertEqual(pl[i], ul[i], 'get single item [%d]' % i)
|
self.assertEqual(pl[i], ul[i], 'get single item [%d]' % i)
|
||||||
|
@ -207,7 +200,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertEqual(pl[:], ul[:], 'del single item [%d]' % i)
|
self.assertEqual(pl[:], ul[:], 'del single item [%d]' % i)
|
||||||
|
|
||||||
def test05_out_of_range_exceptions(self):
|
def test05_out_of_range_exceptions(self):
|
||||||
'Testing out of range exceptions'
|
'Out of range exceptions'
|
||||||
def setfcn(x, i): x[i] = 20
|
def setfcn(x, i): x[i] = 20
|
||||||
def getfcn(x, i): return x[i]
|
def getfcn(x, i): return x[i]
|
||||||
def delfcn(x, i): del x[i]
|
def delfcn(x, i): del x[i]
|
||||||
|
@ -218,7 +211,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertRaises(IndexError, delfcn, ul, i) # 'del index %d' % i)
|
self.assertRaises(IndexError, delfcn, ul, i) # 'del index %d' % i)
|
||||||
|
|
||||||
def test06_list_methods(self):
|
def test06_list_methods(self):
|
||||||
'Testing list methods'
|
'List methods'
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
pl.append(40)
|
pl.append(40)
|
||||||
ul.append(40)
|
ul.append(40)
|
||||||
|
@ -228,6 +221,10 @@ class ListMixinTest(unittest.TestCase):
|
||||||
ul.extend(range(50,55))
|
ul.extend(range(50,55))
|
||||||
self.assertEqual(pl[:], ul[:], 'extend')
|
self.assertEqual(pl[:], ul[:], 'extend')
|
||||||
|
|
||||||
|
pl.reverse()
|
||||||
|
ul.reverse()
|
||||||
|
self.assertEqual(pl[:], ul[:], 'reverse')
|
||||||
|
|
||||||
for i in self.limits_plus(1):
|
for i in self.limits_plus(1):
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
pl.insert(i,50)
|
pl.insert(i,50)
|
||||||
|
@ -267,7 +264,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertRaises(ValueError, removefcn, ul, 40)
|
self.assertRaises(ValueError, removefcn, ul, 40)
|
||||||
|
|
||||||
def test07_allowed_types(self):
|
def test07_allowed_types(self):
|
||||||
'Testing type-restricted list'
|
'Type-restricted list'
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
ul._allowed = (int, long)
|
ul._allowed = (int, long)
|
||||||
ul[1] = 50
|
ul[1] = 50
|
||||||
|
@ -277,7 +274,7 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, setfcn, ul, slice(0,3,2), ('hello','goodbye'))
|
self.assertRaises(TypeError, setfcn, ul, slice(0,3,2), ('hello','goodbye'))
|
||||||
|
|
||||||
def test08_min_length(self):
|
def test08_min_length(self):
|
||||||
'Testing length limits'
|
'Length limits'
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
ul._minlength = 1
|
ul._minlength = 1
|
||||||
def delfcn(x,i): del x[:i]
|
def delfcn(x,i): del x[:i]
|
||||||
|
@ -293,13 +290,13 @@ class ListMixinTest(unittest.TestCase):
|
||||||
self.assertRaises(ValueError, ul.append, 10)
|
self.assertRaises(ValueError, ul.append, 10)
|
||||||
|
|
||||||
def test09_iterable_check(self):
|
def test09_iterable_check(self):
|
||||||
'Testing error on assigning non-iterable to slice'
|
'Error on assigning non-iterable to slice'
|
||||||
pl, ul = self.lists_of_len(self.limit + 1)
|
pl, ul = self.lists_of_len(self.limit + 1)
|
||||||
def setfcn(x, i, v): x[i] = v
|
def setfcn(x, i, v): x[i] = v
|
||||||
self.assertRaises(TypeError, setfcn, ul, slice(0,3,2), 2)
|
self.assertRaises(TypeError, setfcn, ul, slice(0,3,2), 2)
|
||||||
|
|
||||||
def test10_checkindex(self):
|
def test10_checkindex(self):
|
||||||
'Testing index check'
|
'Index check'
|
||||||
pl, ul = self.lists_of_len()
|
pl, ul = self.lists_of_len()
|
||||||
for i in self.limits_plus(0):
|
for i in self.limits_plus(0):
|
||||||
if i < 0:
|
if i < 0:
|
||||||
|
@ -313,6 +310,78 @@ class ListMixinTest(unittest.TestCase):
|
||||||
ul._IndexError = TypeError
|
ul._IndexError = TypeError
|
||||||
self.assertRaises(TypeError, ul._checkindex, -self.limit - 1)
|
self.assertRaises(TypeError, ul._checkindex, -self.limit - 1)
|
||||||
|
|
||||||
|
def test_11_sorting(self):
|
||||||
|
'Sorting'
|
||||||
|
pl, ul = self.lists_of_len()
|
||||||
|
pl.insert(0, pl.pop())
|
||||||
|
ul.insert(0, ul.pop())
|
||||||
|
pl.sort()
|
||||||
|
ul.sort()
|
||||||
|
self.assertEqual(pl[:], ul[:], 'sort')
|
||||||
|
mid = pl[len(pl) / 2]
|
||||||
|
pl.sort(key=lambda x: (mid-x)**2)
|
||||||
|
ul.sort(key=lambda x: (mid-x)**2)
|
||||||
|
self.assertEqual(pl[:], ul[:], 'sort w/ key')
|
||||||
|
|
||||||
|
pl.insert(0, pl.pop())
|
||||||
|
ul.insert(0, ul.pop())
|
||||||
|
pl.sort(reverse=True)
|
||||||
|
ul.sort(reverse=True)
|
||||||
|
self.assertEqual(pl[:], ul[:], 'sort w/ reverse')
|
||||||
|
mid = pl[len(pl) / 2]
|
||||||
|
pl.sort(key=lambda x: (mid-x)**2)
|
||||||
|
ul.sort(key=lambda x: (mid-x)**2)
|
||||||
|
self.assertEqual(pl[:], ul[:], 'sort w/ key')
|
||||||
|
|
||||||
|
def test_12_arithmetic(self):
|
||||||
|
'Arithmetic'
|
||||||
|
pl, ul = self.lists_of_len()
|
||||||
|
al = range(10,14)
|
||||||
|
self.assertEqual(list(pl + al), list(ul + al), 'add')
|
||||||
|
self.assertEqual(type(ul), type(ul + al), 'type of add result')
|
||||||
|
self.assertEqual(list(al + pl), list(al + ul), 'radd')
|
||||||
|
self.assertEqual(type(al), type(al + ul), 'type of radd result')
|
||||||
|
objid = id(ul)
|
||||||
|
pl += al
|
||||||
|
ul += al
|
||||||
|
self.assertEqual(pl[:], ul[:], 'in-place add')
|
||||||
|
self.assertEqual(objid, id(ul), 'in-place add id')
|
||||||
|
|
||||||
|
for n in (-1,0,1,3):
|
||||||
|
pl, ul = self.lists_of_len()
|
||||||
|
self.assertEqual(list(pl * n), list(ul * n), 'mul by %d' % n)
|
||||||
|
self.assertEqual(type(ul), type(ul * n), 'type of mul by %d result' % n)
|
||||||
|
self.assertEqual(list(n * pl), list(n * ul), 'rmul by %d' % n)
|
||||||
|
self.assertEqual(type(ul), type(n * ul), 'type of rmul by %d result' % n)
|
||||||
|
objid = id(ul)
|
||||||
|
pl *= n
|
||||||
|
ul *= n
|
||||||
|
self.assertEqual(pl[:], ul[:], 'in-place mul by %d' % n)
|
||||||
|
self.assertEqual(objid, id(ul), 'in-place mul by %d id' % n)
|
||||||
|
|
||||||
|
pl, ul = self.lists_of_len()
|
||||||
|
self.assertEqual(pl, ul, 'cmp for equal')
|
||||||
|
self.assert_(pl >= ul, 'cmp for gte self')
|
||||||
|
self.assert_(pl <= ul, 'cmp for lte self')
|
||||||
|
self.assert_(ul >= pl, 'cmp for self gte')
|
||||||
|
self.assert_(ul <= pl, 'cmp for self lte')
|
||||||
|
|
||||||
|
self.assert_(pl + [5] > ul, 'cmp')
|
||||||
|
self.assert_(pl + [5] >= ul, 'cmp')
|
||||||
|
self.assert_(pl < ul + [2], 'cmp')
|
||||||
|
self.assert_(pl <= ul + [2], 'cmp')
|
||||||
|
self.assert_(ul + [5] > pl, 'cmp')
|
||||||
|
self.assert_(ul + [5] >= pl, 'cmp')
|
||||||
|
self.assert_(ul < pl + [2], 'cmp')
|
||||||
|
self.assert_(ul <= pl + [2], 'cmp')
|
||||||
|
|
||||||
|
pl[1] = 20
|
||||||
|
self.assert_(pl > ul, 'cmp for gt self')
|
||||||
|
self.assert_(ul < pl, 'cmp for self lt')
|
||||||
|
pl[1] = -20
|
||||||
|
self.assert_(pl < ul, 'cmp for lt self')
|
||||||
|
self.assert_(pl < ul, 'cmp for lt self')
|
||||||
|
|
||||||
class ListMixinTestSingle(ListMixinTest):
|
class ListMixinTestSingle(ListMixinTest):
|
||||||
listType = UserListB
|
listType = UserListB
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue