libgdal.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import logging
  2. import os
  3. import re
  4. from ctypes import CDLL, CFUNCTYPE, c_char_p, c_int
  5. from ctypes.util import find_library
  6. from django.contrib.gis.gdal.error import GDALException
  7. from django.core.exceptions import ImproperlyConfigured
  8. logger = logging.getLogger('django.contrib.gis')
  9. # Custom library path set?
  10. try:
  11. from django.conf import settings
  12. lib_path = settings.GDAL_LIBRARY_PATH
  13. except (AttributeError, ImportError, ImproperlyConfigured, OSError):
  14. lib_path = None
  15. if lib_path:
  16. lib_names = None
  17. elif os.name == 'nt':
  18. # Windows NT shared libraries
  19. lib_names = ['gdal204', 'gdal203', 'gdal202', 'gdal201', 'gdal20']
  20. elif os.name == 'posix':
  21. # *NIX library names.
  22. lib_names = ['gdal', 'GDAL', 'gdal2.4.0', 'gdal2.3.0', 'gdal2.2.0', 'gdal2.1.0', 'gdal2.0.0']
  23. else:
  24. raise ImproperlyConfigured('GDAL is unsupported on OS "%s".' % os.name)
  25. # Using the ctypes `find_library` utility to find the
  26. # path to the GDAL library from the list of library names.
  27. if lib_names:
  28. for lib_name in lib_names:
  29. lib_path = find_library(lib_name)
  30. if lib_path is not None:
  31. break
  32. if lib_path is None:
  33. raise ImproperlyConfigured(
  34. 'Could not find the GDAL library (tried "%s"). Is GDAL installed? '
  35. 'If it is, try setting GDAL_LIBRARY_PATH in your settings.'
  36. % '", "'.join(lib_names)
  37. )
  38. # This loads the GDAL/OGR C library
  39. lgdal = CDLL(lib_path)
  40. # On Windows, the GDAL binaries have some OSR routines exported with
  41. # STDCALL, while others are not. Thus, the library will also need to
  42. # be loaded up as WinDLL for said OSR functions that require the
  43. # different calling convention.
  44. if os.name == 'nt':
  45. from ctypes import WinDLL
  46. lwingdal = WinDLL(lib_path)
  47. def std_call(func):
  48. """
  49. Return the correct STDCALL function for certain OSR routines on Win32
  50. platforms.
  51. """
  52. if os.name == 'nt':
  53. return lwingdal[func]
  54. else:
  55. return lgdal[func]
  56. # #### Version-information functions. ####
  57. # Return GDAL library version information with the given key.
  58. _version_info = std_call('GDALVersionInfo')
  59. _version_info.argtypes = [c_char_p]
  60. _version_info.restype = c_char_p
  61. def gdal_version():
  62. "Return only the GDAL version number information."
  63. return _version_info(b'RELEASE_NAME')
  64. def gdal_full_version():
  65. "Return the full GDAL version information."
  66. return _version_info('')
  67. version_regex = re.compile(r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<subminor>\d+))?')
  68. def gdal_version_info():
  69. ver = gdal_version().decode()
  70. m = version_regex.match(ver)
  71. if not m:
  72. raise GDALException('Could not parse GDAL version string "%s"' % ver)
  73. return {key: m.group(key) for key in ('major', 'minor', 'subminor')}
  74. _verinfo = gdal_version_info()
  75. GDAL_MAJOR_VERSION = int(_verinfo['major'])
  76. GDAL_MINOR_VERSION = int(_verinfo['minor'])
  77. GDAL_SUBMINOR_VERSION = _verinfo['subminor'] and int(_verinfo['subminor'])
  78. GDAL_VERSION = (GDAL_MAJOR_VERSION, GDAL_MINOR_VERSION, GDAL_SUBMINOR_VERSION)
  79. del _verinfo
  80. # Set library error handling so as errors are logged
  81. CPLErrorHandler = CFUNCTYPE(None, c_int, c_int, c_char_p)
  82. def err_handler(error_class, error_number, message):
  83. logger.error('GDAL_ERROR %d: %s', error_number, message)
  84. err_handler = CPLErrorHandler(err_handler)
  85. def function(name, args, restype):
  86. func = std_call(name)
  87. func.argtypes = args
  88. func.restype = restype
  89. return func
  90. set_error_handler = function('CPLSetErrorHandler', [CPLErrorHandler], CPLErrorHandler)
  91. set_error_handler(err_handler)