this module houses the ctypes initialization procedures as well as the notice and error handler function callbacks get called when an error occurs in geos this module also houses geos pointer utilities including getpointerarr and geomptr custom library path set setting the appropriate names for the geosc library windows nt libraries nix libraries using the ctypes findlibrary utility to find the path to the geos shared library this is better than manually specifying each library name and extension e g libgeosc soso 1dylib no geos library could be found getting the geos c library the c interface cdll is used for both nix and windows see the geos c api source code for more details on the library function calls https libgeos orgdoxygengeosc8hsource html here we set up the prototypes for the initgeosr and finishgeosr routines these functions aren t actually called until they are attached to a geos context handle this actually occurs in geosprototypesthreadsafe py set restype for compatibility across 32 and 64bit platforms the notice and error handler c function callback definitions supposed to mimic the geos message handler c below typedef void geosmessagehandlerconst char fmt geos geometry c data structures and utility functions opaque geos geometry structures used for geomptr and csptr pointers to opaque geos geometry structures lazy loading of geos functions return the string version of the geos library return lgeos geosversion def geosversiontuple custom library path set setting the appropriate names for the geos c library windows nt libraries nix libraries using the ctypes find_library utility to find the path to the geos shared library this is better than manually specifying each library name and extension e g libgeos_c so so 1 dylib no geos library could be found getting the geos c library the c interface cdll is used for both nix and windows see the geos c api source code for more details on the library function calls https libgeos org doxygen geos__c_8h_source html here we set up the prototypes for the initgeos_r and finishgeos_r routines these functions aren t actually called until they are attached to a geos context handle this actually occurs in geos prototypes threadsafe py set restype for compatibility across 32 and 64 bit platforms the notice and error handler c function callback definitions supposed to mimic the geos message handler c below typedef void geosmessagehandler const char fmt geos geometry c data structures and utility functions opaque geos geometry structures used for geom_ptr and cs_ptr pointers to opaque geos geometry structures lazy loading of geos functions return the string version of the geos library return the geos version as a tuple major minor subminor
import logging
import os
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, cached_property
from django.utils.version import get_version_tuple

logger = logging.getLogger("django.contrib.gis")


def load_geos():
    
    try:
        from django.conf import settings

        lib_path = settings.GEOS_LIBRARY_PATH
    except (AttributeError, ImportError, ImproperlyConfigured, OSError):
        lib_path = None

    
    if lib_path:
        lib_names = None
    elif os.name == "nt":
        
        lib_names = ["geos_c", "libgeos_c-1"]
    elif os.name == "posix":
        
        lib_names = ["geos_c", "GEOS"]
    else:
        raise ImportError('Unsupported OS "%s"' % os.name)

    
    
    
    if lib_names:
        for lib_name in lib_names:
            lib_path = find_library(lib_name)
            if lib_path is not None:
                break

    
    if lib_path is None:
        raise ImportError(
            'Could not find the GEOS library (tried "%s"). '
            "Try setting GEOS_LIBRARY_PATH in your settings." % '", "'.join(lib_names)
        )
    
    
    
    
    _lgeos = CDLL(lib_path)
    
    
    
    
    _lgeos.initGEOS_r.restype = CONTEXT_PTR
    _lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]
    
    _lgeos.GEOSversion.restype = c_char_p
    return _lgeos





NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)


def notice_h(fmt, lst):
    fmt, lst = fmt.decode(), lst.decode()
    try:
        warn_msg = fmt % lst
    except TypeError:
        warn_msg = fmt
    logger.warning("GEOS_NOTICE: %s\n", warn_msg)


notice_h = NOTICEFUNC(notice_h)

ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)


def error_h(fmt, lst):
    fmt, lst = fmt.decode(), lst.decode()
    try:
        err_msg = fmt % lst
    except TypeError:
        err_msg = fmt
    logger.error("GEOS_ERROR: %s\n", err_msg)


error_h = ERRORFUNC(error_h)





class GEOSGeom_t(Structure):
    pass


class GEOSPrepGeom_t(Structure):
    pass


class GEOSCoordSeq_t(Structure):
    pass


class GEOSContextHandle_t(Structure):
    pass



GEOM_PTR = POINTER(GEOSGeom_t)
PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
CS_PTR = POINTER(GEOSCoordSeq_t)
CONTEXT_PTR = POINTER(GEOSContextHandle_t)


lgeos = SimpleLazyObject(load_geos)


class GEOSFuncFactory:
    

    argtypes = None
    restype = None
    errcheck = None

    def __init__(self, func_name, *, restype=None, errcheck=None, argtypes=None):
        self.func_name = func_name
        if restype is not None:
            self.restype = restype
        if errcheck is not None:
            self.errcheck = errcheck
        if argtypes is not None:
            self.argtypes = argtypes

    def __call__(self, *args):
        return self.func(*args)

    @cached_property
    def func(self):
        from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc

        func = GEOSFunc(self.func_name)
        func.argtypes = self.argtypes or []
        func.restype = self.restype
        if self.errcheck:
            func.errcheck = self.errcheck
        return func


def geos_version():
    
    return lgeos.GEOSversion()


def geos_version_tuple():
    
    return get_version_tuple(geos_version().decode())