Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Maintenance refactor of the GDAL (OGR) ctypes interface. Changes incl…

…ude:

* All C API method explictly called from their prototype module, no longer imported via *.
* Applied DRY to C pointer management, classes that do so subclass from `GDALBase`.
* `OGRGeometry`: Added `from_bbox` class method (patch from Christopher Schmidt) and `kml` property.
* `SpatialReference`: Now initialize with `SetFromUserInput` (initialization is now more simple and flexible); removed duplicate methods.
* `Envelope`: Added `expand_to_include` method and now allow same coordinates for lower left and upper right points.  Thanks to Paul Smith for tickets and patches.
* `OGRGeomType`: Now treat OGC 'Geometry' type as 'Unknown'.

Fixed #9855, #10368, #10380.  Refs #9806.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@9985 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f1ada99997de72fdd3f765ffa11fa4d1d9f438f9 1 parent 53da1e4
@jbronn jbronn authored
Showing with 516 additions and 373 deletions.
  1. +1 −1  django/contrib/gis/gdal/LICENSE
  2. +35 −0 django/contrib/gis/gdal/base.py
  3. +15 −25 django/contrib/gis/gdal/datasource.py
  4. +9 −10 django/contrib/gis/gdal/driver.py
  5. +48 −7 django/contrib/gis/gdal/envelope.py
  6. +1 −0  django/contrib/gis/gdal/error.py
  7. +15 −20 django/contrib/gis/gdal/feature.py
  8. +20 −21 django/contrib/gis/gdal/field.py
  9. +97 −77 django/contrib/gis/gdal/geometries.py
  10. +7 −4 django/contrib/gis/gdal/geomtype.py
  11. +21 −26 django/contrib/gis/gdal/layer.py
  12. +2 −0  django/contrib/gis/gdal/prototypes/geom.py
  13. +1 −0  django/contrib/gis/gdal/prototypes/srs.py
  14. +68 −91 django/contrib/gis/gdal/srs.py
  15. +6 −9 django/contrib/gis/{tests/test_gdal.py → gdal/tests/__init__.py}
  16. 0  django/contrib/gis/{tests/test_gdal_driver.py → gdal/tests/test_driver.py}
  17. +4 −1 django/contrib/gis/{tests/test_gdal_ds.py → gdal/tests/test_ds.py}
  18. +94 −0 django/contrib/gis/gdal/tests/test_envelope.py
  19. +16 −5 django/contrib/gis/{tests/test_gdal_geom.py → gdal/tests/test_geom.py}
  20. 0  django/contrib/gis/{tests/test_gdal_srs.py → gdal/tests/test_srs.py}
  21. +56 −31 django/contrib/gis/tests/__init__.py
  22. +0 −45 django/contrib/gis/tests/test_gdal_envelope.py
View
2  django/contrib/gis/gdal/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2007, Justin Bronn
+Copyright (c) 2007-2009, Justin Bronn
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
View
35 django/contrib/gis/gdal/base.py
@@ -0,0 +1,35 @@
+from ctypes import c_void_p
+from types import NoneType
+from django.contrib.gis.gdal.error import GDALException
+
+class GDALBase(object):
+ """
+ Base object for GDAL objects that has a pointer access property
+ that controls access to the underlying C pointer.
+ """
+ # Initially the pointer is NULL.
+ _ptr = None
+
+ # Default allowed pointer type.
+ ptr_type = c_void_p
+
+ # Pointer access property.
+ def _get_ptr(self):
+ # Raise an exception if the pointer isn't valid don't
+ # want to be passing NULL pointers to routines --
+ # that's very bad.
+ if self._ptr: return self._ptr
+ else: raise GDALException('GDAL %s pointer no longer valid.' % self.__class__.__name__)
+
+ def _set_ptr(self, ptr):
+ # Only allow the pointer to be set with pointers of the
+ # compatible type or None (NULL).
+ if isinstance(ptr, int):
+ self._ptr = self.ptr_type(ptr)
+ elif isinstance(ptr, (self.ptr_type, NoneType)):
+ self._ptr = ptr
+ else:
+ raise TypeError('Incompatible pointer type')
+
+ ptr = property(_get_ptr, _set_ptr)
+
View
40 django/contrib/gis/gdal/datasource.py
@@ -37,28 +37,23 @@
from ctypes import byref, c_void_p
# The GDAL C library, OGR exceptions, and the Layer object.
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.driver import Driver
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
from django.contrib.gis.gdal.layer import Layer
# Getting the ctypes prototypes for the DataSource.
-from django.contrib.gis.gdal.prototypes.ds import \
- destroy_ds, get_driver_count, register_all, open_ds, release_ds, \
- get_ds_name, get_layer, get_layer_count, get_layer_by_name
+from django.contrib.gis.gdal.prototypes import ds as capi
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_DS_* routines are relevant here.
-class DataSource(object):
+class DataSource(GDALBase):
"Wraps an OGR Data Source object."
#### Python 'magic' routines ####
def __init__(self, ds_input, ds_driver=False, write=False):
-
- # DataSource pointer is initially NULL.
- self._ptr = None
-
# The write flag.
if write:
self._write = 1
@@ -67,33 +62,34 @@ def __init__(self, ds_input, ds_driver=False, write=False):
# Registering all the drivers, this needs to be done
# _before_ we try to open up a data source.
- if not get_driver_count(): register_all()
+ if not capi.get_driver_count():
+ capi.register_all()
if isinstance(ds_input, basestring):
# The data source driver is a void pointer.
- ds_driver = c_void_p()
+ ds_driver = Driver.ptr_type()
try:
# OGROpen will auto-detect the data source type.
- ds = open_ds(ds_input, self._write, byref(ds_driver))
+ ds = capi.open_ds(ds_input, self._write, byref(ds_driver))
except OGRException:
# Making the error message more clear rather than something
# like "Invalid pointer returned from OGROpen".
raise OGRException('Could not open the datasource at "%s"' % ds_input)
- elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p):
+ elif isinstance(ds_input, self.ptr_type) and isinstance(ds_driver, Driver.ptr_type):
ds = ds_input
else:
raise OGRException('Invalid data source input type: %s' % type(ds_input))
if bool(ds):
- self._ptr = ds
- self._driver = Driver(ds_driver)
+ self.ptr = ds
+ self.driver = Driver(ds_driver)
else:
# Raise an exception if the returned pointer is NULL
raise OGRException('Invalid data source file "%s"' % ds_input)
def __del__(self):
"Destroys this DataStructure object."
- if self._ptr: destroy_ds(self._ptr)
+ if self._ptr: capi.destroy_ds(self._ptr)
def __iter__(self):
"Allows for iteration over the layers in a data source."
@@ -103,12 +99,12 @@ def __iter__(self):
def __getitem__(self, index):
"Allows use of the index [] operator to get a layer at the index."
if isinstance(index, basestring):
- l = get_layer_by_name(self._ptr, index)
+ l = capi.get_layer_by_name(self.ptr, index)
if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
elif isinstance(index, int):
if index < 0 or index >= self.layer_count:
raise OGRIndexError('index out of range')
- l = get_layer(self._ptr, index)
+ l = capi.get_layer(self._ptr, index)
else:
raise TypeError('Invalid index type: %s' % type(index))
return Layer(l, self)
@@ -121,18 +117,12 @@ def __str__(self):
"Returns OGR GetName and Driver for the Data Source."
return '%s (%s)' % (self.name, str(self.driver))
- #### DataSource Properties ####
- @property
- def driver(self):
- "Returns the Driver object for this Data Source."
- return self._driver
-
@property
def layer_count(self):
"Returns the number of layers in the data source."
- return get_layer_count(self._ptr)
+ return capi.get_layer_count(self._ptr)
@property
def name(self):
"Returns the name of the data source."
- return get_ds_name(self._ptr)
+ return capi.get_ds_name(self._ptr)
View
19 django/contrib/gis/gdal/driver.py
@@ -1,14 +1,14 @@
# prerequisites imports
from ctypes import c_void_p
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import OGRException
-from django.contrib.gis.gdal.prototypes.ds import \
- get_driver, get_driver_by_name, get_driver_count, get_driver_name, register_all
+from django.contrib.gis.gdal.prototypes import ds as capi
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_Dr_* routines are relevant here.
-class Driver(object):
+class Driver(GDALBase):
"Wraps an OGR Data Source Driver."
# Case-insensitive aliases for OGR Drivers.
@@ -24,7 +24,6 @@ def __init__(self, dr_input):
if isinstance(dr_input, basestring):
# If a string name of the driver was passed in
- self._ptr = None # Initially NULL
self._register()
# Checking the alias dictionary (case-insensitive) to see if an alias
@@ -35,10 +34,10 @@ def __init__(self, dr_input):
name = dr_input
# Attempting to get the OGR driver by the string name.
- dr = get_driver_by_name(name)
+ dr = capi.get_driver_by_name(name)
elif isinstance(dr_input, int):
self._register()
- dr = get_driver(dr_input)
+ dr = capi.get_driver(dr_input)
elif isinstance(dr_input, c_void_p):
dr = dr_input
else:
@@ -47,20 +46,20 @@ def __init__(self, dr_input):
# Making sure we get a valid pointer to the OGR Driver
if not dr:
raise OGRException('Could not initialize OGR Driver on input: %s' % str(dr_input))
- self._ptr = dr
+ self.ptr = dr
def __str__(self):
"Returns the string name of the OGR Driver."
- return get_driver_name(self._ptr)
+ return capi.get_driver_name(self.ptr)
def _register(self):
"Attempts to register all the data source drivers."
# Only register all if the driver count is 0 (or else all drivers
# will be registered over and over again)
- if not self.driver_count: register_all()
+ if not self.driver_count: capi.register_all()
# Driver properties
@property
def driver_count(self):
"Returns the number of OGR data source drivers registered."
- return get_driver_count()
+ return capi.get_driver_count()
View
55 django/contrib/gis/gdal/envelope.py
@@ -11,7 +11,6 @@
Lower left (min_x, min_y) o----------+
"""
from ctypes import Structure, c_double
-from types import TupleType, ListType
from django.contrib.gis.gdal.error import OGRException
# The OGR definition of an Envelope is a C structure containing four doubles.
@@ -42,7 +41,7 @@ def __init__(self, *args):
if isinstance(args[0], OGREnvelope):
# OGREnvelope (a ctypes Structure) was passed in.
self._envelope = args[0]
- elif isinstance(args[0], (TupleType, ListType)):
+ elif isinstance(args[0], (tuple, list)):
# A tuple was passed in.
if len(args[0]) != 4:
raise OGRException('Incorrect number of tuple elements (%d).' % len(args[0]))
@@ -58,10 +57,10 @@ def __init__(self, *args):
raise OGRException('Incorrect number (%d) of arguments.' % len(args))
# Checking the x,y coordinates
- if self.min_x >= self.max_x:
- raise OGRException('Envelope minimum X >= maximum X.')
- if self.min_y >= self.max_y:
- raise OGRException('Envelope minimum Y >= maximum Y.')
+ if self.min_x > self.max_x:
+ raise OGRException('Envelope minimum X > maximum X.')
+ if self.min_y > self.max_y:
+ raise OGRException('Envelope minimum Y > maximum Y.')
def __eq__(self, other):
"""
@@ -71,7 +70,7 @@ def __eq__(self, other):
if isinstance(other, Envelope):
return (self.min_x == other.min_x) and (self.min_y == other.min_y) and \
(self.max_x == other.max_x) and (self.max_y == other.max_y)
- elif isinstance(other, TupleType) and len(other) == 4:
+ elif isinstance(other, tuple) and len(other) == 4:
return (self.min_x == other[0]) and (self.min_y == other[1]) and \
(self.max_x == other[2]) and (self.max_y == other[3])
else:
@@ -89,6 +88,48 @@ def _from_sequence(self, seq):
self._envelope.MaxX = seq[2]
self._envelope.MaxY = seq[3]
+ def expand_to_include(self, *args):
+ """
+ Modifies the envelope to expand to include the boundaries of
+ the passed-in 2-tuple (a point), 4-tuple (an extent) or
+ envelope.
+ """
+ # We provide a number of different signatures for this method,
+ # and the logic here is all about converting them into a
+ # 4-tuple single parameter which does the actual work of
+ # expanding the envelope.
+ if len(args) == 1:
+ if isinstance(args[0], Envelope):
+ return self.expand_to_include(args[0].tuple)
+ elif hasattr(args[0], 'x') and hasattr(args[0], 'y'):
+ return self.expand_to_include(args[0].x, args[0].y, args[0].x, args[0].y)
+ elif isinstance(args[0], (tuple, list)):
+ # A tuple was passed in.
+ if len(args[0]) == 2:
+ return self.expand_to_include((args[0][0], args[0][1], args[0][0], args[0][1]))
+ elif len(args[0]) == 4:
+ (minx, miny, maxx, maxy) = args[0]
+ if minx < self._envelope.MinX:
+ self._envelope.MinX = minx
+ if miny < self._envelope.MinY:
+ self._envelope.MinY = miny
+ if maxx > self._envelope.MaxX:
+ self._envelope.MaxX = maxx
+ if maxy > self._envelope.MaxY:
+ self._envelope.MaxY = maxy
+ else:
+ raise OGRException('Incorrect number of tuple elements (%d).' % len(args[0]))
+ else:
+ raise TypeError('Incorrect type of argument: %s' % str(type(args[0])))
+ elif len(args) == 2:
+ # An x and an y parameter were passed in
+ return self.expand_to_include((args[0], args[1], args[0], args[1]))
+ elif len(args) == 4:
+ # Individiual parameters passed in.
+ return self.expand_to_include(args)
+ else:
+ raise OGRException('Incorrect number (%d) of arguments.' % len(args[0]))
+
@property
def min_x(self):
"Returns the value of the minimum X coordinate."
View
1  django/contrib/gis/gdal/error.py
@@ -4,6 +4,7 @@
OGR methods.
"""
#### OGR & SRS Exceptions ####
+class GDALException(Exception): pass
class OGRException(Exception): pass
class SRSException(Exception): pass
class OGRIndexError(OGRException, KeyError):
View
35 django/contrib/gis/gdal/feature.py
@@ -1,36 +1,31 @@
# The GDAL C library, OGR exception, and the Field object
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
from django.contrib.gis.gdal.field import Field
from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
from django.contrib.gis.gdal.srs import SpatialReference
# ctypes function prototypes
-from django.contrib.gis.gdal.prototypes.ds import \
- destroy_feature, feature_equal, get_fd_geom_type, get_feat_geom_ref, \
- get_feat_name, get_feat_field_count, get_fid, get_field_defn, \
- get_field_index, get_field_name
-from django.contrib.gis.gdal.prototypes.geom import clone_geom, get_geom_srs
-from django.contrib.gis.gdal.prototypes.srs import clone_srs
+from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_F_* routines are relevant here.
-class Feature(object):
+class Feature(GDALBase):
"A class that wraps an OGR Feature, needs to be instantiated from a Layer object."
#### Python 'magic' routines ####
def __init__(self, feat, fdefn):
"Initializes on the pointers for the feature and the layer definition."
- self._ptr = None # Initially NULL
if not feat or not fdefn:
raise OGRException('Cannot create OGR Feature, invalid pointer given.')
- self._ptr = feat
+ self.ptr = feat
self._fdefn = fdefn
def __del__(self):
"Releases a reference to this object."
- if self._ptr: destroy_feature(self._ptr)
+ if self._ptr: capi.destroy_feature(self._ptr)
def __getitem__(self, index):
"""
@@ -45,7 +40,7 @@ def __getitem__(self, index):
if index < 0 or index > self.num_fields:
raise OGRIndexError('index out of range')
i = index
- return Field(self._ptr, i)
+ return Field(self.ptr, i)
def __iter__(self):
"Iterates over each field in the Feature."
@@ -62,41 +57,41 @@ def __str__(self):
def __eq__(self, other):
"Does equivalence testing on the features."
- return bool(feature_equal(self._ptr, other._ptr))
+ return bool(capi.feature_equal(self.ptr, other._ptr))
#### Feature Properties ####
@property
def fid(self):
"Returns the feature identifier."
- return get_fid(self._ptr)
+ return capi.get_fid(self.ptr)
@property
def layer_name(self):
"Returns the name of the layer for the feature."
- return get_feat_name(self._fdefn)
+ return capi.get_feat_name(self._fdefn)
@property
def num_fields(self):
"Returns the number of fields in the Feature."
- return get_feat_field_count(self._ptr)
+ return capi.get_feat_field_count(self.ptr)
@property
def fields(self):
"Returns a list of fields in the Feature."
- return [get_field_name(get_field_defn(self._fdefn, i))
+ return [capi.get_field_name(capi.get_field_defn(self._fdefn, i))
for i in xrange(self.num_fields)]
@property
def geom(self):
"Returns the OGR Geometry for this Feature."
# Retrieving the geometry pointer for the feature.
- geom_ptr = get_feat_geom_ref(self._ptr)
- return OGRGeometry(clone_geom(geom_ptr))
+ geom_ptr = capi.get_feat_geom_ref(self.ptr)
+ return OGRGeometry(geom_api.clone_geom(geom_ptr))
@property
def geom_type(self):
"Returns the OGR Geometry Type for this Feture."
- return OGRGeomType(get_fd_geom_type(self._fdefn))
+ return OGRGeomType(capi.get_fd_geom_type(self._fdefn))
#### Feature Methods ####
def get(self, field):
@@ -110,6 +105,6 @@ def get(self, field):
def index(self, field_name):
"Returns the index of the given field name."
- i = get_field_index(self._ptr, field_name)
+ i = capi.get_field_index(self.ptr, field_name)
if i < 0: raise OGRIndexError('invalid OFT field name given: "%s"' % field_name)
return i
View
41 django/contrib/gis/gdal/field.py
@@ -1,16 +1,14 @@
from ctypes import byref, c_int
from datetime import date, datetime, time
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import OGRException
-from django.contrib.gis.gdal.prototypes.ds import \
- get_feat_field_defn, get_field_as_datetime, get_field_as_double, \
- get_field_as_integer, get_field_as_string, get_field_name, get_field_precision, \
- get_field_type, get_field_type_name, get_field_width
+from django.contrib.gis.gdal.prototypes import ds as capi
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_Fld_* routines are relevant here.
-class Field(object):
+class Field(GDALBase):
"A class that wraps an OGR Field, needs to be instantiated from a Feature object."
#### Python 'magic' routines ####
@@ -24,13 +22,13 @@ def __init__(self, feat, index):
self._index = index
# Getting the pointer for this field.
- fld = get_feat_field_defn(feat, index)
- if not fld:
+ fld_ptr = capi.get_feat_field_defn(feat, index)
+ if not fld_ptr:
raise OGRException('Cannot create OGR Field, invalid pointer given.')
- self._ptr = fld
+ self.ptr = fld_ptr
# Setting the class depending upon the OGR Field Type (OFT)
- self.__class__ = FIELD_CLASSES[self.type]
+ self.__class__ = OGRFieldTypes[self.type]
# OFTReal with no precision should be an OFTInteger.
if isinstance(self, OFTReal) and self.precision == 0:
@@ -43,21 +41,21 @@ def __str__(self):
#### Field Methods ####
def as_double(self):
"Retrieves the Field's value as a double (float)."
- return get_field_as_double(self._feat, self._index)
+ return capi.get_field_as_double(self._feat, self._index)
def as_int(self):
"Retrieves the Field's value as an integer."
- return get_field_as_integer(self._feat, self._index)
+ return capi.get_field_as_integer(self._feat, self._index)
def as_string(self):
"Retrieves the Field's value as a string."
- return get_field_as_string(self._feat, self._index)
+ return capi.get_field_as_string(self._feat, self._index)
def as_datetime(self):
"Retrieves the Field's value as a tuple of date & time components."
yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)]
- status = get_field_as_datetime(self._feat, self._index, byref(yy), byref(mm), byref(dd),
- byref(hh), byref(mn), byref(ss), byref(tz))
+ status = capi.get_field_as_datetime(self._feat, self._index, byref(yy), byref(mm), byref(dd),
+ byref(hh), byref(mn), byref(ss), byref(tz))
if status:
return (yy, mm, dd, hh, mn, ss, tz)
else:
@@ -67,22 +65,22 @@ def as_datetime(self):
@property
def name(self):
"Returns the name of this Field."
- return get_field_name(self._ptr)
+ return capi.get_field_name(self.ptr)
@property
def precision(self):
"Returns the precision of this Field."
- return get_field_precision(self._ptr)
+ return capi.get_field_precision(self.ptr)
@property
def type(self):
"Returns the OGR type of this Field."
- return get_field_type(self._ptr)
+ return capi.get_field_type(self.ptr)
@property
def type_name(self):
"Return the OGR field type name for this Field."
- return get_field_type_name(self.type)
+ return capi.get_field_type_name(self.type)
@property
def value(self):
@@ -93,7 +91,7 @@ def value(self):
@property
def width(self):
"Returns the width of this Field."
- return get_field_width(self._ptr)
+ return capi.get_field_width(self.ptr)
### The Field sub-classes for each OGR Field type. ###
class OFTInteger(Field):
@@ -163,8 +161,8 @@ class OFTRealList(Field): pass
class OFTStringList(Field): pass
class OFTWideStringList(Field): pass
-# Class mapping dictionary for OFT Types
-FIELD_CLASSES = { 0 : OFTInteger,
+# Class mapping dictionary for OFT Types and reverse mapping.
+OGRFieldTypes = { 0 : OFTInteger,
1 : OFTIntegerList,
2 : OFTReal,
3 : OFTRealList,
@@ -177,3 +175,4 @@ class OFTWideStringList(Field): pass
10 : OFTTime,
11 : OFTDateTime,
}
+ROGRFieldTypes = dict([(cls, num) for num, cls in OGRFieldTypes.items()])
View
174 django/contrib/gis/gdal/geometries.py
@@ -44,14 +44,15 @@
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
# Getting GDAL prerequisites
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
# Getting the ctypes prototype functions that interface w/the GDAL C library.
-from django.contrib.gis.gdal.prototypes.geom import *
-from django.contrib.gis.gdal.prototypes.srs import clone_srs
+from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
+GEOJSON = capi.GEOJSON
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
@@ -64,13 +65,12 @@
json_regex = re.compile(r'^(\s+)?\{[\s\w,\[\]\{\}\-\."\':]+\}(\s+)?$')
#### OGRGeometry Class ####
-class OGRGeometry(object):
+class OGRGeometry(GDALBase):
"Generally encapsulates an OGR geometry."
def __init__(self, geom_input, srs=None):
"Initializes Geometry on either WKT or an OGR pointer as input."
- self._ptr = c_void_p(None) # Initially NULL
str_instance = isinstance(geom_input, basestring)
# If HEX, unpack input to to a binary buffer.
@@ -91,27 +91,27 @@ def __init__(self, geom_input, srs=None):
if wkt_m.group('type').upper() == 'LINEARRING':
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
# See http://trac.osgeo.org/gdal/ticket/1992.
- g = create_geom(OGRGeomType(wkt_m.group('type')).num)
- import_wkt(g, byref(c_char_p(geom_input)))
+ g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num)
+ capi.import_wkt(g, byref(c_char_p(geom_input)))
else:
- g = from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
+ g = capi.from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
elif json_m:
if GEOJSON:
- g = from_json(geom_input)
+ g = capi.from_json(geom_input)
else:
raise NotImplementedError('GeoJSON input only supported on GDAL 1.5+.')
else:
# Seeing if the input is a valid short-hand string
# (e.g., 'Point', 'POLYGON').
ogr_t = OGRGeomType(geom_input)
- g = create_geom(OGRGeomType(geom_input).num)
+ g = capi.create_geom(OGRGeomType(geom_input).num)
elif isinstance(geom_input, buffer):
# WKB was passed in
- g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
+ g = capi.from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
elif isinstance(geom_input, OGRGeomType):
# OGRGeomType was passed in, an empty geometry will be created.
- g = create_geom(geom_input.num)
- elif isinstance(geom_input, c_void_p):
+ g = capi.create_geom(geom_input.num)
+ elif isinstance(geom_input, self.ptr_type):
# OGR pointer (c_void_p) was the input.
g = geom_input
else:
@@ -121,7 +121,7 @@ def __init__(self, geom_input, srs=None):
# by setting the pointer for the object.
if not g:
raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
- self._ptr = g
+ self.ptr = g
# Assigning the SpatialReference object to the geometry, if valid.
if bool(srs): self.srs = srs
@@ -129,9 +129,16 @@ def __init__(self, geom_input, srs=None):
# Setting the class depending upon the OGR Geometry Type
self.__class__ = GEO_CLASSES[self.geom_type.num]
+ @classmethod
+ def from_bbox(cls, bbox):
+ "Constructs a Polygon from a bounding box (4-tuple)."
+ x0, y0, x1, y1 = bbox
+ return OGRGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
+ x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
+
def __del__(self):
"Deletes this Geometry."
- if self._ptr: destroy_geom(self._ptr)
+ if self._ptr: capi.destroy_geom(self._ptr)
### Geometry set-like operations ###
# g = g1 | g2
@@ -170,22 +177,22 @@ def __str__(self):
@property
def dimension(self):
"Returns 0 for points, 1 for lines, and 2 for surfaces."
- return get_dims(self._ptr)
+ return capi.get_dims(self.ptr)
@property
def coord_dim(self):
"Returns the coordinate dimension of the Geometry."
- return get_coord_dims(self._ptr)
+ return capi.get_coord_dims(self.ptr)
@property
def geom_count(self):
"The number of elements in this Geometry."
- return get_geom_count(self._ptr)
+ return capi.get_geom_count(self.ptr)
@property
def point_count(self):
"Returns the number of Points in this Geometry."
- return get_point_count(self._ptr)
+ return capi.get_point_count(self.ptr)
@property
def num_points(self):
@@ -201,28 +208,28 @@ def num_coords(self):
def geom_type(self):
"Returns the Type for this Geometry."
try:
- return OGRGeomType(get_geom_type(self._ptr))
+ return OGRGeomType(capi.get_geom_type(self.ptr))
except OGRException:
# VRT datasources return an invalid geometry type
# number, but a valid name -- we'll try that instead.
# See: http://trac.osgeo.org/gdal/ticket/2491
- return OGRGeomType(get_geom_name(self._ptr))
+ return OGRGeomType(capi.get_geom_name(self.ptr))
@property
def geom_name(self):
"Returns the Name of this Geometry."
- return get_geom_name(self._ptr)
+ return capi.get_geom_name(self.ptr)
@property
def area(self):
"Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
- return get_area(self._ptr)
+ return capi.get_area(self.ptr)
@property
def envelope(self):
"Returns the envelope for this Geometry."
# TODO: Fix Envelope() for Point geometries.
- return Envelope(get_envelope(self._ptr, byref(OGREnvelope())))
+ return Envelope(capi.get_envelope(self.ptr, byref(OGREnvelope())))
@property
def extent(self):
@@ -232,39 +239,40 @@ def extent(self):
#### SpatialReference-related Properties ####
# The SRS property
- def get_srs(self):
+ def _get_srs(self):
"Returns the Spatial Reference for this Geometry."
try:
- srs_ptr = get_geom_srs(self._ptr)
- return SpatialReference(clone_srs(srs_ptr))
+ srs_ptr = capi.get_geom_srs(self.ptr)
+ return SpatialReference(srs_api.clone_srs(srs_ptr))
except SRSException:
return None
- def set_srs(self, srs):
+ def _set_srs(self, srs):
"Sets the SpatialReference for this geometry."
if isinstance(srs, SpatialReference):
- srs_ptr = clone_srs(srs._ptr)
+ srs_ptr = srs_api.clone_srs(srs.ptr)
elif isinstance(srs, (int, long, basestring)):
sr = SpatialReference(srs)
- srs_ptr = clone_srs(sr._ptr)
+ srs_ptr = srs_api.clone_srs(sr.ptr)
else:
raise TypeError('Cannot assign spatial reference with object of type: %s' % type(srs))
- assign_srs(self._ptr, srs_ptr)
+ capi.assign_srs(self.ptr, srs_ptr)
- srs = property(get_srs, set_srs)
+ srs = property(_get_srs, _set_srs)
# The SRID property
- def get_srid(self):
- if self.srs: return self.srs.srid
- else: return None
+ def _get_srid(self):
+ srs = self.srs
+ if srs: return srs.srid
+ return None
- def set_srid(self, srid):
+ def _set_srid(self, srid):
if isinstance(srid, (int, long)):
self.srs = srid
else:
raise TypeError('SRID must be set with an integer.')
- srid = property(get_srid, set_srid)
+ srid = property(_get_srid, _set_srid)
#### Output Methods ####
@property
@@ -276,7 +284,7 @@ def geos(self):
@property
def gml(self):
"Returns the GML representation of the Geometry."
- return to_gml(self._ptr)
+ return capi.to_gml(self.ptr)
@property
def hex(self):
@@ -286,16 +294,28 @@ def hex(self):
@property
def json(self):
+ """
+ Returns the GeoJSON representation of this Geometry (requires
+ GDAL 1.5+).
+ """
if GEOJSON:
- return to_json(self._ptr)
+ return capi.to_json(self.ptr)
else:
raise NotImplementedError('GeoJSON output only supported on GDAL 1.5+.')
geojson = json
@property
+ def kml(self):
+ "Returns the KML representation of the Geometry."
+ if GEOJSON:
+ return capi.to_kml(self.ptr, None)
+ else:
+ raise NotImplementedError('KML output only supported on GDAL 1.5+.')
+
+ @property
def wkb_size(self):
"Returns the size of the WKB buffer."
- return get_wkbsize(self._ptr)
+ return capi.get_wkbsize(self.ptr)
@property
def wkb(self):
@@ -307,19 +327,19 @@ def wkb(self):
sz = self.wkb_size
# Creating the unsigned character buffer, and passing it in by reference.
buf = (c_ubyte * sz)()
- wkb = to_wkb(self._ptr, byteorder, byref(buf))
+ wkb = capi.to_wkb(self.ptr, byteorder, byref(buf))
# Returning a buffer of the string at the pointer.
return buffer(string_at(buf, sz))
@property
def wkt(self):
"Returns the WKT representation of the Geometry."
- return to_wkt(self._ptr, byref(c_char_p()))
+ return capi.to_wkt(self.ptr, byref(c_char_p()))
#### Geometry Methods ####
def clone(self):
"Clones this OGR Geometry."
- return OGRGeometry(clone_geom(self._ptr), self.srs)
+ return OGRGeometry(capi.clone_geom(self.ptr), self.srs)
def close_rings(self):
"""
@@ -328,7 +348,7 @@ def close_rings(self):
end.
"""
# Closing the open rings.
- geom_close_rings(self._ptr)
+ capi.geom_close_rings(self.ptr)
def transform(self, coord_trans, clone=False):
"""
@@ -344,12 +364,12 @@ def transform(self, coord_trans, clone=False):
klone.transform(coord_trans)
return klone
if isinstance(coord_trans, CoordTransform):
- geom_transform(self._ptr, coord_trans._ptr)
+ capi.geom_transform(self.ptr, coord_trans.ptr)
elif isinstance(coord_trans, SpatialReference):
- geom_transform_to(self._ptr, coord_trans._ptr)
+ capi.geom_transform_to(self.ptr, coord_trans.ptr)
elif isinstance(coord_trans, (int, long, basestring)):
sr = SpatialReference(coord_trans)
- geom_transform_to(self._ptr, sr._ptr)
+ capi.geom_transform_to(self.ptr, sr.ptr)
else:
raise TypeError('Transform only accepts CoordTransform, SpatialReference, string, and integer objects.')
@@ -366,52 +386,52 @@ def _topology(self, func, other):
# Returning the output of the given function with the other geometry's
# pointer.
- return func(self._ptr, other._ptr)
+ return func(self.ptr, other.ptr)
def intersects(self, other):
"Returns True if this geometry intersects with the other."
- return self._topology(ogr_intersects, other)
+ return self._topology(capi.ogr_intersects, other)
def equals(self, other):
"Returns True if this geometry is equivalent to the other."
- return self._topology(ogr_equals, other)
+ return self._topology(capi.ogr_equals, other)
def disjoint(self, other):
"Returns True if this geometry and the other are spatially disjoint."
- return self._topology(ogr_disjoint, other)
+ return self._topology(capi.ogr_disjoint, other)
def touches(self, other):
"Returns True if this geometry touches the other."
- return self._topology(ogr_touches, other)
+ return self._topology(capi.ogr_touches, other)
def crosses(self, other):
"Returns True if this geometry crosses the other."
- return self._topology(ogr_crosses, other)
+ return self._topology(capi.ogr_crosses, other)
def within(self, other):
"Returns True if this geometry is within the other."
- return self._topology(ogr_within, other)
+ return self._topology(capi.ogr_within, other)
def contains(self, other):
"Returns True if this geometry contains the other."
- return self._topology(ogr_contains, other)
+ return self._topology(capi.ogr_contains, other)
def overlaps(self, other):
"Returns True if this geometry overlaps the other."
- return self._topology(ogr_overlaps, other)
+ return self._topology(capi.ogr_overlaps, other)
#### Geometry-generation Methods ####
def _geomgen(self, gen_func, other=None):
"A helper routine for the OGR routines that generate geometries."
if isinstance(other, OGRGeometry):
- return OGRGeometry(gen_func(self._ptr, other._ptr), self.srs)
+ return OGRGeometry(gen_func(self.ptr, other.ptr), self.srs)
else:
- return OGRGeometry(gen_func(self._ptr), self.srs)
+ return OGRGeometry(gen_func(self.ptr), self.srs)
@property
def boundary(self):
"Returns the boundary of this geometry."
- return self._geomgen(get_boundary)
+ return self._geomgen(capi.get_boundary)
@property
def convex_hull(self):
@@ -419,35 +439,35 @@ def convex_hull(self):
Returns the smallest convex Polygon that contains all the points in
this Geometry.
"""
- return self._geomgen(geom_convex_hull)
+ return self._geomgen(capi.geom_convex_hull)
def difference(self, other):
"""
Returns a new geometry consisting of the region which is the difference
of this geometry and the other.
"""
- return self._geomgen(geom_diff, other)
+ return self._geomgen(capi.geom_diff, other)
def intersection(self, other):
"""
Returns a new geometry consisting of the region of intersection of this
geometry and the other.
"""
- return self._geomgen(geom_intersection, other)
+ return self._geomgen(capi.geom_intersection, other)
def sym_difference(self, other):
"""
Returns a new geometry which is the symmetric difference of this
geometry and the other.
"""
- return self._geomgen(geom_sym_diff, other)
+ return self._geomgen(capi.geom_sym_diff, other)
def union(self, other):
"""
Returns a new geometry consisting of the region which is the union of
this geometry and the other.
"""
- return self._geomgen(geom_union, other)
+ return self._geomgen(capi.geom_union, other)
# The subclasses for OGR Geometry.
class Point(OGRGeometry):
@@ -455,18 +475,18 @@ class Point(OGRGeometry):
@property
def x(self):
"Returns the X coordinate for this Point."
- return getx(self._ptr, 0)
+ return capi.getx(self.ptr, 0)
@property
def y(self):
"Returns the Y coordinate for this Point."
- return gety(self._ptr, 0)
+ return capi.gety(self.ptr, 0)
@property
def z(self):
"Returns the Z coordinate for this Point."
if self.coord_dim == 3:
- return getz(self._ptr, 0)
+ return capi.getz(self.ptr, 0)
@property
def tuple(self):
@@ -483,7 +503,7 @@ def __getitem__(self, index):
"Returns the Point at the given index."
if index >= 0 and index < self.point_count:
x, y, z = c_double(), c_double(), c_double()
- get_point(self._ptr, index, byref(x), byref(y), byref(z))
+ capi.get_point(self.ptr, index, byref(x), byref(y), byref(z))
dim = self.coord_dim
if dim == 1:
return (x.value,)
@@ -514,23 +534,23 @@ def _listarr(self, func):
Internal routine that returns a sequence (list) corresponding with
the given function.
"""
- return [func(self._ptr, i) for i in xrange(len(self))]
+ return [func(self.ptr, i) for i in xrange(len(self))]
@property
def x(self):
"Returns the X coordinates in a list."
- return self._listarr(getx)
+ return self._listarr(capi.getx)
@property
def y(self):
"Returns the Y coordinates in a list."
- return self._listarr(gety)
+ return self._listarr(capi.gety)
@property
def z(self):
"Returns the Z coordinates in a list."
if self.coord_dim == 3:
- return self._listarr(getz)
+ return self._listarr(capi.getz)
# LinearRings are used in Polygons.
class LinearRing(LineString): pass
@@ -551,7 +571,7 @@ def __getitem__(self, index):
if index < 0 or index >= self.geom_count:
raise OGRIndexError('index out of range: %s' % index)
else:
- return OGRGeometry(clone_geom(get_geom_ref(self._ptr, index)), self.srs)
+ return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
# Polygon Properties
@property
@@ -577,7 +597,7 @@ def centroid(self):
"Returns the centroid (a Point) of this Polygon."
# The centroid is a Point, create a geometry for this.
p = OGRGeometry(OGRGeomType('Point'))
- get_centroid(self._ptr, p._ptr)
+ capi.get_centroid(self.ptr, p.ptr)
return p
# Geometry Collection base class.
@@ -589,7 +609,7 @@ def __getitem__(self, index):
if index < 0 or index >= self.geom_count:
raise OGRIndexError('index out of range: %s' % index)
else:
- return OGRGeometry(clone_geom(get_geom_ref(self._ptr, index)), self.srs)
+ return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
def __iter__(self):
"Iterates over each Geometry."
@@ -604,12 +624,12 @@ def add(self, geom):
"Add the geometry to this Geometry Collection."
if isinstance(geom, OGRGeometry):
if isinstance(geom, self.__class__):
- for g in geom: add_geom(self._ptr, g._ptr)
+ for g in geom: capi.add_geom(self.ptr, g.ptr)
else:
- add_geom(self._ptr, geom._ptr)
+ capi.add_geom(self.ptr, geom.ptr)
elif isinstance(geom, basestring):
tmp = OGRGeometry(geom)
- add_geom(self._ptr, tmp._ptr)
+ capi.add_geom(self.ptr, tmp.ptr)
else:
raise OGRException('Must add an OGRGeometry.')
View
11 django/contrib/gis/gdal/geomtype.py
@@ -24,7 +24,9 @@ def __init__(self, type_input):
if isinstance(type_input, OGRGeomType):
num = type_input.num
elif isinstance(type_input, basestring):
- num = self._str_types.get(type_input.lower(), None)
+ type_input = type_input.lower()
+ if type_input == 'geometry': type_input='unknown'
+ num = self._str_types.get(type_input, None)
if num is None:
raise OGRException('Invalid OGR String Type "%s"' % type_input)
elif isinstance(type_input, int):
@@ -67,7 +69,8 @@ def name(self):
def django(self):
"Returns the Django GeometryField for this OGR Type."
s = self.name
- if s in ('Unknown', 'LinearRing', 'None'):
+ if s in ('LinearRing', 'None'):
return None
- else:
- return s + 'Field'
+ elif s == 'Unknown':
+ s = 'Geometry'
+ return s + 'Field'
View
47 django/contrib/gis/gdal/layer.py
@@ -2,26 +2,22 @@
from ctypes import byref
# Other GDAL imports.
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
from django.contrib.gis.gdal.feature import Feature
-from django.contrib.gis.gdal.field import FIELD_CLASSES
+from django.contrib.gis.gdal.field import OGRFieldTypes
from django.contrib.gis.gdal.geometries import OGRGeomType
from django.contrib.gis.gdal.srs import SpatialReference
# GDAL ctypes function prototypes.
-from django.contrib.gis.gdal.prototypes.ds import \
- get_extent, get_fd_geom_type, get_fd_name, get_feature, get_feature_count, \
- get_field_count, get_field_defn, get_field_name, get_field_precision, \
- get_field_width, get_field_type, get_layer_defn, get_layer_srs, \
- get_next_feature, reset_reading, test_capability
-from django.contrib.gis.gdal.prototypes.srs import clone_srs
+from django.contrib.gis.gdal.prototypes import ds as capi, srs as srs_api
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_L_* routines are relevant here.
-class Layer(object):
+class Layer(GDALBase):
"A class that wraps an OGR Layer, needs to be instantiated from a DataSource object."
#### Python 'magic' routines ####
@@ -32,12 +28,11 @@ def __init__(self, layer_ptr, ds):
reference to it is kept with this Layer. This prevents garbage
collection of the `DataSource` while this Layer is still active.
"""
- self._ptr = None # Initially NULL
if not layer_ptr:
raise OGRException('Cannot create Layer, invalid pointer given')
- self._ptr = layer_ptr
+ self.ptr = layer_ptr
self._ds = ds
- self._ldefn = get_layer_defn(self._ptr)
+ self._ldefn = capi.get_layer_defn(self._ptr)
# Does the Layer support random reading?
self._random_read = self.test_capability('RandomRead')
@@ -59,9 +54,9 @@ def __getitem__(self, index):
def __iter__(self):
"Iterates over each Feature in the Layer."
# ResetReading() must be called before iteration is to begin.
- reset_reading(self._ptr)
+ capi.reset_reading(self._ptr)
for i in xrange(self.num_feat):
- yield Feature(get_next_feature(self._ptr), self._ldefn)
+ yield Feature(capi.get_next_feature(self._ptr), self._ldefn)
def __len__(self):
"The length is the number of features."
@@ -81,7 +76,7 @@ def _make_feature(self, feat_id):
if self._random_read:
# If the Layer supports random reading, return.
try:
- return Feature(get_feature(self._ptr, feat_id), self._ldefn)
+ return Feature(capi.get_feature(self.ptr, feat_id), self._ldefn)
except OGRException:
pass
else:
@@ -97,35 +92,35 @@ def _make_feature(self, feat_id):
def extent(self):
"Returns the extent (an Envelope) of this layer."
env = OGREnvelope()
- get_extent(self._ptr, byref(env), 1)
+ capi.get_extent(self.ptr, byref(env), 1)
return Envelope(env)
@property
def name(self):
"Returns the name of this layer in the Data Source."
- return get_fd_name(self._ldefn)
+ return capi.get_fd_name(self._ldefn)
@property
def num_feat(self, force=1):
"Returns the number of features in the Layer."
- return get_feature_count(self._ptr, force)
+ return capi.get_feature_count(self.ptr, force)
@property
def num_fields(self):
"Returns the number of fields in the Layer."
- return get_field_count(self._ldefn)
+ return capi.get_field_count(self._ldefn)
@property
def geom_type(self):
"Returns the geometry type (OGRGeomType) of the Layer."
- return OGRGeomType(get_fd_geom_type(self._ldefn))
+ return OGRGeomType(capi.get_fd_geom_type(self._ldefn))
@property
def srs(self):
"Returns the Spatial Reference used in this Layer."
try:
- ptr = get_layer_srs(self._ptr)
- return SpatialReference(clone_srs(ptr))
+ ptr = capi.get_layer_srs(self.ptr)
+ return SpatialReference(srs_api.clone_srs(ptr))
except SRSException:
return None
@@ -135,7 +130,7 @@ def fields(self):
Returns a list of string names corresponding to each of the Fields
available in this Layer.
"""
- return [get_field_name(get_field_defn(self._ldefn, i))
+ return [capi.get_field_name(capi.get_field_defn(self._ldefn, i))
for i in xrange(self.num_fields) ]
@property
@@ -146,19 +141,19 @@ def field_types(self):
an OGR layer that had an integer, a floating-point, and string
fields.
"""
- return [FIELD_CLASSES[get_field_type(get_field_defn(self._ldefn, i))]
+ return [OGRFieldTypes[capi.get_field_type(capi.get_field_defn(self._ldefn, i))]
for i in xrange(self.num_fields)]
@property
def field_widths(self):
"Returns a list of the maximum field widths for the features."
- return [get_field_width(get_field_defn(self._ldefn, i))
+ return [capi.get_field_width(capi.get_field_defn(self._ldefn, i))
for i in xrange(self.num_fields)]
@property
def field_precisions(self):
"Returns the field precisions for the features."
- return [get_field_precision(get_field_defn(self._ldefn, i))
+ return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
for i in xrange(self.num_fields)]
#### Layer Methods ####
@@ -190,4 +185,4 @@ def test_capability(self, capability):
'FastFeatureCount', 'FastGetExtent', 'CreateField', 'Transactions',
'DeleteFeature', and 'FastSetNextByIndex'.
"""
- return bool(test_capability(self._ptr, capability))
+ return bool(capi.test_capability(self.ptr, capability))
View
2  django/contrib/gis/gdal/prototypes/geom.py
@@ -38,9 +38,11 @@ def topology_func(f):
if GEOJSON:
from_json = geom_output(lgdal.OGR_G_CreateGeometryFromJson, [c_char_p])
to_json = string_output(lgdal.OGR_G_ExportToJson, [c_void_p], str_result=True)
+ to_kml = string_output(lgdal.OGR_G_ExportToKML, [c_void_p, c_char_p], str_result=True)
else:
from_json = False
to_json = False
+ to_kml = False
# GetX, GetY, GetZ all return doubles.
getx = pnt_func(lgdal.OGR_G_GetX)
View
1  django/contrib/gis/gdal/prototypes/srs.py
@@ -36,6 +36,7 @@ def units_func(f):
from_proj = void_output(lgdal.OSRImportFromProj4, [c_void_p, c_char_p])
from_epsg = void_output(std_call('OSRImportFromEPSG'), [c_void_p, c_int])
from_xml = void_output(lgdal.OSRImportFromXML, [c_void_p, c_char_p])
+from_user_input = void_output(std_call('OSRSetFromUserInput'), [c_void_p, c_char_p])
# Morphing to/from ESRI WKT.
morph_to_esri = void_output(lgdal.OSRMorphToESRI, [c_void_p])
View
159 django/contrib/gis/gdal/srs.py
@@ -27,89 +27,74 @@
NAD83 / Texas South Central
"""
import re
-from types import UnicodeType, TupleType
from ctypes import byref, c_char_p, c_int, c_void_p
# Getting the error checking routine and exceptions
+from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import OGRException, SRSException
-from django.contrib.gis.gdal.prototypes.srs import *
+from django.contrib.gis.gdal.prototypes import srs as capi
#### Spatial Reference class. ####
-class SpatialReference(object):
+class SpatialReference(GDALBase):
"""
A wrapper for the OGRSpatialReference object. According to the GDAL website,
the SpatialReference object "provide[s] services to represent coordinate
systems (projections and datums) and to transform between them."
"""
- # Well-Known Geographical Coordinate System Name
- _well_known = {'WGS84':4326, 'WGS72':4322, 'NAD27':4267, 'NAD83':4269}
- _epsg_regex = re.compile('^(EPSG:)?(?P<epsg>\d+)$', re.I)
- _proj_regex = re.compile(r'^\+proj')
-
#### Python 'magic' routines ####
- def __init__(self, srs_input='', srs_type='wkt'):
+ def __init__(self, srs_input=''):
"""
Creates a GDAL OSR Spatial Reference object from the given input.
The input may be string of OGC Well Known Text (WKT), an integer
EPSG code, a PROJ.4 string, and/or a projection "well known" shorthand
string (one of 'WGS84', 'WGS72', 'NAD27', 'NAD83').
"""
- # Intializing pointer and string buffer.
- self._ptr = None
buf = c_char_p('')
+ srs_type = 'user'
if isinstance(srs_input, basestring):
# Encoding to ASCII if unicode passed in.
- if isinstance(srs_input, UnicodeType):
+ if isinstance(srs_input, unicode):
srs_input = srs_input.encode('ascii')
-
- epsg_m = self._epsg_regex.match(srs_input)
- proj_m = self._proj_regex.match(srs_input)
- if epsg_m:
- # Is this an EPSG well known name?
- srs_type = 'epsg'
- srs_input = int(epsg_m.group('epsg'))
- elif proj_m:
- # Is the string a PROJ.4 string?
- srs_type = 'proj'
- elif srs_input in self._well_known:
- # Is this a short-hand well known name?
- srs_type = 'epsg'
- srs_input = self._well_known[srs_input]
- elif srs_type == 'proj':
+ try:
+ # If SRID is a string, e.g., '4326', then make acceptable
+ # as user input.
+ srid = int(srs_input)
+ srs_input = 'EPSG:%d' % srid
+ except ValueError:
pass
- else:
- # Setting the buffer with WKT, PROJ.4 string, etc.
- buf = c_char_p(srs_input)
- elif isinstance(srs_input, int):
+ elif isinstance(srs_input, (int, long)):
# EPSG integer code was input.
- if srs_type != 'epsg': srs_type = 'epsg'
- elif isinstance(srs_input, c_void_p):
+ srs_type = 'epsg'
+ elif isinstance(srs_input, self.ptr_type):
+ srs = srs_input
srs_type = 'ogr'
else:
raise TypeError('Invalid SRS type "%s"' % srs_type)
if srs_type == 'ogr':
- # SRS input is OGR pointer
+ # Input is already an SRS pointer.
srs = srs_input
else:
- # Creating a new pointer, using the string buffer.
- srs = new_srs(buf)
+ # Creating a new SRS pointer, using the string buffer.
+ srs = capi.new_srs(buf)
# If the pointer is NULL, throw an exception.
if not srs:
raise SRSException('Could not create spatial reference from: %s' % srs_input)
else:
- self._ptr = srs
+ self.ptr = srs
- # Post-processing if in PROJ.4 or EPSG formats.
- if srs_type == 'proj': self.import_proj(srs_input)
- elif srs_type == 'epsg': self.import_epsg(srs_input)
+ # Importing from either the user input string or an integer SRID.
+ if srs_type == 'user':
+ self.import_user_input(srs_input)
+ elif srs_type == 'epsg':
+ self.import_epsg(srs_input)
def __del__(self):
"Destroys this spatial reference."
- if self._ptr: release_srs(self._ptr)
+ if self._ptr: capi.release_srs(self._ptr)
def __getitem__(self, target):
"""
@@ -134,7 +119,7 @@ def __getitem__(self, target):
>>> print srs['UNIT|AUTHORITY', 1] # The authority value for the untis
9122
"""
- if isinstance(target, TupleType):
+ if isinstance(target, tuple):
return self.attr_value(*target)
else:
return self.attr_value(target)
@@ -149,40 +134,40 @@ def attr_value(self, target, index=0):
The attribute value for the given target node (e.g. 'PROJCS'). The index
keyword specifies an index of the child node to return.
"""
- if not isinstance(target, str) or not isinstance(index, int):
+ if not isinstance(target, basestring) or not isinstance(index, int):
raise TypeError
- return get_attr_value(self._ptr, target, index)
+ return capi.get_attr_value(self.ptr, target, index)
def auth_name(self, target):
"Returns the authority name for the given string target node."
- return get_auth_name(self._ptr, target)
+ return capi.get_auth_name(self.ptr, target)
def auth_code(self, target):
"Returns the authority code for the given string target node."
- return get_auth_code(self._ptr, target)
+ return capi.get_auth_code(self.ptr, target)
def clone(self):
"Returns a clone of this SpatialReference object."
- return SpatialReference(clone_srs(self._ptr))
+ return SpatialReference(capi.clone_srs(self.ptr))
def from_esri(self):
"Morphs this SpatialReference from ESRI's format to EPSG."
- morph_from_esri(self._ptr)
+ capi.morph_from_esri(self.ptr)
def identify_epsg(self):
"""
This method inspects the WKT of this SpatialReference, and will
add EPSG authority nodes where an EPSG identifier is applicable.
"""
- identify_epsg(self._ptr)
+ capi.identify_epsg(self.ptr)
def to_esri(self):
"Morphs this SpatialReference to ESRI's format."
- morph_to_esri(self._ptr)
+ capi.morph_to_esri(self.ptr)
def validate(self):
"Checks to see if the given spatial reference is valid."
- srs_validate(self._ptr)
+ capi.srs_validate(self.ptr)
#### Name & SRID properties ####
@property
@@ -205,25 +190,25 @@ def srid(self):
@property
def linear_name(self):
"Returns the name of the linear units."
- units, name = linear_units(self._ptr, byref(c_char_p()))
+ units, name = capi.linear_units(self.ptr, byref(c_char_p()))
return name
@property
def linear_units(self):
"Returns the value of the linear units."
- units, name = linear_units(self._ptr, byref(c_char_p()))
+ units, name = capi.linear_units(self.ptr, byref(c_char_p()))
return units
@property
def angular_name(self):
"Returns the name of the angular units."
- units, name = angular_units(self._ptr, byref(c_char_p()))
+ units, name = capi.angular_units(self.ptr, byref(c_char_p()))
return name
@property
def angular_units(self):
"Returns the value of the angular units."
- units, name = angular_units(self._ptr, byref(c_char_p()))
+ units, name = capi.angular_units(self.ptr, byref(c_char_p()))
return units
@property
@@ -234,9 +219,9 @@ def units(self):
or angular units.
"""
if self.projected or self.local:
- return linear_units(self._ptr, byref(c_char_p()))
+ return capi.linear_units(self.ptr, byref(c_char_p()))
elif self.geographic:
- return angular_units(self._ptr, byref(c_char_p()))
+ return capi.angular_units(self.ptr, byref(c_char_p()))
else:
return (None, None)
@@ -252,17 +237,17 @@ def ellipsoid(self):
@property
def semi_major(self):
"Returns the Semi Major Axis for this Spatial Reference."
- return semi_major(self._ptr, byref(c_int()))
+ return capi.semi_major(self.ptr, byref(c_int()))
@property
def semi_minor(self):
"Returns the Semi Minor Axis for this Spatial Reference."
- return semi_minor(self._ptr, byref(c_int()))
+ return capi.semi_minor(self.ptr, byref(c_int()))
@property
def inverse_flattening(self):
"Returns the Inverse Flattening for this Spatial Reference."
- return invflattening(self._ptr, byref(c_int()))
+ return capi.invflattening(self.ptr, byref(c_int()))
#### Boolean Properties ####
@property
@@ -271,12 +256,12 @@ def geographic(self):
Returns True if this SpatialReference is geographic
(root node is GEOGCS).
"""
- return bool(isgeographic(self._ptr))
+ return bool(capi.isgeographic(self.ptr))
@property
def local(self):
"Returns True if this SpatialReference is local (root node is LOCAL_CS)."
- return bool(islocal(self._ptr))
+ return bool(capi.islocal(self.ptr))
@property
def projected(self):
@@ -284,40 +269,44 @@ def projected(self):
Returns True if this SpatialReference is a projected coordinate system
(root node is PROJCS).
"""
- return bool(isprojected(self._ptr))
+ return bool(capi.isprojected(self.ptr))
#### Import Routines #####
- def import_wkt(self, wkt):
- "Imports the Spatial Reference from OGC WKT (string)"
- from_wkt(self._ptr, byref(c_char_p(wkt)))
+ def import_epsg(self, epsg):
+ "Imports the Spatial Reference from the EPSG code (an integer)."
+ capi.from_epsg(self.ptr, epsg)
def import_proj(self, proj):
"Imports the Spatial Reference from a PROJ.4 string."
- from_proj(self._ptr, proj)
+ capi.from_proj(self.ptr, proj)
- def import_epsg(self, epsg):
- "Imports the Spatial Reference from the EPSG code (an integer)."
- from_epsg(self._ptr, epsg)
+ def import_user_input(self, user_input):
+ "Imports the Spatial Reference from the given user input string."
+ capi.from_user_input(self.ptr, user_input)
+
+ def import_wkt(self, wkt):
+ "Imports the Spatial Reference from OGC WKT (string)"
+ capi.from_wkt(self.ptr, byref(c_char_p(wkt)))
def import_xml(self, xml):
"Imports the Spatial Reference from an XML string."
- from_xml(self._ptr, xml)
+ capi.from_xml(self.ptr, xml)
#### Export Properties ####
@property
def wkt(self):
"Returns the WKT representation of this Spatial Reference."
- return to_wkt(self._ptr, byref(c_char_p()))
+ return capi.to_wkt(self.ptr, byref(c_char_p()))
@property
def pretty_wkt(self, simplify=0):
"Returns the 'pretty' representation of the WKT."
- return to_pretty_wkt(self._ptr, byref(c_char_p()), simplify)
+ return capi.to_pretty_wkt(self.ptr, byref(c_char_p()), simplify)
@property
def proj(self):
"Returns the PROJ.4 representation for this Spatial Reference."
- return to_proj(self._ptr, byref(c_char_p()))
+ return capi.to_proj(self.ptr, byref(c_char_p()))
@property
def proj4(self):
@@ -327,34 +316,22 @@ def proj4(self):
@property
def xml(self, dialect=''):
"Returns the XML representation of this Spatial Reference."
- # FIXME: This leaks memory, have to figure out why.
- return to_xml(self._ptr, byref(c_char_p()), dialect)
-
- def to_esri(self):
- "Morphs this SpatialReference to ESRI's format."
- morph_to_esri(self._ptr)
-
- def from_esri(self):
- "Morphs this SpatialReference from ESRI's format to EPSG."
- morph_from_esri(self._ptr)
+ return capi.to_xml(self.ptr, byref(c_char_p()), dialect)
-class CoordTransform(object):
+class CoordTransform(GDALBase):
"The coordinate system transformation object."
def __init__(self, source, target):
"Initializes on a source and target SpatialReference objects."
- self._ptr = None # Initially NULL
if not isinstance(source, SpatialReference) or not isinstance(target, SpatialReference):
- raise SRSException('source and target must be of type SpatialReference')
- self._ptr = new_ct(source._ptr, target._ptr)
- if not self._ptr:
- raise SRSException('could not intialize CoordTransform object')
+ raise TypeError('source and target must be of type SpatialReference')
+ self.ptr = capi.new_ct(source._ptr, target._ptr)
self._srs1_name = source.name
self._srs2_name = target.name
def __del__(self):
"Deletes this Coordinate Transformation object."
- if self._ptr: destroy_ct(self._ptr)
+ if self._ptr: capi.destroy_ct(self._ptr)
def __str__(self):
return 'Transform from "%s" to "%s"' % (self._srs1_name, self._srs2_name)
View
15 django/contrib/gis/tests/test_gdal.py → django/contrib/gis/gdal/tests/__init__.py
@@ -5,16 +5,13 @@
from unittest import TestSuite, TextTestRunner
# Importing the GDAL test modules.
-from django.contrib.gis.tests import \
- test_gdal_driver, test_gdal_ds, test_gdal_envelope, \
- test_gdal_geom, test_gdal_srs
-
+import test_driver, test_ds, test_envelope, test_geom, test_srs
-test_suites = [test_gdal_driver.suite(),
- test_gdal_ds.suite(),
- test_gdal_envelope.suite(),
- test_gdal_geom.suite(),
- test_gdal_srs.suite(),
+test_suites = [test_driver.suite(),
+ test_ds.suite(),
+ test_envelope.suite(),
+ test_geom.suite(),
+ test_srs.suite(),
]
def suite():
View
0  django/contrib/gis/tests/test_gdal_driver.py → django/contrib/gis/gdal/tests/test_driver.py
File renamed without changes
View
5 django/contrib/gis/tests/test_gdal_ds.py → django/contrib/gis/gdal/tests/test_ds.py
@@ -1,10 +1,13 @@
import os, os.path, unittest
from django.contrib.gis.gdal import DataSource, Envelope, OGRException, OGRIndexError
from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString
+from django.contrib import gis
# Path for SHP files
-data_path = os.path.join(os.path.dirname(__file__), 'data')
+data_path = os.path.join(os.path.dirname(gis.__file__), 'tests' + os.sep + 'data')
def get_ds_file(name, ext):
+
+
return os.sep.join([data_path, name, name + '.%s' % ext])
# Test SHP data source object
View
94 django/contrib/gis/gdal/tests/test_envelope.py
@@ -0,0 +1,94 @@
+import unittest
+from django.contrib.gis.gdal import Envelope, OGRException
+
+class TestPoint(object):
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+
+class EnvelopeTest(unittest.TestCase):
+
+ def setUp(self):
+ self.e = Envelope(0, 0, 5, 5)
+
+ def test01_init(self):
+ "Testing Envelope initilization."
+ e1 = Envelope((0, 0, 5, 5))
+ e2 = Envelope(0, 0, 5, 5)
+ e3 = Envelope(0, '0', '5', 5) # Thanks to ww for this
+ e4 = Envelope(e1._envelope)
+ self.assertRaises(OGRException, Envelope, (5, 5, 0, 0))
+ self.assertRaises(OGRException, Envelope, 5, 5, 0, 0)
+ self.assertRaises(OGRException, Envelope, (0, 0, 5, 5, 3))
+ self.assertRaises(OGRException, Envelope, ())
+ self.assertRaises(ValueError, Envelope, 0, 'a', 5, 5)
+ self.assertRaises(TypeError, Envelope, u'foo')
+ self.assertRaises(OGRException, Envelope, (1, 1, 0, 0))
+ try:
+ Envelope(0, 0, 0, 0)
+ except OGRException:
+ self.fail("shouldn't raise an exception for min_x == max_x or min_y == max_y")
+
+ def test02_properties(self):
+ "Testing Envelope properties."
+ e = Envelope(0, 0, 2, 3)
+ self.assertEqual(0, e.min_x)
+ self.assertEqual(0, e.min_y)
+ self.assertEqual(2, e.max_x)
+ self.assertEqual(3, e.max_y)
+ self.assertEqual((0, 0), e.ll)
+ self.assertEqual((2, 3), e.ur)
+ self.assertEqual((0, 0, 2, 3), e.tuple)
+ self.assertEqual('POLYGON((0.0 0.0,0.0 3.0,2.0 3.0,2.0 0.0,0.0 0.0))', e.wkt)
+ self.assertEqual('(0.0, 0.0, 2.0, 3.0)', str(e))
+
+ def test03_equivalence(self):
+ "Testing Envelope equivalence."
+ e1 = Envelope(0.523, 0.217, 253.23, 523.69)
+ e2 = Envelope((0.523, 0.217, 253.23, 523.69))
+ self.assertEqual(e1, e2)
+ self.assertEqual((0.523, 0.217, 253.23, 523.69), e1)
+
+ def test04_expand_to_include_pt_2_params(self):
+ "Testing Envelope expand_to_include -- point as two parameters."
+ self.e.expand_to_include(2, 6)
+ self.assertEqual((0, 0, 5, 6), self.e)
+ self.e.expand_to_include(-1, -1)
+ self.assertEqual((-1, -1, 5, 6), self.e)
+
+ def test05_expand_to_include_pt_2_tuple(self):
+ "Testing Envelope expand_to_include -- point as a single 2-tuple parameter."
+ self.e.expand_to_include((10, 10))
+ self.assertEqual((0, 0, 10, 10), self.e)
+ self.e.expand_to_include((-10, -10))
+ self.assertEqual((-10, -10, 10, 10), self.e)
+
+ def test06_expand_to_include_extent_4_params(self):
+ "Testing Envelope expand_to_include -- extent as 4 parameters."
+ self.e.expand_to_include(-1, 1, 3, 7)
+ self.assertEqual((-1, 0, 5, 7), self.e)
+
+ def test06_expand_to_include_extent_4_tuple(self):
+ "Testing Envelope expand_to_include -- extent as a single 4-tuple parameter."
+ self.e.expand_to_include((-1, 1, 3, 7))
+ self.assertEqual((-1, 0, 5, 7), self.e)
+
+ def test07_expand_to_include_envelope(self):
+ "Testing Envelope expand_to_include with Envelope as parameter."
+ self.e.expand_to_include(Envelope(-1, 1, 3, 7))
+ self.assertEqual((-1, 0, 5, 7), self.e)
+
+ def test08_expand_to_include_point(self):
+ "Testing Envelope expand_to_include with Point as parameter."
+ self.e.expand_to_include(TestPoint(-1, 1))
+ self.assertEqual((-1, 0, 5, 5), self.e)
+ self.e.expand_to_include(TestPoint(10, 10))
+ self.assertEqual((-1, 0, 10, 10), self.e)
+
+def suite():
+ s = unittest.TestSuite()
+ s.addTest(unittest.makeSuite(EnvelopeTest))
+ return s
+
+def run(verbosity=2):
+ unittest.TextTestRunner(verbosity=verbosity).run(suite())
View
21 django/contrib/gis/tests/test_gdal_geom.py → django/contrib/gis/gdal/tests/test_geom.py
@@ -7,7 +7,7 @@
class OGRGeomTest(unittest.TestCase):
"This tests the OGR Geometry."
- def test00_geomtype(self):
+ def test00a_geomtype(self):
"Testing OGRGeomType object."
# OGRGeomType should initialize on all these inputs.
@@ -22,9 +22,9 @@ def test00_geomtype(self):
self.fail('Could not create an OGRGeomType object!')
# Should throw TypeError on this input
- self.assertRaises(TypeError, OGRGeomType.__init__, 23)
- self.assertRaises(TypeError, OGRGeomType.__init__, 'fooD')
- self.assertRaises(TypeError, OGRGeomType.__init__, 9)
+ self.assertRaises(OGRException, OGRGeomType, 23)
+ self.assertRaises(OGRException, OGRGeomType, 'fooD')
+ self.assertRaises(OGRException, OGRGeomType, 9)
# Equivalence can take strings, ints, and other OGRGeomTypes
self.assertEqual(True, OGRGeomType(1) == OGRGeomType(1))
@@ -38,9 +38,14 @@ def test00_geomtype(self):
# Testing the Django field name equivalent property.
self.assertEqual('PointField', OGRGeomType('Point').django)
- self.assertEqual(None, OGRGeomType('Unknown').django)
+ self.assertEqual('GeometryField', OGRGeomType('Unknown').django)
self.assertEqual(None, OGRGeomType('none').django)
+ # 'Geometry' initialization implies an unknown geometry type.
+ gt = OGRGeomType('Geometry')
+ self.assertEqual(0, gt.num)
+ self.assertEqual('Unknown', gt.name)
+
def test01a_wkt(self):
"Testing WKT output."
for g in wkt_out:
@@ -165,6 +170,12 @@ def test06_linearring(self):
def test07a_polygons(self):
"Testing Polygon objects."
+
+ # Testing `from_bbox` class method
+ bbox = (-180,-90,180,90)
+ p = OGRGeometry.from_bbox( bbox )
+ self.assertEqual(bbox, p.extent)
+
prev = OGRGeometry('POINT(0 0)')
for p in polygons:
poly = OGRGeometry(p.wkt)
View
0  django/contrib/gis/tests/test_gdal_srs.py → django/contrib/gis/gdal/tests/test_srs.py
File renamed without changes
View
87 django/contrib/gis/tests/__init__.py
@@ -9,42 +9,45 @@ def geo_suite():
"""
from django.conf import settings
from django.contrib.gis.tests.utils import mysql, oracle, postgis
- from django.contrib.gis.gdal import HAS_GDAL
- from django.contrib.gis.utils import HAS_GEOIP
+ from django.contrib.gis import gdal, utils
- # Tests that require use of a spatial database (e.g., creation of models)
- test_models = ['geoapp',]
+ # The test suite.
+ s = unittest.TestSuite()
+
+ # Adding the GEOS tests. (__future__)
+ #from django.contrib.gis.geos import tests as geos_tests
+ #s.addTest(geos_tests.suite())
- # Tests that do not require setting up and tearing down a spatial database.
+ # Test apps that require use of a spatial database (e.g., creation of models)
+ test_apps = ['geoapp', 'relatedapp']
+ if oracle or postgis:
+ test_apps.append('distapp')
+
+ # Tests that do not require setting up and tearing down a spatial database
+ # and are modules in `django.contrib.gis.tests`.
test_suite_names = [
'test_geos',
'test_measure',
]
- if HAS_GDAL:
- if oracle or postgis:
- test_models += ['distapp', 'layermap', 'relatedapp']
- elif mysql:
- test_models += ['relatedapp', 'layermap']
-
- test_suite_names += [
- 'test_gdal_driver',
- 'test_gdal_ds',
- 'test_gdal_envelope',
- 'test_gdal_geom',
- 'test_gdal_srs',
- 'test_spatialrefsys',
- ]
+
+ if gdal.HAS_GDAL:
+ # These tests require GDAL.
+ test_suite_names.append('test_spatialrefsys')
+ test_apps.append('layermap')
+
+ # Adding the GDAL tests.
+ from django.contrib.gis.gdal import tests as gdal_tests
+ s.addTest(gdal_tests.suite())
else:
print >>sys.stderr, "GDAL not available - no GDAL tests will be run."
- if HAS_GEOIP and hasattr(settings, 'GEOIP_PATH'):
+ if utils.HAS_GEOIP and hasattr(settings, 'GEOIP_PATH'):
test_suite_names.append('test_geoip')
- s = unittest.TestSuite()
- for test_suite in test_suite_names:
- tsuite = getattr(__import__('django.contrib.gis.tests', globals(), locals(), [test_suite]),test_suite)
+ for suite_name in test_suite_names:
+ tsuite = getattr(__import__('django.contrib.gis.tests', globals(), locals(), [suite_name]), suite_name)
s.addTest(tsuite.suite())
- return s, test_models
+ return s, test_apps
def run_gis_tests(test_labels, **kwargs):
"""
@@ -80,9 +83,9 @@ def run_gis_tests(test_labels, **kwargs):
# Creating the test suite, adding the test models to INSTALLED_APPS, and
# adding the model test suites to our suite package.
- gis_suite, test_models = geo_suite()
- for test_model in test_models:
- module_name = 'django.contrib.gis.tests.%s' % test_model
+ gis_suite, test_apps = geo_suite()
+ for test_app in test_apps:
+ module_name = 'django.contrib.gis.tests.%s' % test_app
if mysql:
test_module_name = 'tests_mysql'
else:
@@ -90,13 +93,13 @@ def run_gis_tests(test_labels, **kwargs):
new_installed.append(module_name)
# Getting the model test suite
- tsuite = getattr(__import__('django.contrib.gis.tests.%s' % test_model, globals(), locals(), [test_module_name]),
+ tsuite = getattr(__import__('django.contrib.gis.tests.%s' % test_app, globals(), locals(), [test_module_name]),
test_module_name)
gis_suite.addTest(tsuite.suite())
- # Resetting the loaded flag to take into account what we appended to
- # the INSTALLED_APPS (since this routine is invoked through
- # django/core/management, it caches the apps; this ensures that syncdb
+ # Resetting the loaded flag to take into account what we appended to
+ # the INSTALLED_APPS (since this routine is invoked through
+ # django/core/management, it caches the apps; this ensures that syncdb
# will see our appended models)
settings.INSTALLED_APPS = new_installed
loading.cache.loaded = False
@@ -198,3 +201,25 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[], suite=
# Returning the total failures and errors
return len(result.failures) + len(result.errors)
+
+# Class for creating a fake module with a run method. This is for the
+# GEOS and GDAL tests that were moved to their respective modules.
+class _DeprecatedTestModule(object):
+ def __init__(self, tests, mod):
+ self.tests = tests
+ self.mod = mod
+
+ def run(self):
+ from warnings import warn
+ warn('This test module is deprecated because it has moved to ' \
+ '`django.contrib.gis.%s.tests` and will disappear in 1.2.' %
+ self.mod, DeprecationWarning)
+ self.tests.run()
+
+#from django.contrib.gis.geos import tests as _tests
+#test_geos = _DeprecatedTestModule(_tests, 'geos')
+
+from django.contrib.gis.gdal import HAS_GDAL
+if HAS_GDAL:
+ from django.contrib.gis.gdal import tests as _tests
+ test_gdal = _DeprecatedTestModule(_tests, 'gdal')
View
45 django/contrib/gis/tests/test_gdal_envelope.py
@@ -1,45 +0,0 @@
-import unittest
-from django.contrib.gis.gdal import Envelope, OGRException
-
-class EnvelopeTest(unittest.TestCase):
-
- def test01_init(self):
- "Testing Envelope initilization."
- e1 = Envelope((0, 0, 5, 5))
- e2 = Envelope(0, 0, 5, 5)
- e3 = Envelope(0, '0', '5', 5) # Thanks to ww for this
- e4 = Envelope(e1._envelope)
- self.assertRaises(OGRException, Envelope, (5, 5, 0, 0))
- self.assertRaises(OGRException, Envelope, 5, 5, 0, 0)
- self.assertRaises(OGRException, Envelope, (0, 0, 5, 5, 3))
- self.assertRaises(OGRException, Envelope, ())
- self.assertRaises(ValueError, Envelope, 0, 'a', 5, 5)
- self.assertRaises(TypeError, Envelope, u'foo')
-
- def test02_properties(self):
- "Testing Envelope properties."
- e = Envelope(0, 0, 2, 3)
- self.assertEqual(0, e.min_x)
- self.assertEqual(0, e.min_y)
- self.assertEqual(2, e.max_x)
- self.assertEqual(3, e.max_y)
- self.assertEqual((0, 0), e.ll)
- self.assertEqual((2, 3), e.ur)
- self.assertEqual((0, 0, 2, 3), e.tuple)
- self.assertEqual('POLYGON((0.0 0.0,0.0 3.0,2.0 3.0,2.0 0.0,0.0 0.0))', e.wkt)
- self.assertEqual('(0.0, 0.0, 2.0, 3.0)', str(e))
-
- def test03_equivalence(self):
- "Testing Envelope equivalence."
- e1 = Envelope(0.523, 0.217, 253.23, 523.69)
- e2 = Envelope((0.523, 0.217, 253.23, 523.69))
- self.assertEqual(e1, e2)
- self.assertEqual((0.523, 0.217, 253.23, 523.69), e1)
-
-def suite():
- s = unittest.TestSuite()
- s.addTest(unittest.makeSuite(EnvelopeTest))
- return s
-
-def run(verbosity=2):
- unittest.TextTestRunner(verbosity=verbosity).run(suite())

0 comments on commit f1ada99

Please sign in to comment.
Something went wrong with that request. Please try again.