datasource.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """
  2. DataSource is a wrapper for the OGR Data Source object, which provides
  3. an interface for reading vector geometry data from many different file
  4. formats (including ESRI shapefiles).
  5. When instantiating a DataSource object, use the filename of a
  6. GDAL-supported data source. For example, a SHP file or a
  7. TIGER/Line file from the government.
  8. The ds_driver keyword is used internally when a ctypes pointer
  9. is passed in directly.
  10. Example:
  11. ds = DataSource('/home/foo/bar.shp')
  12. for layer in ds:
  13. for feature in layer:
  14. # Getting the geometry for the feature.
  15. g = feature.geom
  16. # Getting the 'description' field for the feature.
  17. desc = feature['description']
  18. # We can also increment through all of the fields
  19. # attached to this feature.
  20. for field in feature:
  21. # Get the name of the field (e.g. 'description')
  22. nm = field.name
  23. # Get the type (integer) of the field, e.g. 0 => OFTInteger
  24. t = field.type
  25. # Returns the value the field; OFTIntegers return ints,
  26. # OFTReal returns floats, all else returns string.
  27. val = field.value
  28. """
  29. # ctypes prerequisites.
  30. from ctypes import byref
  31. # The GDAL C library, OGR exceptions, and the Layer object.
  32. from django.contrib.gis.gdal.base import GDALBase
  33. from django.contrib.gis.gdal.driver import Driver
  34. from django.contrib.gis.gdal.error import OGRException, OGRIndexError
  35. from django.contrib.gis.gdal.layer import Layer
  36. # Getting the ctypes prototypes for the DataSource.
  37. from django.contrib.gis.gdal.prototypes import ds as capi
  38. from django.utils.encoding import force_bytes, force_text
  39. from django.utils import six
  40. from django.utils.six.moves import xrange
  41. # For more information, see the OGR C API source code:
  42. # http://www.gdal.org/ogr/ogr__api_8h.html
  43. #
  44. # The OGR_DS_* routines are relevant here.
  45. class DataSource(GDALBase):
  46. "Wraps an OGR Data Source object."
  47. #### Python 'magic' routines ####
  48. def __init__(self, ds_input, ds_driver=False, write=False, encoding='utf-8'):
  49. # The write flag.
  50. if write:
  51. self._write = 1
  52. else:
  53. self._write = 0
  54. # See also http://trac.osgeo.org/gdal/wiki/rfc23_ogr_unicode
  55. self.encoding = encoding
  56. # Registering all the drivers, this needs to be done
  57. # _before_ we try to open up a data source.
  58. if not capi.get_driver_count():
  59. capi.register_all()
  60. if isinstance(ds_input, six.string_types):
  61. # The data source driver is a void pointer.
  62. ds_driver = Driver.ptr_type()
  63. try:
  64. # OGROpen will auto-detect the data source type.
  65. ds = capi.open_ds(force_bytes(ds_input), self._write, byref(ds_driver))
  66. except OGRException:
  67. # Making the error message more clear rather than something
  68. # like "Invalid pointer returned from OGROpen".
  69. raise OGRException('Could not open the datasource at "%s"' % ds_input)
  70. elif isinstance(ds_input, self.ptr_type) and isinstance(ds_driver, Driver.ptr_type):
  71. ds = ds_input
  72. else:
  73. raise OGRException('Invalid data source input type: %s' % type(ds_input))
  74. if ds:
  75. self.ptr = ds
  76. self.driver = Driver(ds_driver)
  77. else:
  78. # Raise an exception if the returned pointer is NULL
  79. raise OGRException('Invalid data source file "%s"' % ds_input)
  80. def __del__(self):
  81. "Destroys this DataStructure object."
  82. if self._ptr:
  83. capi.destroy_ds(self._ptr)
  84. def __iter__(self):
  85. "Allows for iteration over the layers in a data source."
  86. for i in xrange(self.layer_count):
  87. yield self[i]
  88. def __getitem__(self, index):
  89. "Allows use of the index [] operator to get a layer at the index."
  90. if isinstance(index, six.string_types):
  91. l = capi.get_layer_by_name(self.ptr, force_bytes(index))
  92. if not l:
  93. raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
  94. elif isinstance(index, int):
  95. if index < 0 or index >= self.layer_count:
  96. raise OGRIndexError('index out of range')
  97. l = capi.get_layer(self._ptr, index)
  98. else:
  99. raise TypeError('Invalid index type: %s' % type(index))
  100. return Layer(l, self)
  101. def __len__(self):
  102. "Returns the number of layers within the data source."
  103. return self.layer_count
  104. def __str__(self):
  105. "Returns OGR GetName and Driver for the Data Source."
  106. return '%s (%s)' % (self.name, str(self.driver))
  107. @property
  108. def layer_count(self):
  109. "Returns the number of layers in the data source."
  110. return capi.get_layer_count(self._ptr)
  111. @property
  112. def name(self):
  113. "Returns the name of the data source."
  114. name = capi.get_ds_name(self._ptr)
  115. return force_text(name, self.encoding, strings_only=True)