Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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())
Please sign in to comment.
Something went wrong with that request. Please try again.