Simplified GEOSFuncFactory.

This commit is contained in:
Sergey Fedoseev 2017-09-08 19:38:30 +05:00 committed by Tim Graham
parent 4ac2ab30f5
commit ff17ef1ada
6 changed files with 28 additions and 59 deletions

View File

@ -12,7 +12,7 @@ from ctypes import CDLL, CFUNCTYPE, POINTER, Structure, c_char_p
from ctypes.util import find_library
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import SimpleLazyObject
from django.utils.functional import SimpleLazyObject, cached_property
from django.utils.version import get_version_tuple
logger = logging.getLogger('django.contrib.gis')
@ -148,14 +148,12 @@ class GEOSFuncFactory:
self.argtypes = argtypes
self.args = args
self.kwargs = kwargs
self.func = None
def __call__(self, *args, **kwargs):
if self.func is None:
self.func = self.get_func(*self.args, **self.kwargs)
return self.func(*args, **kwargs)
def get_func(self, *args, **kwargs):
@cached_property
def func(self):
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
func = GEOSFunc(self.func_name)
func.argtypes = self.argtypes or []

View File

@ -34,30 +34,27 @@ class CsOperation(GEOSFuncFactory):
"For coordinate sequence operations."
restype = c_int
def get_func(self, ordinate=False, get=False):
def __init__(self, *args, ordinate=False, get=False, **kwargs):
if get:
# Get routines have double parameter passed-in by reference.
self.errcheck = check_cs_get
errcheck = check_cs_get
dbl_param = POINTER(c_double)
else:
self.errcheck = check_cs_op
errcheck = check_cs_op
dbl_param = c_double
if ordinate:
# Get/Set ordinate routines have an extra uint parameter.
self.argtypes = [CS_PTR, c_uint, c_uint, dbl_param]
argtypes = [CS_PTR, c_uint, c_uint, dbl_param]
else:
self.argtypes = [CS_PTR, c_uint, dbl_param]
return super().get_func()
argtypes = [CS_PTR, c_uint, dbl_param]
super().__init__(*args, **dict(kwargs, errcheck=errcheck, argtypes=argtypes))
class CsOutput(GEOSFuncFactory):
restype = CS_PTR
def get_func(self, argtypes):
self.argtypes = argtypes
return super().get_func()
@staticmethod
def errcheck(result, func, cargs):
if not result:
@ -71,9 +68,9 @@ class CsOutput(GEOSFuncFactory):
# ## Coordinate Sequence ctypes prototypes ##
# Coordinate Sequence constructors & cloning.
cs_clone = CsOutput('GEOSCoordSeq_clone', [CS_PTR])
create_cs = CsOutput('GEOSCoordSeq_create', [c_uint, c_uint])
get_cs = CsOutput('GEOSGeom_getCoordSeq', [GEOM_PTR])
cs_clone = CsOutput('GEOSCoordSeq_clone', argtypes=[CS_PTR])
create_cs = CsOutput('GEOSCoordSeq_create', argtypes=[c_uint, c_uint])
get_cs = CsOutput('GEOSGeom_getCoordSeq', argtypes=[GEOM_PTR])
# Getting, setting ordinate
cs_getordinate = CsOperation('GEOSCoordSeq_getOrdinate', ordinate=True, get=True)

View File

@ -81,11 +81,3 @@ def check_string(result, func, cargs):
# Freeing the memory allocated within GEOS
free(result)
return s
def check_zero(result, func, cargs):
"Error checking on routines that should not return 0."
if result == 0:
raise GEOSException('Error encountered in GEOS C function "%s".' % func.__name__)
else:
return result

View File

@ -2,7 +2,7 @@ from ctypes import POINTER, c_char_p, c_int, c_size_t, c_ubyte
from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, GEOSFuncFactory
from django.contrib.gis.geos.prototypes.errcheck import (
check_geom, check_minus_one, check_sized_string, check_string, check_zero,
check_geom, check_minus_one, check_sized_string, check_string,
)
# This is the return type used by binary output (WKB, HEX) routines.
@ -41,22 +41,12 @@ class GeomOutput(GEOSFuncFactory):
restype = GEOM_PTR
errcheck = staticmethod(check_geom)
def get_func(self, argtypes):
self.argtypes = argtypes
return super().get_func()
class IntFromGeom(GEOSFuncFactory):
"Argument is a geometry, return type is an integer."
argtypes = [GEOM_PTR]
restype = c_int
def get_func(self, zero=False):
if zero:
self.errcheck = check_zero
else:
self.errcheck = check_minus_one
return super().get_func()
errcheck = staticmethod(check_minus_one)
class StringFromGeom(GEOSFuncFactory):
@ -77,23 +67,23 @@ get_num_coords = IntFromGeom('GEOSGetNumCoordinates')
get_num_geoms = IntFromGeom('GEOSGetNumGeometries')
# Geometry creation factories
create_point = GeomOutput('GEOSGeom_createPoint', [CS_PTR])
create_linestring = GeomOutput('GEOSGeom_createLineString', [CS_PTR])
create_linearring = GeomOutput('GEOSGeom_createLinearRing', [CS_PTR])
create_point = GeomOutput('GEOSGeom_createPoint', argtypes=[CS_PTR])
create_linestring = GeomOutput('GEOSGeom_createLineString', argtypes=[CS_PTR])
create_linearring = GeomOutput('GEOSGeom_createLinearRing', argtypes=[CS_PTR])
# Polygon and collection creation routines are special and will not
# have their argument types defined.
create_polygon = GeomOutput('GEOSGeom_createPolygon', None)
create_empty_polygon = GeomOutput('GEOSGeom_createEmptyPolygon', None)
create_collection = GeomOutput('GEOSGeom_createCollection', None)
create_polygon = GeomOutput('GEOSGeom_createPolygon')
create_empty_polygon = GeomOutput('GEOSGeom_createEmptyPolygon')
create_collection = GeomOutput('GEOSGeom_createCollection')
# Ring routines
get_extring = GeomOutput('GEOSGetExteriorRing', [GEOM_PTR])
get_intring = GeomOutput('GEOSGetInteriorRingN', [GEOM_PTR, c_int])
get_extring = GeomOutput('GEOSGetExteriorRing', argtypes=[GEOM_PTR])
get_intring = GeomOutput('GEOSGetInteriorRingN', argtypes=[GEOM_PTR, c_int])
get_nrings = IntFromGeom('GEOSGetNumInteriorRings')
# Collection Routines
get_geomn = GeomOutput('GEOSGetGeometryN', [GEOM_PTR, c_int])
get_geomn = GeomOutput('GEOSGetGeometryN', argtypes=[GEOM_PTR, c_int])
# Cloning
geom_clone = GEOSFuncFactory('GEOSGeom_clone', argtypes=[GEOM_PTR], restype=GEOM_PTR)

View File

@ -118,9 +118,7 @@ class IOBase(GEOSBase):
self.ptr = self._constructor()
# Loading the real destructor function at this point as doing it in
# __del__ is too late (import error).
self.destructor.func = self.destructor.get_func(
*self.destructor.args, **self.destructor.kwargs
)
self.destructor.func
# ### Base WKB/WKT Reading and Writing objects ###

View File

@ -19,19 +19,13 @@ class DblFromGeom(GEOSFuncFactory):
restype = c_int # Status code returned
errcheck = staticmethod(check_dbl)
def get_func(self, num_geom=1):
argtypes = [GEOM_PTR for i in range(num_geom)]
argtypes += [POINTER(c_double)]
self.argtypes = argtypes
return super().get_func()
# ### ctypes prototypes ###
# Area, distance, and length prototypes.
geos_area = DblFromGeom('GEOSArea')
geos_distance = DblFromGeom('GEOSDistance', num_geom=2)
geos_length = DblFromGeom('GEOSLength')
geos_area = DblFromGeom('GEOSArea', argtypes=[GEOM_PTR, POINTER(c_double)])
geos_distance = DblFromGeom('GEOSDistance', argtypes=[GEOM_PTR, GEOM_PTR, POINTER(c_double)])
geos_length = DblFromGeom('GEOSLength', argtypes=[GEOM_PTR, POINTER(c_double)])
geos_isvalidreason = GEOSFuncFactory(
'GEOSisValidReason', restype=geos_char_p, errcheck=check_string, argtypes=[GEOM_PTR]
)