Ticket #10923: geos_threadsafe_v2.diff

File geos_threadsafe_v2.diff, 40.0 KB (added by jbronn, 14 years ago)

threading.local subclasses and I/O function accessors are actually necessary

  • django/contrib/gis/geos/geometry.py

     
    2121# the underlying GEOS library.
    2222from django.contrib.gis.geos import prototypes as capi
    2323
     24# These functions provide access to a thread-local instance
     25# of their corresponding GEOS I/O class.
     26from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
     27
    2428# Regular expression for recognizing HEXEWKB and WKT.  A prophylactic measure
    2529# to prevent potentially malicious input from reaching the underlying C
    2630# library.  Not a substitute for good web security programming practices.
     
    6165            if wkt_m:
    6266                # Handling WKT input.
    6367                if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
    64                 g = wkt_r.read(wkt_m.group('wkt'))
     68                g = wkt_r().read(wkt_m.group('wkt'))
    6569            elif hex_regex.match(geo_input):
    6670                # Handling HEXEWKB input.
    67                 g = wkb_r.read(geo_input)
     71                g = wkb_r().read(geo_input)
    6872            elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input):
    6973                # Handling GeoJSON input.
    70                 g = wkb_r.read(gdal.OGRGeometry(geo_input).wkb)
     74                g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
    7175            else:
    7276                raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
    7377        elif isinstance(geo_input, GEOM_PTR):
     
    7579            g = geo_input
    7680        elif isinstance(geo_input, buffer):
    7781            # When the input is a buffer (WKB).
    78             g = wkb_r.read(geo_input)
     82            g = wkb_r().read(geo_input)
    7983        elif isinstance(geo_input, GEOSGeometry):
    8084            g = capi.geom_clone(geo_input.ptr)
    8185        else:
     
    368372    @property
    369373    def wkt(self):
    370374        "Returns the WKT (Well-Known Text) representation of this Geometry."
    371         return wkt_w.write(self)
     375        return wkt_w().write(self)
    372376
    373377    @property
    374378    def hex(self):
     
    380384        """
    381385        # A possible faster, all-python, implementation:
    382386        #  str(self.wkb).encode('hex')
    383         return wkb_w.write_hex(self)
     387        return wkb_w().write_hex(self)
    384388
    385389    @property
    386390    def hexewkb(self):
     
    393397            if not GEOS_PREPARE:
    394398                # See: http://trac.osgeo.org/geos/ticket/216
    395399                raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')               
    396             return ewkb_w3d.write_hex(self)
     400            return ewkb_w3d().write_hex(self)
    397401        else:
    398             return ewkb_w.write_hex(self)
     402            return ewkb_w().write_hex(self)
    399403
    400404    @property
    401405    def json(self):
     
    416420        as a Python buffer.  SRID and Z values are not included, use the
    417421        `ewkb` property instead.
    418422        """
    419         return wkb_w.write(self)
     423        return wkb_w().write(self)
    420424
    421425    @property
    422426    def ewkb(self):
     
    429433            if not GEOS_PREPARE:
    430434                # See: http://trac.osgeo.org/geos/ticket/216
    431435                raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
    432             return ewkb_w3d.write(self)
     436            return ewkb_w3d().write(self)
    433437        else:
    434             return ewkb_w.write(self)
     438            return ewkb_w().write(self)
    435439
    436440    @property
    437441    def kml(self):
     
    493497            g = gdal.OGRGeometry(self.wkb, srid)
    494498            g.transform(ct)
    495499            # Getting a new GEOS pointer
    496             ptr = wkb_r.read(g.wkb)
     500            ptr = wkb_r().read(g.wkb)
    497501            if clone:
    498502                # User wants a cloned transformed geometry returned.
    499503                return GEOSGeometry(ptr, srid=g.srid)
     
    655659                7 : GeometryCollection,
    656660                }
    657661
    658 # Similarly, import the GEOS I/O instances here to avoid conflicts.
    659 from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
    660 
    661662# If supported, import the PreparedGeometry class.
    662663if GEOS_PREPARE:
    663664    from django.contrib.gis.geos.prepared import PreparedGeometry
  • django/contrib/gis/geos/prototypes/misc.py

     
    33 ones that return the area, distance, and length.
    44"""
    55from ctypes import c_int, c_double, POINTER
    6 from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR
     6from django.contrib.gis.geos.libgeos import GEOM_PTR
    77from django.contrib.gis.geos.prototypes.errcheck import check_dbl
     8from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    89
    910### ctypes generator function ###
    1011def dbl_from_geom(func, num_geom=1):
     
    2223### ctypes prototypes ###
    2324
    2425# Area, distance, and length prototypes.
    25 geos_area = dbl_from_geom(lgeos.GEOSArea)
    26 geos_distance = dbl_from_geom(lgeos.GEOSDistance, num_geom=2)
    27 geos_length = dbl_from_geom(lgeos.GEOSLength)
     26geos_area = dbl_from_geom(GEOSFunc('GEOSArea'))
     27geos_distance = dbl_from_geom(GEOSFunc('GEOSDistance'), num_geom=2)
     28geos_length = dbl_from_geom(GEOSFunc('GEOSLength'))
  • django/contrib/gis/geos/prototypes/topology.py

     
    88           'geos_simplify', 'geos_symdifference', 'geos_union', 'geos_relate']
    99
    1010from ctypes import c_char_p, c_double, c_int
    11 from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, GEOS_PREPARE
     11from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE
    1212from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string
    1313from django.contrib.gis.geos.prototypes.geom import geos_char_p
     14from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    1415
    1516def topology(func, *args):
    1617    "For GEOS unary topology functions."
     
    2223    return func
    2324
    2425### Topology Routines ###
    25 geos_boundary = topology(lgeos.GEOSBoundary)
    26 geos_buffer = topology(lgeos.GEOSBuffer, c_double, c_int)
    27 geos_centroid = topology(lgeos.GEOSGetCentroid)
    28 geos_convexhull = topology(lgeos.GEOSConvexHull)
    29 geos_difference = topology(lgeos.GEOSDifference, GEOM_PTR)
    30 geos_envelope = topology(lgeos.GEOSEnvelope)
    31 geos_intersection = topology(lgeos.GEOSIntersection, GEOM_PTR)
    32 geos_linemerge = topology(lgeos.GEOSLineMerge)
    33 geos_pointonsurface = topology(lgeos.GEOSPointOnSurface)
    34 geos_preservesimplify = topology(lgeos.GEOSTopologyPreserveSimplify, c_double)
    35 geos_simplify = topology(lgeos.GEOSSimplify, c_double)
    36 geos_symdifference = topology(lgeos.GEOSSymDifference, GEOM_PTR)
    37 geos_union = topology(lgeos.GEOSUnion, GEOM_PTR)
     26geos_boundary = topology(GEOSFunc('GEOSBoundary'))
     27geos_buffer = topology(GEOSFunc('GEOSBuffer'), c_double, c_int)
     28geos_centroid = topology(GEOSFunc('GEOSGetCentroid'))
     29geos_convexhull = topology(GEOSFunc('GEOSConvexHull'))
     30geos_difference = topology(GEOSFunc('GEOSDifference'), GEOM_PTR)
     31geos_envelope = topology(GEOSFunc('GEOSEnvelope'))
     32geos_intersection = topology(GEOSFunc('GEOSIntersection'), GEOM_PTR)
     33geos_linemerge = topology(GEOSFunc('GEOSLineMerge'))
     34geos_pointonsurface = topology(GEOSFunc('GEOSPointOnSurface'))
     35geos_preservesimplify = topology(GEOSFunc('GEOSTopologyPreserveSimplify'), c_double)
     36geos_simplify = topology(GEOSFunc('GEOSSimplify'), c_double)
     37geos_symdifference = topology(GEOSFunc('GEOSSymDifference'), GEOM_PTR)
     38geos_union = topology(GEOSFunc('GEOSUnion'), GEOM_PTR)
    3839
    3940# GEOSRelate returns a string, not a geometry.
    40 geos_relate = lgeos.GEOSRelate
     41geos_relate = GEOSFunc('GEOSRelate')
    4142geos_relate.argtypes = [GEOM_PTR, GEOM_PTR]
    4243geos_relate.restype = geos_char_p
    4344geos_relate.errcheck = check_string
    4445
    4546# Routines only in GEOS 3.1+
    4647if GEOS_PREPARE:
    47     geos_cascaded_union = lgeos.GEOSUnionCascaded
     48    geos_cascaded_union = GEOSFunc('GEOSUnionCascaded')
    4849    geos_cascaded_union.argtypes = [GEOM_PTR]
    4950    geos_cascaded_union.restype = GEOM_PTR
    5051    __all__.append('geos_cascaded_union')
  • django/contrib/gis/geos/prototypes/coordseq.py

     
    11from ctypes import c_double, c_int, c_uint, POINTER
    2 from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, CS_PTR
     2from django.contrib.gis.geos.libgeos import GEOM_PTR, CS_PTR
    33from django.contrib.gis.geos.prototypes.errcheck import last_arg_byref, GEOSException
     4from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    45
    56## Error-checking routines specific to coordinate sequences. ##
    67def check_cs_ptr(result, func, cargs):
     
    5960## Coordinate Sequence ctypes prototypes ##
    6061
    6162# Coordinate Sequence constructors & cloning.
    62 cs_clone = cs_output(lgeos.GEOSCoordSeq_clone, [CS_PTR])
    63 create_cs = cs_output(lgeos.GEOSCoordSeq_create, [c_uint, c_uint])
    64 get_cs = cs_output(lgeos.GEOSGeom_getCoordSeq, [GEOM_PTR])
     63cs_clone = cs_output(GEOSFunc('GEOSCoordSeq_clone'), [CS_PTR])
     64create_cs = cs_output(GEOSFunc('GEOSCoordSeq_create'), [c_uint, c_uint])
     65get_cs = cs_output(GEOSFunc('GEOSGeom_getCoordSeq'), [GEOM_PTR])
    6566
    6667# Getting, setting ordinate
    67 cs_getordinate = cs_operation(lgeos.GEOSCoordSeq_getOrdinate, ordinate=True, get=True)
    68 cs_setordinate = cs_operation(lgeos.GEOSCoordSeq_setOrdinate, ordinate=True)
     68cs_getordinate = cs_operation(GEOSFunc('GEOSCoordSeq_getOrdinate'), ordinate=True, get=True)
     69cs_setordinate = cs_operation(GEOSFunc('GEOSCoordSeq_setOrdinate'), ordinate=True)
    6970
    7071# For getting, x, y, z
    71 cs_getx = cs_operation(lgeos.GEOSCoordSeq_getX, get=True)
    72 cs_gety = cs_operation(lgeos.GEOSCoordSeq_getY, get=True)
    73 cs_getz = cs_operation(lgeos.GEOSCoordSeq_getZ, get=True)
     72cs_getx = cs_operation(GEOSFunc('GEOSCoordSeq_getX'), get=True)
     73cs_gety = cs_operation(GEOSFunc('GEOSCoordSeq_getY'), get=True)
     74cs_getz = cs_operation(GEOSFunc('GEOSCoordSeq_getZ'), get=True)
    7475
    7576# For setting, x, y, z
    76 cs_setx = cs_operation(lgeos.GEOSCoordSeq_setX)
    77 cs_sety = cs_operation(lgeos.GEOSCoordSeq_setY)
    78 cs_setz = cs_operation(lgeos.GEOSCoordSeq_setZ)
     77cs_setx = cs_operation(GEOSFunc('GEOSCoordSeq_setX'))
     78cs_sety = cs_operation(GEOSFunc('GEOSCoordSeq_setY'))
     79cs_setz = cs_operation(GEOSFunc('GEOSCoordSeq_setZ'))
    7980
    8081# These routines return size & dimensions.
    81 cs_getsize = cs_int(lgeos.GEOSCoordSeq_getSize)
    82 cs_getdims = cs_int(lgeos.GEOSCoordSeq_getDimensions)
     82cs_getsize = cs_int(GEOSFunc('GEOSCoordSeq_getSize'))
     83cs_getdims = cs_int(GEOSFunc('GEOSCoordSeq_getDimensions'))
  • django/contrib/gis/geos/prototypes/prepared.py

     
    11from ctypes import c_char
    2 from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, PREPGEOM_PTR
     2from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR
    33from django.contrib.gis.geos.prototypes.errcheck import check_predicate
     4from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    45
    56# Prepared geometry constructor and destructors.
    6 geos_prepare = lgeos.GEOSPrepare
     7geos_prepare = GEOSFunc('GEOSPrepare')
    78geos_prepare.argtypes = [GEOM_PTR]
    89geos_prepare.restype = PREPGEOM_PTR
    910
    10 prepared_destroy = lgeos.GEOSPreparedGeom_destroy
     11prepared_destroy = GEOSFunc('GEOSPreparedGeom_destroy')
    1112prepared_destroy.argtpes = [PREPGEOM_PTR]
    1213prepared_destroy.restype = None
    1314
     
    1819    func.errcheck = check_predicate
    1920    return func
    2021
    21 prepared_contains = prepared_predicate(lgeos.GEOSPreparedContains)
    22 prepared_contains_properly = prepared_predicate(lgeos.GEOSPreparedContainsProperly)
    23 prepared_covers = prepared_predicate(lgeos.GEOSPreparedCovers)
    24 prepared_intersects = prepared_predicate(lgeos.GEOSPreparedIntersects)
     22prepared_contains = prepared_predicate(GEOSFunc('GEOSPreparedContains'))
     23prepared_contains_properly = prepared_predicate(GEOSFunc('GEOSPreparedContainsProperly'))
     24prepared_covers = prepared_predicate(GEOSFunc('GEOSPreparedCovers'))
     25prepared_intersects = prepared_predicate(GEOSFunc('GEOSPreparedIntersects'))
  • django/contrib/gis/geos/prototypes/predicates.py

     
    33 unary and binary predicate operations on geometries.
    44"""
    55from ctypes import c_char, c_char_p, c_double
    6 from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR
     6from django.contrib.gis.geos.libgeos import GEOM_PTR
    77from django.contrib.gis.geos.prototypes.errcheck import check_predicate
     8from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    89
    910## Binary & unary predicate functions ##
    1011def binary_predicate(func, *args):
     
    2425    return func
    2526
    2627## Unary Predicates ##
    27 geos_hasz = unary_predicate(lgeos.GEOSHasZ)
    28 geos_isempty = unary_predicate(lgeos.GEOSisEmpty)
    29 geos_isring = unary_predicate(lgeos.GEOSisRing)
    30 geos_issimple = unary_predicate(lgeos.GEOSisSimple)
    31 geos_isvalid = unary_predicate(lgeos.GEOSisValid)
     28geos_hasz = unary_predicate(GEOSFunc('GEOSHasZ'))
     29geos_isempty = unary_predicate(GEOSFunc('GEOSisEmpty'))
     30geos_isring = unary_predicate(GEOSFunc('GEOSisRing'))
     31geos_issimple = unary_predicate(GEOSFunc('GEOSisSimple'))
     32geos_isvalid = unary_predicate(GEOSFunc('GEOSisValid'))
    3233
    3334## Binary Predicates ##
    34 geos_contains = binary_predicate(lgeos.GEOSContains)
    35 geos_crosses = binary_predicate(lgeos.GEOSCrosses)
    36 geos_disjoint = binary_predicate(lgeos.GEOSDisjoint)
    37 geos_equals = binary_predicate(lgeos.GEOSEquals)
    38 geos_equalsexact = binary_predicate(lgeos.GEOSEqualsExact, c_double)
    39 geos_intersects = binary_predicate(lgeos.GEOSIntersects)
    40 geos_overlaps = binary_predicate(lgeos.GEOSOverlaps)
    41 geos_relatepattern = binary_predicate(lgeos.GEOSRelatePattern, c_char_p)
    42 geos_touches = binary_predicate(lgeos.GEOSTouches)
    43 geos_within = binary_predicate(lgeos.GEOSWithin)
     35geos_contains = binary_predicate(GEOSFunc('GEOSContains'))
     36geos_crosses = binary_predicate(GEOSFunc('GEOSCrosses'))
     37geos_disjoint = binary_predicate(GEOSFunc('GEOSDisjoint'))
     38geos_equals = binary_predicate(GEOSFunc('GEOSEquals'))
     39geos_equalsexact = binary_predicate(GEOSFunc('GEOSEqualsExact'), c_double)
     40geos_intersects = binary_predicate(GEOSFunc('GEOSIntersects'))
     41geos_overlaps = binary_predicate(GEOSFunc('GEOSOverlaps'))
     42geos_relatepattern = binary_predicate(GEOSFunc('GEOSRelatePattern'), c_char_p)
     43geos_touches = binary_predicate(GEOSFunc('GEOSTouches'))
     44geos_within = binary_predicate(GEOSFunc('GEOSWithin'))
  • django/contrib/gis/geos/prototypes/errcheck.py

     
    33"""
    44import os
    55from ctypes import c_void_p, string_at, CDLL
     6from ctypes.util import find_library
    67from django.contrib.gis.geos.error import GEOSException
    78from django.contrib.gis.geos.libgeos import lgeos, GEOS_VERSION
     9from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    810
    911# Getting the `free` routine used to free the memory allocated for
    1012# string pointers returned by GEOS.
    1113if GEOS_VERSION >= (3, 1, 1):
    1214    # In versions 3.1.1 and above, `GEOSFree` was added to the C API
    1315    # because `free` isn't always available on all platforms.
    14     free = lgeos.GEOSFree
     16    free = GEOSFunc('GEOSFree')
    1517    free.argtypes = [c_void_p]
    1618    free.restype = None
    1719else:
  • django/contrib/gis/geos/prototypes/threadsafe.py

     
     1import threading
     2from django.contrib.gis.geos.libgeos import lgeos, notice_h, error_h, CONTEXT_PTR
     3
     4class GEOSContextHandle(object):
     5    """
     6    Python object representing a GEOS context handle.
     7    """
     8    def __init__(self):
     9        self.ptr = lgeos.initGEOS_r(notice_h, error_h)
     10
     11    def __del__(self):
     12        lgeos.finishGEOS_r(self.ptr)
     13
     14# Defining a thread-local object and creating an instance
     15# to hold a reference to GEOSContextHandle for this thread.
     16class GEOSContext(threading.local):
     17    handle = None
     18
     19thread_context = GEOSContext()
     20
     21def call_geos_threaded(cfunc, args):
     22    """
     23    This module-level routine calls the specified GEOS C thread-safe
     24    function with the context for this current thread.
     25    """
     26    if not thread_context.handle:
     27        thread_context.handle = GEOSContextHandle()
     28    return cfunc(thread_context.handle.ptr, *args)
     29
     30class GEOSFunc(object):
     31    """
     32    Class that serves as a wrapper for GEOS C Functions, and will
     33    use thread-safe function variants when available.
     34    """
     35    def __init__(self, func_name):
     36        try:
     37            # GEOS thread-safe function signatures end with '_r'.
     38            self.cfunc = getattr(lgeos, func_name + '_r')
     39            self.threaded = True
     40        except AttributeError:
     41            # Otherwise, use usual function.
     42            self.cfunc = getattr(lgeos, func_name)
     43            self.threaded = False
     44
     45    def __call__(self, *args):
     46        if self.threaded:
     47            return call_geos_threaded(self.cfunc, args)
     48        else:
     49            return self.cfunc(*args)
     50
     51    def __str__(self):
     52        return self.cfunc.__name__
     53
     54    # argtypes property
     55    def _get_argtypes(self):
     56        return self.cfunc.argtypes
     57
     58    def _set_argtypes(self, argtypes):
     59        if self.threaded:
     60            new_argtypes = [CONTEXT_PTR]
     61            new_argtypes.extend(argtypes)
     62            self.cfunc.argtypes = new_argtypes
     63        else:
     64            self.cfunc.argtypes = argtypes
     65
     66    argtypes = property(_get_argtypes, _set_argtypes)
     67
     68    # restype property
     69    def _get_restype(self):
     70        return self.cfunc.restype
     71
     72    def _set_restype(self, restype):
     73        self.cfunc.restype = restype
     74
     75    restype = property(_get_restype, _set_restype)
     76
     77    # errcheck property
     78    def _get_errcheck(self):
     79        return self.cfunc.errcheck
     80
     81    def _set_errcheck(self, errcheck):
     82        self.cfunc.errcheck = errcheck
     83
     84    errcheck = property(_get_errcheck, _set_errcheck)
  • django/contrib/gis/geos/prototypes/geom.py

     
    11from ctypes import c_char_p, c_int, c_size_t, c_ubyte, c_uint, POINTER
    2 from django.contrib.gis.geos.libgeos import lgeos, CS_PTR, GEOM_PTR, PREPGEOM_PTR, GEOS_PREPARE
     2from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, PREPGEOM_PTR, GEOS_PREPARE
    33from django.contrib.gis.geos.prototypes.errcheck import \
    44    check_geom, check_minus_one, check_sized_string, check_string, check_zero
     5from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    56
    67# This is the return type used by binary output (WKB, HEX) routines.
    78c_uchar_p = POINTER(c_ubyte)
     
    6263
    6364### ctypes prototypes ###
    6465
    65 # Deprecated creation and output routines from WKB, HEX, WKT
    66 from_hex = bin_constructor(lgeos.GEOSGeomFromHEX_buf)
    67 from_wkb = bin_constructor(lgeos.GEOSGeomFromWKB_buf)
    68 from_wkt = geom_output(lgeos.GEOSGeomFromWKT, [c_char_p])
     66# Deprecated creation routines from WKB, HEX, WKT
     67from_hex = bin_constructor(GEOSFunc('GEOSGeomFromHEX_buf'))
     68from_wkb = bin_constructor(GEOSFunc('GEOSGeomFromWKB_buf'))
     69from_wkt = geom_output(GEOSFunc('GEOSGeomFromWKT'), [c_char_p])
    6970
    70 to_hex = bin_output(lgeos.GEOSGeomToHEX_buf)
    71 to_wkb = bin_output(lgeos.GEOSGeomToWKB_buf)
    72 to_wkt = string_from_geom(lgeos.GEOSGeomToWKT)
     71# Deprecated output routines
     72to_hex = bin_output(GEOSFunc('GEOSGeomToHEX_buf'))
     73to_wkb = bin_output(GEOSFunc('GEOSGeomToWKB_buf'))
     74to_wkt = string_from_geom(GEOSFunc('GEOSGeomToWKT'))
    7375
    74 # The GEOS geometry type, typeid, num_coordinates and number of geometries
    75 geos_normalize = int_from_geom(lgeos.GEOSNormalize)
    76 geos_type = string_from_geom(lgeos.GEOSGeomType)
    77 geos_typeid = int_from_geom(lgeos.GEOSGeomTypeId)
    78 get_dims = int_from_geom(lgeos.GEOSGeom_getDimensions, zero=True)
    79 get_num_coords = int_from_geom(lgeos.GEOSGetNumCoordinates)
    80 get_num_geoms = int_from_geom(lgeos.GEOSGetNumGeometries)
     76# The GEOS geometry type, typeid, num_coordites and number of geometries
     77geos_normalize = int_from_geom(GEOSFunc('GEOSNormalize'))
     78geos_type = string_from_geom(GEOSFunc('GEOSGeomType'))
     79geos_typeid = int_from_geom(GEOSFunc('GEOSGeomTypeId'))
     80get_dims = int_from_geom(GEOSFunc('GEOSGeom_getDimensions'), zero=True)
     81get_num_coords = int_from_geom(GEOSFunc('GEOSGetNumCoordinates'))
     82get_num_geoms = int_from_geom(GEOSFunc('GEOSGetNumGeometries'))
    8183
    8284# Geometry creation factories
    83 create_point = geom_output(lgeos.GEOSGeom_createPoint, [CS_PTR])
    84 create_linestring = geom_output(lgeos.GEOSGeom_createLineString, [CS_PTR])
    85 create_linearring = geom_output(lgeos.GEOSGeom_createLinearRing, [CS_PTR])
     85create_point = geom_output(GEOSFunc('GEOSGeom_createPoint'), [CS_PTR])
     86create_linestring = geom_output(GEOSFunc('GEOSGeom_createLineString'), [CS_PTR])
     87create_linearring = geom_output(GEOSFunc('GEOSGeom_createLinearRing'), [CS_PTR])
    8688
    8789# Polygon and collection creation routines are special and will not
    8890# have their argument types defined.
    89 create_polygon = geom_output(lgeos.GEOSGeom_createPolygon, None)
    90 create_collection = geom_output(lgeos.GEOSGeom_createCollection, None)
     91create_polygon = geom_output(GEOSFunc('GEOSGeom_createPolygon'), None)
     92create_collection = geom_output(GEOSFunc('GEOSGeom_createCollection'), None)
    9193
    9294# Ring routines
    93 get_extring = geom_output(lgeos.GEOSGetExteriorRing, [GEOM_PTR])
    94 get_intring = geom_index(lgeos.GEOSGetInteriorRingN)
    95 get_nrings = int_from_geom(lgeos.GEOSGetNumInteriorRings)
     95get_extring = geom_output(GEOSFunc('GEOSGetExteriorRing'), [GEOM_PTR])
     96get_intring = geom_index(GEOSFunc('GEOSGetInteriorRingN'))
     97get_nrings = int_from_geom(GEOSFunc('GEOSGetNumInteriorRings'))
    9698
    9799# Collection Routines
    98 get_geomn = geom_index(lgeos.GEOSGetGeometryN)
     100get_geomn = geom_index(GEOSFunc('GEOSGetGeometryN'))
    99101
    100102# Cloning
    101 geom_clone = lgeos.GEOSGeom_clone
     103geom_clone = GEOSFunc('GEOSGeom_clone')
    102104geom_clone.argtypes = [GEOM_PTR]
    103105geom_clone.restype = GEOM_PTR
    104106
    105107# Destruction routine.
    106 destroy_geom = lgeos.GEOSGeom_destroy
     108destroy_geom = GEOSFunc('GEOSGeom_destroy')
    107109destroy_geom.argtypes = [GEOM_PTR]
    108110destroy_geom.restype = None
    109111
    110112# SRID routines
    111 geos_get_srid = lgeos.GEOSGetSRID
     113geos_get_srid = GEOSFunc('GEOSGetSRID')
    112114geos_get_srid.argtypes = [GEOM_PTR]
    113115geos_get_srid.restype = c_int
    114116
    115 geos_set_srid = lgeos.GEOSSetSRID
     117geos_set_srid = GEOSFunc('GEOSSetSRID')
    116118geos_set_srid.argtypes = [GEOM_PTR, c_int]
    117119geos_set_srid.restype = None
  • django/contrib/gis/geos/prototypes/io.py

     
    1 from ctypes import c_char_p, c_int, c_char, c_size_t, Structure, POINTER
    2 from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR
     1import threading
     2from ctypes import byref, c_char_p, c_int, c_char, c_size_t, Structure, POINTER
     3from django.contrib.gis.geos.base import GEOSBase
     4from django.contrib.gis.geos.libgeos import GEOM_PTR
    35from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string, check_sized_string
    46from django.contrib.gis.geos.prototypes.geom import c_uchar_p, geos_char_p
     7from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
    58
    69### The WKB/WKT Reader/Writer structures and pointers ###
    710class WKTReader_st(Structure): pass
     
    1518WKB_WRITE_PTR = POINTER(WKBReader_st)
    1619
    1720### WKTReader routines ###
    18 wkt_reader_create = lgeos.GEOSWKTReader_create
     21wkt_reader_create = GEOSFunc('GEOSWKTReader_create')
    1922wkt_reader_create.restype = WKT_READ_PTR
    2023
    21 wkt_reader_destroy = lgeos.GEOSWKTReader_destroy
     24wkt_reader_destroy = GEOSFunc('GEOSWKTReader_destroy')
    2225wkt_reader_destroy.argtypes = [WKT_READ_PTR]
    2326
    24 wkt_reader_read = lgeos.GEOSWKTReader_read
     27wkt_reader_read = GEOSFunc('GEOSWKTReader_read')
    2528wkt_reader_read.argtypes = [WKT_READ_PTR, c_char_p]
    2629wkt_reader_read.restype = GEOM_PTR
    2730wkt_reader_read.errcheck = check_geom
    2831
    2932### WKTWriter routines ###
    30 wkt_writer_create = lgeos.GEOSWKTWriter_create
     33wkt_writer_create = GEOSFunc('GEOSWKTWriter_create')
    3134wkt_writer_create.restype = WKT_WRITE_PTR
    3235
    33 wkt_writer_destroy = lgeos.GEOSWKTWriter_destroy
     36wkt_writer_destroy = GEOSFunc('GEOSWKTWriter_destroy')
    3437wkt_writer_destroy.argtypes = [WKT_WRITE_PTR]
    3538
    36 wkt_writer_write = lgeos.GEOSWKTWriter_write
     39wkt_writer_write = GEOSFunc('GEOSWKTWriter_write')
    3740wkt_writer_write.argtypes = [WKT_WRITE_PTR, GEOM_PTR]
    3841wkt_writer_write.restype = geos_char_p
    3942wkt_writer_write.errcheck = check_string
    4043
    4144### WKBReader routines ###
    42 wkb_reader_create = lgeos.GEOSWKBReader_create
     45wkb_reader_create = GEOSFunc('GEOSWKBReader_create')
    4346wkb_reader_create.restype = WKB_READ_PTR
    4447
    45 wkb_reader_destroy = lgeos.GEOSWKBReader_destroy
     48wkb_reader_destroy = GEOSFunc('GEOSWKBReader_destroy')
    4649wkb_reader_destroy.argtypes = [WKB_READ_PTR]
    4750
    4851def wkb_read_func(func):
     
    5659    func.errcheck = check_geom
    5760    return func
    5861
    59 wkb_reader_read = wkb_read_func(lgeos.GEOSWKBReader_read)
    60 wkb_reader_read_hex = wkb_read_func(lgeos.GEOSWKBReader_readHEX)
     62wkb_reader_read = wkb_read_func(GEOSFunc('GEOSWKBReader_read'))
     63wkb_reader_read_hex = wkb_read_func(GEOSFunc('GEOSWKBReader_readHEX'))
    6164
    6265### WKBWriter routines ###
    63 wkb_writer_create = lgeos.GEOSWKBWriter_create
     66wkb_writer_create = GEOSFunc('GEOSWKBWriter_create')
    6467wkb_writer_create.restype = WKB_WRITE_PTR
    6568
    66 wkb_writer_destroy = lgeos.GEOSWKBWriter_destroy
     69wkb_writer_destroy = GEOSFunc('GEOSWKBWriter_destroy')
    6770wkb_writer_destroy.argtypes = [WKB_WRITE_PTR]
    6871
    6972# WKB Writing prototypes.
     
    7376    func.errcheck = check_sized_string
    7477    return func
    7578
    76 wkb_writer_write = wkb_write_func(lgeos.GEOSWKBWriter_write)
    77 wkb_writer_write_hex = wkb_write_func(lgeos.GEOSWKBWriter_writeHEX)
     79wkb_writer_write = wkb_write_func(GEOSFunc('GEOSWKBWriter_write'))
     80wkb_writer_write_hex = wkb_write_func(GEOSFunc('GEOSWKBWriter_writeHEX'))
    7881
    7982# WKBWriter property getter/setter prototypes.
    8083def wkb_writer_get(func, restype=c_int):
     
    8689    func.argtypes = [WKB_WRITE_PTR, argtype]
    8790    return func
    8891
    89 wkb_writer_get_byteorder = wkb_writer_get(lgeos.GEOSWKBWriter_getByteOrder)
    90 wkb_writer_set_byteorder = wkb_writer_set(lgeos.GEOSWKBWriter_setByteOrder)
    91 wkb_writer_get_outdim    = wkb_writer_get(lgeos.GEOSWKBWriter_getOutputDimension)
    92 wkb_writer_set_outdim    = wkb_writer_set(lgeos.GEOSWKBWriter_setOutputDimension)
    93 wkb_writer_get_include_srid = wkb_writer_get(lgeos.GEOSWKBWriter_getIncludeSRID, restype=c_char)
    94 wkb_writer_set_include_srid = wkb_writer_set(lgeos.GEOSWKBWriter_setIncludeSRID, argtype=c_char)
     92wkb_writer_get_byteorder = wkb_writer_get(GEOSFunc('GEOSWKBWriter_getByteOrder'))
     93wkb_writer_set_byteorder = wkb_writer_set(GEOSFunc('GEOSWKBWriter_setByteOrder'))
     94wkb_writer_get_outdim    = wkb_writer_get(GEOSFunc('GEOSWKBWriter_getOutputDimension'))
     95wkb_writer_set_outdim    = wkb_writer_set(GEOSFunc('GEOSWKBWriter_setOutputDimension'))
     96wkb_writer_get_include_srid = wkb_writer_get(GEOSFunc('GEOSWKBWriter_getIncludeSRID'), restype=c_char)
     97wkb_writer_set_include_srid = wkb_writer_set(GEOSFunc('GEOSWKBWriter_setIncludeSRID'), argtype=c_char)
     98
     99### Base I/O Class ###
     100class IOBase(GEOSBase):
     101    "Base class for GEOS I/O objects."
     102    def __init__(self):
     103        # Getting the pointer with the constructor.
     104        self.ptr = self._constructor()
     105
     106    def __del__(self):
     107        # Cleaning up with the appropriate destructor.
     108        if self._ptr: self._destructor(self._ptr)
     109
     110### WKB/WKT Reading and Writing objects ###
     111
     112# Non-public WKB/WKT reader classes for internal use because
     113# their `read` methods return _pointers_ instead of GEOSGeometry
     114# objects.
     115class _WKTReader(IOBase):
     116    _constructor = wkt_reader_create
     117    _destructor = wkt_reader_destroy
     118    ptr_type = WKT_READ_PTR
     119
     120    def read(self, wkt):
     121        if not isinstance(wkt, basestring): raise TypeError
     122        return wkt_reader_read(self.ptr, wkt)
     123
     124class _WKBReader(IOBase):
     125    _constructor = wkb_reader_create
     126    _destructor = wkb_reader_destroy
     127    ptr_type = WKB_READ_PTR
     128
     129    def read(self, wkb):
     130        "Returns a _pointer_ to C GEOS Geometry object from the given WKB."
     131        if isinstance(wkb, buffer):
     132            wkb_s = str(wkb)
     133            return wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
     134        elif isinstance(wkb, basestring):
     135            return wkb_reader_read_hex(self.ptr, wkb, len(wkb))
     136        else:
     137            raise TypeError
     138
     139### WKB/WKT Writer Classes ###
     140class WKTWriter(IOBase):
     141    _constructor = wkt_writer_create
     142    _destructor = wkt_writer_destroy
     143    ptr_type = WKT_WRITE_PTR
     144
     145    def write(self, geom):
     146        "Returns the WKT representation of the given geometry."
     147        return wkt_writer_write(self.ptr, geom.ptr)
     148
     149class WKBWriter(IOBase):
     150    _constructor = wkb_writer_create
     151    _destructor = wkb_writer_destroy
     152    ptr_type = WKB_WRITE_PTR
     153
     154    def write(self, geom):
     155        "Returns the WKB representation of the given geometry."
     156        return buffer(wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
     157
     158    def write_hex(self, geom):
     159        "Returns the HEXEWKB representation of the given geometry."
     160        return wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
     161
     162    ### WKBWriter Properties ###
     163
     164    # Property for getting/setting the byteorder.
     165    def _get_byteorder(self):
     166        return wkb_writer_get_byteorder(self.ptr)
     167
     168    def _set_byteorder(self, order):
     169        if not order in (0, 1): raise ValueError('Byte order parameter must be 0 (Big Endian) or 1 (Little Endian).')
     170        wkb_writer_set_byteorder(self.ptr, order)
     171
     172    byteorder = property(_get_byteorder, _set_byteorder)
     173
     174    # Property for getting/setting the output dimension.
     175    def _get_outdim(self):
     176        return wkb_writer_get_outdim(self.ptr)
     177
     178    def _set_outdim(self, new_dim):
     179        if not new_dim in (2, 3): raise ValueError('WKB output dimension must be 2 or 3')
     180        wkb_writer_set_outdim(self.ptr, new_dim)
     181
     182    outdim = property(_get_outdim, _set_outdim)
     183
     184    # Property for getting/setting the include srid flag.
     185    def _get_include_srid(self):
     186        return bool(ord(wkb_writer_get_include_srid(self.ptr)))
     187
     188    def _set_include_srid(self, include):
     189        if bool(include): flag = chr(1)
     190        else: flag = chr(0)
     191        wkb_writer_set_include_srid(self.ptr, flag)
     192
     193    srid = property(_get_include_srid, _set_include_srid)
     194
     195# Thread-local instances of the WKT and WKB reader/writer objects,
     196# accessed by calling module-level function, defined below.
     197class ThreadLocalIO(threading.local):
     198    wkt_r = None
     199    wkt_w = None
     200    wkb_r = None
     201    wkb_w = None
     202    ewkb_w = None
     203    ewkb_w3d = None
     204
     205thread_context = ThreadLocalIO()
     206
     207def wkt_r():
     208    if not thread_context.wkt_r:
     209        thread_context.wkt_r = _WKTReader()
     210    return thread_context.wkt_r
     211
     212def wkt_w():
     213    if not thread_context.wkt_w:
     214        thread_context.wkt_w = WKTWriter()
     215    return thread_context.wkt_w
     216
     217def wkb_r():
     218    if not thread_context.wkb_r:
     219        thread_context.wkb_r = _WKBReader()
     220    return thread_context.wkb_r
     221
     222def wkb_w():
     223   if not thread_context.wkb_w:
     224       thread_context.wkb_w = WKBWriter()
     225   return thread_context.wkb_w
     226
     227def ewkb_w():
     228    if not thread_context.ewkb_w:
     229        thread_context.ewkb_w = WKBWriter()
     230        thread_context.ewkb_w.srid = True
     231    return thread_context.ewkb_w
     232
     233def ewkb_w3d():
     234    if not thread_context.ewkb_w3d:
     235        thread_context.ewkb_w3d = WKBWriter()
     236        thread_context.ewkb_w3d.srid = True
     237        thread_context.ewkb_w3d.outdim = 3
     238    return thread_context.ewkb_w3d
  • django/contrib/gis/geos/io.py

     
    33objects.  Specifically, this has Python implementations of WKB/WKT
    44reader and writer classes.
    55"""
    6 from ctypes import byref, c_size_t
    7 from django.contrib.gis.geos.base import GEOSBase
    8 from django.contrib.gis.geos.error import GEOSException
    96from django.contrib.gis.geos.geometry import GEOSGeometry
    10 from django.contrib.gis.geos.libgeos import GEOM_PTR
    11 from django.contrib.gis.geos.prototypes import io as capi
     7from django.contrib.gis.geos.prototypes.io import _WKTReader, _WKBReader, WKBWriter, WKTWriter
    128
    13 class IOBase(GEOSBase):
    14     "Base class for GEOS I/O objects."
    15     def __init__(self):
    16         # Getting the pointer with the constructor.
    17         self.ptr = self._constructor()
     9# Public classes for (WKB|WKT)Reader, which return GEOSGeometry
     10class WKBReader(_WKBReader):
     11    def read(self, wkb):
     12        "Returns a GEOSGeometry for the given WKB buffer."
     13        return GEOSGeometry(super(WKBReader, self).read(wkb))
    1814
    19     def __del__(self):
    20         # Cleaning up with the appropriate destructor.
    21         if self._ptr: self._destructor(self._ptr)
    22 
    23 ### WKT Reading and Writing objects ###
    24 
    25 # Non-public class for internal use because its `read` method returns
    26 # _pointers_ instead of a GEOSGeometry object.
    27 class _WKTReader(IOBase):
    28     _constructor = capi.wkt_reader_create
    29     _destructor = capi.wkt_reader_destroy
    30     ptr_type = capi.WKT_READ_PTR
    31 
    32     def read(self, wkt):
    33         if not isinstance(wkt, basestring): raise TypeError
    34         return capi.wkt_reader_read(self.ptr, wkt)
    35 
    3615class WKTReader(_WKTReader):
    3716    def read(self, wkt):
    3817        "Returns a GEOSGeometry for the given WKT string."
    3918        return GEOSGeometry(super(WKTReader, self).read(wkt))
    4019
    41 class WKTWriter(IOBase):
    42     _constructor = capi.wkt_writer_create
    43     _destructor = capi.wkt_writer_destroy
    44     ptr_type = capi.WKT_WRITE_PTR
    4520
    46     def write(self, geom):
    47         "Returns the WKT representation of the given geometry."
    48         return capi.wkt_writer_write(self.ptr, geom.ptr)
    49 
    50 ### WKB Reading and Writing objects ###
    51 
    52 # Non-public class for the same reason as _WKTReader above.
    53 class _WKBReader(IOBase):
    54     _constructor = capi.wkb_reader_create
    55     _destructor = capi.wkb_reader_destroy
    56     ptr_type = capi.WKB_READ_PTR
    57 
    58     def read(self, wkb):
    59         "Returns a _pointer_ to C GEOS Geometry object from the given WKB."
    60         if isinstance(wkb, buffer):
    61             wkb_s = str(wkb)
    62             return capi.wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
    63         elif isinstance(wkb, basestring):
    64             return capi.wkb_reader_read_hex(self.ptr, wkb, len(wkb))
    65         else:
    66             raise TypeError
    67 
    68 class WKBReader(_WKBReader):
    69     def read(self, wkb):
    70         "Returns a GEOSGeometry for the given WKB buffer."
    71         return GEOSGeometry(super(WKBReader, self).read(wkb))
    72 
    73 class WKBWriter(IOBase):
    74     _constructor = capi.wkb_writer_create
    75     _destructor = capi.wkb_writer_destroy
    76     ptr_type = capi.WKB_WRITE_PTR
    77 
    78     def write(self, geom):
    79         "Returns the WKB representation of the given geometry."
    80         return buffer(capi.wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
    81 
    82     def write_hex(self, geom):
    83         "Returns the HEXEWKB representation of the given geometry."
    84         return capi.wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
    85 
    86     ### WKBWriter Properties ###
    87 
    88     # Property for getting/setting the byteorder.
    89     def _get_byteorder(self):
    90         return capi.wkb_writer_get_byteorder(self.ptr)
    91 
    92     def _set_byteorder(self, order):
    93         if not order in (0, 1): raise ValueError('Byte order parameter must be 0 (Big Endian) or 1 (Little Endian).')
    94         capi.wkb_writer_set_byteorder(self.ptr, order)
    95 
    96     byteorder = property(_get_byteorder, _set_byteorder)
    97 
    98     # Property for getting/setting the output dimension.
    99     def _get_outdim(self):
    100         return capi.wkb_writer_get_outdim(self.ptr)
    101 
    102     def _set_outdim(self, new_dim):
    103         if not new_dim in (2, 3): raise ValueError('WKB output dimension must be 2 or 3')
    104         capi.wkb_writer_set_outdim(self.ptr, new_dim)
    105 
    106     outdim = property(_get_outdim, _set_outdim)
    107 
    108     # Property for getting/setting the include srid flag.
    109     def _get_include_srid(self):
    110         return bool(ord(capi.wkb_writer_get_include_srid(self.ptr)))
    111 
    112     def _set_include_srid(self, include):
    113         if bool(include): flag = chr(1)
    114         else: flag = chr(0)
    115         capi.wkb_writer_set_include_srid(self.ptr, flag)
    116 
    117     srid = property(_get_include_srid, _set_include_srid)
    118 
    119 # Instances of the WKT and WKB reader/writer objects.
    120 wkt_r = _WKTReader()
    121 wkt_w = WKTWriter()
    122 wkb_r = _WKBReader()
    123 wkb_w = WKBWriter()
    124 
    125 # These instances are for writing EWKB in 2D and 3D.
    126 ewkb_w = WKBWriter()
    127 ewkb_w.srid = True
    128 ewkb_w3d = WKBWriter()
    129 ewkb_w3d.srid = True
    130 ewkb_w3d.outdim = 3
  • django/contrib/gis/geos/libgeos.py

     
    4545                        '", "'.join(lib_names))
    4646
    4747# Getting the GEOS C library.  The C interface (CDLL) is used for
    48 #  both *NIX and Windows.
     48# both *NIX and Windows.
    4949# See the GEOS C API source code for more details on the library function calls:
    5050#  http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
    5151lgeos = CDLL(lib_path)
    5252
    5353# The notice and error handler C function callback definitions.
    54 #  Supposed to mimic the GEOS message handler (C below):
    55 "typedef void (*GEOSMessageHandler)(const char *fmt, ...);"
     54# Supposed to mimic the GEOS message handler (C below):
     55typedef void (*GEOSMessageHandler)(const char *fmt, ...);
    5656NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
    5757def notice_h(fmt, lst, output_h=sys.stdout):
    5858    try:
     
    7171    output_h.write('GEOS_ERROR: %s\n' % err_msg)
    7272error_h = ERRORFUNC(error_h)
    7373
    74 # The initGEOS routine should be called first, however, that routine takes
    75 #  the notice and error functions as parameters.  Here is the C code that
    76 #  is wrapped:
    77 #  "extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);"
    78 lgeos.initGEOS(notice_h, error_h)
    79 
    8074#### GEOS Geometry C data structures, and utility functions. ####
    8175
    8276# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
    8377class GEOSGeom_t(Structure): pass
    8478class GEOSPrepGeom_t(Structure): pass
    8579class GEOSCoordSeq_t(Structure): pass
     80class GEOSContextHandle_t(Structure): pass
    8681
    8782# Pointers to opaque GEOS geometry structures.
    8883GEOM_PTR = POINTER(GEOSGeom_t)
    8984PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
    9085CS_PTR = POINTER(GEOSCoordSeq_t)
     86CONTEXT_PTR  = POINTER(GEOSContextHandle_t)
    9187
    9288# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection
    9389#  GEOS routines
     
    126122GEOS_VERSION = (GEOS_MAJOR_VERSION, GEOS_MINOR_VERSION, GEOS_SUBMINOR_VERSION)
    127123GEOS_PREPARE = GEOS_VERSION >= (3, 1, 0)
    128124
    129 # Calling the finishGEOS() upon exit of the interpreter.
    130 atexit.register(lgeos.finishGEOS)
     125if GEOS_PREPARE:
     126    # Here we set up the prototypes for the initGEOS_r and finishGEOS_r
     127    # routines.  These functions aren't actually called until they are
     128    # attached to a GEOS context handle -- this actually occurs in
     129    # geos/prototypes/threadsafe.py.
     130    lgeos.initGEOS_r.restype = CONTEXT_PTR
     131    lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]
     132else:
     133    # When thread-safety isn't available, the initGEOS routine must be called
     134    # first.  This function takes the notice and error functions, defined
     135    # as Python callbacks above, as parameters. Here is the C code that is
     136    # wrapped:
     137    #  extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);
     138    lgeos.initGEOS(notice_h, error_h)
     139    atexit.register(lgeos.finishGEOS)
Back to Top