Author: jbronn
Date: 2007-08-02 00:31:10 -0500 (Thu, 02 Aug 2007)
New Revision: 5786

Modified:
   django/branches/gis/django/contrib/gis/geos/base.py
   django/branches/gis/django/contrib/gis/geos/collections.py
   django/branches/gis/django/contrib/gis/geos/geometries.py
   django/branches/gis/django/contrib/gis/geos/libgeos.py
   django/branches/gis/django/contrib/gis/tests/__init__.py
   django/branches/gis/django/contrib/gis/tests/geometries.py
   django/branches/gis/django/contrib/gis/tests/test_geos.py
Log:
gis: geos: fully-mutable geometries have landed; fixed GEOSPointer boolean 
value; equivalence now uses equals_exact (vertex-by-vertex matching); added 
in-place set operations; improved tests; getquoted() will return ST_* for 
PostGIS 1.2.2+.


Modified: django/branches/gis/django/contrib/gis/geos/base.py
===================================================================
--- django/branches/gis/django/contrib/gis/geos/base.py 2007-08-02 03:28:52 UTC 
(rev 5785)
+++ django/branches/gis/django/contrib/gis/geos/base.py 2007-08-02 05:31:10 UTC 
(rev 5786)
@@ -12,7 +12,7 @@
 # Python and GEOS-related dependencies.
 import re
 from warnings import warn
-from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, HAS_NUMPY, 
ISQLQuote
+from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, HAS_NUMPY, 
ISQLQuote, GEOM_FUNC_PREFIX
 from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError
 from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs
 if HAS_NUMPY: from numpy import ndarray, array
@@ -87,7 +87,7 @@
 
     def __del__(self):
         "Destroys this geometry -- only if the pointer is valid and whether or 
not it belongs to a parent."
-        #print 'Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, 
self._parent, self._ptr.valid)
+        #print 'base: Deleting %s (parent=%s, valid=%s)' % 
(self.__class__.__name__, self._parent, self._ptr.valid)
         # Only calling destroy on valid pointers not spawned from a parent
         if self._ptr.valid and not self._parent: 
lgeos.GEOSGeom_destroy(self._ptr())
 
@@ -101,11 +101,11 @@
     # Comparison operators
     def __eq__(self, other):
         "Equivalence testing."
-        return self.equals(other)
+        return self.equals_exact(other)
 
     def __ne__(self, other):
         "The not equals operator."
-        return not self.equals(other)
+        return not self.equals_exact(other)
 
     ### Geometry set-like operations ###
     # Thanks to Sean Gillies for inspiration:
@@ -115,21 +115,76 @@
         "Returns the union of this Geometry and the other."
         return self.union(other)
 
+    # g1 |= g2
+    def __ior__(self, other):
+        "Reassigns this Geometry to the union of this Geometry and the other."
+        return self.union(other)
+
     # g = g1 & g2
     def __and__(self, other):
         "Returns the intersection of this Geometry and the other."
         return self.intersection(other)
 
+    # g1 &= g2
+    def __iand__(self, other):
+        "Reassigns this Geometry to the intersection of this Geometry and the 
other."
+        return self.intersection(other)
+
     # g = g1 - g2
     def __sub__(self, other):
         "Return the difference this Geometry and the other."
         return self.difference(other)
 
+    # g1 -= g2
+    def __isub__(self, other):
+        "Reassigns this Geometry to the difference of this Geometry and the 
other."
+        return self.difference(other)
+
     # g = g1 ^ g2
     def __xor__(self, other):
         "Return the symmetric difference of this Geometry and the other."
         return self.sym_difference(other)
 
+    # g1 ^= g2
+    def __ixor__(self, other):
+        "Reassigns this Geometry to the symmetric difference of this Geometry 
and the other."
+        return self.sym_difference(other)
+
+    def _nullify(self):
+        """During initialization of geometries from other geometries, this 
routine is
+        used to nullify any parent geometries (since they will now be missing 
memory
+        components) and to nullify the geometry itself to prevent future 
access.
+        Only the address (an integer) of the current geometry is returned for 
use in
+        initializing the new geometry."""
+        # First getting the memory address of the geometry.
+        address = self._ptr()
+
+        # If the geometry is a child geometry, then the parent geometry 
pointer is
+        #  nullified.
+        if self._parent: self._parent.nullify()
+
+        # Nullifying the geometry pointer
+        self._ptr.nullify()
+
+        return address
+
+    def _reassign(self, new_geom):
+        "Internal routine for reassigning internal pointer to a new geometry."
+        # Only can re-assign when given a pointer or a geometry.
+        if not isinstance(new_geom, (GEOSPointer, GEOSGeometry)):
+            raise TypeError, 'cannot reassign geometry on given type: %s' % 
type(new_geom)
+        gtype = new_geom.geom_type 
+
+        # Re-assigning the internal GEOSPointer to the new geometry, nullifying
+        #  the new Geometry in the process.
+        if isinstance(new_geom, GEOSGeometry): 
self._ptr.set(new_geom._nullify())
+        else: self._ptr = new_geom
+        
+        # The new geometry class may be different from the original, so setting
+        #  the __class__ and populating the internal geometry or ring 
dictionary.
+        self.__class__ = GEOS_CLASSES[gtype]
+        if isinstance(self, (Polygon, GeometryCollection)): self._populate()
+
     #### Psycopg2 database adaptor routines ####
     def __conform__(self, proto):
         # Does the given protocol conform to what Psycopg2 expects?
@@ -140,7 +195,8 @@
 
     def getquoted(self):
         "Returns a properly quoted string for use in PostgresSQL/PostGIS."
-        return "GeometryFromText('%s', %s)" % (self.wkt, self.srid or -1)
+        # GeometryFromText() is ST_GeometryFromText() in PostGIS >= 1.2.2
+        return "%sGeometryFromText('%s', %s)" % (GEOM_FUNC_PREFIX, self.wkt, 
self.srid or -1)
     
     #### Coordinate Sequence Routines ####
     @property
@@ -299,10 +355,8 @@
     def get_srid(self):
         "Gets the SRID for the geometry, returns None if no SRID is set."
         s = lgeos.GEOSGetSRID(self._ptr())
-        if s == 0:
-            return None
-        else:
-            return s
+        if s == 0: return None
+        else: return s
 
     def set_srid(self, srid):
         "Sets the SRID for the geometry."
@@ -404,7 +458,7 @@
 
     def clone(self):
         "Clones this Geometry."
-        return GEOSGeometry(lgeos.GEOSGeom_clone(self._ptr()))
+        return GEOSGeometry(lgeos.GEOSGeom_clone(self._ptr()), srid=self.srid)
 
 # Class mapping dictionary
 from django.contrib.gis.geos.geometries import Point, Polygon, LineString, 
LinearRing

Modified: django/branches/gis/django/contrib/gis/geos/collections.py
===================================================================
--- django/branches/gis/django/contrib/gis/geos/collections.py  2007-08-02 
03:28:52 UTC (rev 5785)
+++ django/branches/gis/django/contrib/gis/geos/collections.py  2007-08-02 
05:31:10 UTC (rev 5786)
@@ -4,37 +4,25 @@
 """
 from ctypes import c_int, c_uint, byref, cast
 from types import TupleType, ListType
-from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, 
init_from_geom, get_pointer_arr, GEOM_PTR
+from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, 
get_pointer_arr, GEOM_PTR
 from django.contrib.gis.geos.base import GEOSGeometry
 from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError
 from django.contrib.gis.geos.geometries import Point, LineString, LinearRing, 
Polygon
 
-def init_from_poly(poly):
-    "Internal routine used for initializing Geometry Collections from 
Polygons."
-    # Constructing a new Polygon to take control of the rings.
-    p = Polygon(*tuple(ring for ring in poly))
-    
-    # If this Polygon came from a GeometryCollection, it is a child
-    #  and the parent geometry pointer is nullified.
-    if poly._parent: poly._parent.nullify()
-    
-    # Nullifying the polygon pointer
-    poly._ptr.nullify()
-
-    # Returning the address of the new Polygon.
-    return p._ptr()
-
 class GeometryCollection(GEOSGeometry):
     _allowed = (Point, LineString, LinearRing, Polygon)
     _typeid = 7
 
     def __init__(self, *args, **kwargs):
+        "Initializes a Geometry Collection from a sequence of Geometry 
objects."
+        # Setting up the collection for creation
         self._ptr = GEOSPointer(0) # Initially NULL
         self._geoms = {}
-        self._parent = False
+        self._parent = None
 
+        # Checking the arguments
         if not args:
-            raise TypeError, 'Must provide at least one LinearRing to 
initialize Polygon.'
+            raise TypeError, 'Must provide at least one Geometry to initialize 
%s.' % self.__class__.__name__
 
         if len(args) == 1: # If only one geometry provided or a list of 
geometries is provided
             if isinstance(args[0], (TupleType, ListType)):
@@ -54,23 +42,18 @@
 
         # Incrementing through each input geometry.
         for i in xrange(ngeom):
-            if isinstance(init_geoms[i], Polygon): 
-                # Special care is taken when importing from Polygons
-                geoms[i] = cast(init_from_poly(init_geoms[i]), GEOM_PTR)
-            else: 
-                geoms[i] = cast(init_from_geom(init_geoms[i]), GEOM_PTR)
-
+            geoms[i] = cast(init_geoms[i]._nullify(), GEOM_PTR)
+        
         # Calling the parent class, using the pointer returned from GEOS 
createCollection()
         super(GeometryCollection, 
self).__init__(lgeos.GEOSGeom_createCollection(c_int(self._typeid), 
byref(geoms), c_uint(ngeom)), **kwargs)
 
     def __del__(self):
         "Overloaded deletion method for Geometry Collections."
-        #print 'Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, 
self._parent, self._ptr.valid)
+        #print 'collection: Deleting %s (parent=%s, valid=%s)' % 
(self.__class__.__name__, self._parent, self._ptr.valid)
         # If this geometry is still valid, it hasn't been modified by others.
         if self._ptr.valid:
             # Nullifying pointers to internal geometries, preventing any 
attempted future access.
             for k in self._geoms: self._geoms[k].nullify()
-            super(GeometryCollection, self).__del__()
         else:
             # Internal memory has become part of other Geometry objects, must 
delete the
             #  internal objects which are still valid individually, since 
calling destructor
@@ -80,20 +63,38 @@
                 if self._geoms[k].valid:
                     lgeos.GEOSGeom_destroy(self._geoms[k].address)
                     self._geoms[k].nullify()
+        super(GeometryCollection, self).__del__()
             
     def __getitem__(self, index):
-        "For indexing on the multiple geometries."
+        "Returns the Geometry from this Collection at the given index 
(0-based)."
         # Checking the index and returning the corresponding GEOS geometry.
         self._checkindex(index)
         return GEOSGeometry(self._geoms[index], parent=self._ptr, 
srid=self.srid)
 
+    def __setitem__(self, index, geom):
+        "Sets the Geometry at the specified index."
+        self._checkindex(index)
+        if not isinstance(geom, self._allowed):
+            raise TypeError, 'Incompatible Geometry for collection.'
+
+        # Constructing the list of geometries that will go in the collection.
+        new_geoms = []
+        for i in xrange(len(self)):
+            if i == index: new_geoms.append(geom)
+            else: new_geoms.append(self[i])
+
+        # Creating a new geometry collection from the list, and
+        #  re-assigning the pointers.
+        new_collection = self.__class__(*new_geoms)
+        self._reassign(new_collection)
+        
     def __iter__(self):
-        "For iteration on the multiple geometries."
+        "Iterates over each Geometry in the Collection."
         for i in xrange(len(self)):
             yield self.__getitem__(i)
 
     def __len__(self):
-        "Returns the number of geometries in this collection."
+        "Returns the number of geometries in this Collection."
         return self.num_geom
 
     def _checkindex(self, index):
@@ -101,13 +102,18 @@
         if index < 0 or index >= self.num_geom:
             raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % 
str(index)
 
+    def _nullify(self):
+        "Overloaded from base method to nullify geometry references in this 
Collection."
+        # Nullifying the references to the internal Geometry objects from this 
Collection.
+        for k in self._geoms: self._geoms[k].nullify()
+        return super(GeometryCollection, self)._nullify()
+
     def _populate(self):
         "Populates the internal child geometry dictionary."
         self._geoms = {}
         for i in xrange(self.num_geom):
             self._geoms[i] = GEOSPointer(lgeos.GEOSGetGeometryN(self._ptr(), 
c_int(i)))
 
-
 # MultiPoint, MultiLineString, and MultiPolygon class definitions.
 class MultiPoint(GeometryCollection): 
     _allowed = Point

Modified: django/branches/gis/django/contrib/gis/geos/geometries.py
===================================================================
--- django/branches/gis/django/contrib/gis/geos/geometries.py   2007-08-02 
03:28:52 UTC (rev 5785)
+++ django/branches/gis/django/contrib/gis/geos/geometries.py   2007-08-02 
05:31:10 UTC (rev 5786)
@@ -7,7 +7,7 @@
 from ctypes import c_double, c_int, c_uint, byref, cast
 from types import FloatType, IntType, ListType, TupleType
 from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs
-from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, 
get_pointer_arr, init_from_geom, GEOM_PTR, HAS_NUMPY
+from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, 
get_pointer_arr, GEOM_PTR, HAS_NUMPY
 from django.contrib.gis.geos.base import GEOSGeometry
 from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError
 if HAS_NUMPY: from numpy import ndarray, array
@@ -21,7 +21,9 @@
           >>> p = Point(5, 23, 8) # 3D point, passed in with individual 
parameters
         """
 
+        # Setting-up for Point Creation
         self._ptr = GEOSPointer(0) # Initially NULL
+        self._parent = None
 
         if isinstance(x, (TupleType, ListType)):
             # Here a tuple or list was passed in under the ``x`` parameter.
@@ -132,7 +134,9 @@
           ls = LineString(array([(1, 1), (2, 2)]))
           ls = LineString(Point(1, 1), Point(2, 2))
         """
+        # Setting up for LineString creation
         self._ptr = GEOSPointer(0) # Initially NULL
+        self._parent = None
 
         # If only one argument was provided, then set the coords array 
appropriately
         if len(args) == 1: coords = args[0]
@@ -254,6 +258,7 @@
           poly = Polygon(shell, (hole1, hole2))
         """
         self._ptr = GEOSPointer(0) # Initially NULL
+        self._parent = None
         self._rings = {} 
         if not args:
             raise TypeError, 'Must provide at list one LinearRing instance to 
initialize Polygon.'
@@ -277,44 +282,59 @@
         holes = get_pointer_arr(nholes)
         for i in xrange(nholes):
             # Casting to the Geometry Pointer type
-            holes[i] = cast(init_from_geom(init_holes[i]), GEOM_PTR)
+            holes[i] = cast(init_holes[i]._nullify(), GEOM_PTR)
                       
         # Getting the shell pointer address, 
-        shell = init_from_geom(ext_ring)
+        shell = ext_ring._nullify()
 
         # Calling with the GEOS createPolygon factory.
         super(Polygon, self).__init__(lgeos.GEOSGeom_createPolygon(shell, 
byref(holes), c_uint(nholes)), **kwargs)
 
     def __del__(self):
         "Overloaded deletion method for Polygons."
-        #print 'Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, 
self._parent, self._ptr.valid)
+        #print 'polygon: Deleting %s (parent=%s, valid=%s)' % 
(self.__class__.__name__, self._parent, self._ptr.valid)
         # If this geometry is still valid, it hasn't been modified by others.
         if self._ptr.valid:
             # Nulling the pointers to internal rings, preventing any attempted 
future access
             for k in self._rings: self._rings[k].nullify()
-            super(Polygon, self).__del__()
-        else:
+        elif not self._parent: 
             # Internal memory has become part of other objects; must delete 
the 
             #  internal objects which are still valid individually, since 
calling
             #  destructor on entire geometry will result in an attempted 
deletion 
-            #  of NULL pointers for the missing components.
+            #  of NULL pointers for the missing components.  Not performed on
+            #  children Polygons from MultiPolygon or GeometryCollection 
objects.
             for k in self._rings:
                 if self._rings[k].valid:
                     lgeos.GEOSGeom_destroy(self._rings[k].address)
                     self._rings[k].nullify()
+        super(Polygon, self).__del__()
 
     def __getitem__(self, index):
         """Returns the ring at the specified index.  The first index, 0, will 
always
         return the exterior ring.  Indices > 0 will return the interior 
ring."""
-        if index < 0 or index > self.num_interior_rings:
-            raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % 
str(index)
+        if index == 0:
+            return self.exterior_ring
         else:
-            if index == 0:
-                return self.exterior_ring
-            else:
-                # Getting the interior ring, have to subtract 1 from the index.
-                return self.get_interior_ring(index-1) 
+            # Getting the interior ring, have to subtract 1 from the index.
+            return self.get_interior_ring(index-1) 
 
+    def __setitem__(self, index, ring):
+        "Sets the ring at the specified index with the given ring."
+        # Checking the index and ring parameters.
+        self._checkindex(index)
+        if not isinstance(ring, LinearRing):
+            raise TypeError, 'must set Polygon index with a LinearRing object'
+
+        # Constructing the ring parameters
+        new_rings = []
+        for i in xrange(len(self)):
+            if index == i: new_rings.append(ring)
+            else: new_rings.append(self[i])
+
+        # Constructing the new Polygon with the ring parameters, and 
reassigning the internals.
+        new_poly = Polygon(*new_rings)
+        self._reassign(new_poly)
+
     def __iter__(self):
         "Iterates over each ring in the polygon."
         for i in xrange(len(self)):
@@ -324,6 +344,17 @@
         "Returns the number of rings in this Polygon."
         return self.num_interior_rings + 1
 
+    def _checkindex(self, index):
+        "Internal routine for checking the given ring index."
+        if index < 0 or index >= len(self):
+            raise GEOSGeometryIndexError, 'invalid Polygon ring index: %s' % 
index
+
+    def _nullify(self):
+        "Overloaded from base method to nullify ring references as well."
+        # Nullifying the references to the internal rings of this Polygon.
+        for k in self._rings: self._rings[k].nullify()
+        return super(Polygon, self)._nullify()
+
     def _populate(self):
         "Populates the internal rings dictionary."
         # Getting the exterior ring first for the 0th index.
@@ -336,13 +367,9 @@
     def get_interior_ring(self, ring_i):
         """Gets the interior ring at the specified index,
         0 is for the first interior ring, not the exterior ring."""
-
-        # Making sure the ring index is within range
-        if ring_i < 0 or ring_i >= self.num_interior_rings:
-            raise IndexError, 'ring index out of range'
-
-        # Returning the ring from the internal ring dictionary (have to
-        #   add one to the index)
+        # Returning the ring from the internal ring dictionary (have to add one
+        #   to index since all internal rings come after the exterior ring)
+        self._checkindex(ring_i+1)
         return GEOSGeometry(self._rings[ring_i+1], parent=self._ptr, 
srid=self.srid)
                                                         
     #### Polygon Properties ####
@@ -361,14 +388,13 @@
         "Gets the exterior ring of the Polygon."
         return GEOSGeometry(self._rings[0], parent=self._ptr, srid=self.srid)
 
-    def set_ext_ring(self):
+    def set_ext_ring(self, ring):
         "Sets the exterior ring of the Polygon."
-        # Sets the exterior ring
-        raise NotImplementedError
+        self[0] = ring
 
     # properties for the exterior ring/shell
-    exterior_ring = property(get_ext_ring)
-    shell = property(get_ext_ring)
+    exterior_ring = property(get_ext_ring, set_ext_ring)
+    shell = property(get_ext_ring, set_ext_ring)
     
     @property
     def tuple(self):

Modified: django/branches/gis/django/contrib/gis/geos/libgeos.py
===================================================================
--- django/branches/gis/django/contrib/gis/geos/libgeos.py      2007-08-02 
03:28:52 UTC (rev 5785)
+++ django/branches/gis/django/contrib/gis/geos/libgeos.py      2007-08-02 
05:31:10 UTC (rev 5786)
@@ -18,11 +18,13 @@
 except ImportError:
     HAS_NUMPY = False
 
-# Psycopg2 supported?
+# Are psycopg2 and GeoDjango models being used?
 try:
     from psycopg2.extensions import ISQLQuote
-except ImportError:
+    from django.contrib.gis.db.backend.postgis import GEOM_FUNC_PREFIX
+except (ImportError, EnvironmentError):
     ISQLQuote = None
+    GEOM_FUNC_PREFIX = None
 
 # Setting the appropriate name for the GEOS-C library, depending on which
 # OS and POSIX platform we're running.
@@ -71,21 +73,22 @@
 #  "extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, 
GEOSMessageHandler error_function);"
 lgeos.initGEOS(notice_h, error_h)
 
-#### GEOS Geometry Pointer utilities. ####
+#### GEOS Geometry Pointer object, related C data structures, and functions. 
####
 
 # Opaque GEOS geometry structure
 class GEOSGeom_t(Structure): 
     "Opaque structure used when arrays of geometries are needed as parameters."
     pass
+
 # Pointer to opaque geometry structure
 GEOM_PTR = POINTER(GEOSGeom_t)
+
 # Used specifically by the GEOSGeom_createPolygon and 
GEOSGeom_createCollection GEOS routines
 def get_pointer_arr(n):
     "Gets a ctypes pointer array (of length `n`) for GEOSGeom_t opaque 
pointer."
     GeomArr = GEOM_PTR * n
     return GeomArr()
 
-#### GEOS Pointer object and routines ####
 class GEOSPointer(object):
     """The GEOSPointer provides a layer of abstraction in accessing the values 
returned by
     GEOS geometry creation routines.  Memory addresses (integers) are kept in 
a C pointer,
@@ -108,13 +111,16 @@
         if self.valid: return self.address
         else: raise GEOSException, 'GEOS pointer no longer valid (was this 
geometry or the parent geometry deleted or modified?)'
 
-    def __bool__(self):
+    def __nonzero__(self):
         "Returns True when the GEOSPointer is valid."
         return self.valid
 
     def __str__(self):
         return str(self.address)
 
+    def __repr__(self):
+        return 'GEOSPointer(%s)' % self.address
+
     ### GEOSPointer Properties ###
     @property
     def address(self):
@@ -161,21 +167,3 @@
         # Nullifying both the geometry and coordinate sequence pointer.
         self.set(0)
         self.set(0, coordseq=True)
-
-def init_from_geom(geom):
-    """During initialization of geometries from other geometries, this routine 
is 
-    used to nullify any parent geometries (since they will now be missing 
memory 
-    components) and to nullify the geometry itself to prevent future access.  
-    Only the address (an integer) of the current geometry is returned for use 
in 
-    initializing the new geometry."""
-    # First getting the memory address of the geometry.
-    address = geom._ptr()
-
-    # If the geometry is a child geometry, then the parent geometry pointer is
-    #  nullified.
-    if geom._parent: geom._parent.nullify()
-
-    # Nullifying the geometry pointer
-    geom._ptr.nullify()
-
-    return address

Modified: django/branches/gis/django/contrib/gis/tests/__init__.py
===================================================================
--- django/branches/gis/django/contrib/gis/tests/__init__.py    2007-08-02 
03:28:52 UTC (rev 5785)
+++ django/branches/gis/django/contrib/gis/tests/__init__.py    2007-08-02 
05:31:10 UTC (rev 5786)
@@ -56,9 +56,13 @@
     from django.conf import settings
 
     # Getting initial values.
+    old_debug = settings.DEBUG
     old_name = copy(settings.DATABASE_NAME)
     old_installed = copy(settings.INSTALLED_APPS)
 
+    # Want DEBUG to be set to False.
+    settings.DEBUG = False
+
     # Creating the test suite, adding the test models to INSTALLED_APPS, and
     #  adding the model test suites to our suite package.
     test_suite = suite()
@@ -82,6 +86,7 @@
 
     # Cleaning up, destroying the test spatial database and resetting the 
INSTALLED_APPS.
     destroy_test_db(old_name, verbosity)
+    settings.DEBUG = old_debug
     settings.INSTALLED_APPS = old_installed
     
     # Returning the total failures and errors

Modified: django/branches/gis/django/contrib/gis/tests/geometries.py
===================================================================
--- django/branches/gis/django/contrib/gis/tests/geometries.py  2007-08-02 
03:28:52 UTC (rev 5785)
+++ django/branches/gis/django/contrib/gis/tests/geometries.py  2007-08-02 
05:31:10 UTC (rev 5786)
@@ -115,19 +115,19 @@
                    )
 
 intersect_geoms = ( TestGeom('POLYGON ((5 5,5 0,0 0,0 5,5 5))'),
-                    TestGeom('POLYGON ((10 1, 11 3, 13 4, 15 6, 16 8, 16 10, 
15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 8, 5 6, 7 4, 9 3, 10 1))')
+                    TestGeom('POLYGON ((10 1, 9 3, 7 4, 5 6, 4 8, 4 10, 5 12, 
7 13, 9 12, 10 10, 11 12, 13 13, 15 12, 16 10, 16 8, 15 6, 13 4, 11 3, 10 1))'),
                     )
 
 union_geoms = ( TestGeom('POLYGON ((-5 0,-5 10,5 10,5 5,10 5,10 -5,0 -5,0 0,-5 
0))'),
-                TestGeom('POLYGON ((2 0, 18 0, 18 15, 2 15, 2 0))'),
+                TestGeom('POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0))'),
                 )
 
 diff_geoms = ( TestGeom('POLYGON ((-5 0,-5 10,5 10,5 5,0 5,0 0,-5 0))'),
-               TestGeom('POLYGON ((2 0, 18 0, 18 15, 2 15, 2 0), (10 1, 11 3, 
13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 
8, 5 6, 7 4, 9 3, 10 1))'),
+               TestGeom('POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0), (10 1, 11 3, 
13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 
8, 5 6, 7 4, 9 3, 10 1))'),
                )
 
 sdiff_geoms = ( TestGeom('MULTIPOLYGON (((-5 0,-5 10,5 10,5 5,0 5,0 0,-5 
0)),((0 0,5 0,5 5,10 5,10 -5,0 -5,0 0)))'),
-                TestGeom('POLYGON ((2 0, 18 0, 18 15, 2 15, 2 0), (10 1, 11 3, 
13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 
8, 5 6, 7 4, 9 3, 10 1))'),
+                TestGeom('POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0), (10 1, 11 3, 
13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 
8, 5 6, 7 4, 9 3, 10 1))'),
                 )
 
 relate_geoms = ( (TestGeom('MULTIPOINT(80 70, 20 20, 200 170, 140 120)'),

Modified: django/branches/gis/django/contrib/gis/tests/test_geos.py
===================================================================
--- django/branches/gis/django/contrib/gis/tests/test_geos.py   2007-08-02 
03:28:52 UTC (rev 5785)
+++ django/branches/gis/django/contrib/gis/tests/test_geos.py   2007-08-02 
05:31:10 UTC (rev 5786)
@@ -1,4 +1,4 @@
-import unittest
+import random, unittest
 from django.contrib.gis.geos import \
     GEOSException, GEOSGeometryIndexError, \
     GEOSGeometry, Point, LineString, LinearRing, Polygon, \
@@ -166,7 +166,7 @@
             self.assertEqual(lr, LinearRing(lr.tuple))
             self.assertEqual(lr, LinearRing(*lr.tuple))
             self.assertEqual(lr, LinearRing([list(tup) for tup in lr.tuple]))
-            if HAS_NUMPY: self.assertEqual(lr, LineString(array(lr.tuple)))
+            if HAS_NUMPY: self.assertEqual(lr, LinearRing(array(lr.tuple)))
     
     def test05a_polygons(self):
         "Testing Polygon objects."
@@ -200,10 +200,15 @@
                 self.assertEqual(p.ext_ring_cs, ring.tuple)
                 self.assertEqual(p.ext_ring_cs, poly[0].tuple) # Testing 
__getitem__
 
-            # Testing __iter__
+            # Testing __getitem__ and __setitem__ on invalid indices
+            self.assertRaises(GEOSGeometryIndexError, poly.__getitem__, 
len(poly))
+            self.assertRaises(GEOSGeometryIndexError, poly.__setitem__, 
len(poly), False)
+            self.assertRaises(GEOSGeometryIndexError, poly.__getitem__, -1)
+
+            # Testing __iter__ 
             for r in poly:
-                self.assertEqual(ring.geom_type, 'LinearRing')
-                self.assertEqual(ring.geom_typeid, 2)
+                self.assertEqual(r.geom_type, 'LinearRing')
+                self.assertEqual(r.geom_typeid, 2)
 
             # Testing polygon construction.
             self.assertRaises(TypeError, Polygon, 0, [1, 2, 3])
@@ -224,8 +229,8 @@
             except TypeError:
                 pass
             poly[0][1] = newval # setting the second point in the polygon with 
the newvalue (based on the old)
-            self.assertEqual(newval, poly[0][1]) # The point in the polygon 
should be the
-            self.assertEqual(False, poly == prev) # Even different from the 
clone we just made
+            self.assertEqual(newval, poly[0][1]) # The point in the polygon 
should be the new value
+            self.assertEqual(False, poly == prev) # Should be different from 
the clone we just made
             
     def test05b_multipolygons(self):
         "Testing MultiPolygon objects."
@@ -426,11 +431,12 @@
             a = GEOSGeometry(g_tup[0].wkt)
             b = GEOSGeometry(g_tup[1].wkt)
             i1 = GEOSGeometry(intersect_geoms[i].wkt) 
-
             self.assertEqual(True, a.intersects(b))
             i2 = a.intersection(b)
             self.assertEqual(i1, i2)
-            self.assertEqual(i1, a & b)
+            self.assertEqual(i1, a & b) # __and__ is intersection operator
+            a &= b # testing __iand__
+            self.assertEqual(i1, a)
 
     def test11_union(self):
         "Testing union()."
@@ -441,7 +447,9 @@
             u1 = GEOSGeometry(union_geoms[i].wkt)
             u2 = a.union(b)
             self.assertEqual(u1, u2)
-            self.assertEqual(u1, a | b) # Union ('|') operator
+            self.assertEqual(u1, a | b) # __or__ is union operator
+            a |= b # testing __ior__
+            self.assertEqual(u1, a) 
 
     def test12_difference(self):
         "Testing difference()."
@@ -452,7 +460,9 @@
             d1 = GEOSGeometry(diff_geoms[i].wkt)
             d2 = a.difference(b)
             self.assertEqual(d1, d2)
-            self.assertEqual(d1, a - b) # Difference ('-') operator
+            self.assertEqual(d1, a - b) # __sub__ is difference operator
+            a -= b # testing __isub__
+            self.assertEqual(d1, a)
 
     def test13_symdifference(self):
         "Testing sym_difference()."
@@ -463,7 +473,9 @@
             d1 = GEOSGeometry(sdiff_geoms[i].wkt)
             d2 = a.sym_difference(b)
             self.assertEqual(d1, d2)
-            self.assertEqual(d1, a ^ b) # Symmetric difference ('^') operator
+            self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference 
operator
+            a ^= b # testing __ixor__
+            self.assertEqual(d1, a)
 
     def test14_buffer(self):
         "Testing buffer()."
@@ -492,6 +504,85 @@
                     self.assertAlmostEqual(exp_ring[k][0], buf_ring[k][0], 9)
                     self.assertAlmostEqual(exp_ring[k][1], buf_ring[k][1], 9)
 
+    def test15_srid(self):
+        "Testing the SRID property and keyword."
+        # Testing SRID keyword on Point
+        pnt = Point(5, 23, srid=4326)
+        self.assertEqual(4326, pnt.srid)
+        pnt.srid = 3084
+        self.assertEqual(3084, pnt.srid)
+        self.assertRaises(TypeError, pnt.set_srid, '4326')
+
+        # Testing SRID keyword on fromstr(), and on Polygon rings.
+        poly = fromstr(polygons[1].wkt, srid=4269)
+        self.assertEqual(4269, poly.srid)
+        for ring in poly: self.assertEqual(4269, ring.srid)
+        poly.srid = 4326
+        self.assertEqual(4326, poly.shell.srid)
+
+        # Testing SRID keyword on GeometryCollection
+        gc = GeometryCollection(Point(5, 23), LineString((0, 0), (1.5, 1.5), 
(3, 3)), srid=32021)
+        self.assertEqual(32021, gc.srid)
+        for i in range(len(gc)): self.assertEqual(32021, gc[i].srid)
+
+    def test16_mutable_geometries(self):
+        "Testing the mutability of Polygons and Geometry Collections."
+        ### Testing the mutability of Polygons ###
+        for p in polygons:
+            poly = fromstr(p.wkt)
+
+            # Should only be able to use __setitem__ with LinearRing 
geometries.
+            self.assertRaises(TypeError, poly.__setitem__, 0, LineString((1, 
1), (2, 2)))
+
+            # Constructing the new shell by adding 500 to every point in the 
old shell.
+            shell_tup = poly.shell.tuple
+            new_coords = []
+            for point in shell_tup: new_coords.append((point[0] + 500., 
point[1] + 500.))
+            shell1 = LinearRing(*tuple(new_coords))
+            shell2 = shell1.clone() 
+
+            # Assigning polygon's exterior ring w/the new shell
+            poly.exterior_ring = shell1
+            self.assertRaises(GEOSException, str, shell1) # shell1 should no 
longer be accessible
+            self.assertEqual(poly.exterior_ring, shell2)
+            self.assertEqual(poly[0], shell2)
+            del poly, shell1, shell_tup # cleaning up
+
+        ### Testing the mutability of Geometry Collections
+        for tg in multipoints:
+            mp = fromstr(tg.wkt)
+            for i in range(len(mp)):
+                # Creating a random point.
+                pnt = mp[i].clone()
+                new = Point(random.randint(1, 100), random.randint(1, 100))
+                tmp = new.clone()
+                # Testing the assignmen
+                mp[i] = tmp
+                self.assertRaises(GEOSException, len, tmp)
+                self.assertEqual(mp[i], new)
+                self.assertEqual(mp[i].wkt, new.wkt)
+                self.assertNotEqual(pnt, mp[i])
+            del mp
+
+        # Multipolygons involve much more memory management because each
+        #  polygon w/in the collection has its own rings.
+        for tg in multipolygons:
+            mpoly = fromstr(tg.wkt)
+            for i in xrange(len(mpoly)):
+                poly = mpoly[i].clone()
+                # Offsetting the each ring in the polygon by 500.
+                tmp = poly.clone()
+                for r in tmp: 
+                    for j in xrange(len(r)): r[j] = (r[j][0] + 500., r[j][1] + 
500.)
+                self.assertNotEqual(poly, tmp)
+                new = tmp.clone() # a 'reference' copy of the geometry used in 
assignment
+                # Testing the assignment
+                mpoly[i] = tmp
+                self.assertRaises(GEOSException, str, tmp)
+                self.assertEqual(mpoly[i], new)
+                self.assertNotEqual(poly, mpoly[i])
+            del mpoly
+
 def suite():
     s = unittest.TestSuite()
     s.addTest(unittest.makeSuite(GEOSTest))


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to