libgdal.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 = [
  20. "gdal307",
  21. "gdal306",
  22. "gdal305",
  23. "gdal304",
  24. "gdal303",
  25. "gdal302",
  26. "gdal301",
  27. "gdal300",
  28. "gdal204",
  29. ]
  30. elif os.name == "posix":
  31. # *NIX library names.
  32. lib_names = [
  33. "gdal",
  34. "GDAL",
  35. "gdal3.7.0",
  36. "gdal3.6.0",
  37. "gdal3.5.0",
  38. "gdal3.4.0",
  39. "gdal3.3.0",
  40. "gdal3.2.0",
  41. "gdal3.1.0",
  42. "gdal3.0.0",
  43. "gdal2.4.0",
  44. ]
  45. else:
  46. raise ImproperlyConfigured('GDAL is unsupported on OS "%s".' % os.name)
  47. # Using the ctypes `find_library` utility to find the
  48. # path to the GDAL library from the list of library names.
  49. if lib_names:
  50. for lib_name in lib_names:
  51. lib_path = find_library(lib_name)
  52. if lib_path is not None:
  53. break
  54. if lib_path is None:
  55. raise ImproperlyConfigured(
  56. 'Could not find the GDAL library (tried "%s"). Is GDAL installed? '
  57. "If it is, try setting GDAL_LIBRARY_PATH in your settings."
  58. % '", "'.join(lib_names)
  59. )
  60. # This loads the GDAL/OGR C library
  61. lgdal = CDLL(lib_path)
  62. # On Windows, the GDAL binaries have some OSR routines exported with
  63. # STDCALL, while others are not. Thus, the library will also need to
  64. # be loaded up as WinDLL for said OSR functions that require the
  65. # different calling convention.
  66. if os.name == "nt":
  67. from ctypes import WinDLL
  68. lwingdal = WinDLL(lib_path)
  69. def std_call(func):
  70. """
  71. Return the correct STDCALL function for certain OSR routines on Win32
  72. platforms.
  73. """
  74. if os.name == "nt":
  75. return lwingdal[func]
  76. else:
  77. return lgdal[func]
  78. # #### Version-information functions. ####
  79. # Return GDAL library version information with the given key.
  80. _version_info = std_call("GDALVersionInfo")
  81. _version_info.argtypes = [c_char_p]
  82. _version_info.restype = c_char_p
  83. def gdal_version():
  84. "Return only the GDAL version number information."
  85. return _version_info(b"RELEASE_NAME")
  86. def gdal_full_version():
  87. "Return the full GDAL version information."
  88. return _version_info(b"")
  89. def gdal_version_info():
  90. ver = gdal_version()
  91. m = re.match(rb"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<subminor>\d+))?", ver)
  92. if not m:
  93. raise GDALException('Could not parse GDAL version string "%s"' % ver)
  94. major, minor, subminor = m.groups()
  95. return (int(major), int(minor), subminor and int(subminor))
  96. GDAL_VERSION = gdal_version_info()
  97. # Set library error handling so as errors are logged
  98. CPLErrorHandler = CFUNCTYPE(None, c_int, c_int, c_char_p)
  99. def err_handler(error_class, error_number, message):
  100. logger.error("GDAL_ERROR %d: %s", error_number, message)
  101. err_handler = CPLErrorHandler(err_handler)
  102. def function(name, args, restype):
  103. func = std_call(name)
  104. func.argtypes = args
  105. func.restype = restype
  106. return func
  107. set_error_handler = function("CPLSetErrorHandler", [CPLErrorHandler], CPLErrorHandler)
  108. set_error_handler(err_handler)