Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion fiona/_shim1.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ cdef const char* osr_get_name(OGRSpatialReferenceH hSrs)
cdef void osr_set_traditional_axis_mapping_strategy(OGRSpatialReferenceH hSrs)
cdef void set_proj_search_path(object path)
cdef (int, int, int) get_proj_version()

cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag)
cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField)

from fiona._shim cimport OGR_F_GetFieldAsInteger as OGR_F_GetFieldAsInteger64
from fiona._shim cimport OGR_F_SetFieldInteger as OGR_F_SetFieldInteger64
Expand Down
20 changes: 20 additions & 0 deletions fiona/_shim1.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,23 @@ cdef void set_proj_search_path(object path):

cdef (int, int, int) get_proj_version():
return (-1, -1, -1)


cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag):
cdef int nSecond
nSecond = int(fSecond)
OGR_F_SetFieldDateTime(cogr_feature, iField, nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag)


cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField):
cdef int retval
cdef int nYear = 0
cdef int nMonth = 0
cdef int nDay = 0
cdef int nHour = 0
cdef int nMinute = 0
cdef int nSecond = 0
cdef int nTZFlag = 0

retval = OGR_F_GetFieldAsDateTime(cogr_feature, iField, &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond, &nTZFlag)
return (retval, nYear, nMonth, nDay, nHour, nMinute, float(nSecond), nTZFlag)
2 changes: 2 additions & 0 deletions fiona/_shim2.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ cdef const char* osr_get_name(OGRSpatialReferenceH hSrs)
cdef void osr_set_traditional_axis_mapping_strategy(OGRSpatialReferenceH hSrs)
cdef void set_proj_search_path(object path)
cdef (int, int, int) get_proj_version()
cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag)
cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField)
19 changes: 19 additions & 0 deletions fiona/_shim2.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,22 @@ cdef void set_proj_search_path(object path):

cdef (int, int, int) get_proj_version():
return (-1, -1, -1)


cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag):
OGR_F_SetFieldDateTimeEx(cogr_feature, iField, nYear, nMonth, nDay, nHour, nMinute, fSecond, nTZFlag)


cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField):
cdef int retval
cdef int nYear = 0
cdef int nMonth = 0
cdef int nDay = 0
cdef int nHour = 0
cdef int nMinute = 0
cdef float fSecond = 0.0
cdef int nTZFlag = 0

retval = OGR_F_GetFieldAsDateTimeEx(cogr_feature, iField, &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond, &nTZFlag)

return (retval, nYear, nMonth, nDay, nHour, nMinute, fSecond, nTZFlag)
2 changes: 2 additions & 0 deletions fiona/_shim22.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ cdef const char* osr_get_name(OGRSpatialReferenceH hSrs)
cdef void osr_set_traditional_axis_mapping_strategy(OGRSpatialReferenceH hSrs)
cdef void set_proj_search_path(object path)
cdef (int, int, int) get_proj_version()
cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag)
cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField)
19 changes: 19 additions & 0 deletions fiona/_shim22.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,22 @@ cdef void set_proj_search_path(object path):

cdef (int, int, int) get_proj_version():
return (-1, -1, -1)


cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag):
OGR_F_SetFieldDateTimeEx(cogr_feature, iField, nYear, nMonth, nDay, nHour, nMinute, fSecond, nTZFlag)


cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField):
cdef int retval
cdef int nYear = 0
cdef int nMonth = 0
cdef int nDay = 0
cdef int nHour = 0
cdef int nMinute = 0
cdef float fSecond = 0.0
cdef int nTZFlag = 0

retval = OGR_F_GetFieldAsDateTimeEx(cogr_feature, iField, &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond, &nTZFlag)

return (retval, nYear, nMonth, nDay, nHour, nMinute, fSecond, nTZFlag)
2 changes: 2 additions & 0 deletions fiona/_shim3.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ cdef const char* osr_get_name(OGRSpatialReferenceH hSrs)
cdef void osr_set_traditional_axis_mapping_strategy(OGRSpatialReferenceH hSrs)
cdef void set_proj_search_path(object path)
cdef (int, int, int) get_proj_version()
cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag)
cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField)
21 changes: 20 additions & 1 deletion fiona/_shim3.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ cdef extern from "ogr_srs_api.h" nogil:
void OSRSetPROJSearchPaths(const char *const *papszPaths)


from fiona.ogrext2 cimport *
from fiona.ogrext3 cimport *
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to this PR and should be changed anyhow.

from fiona._err cimport exc_wrap_pointer
from fiona._err import cpl_errs, CPLE_BaseError, FionaNullPointerError
from fiona.errors import DriverError
Expand Down Expand Up @@ -167,3 +167,22 @@ cdef (int, int, int) get_proj_version():
cdef int patch
OSRGetPROJVersion(&major, &minor, &patch)
return (major, minor, patch)


cdef void set_field_datetime(void *cogr_feature, int iField, int nYear, int nMonth, int nDay, int nHour, int nMinute, float fSecond, int nTZFlag):
OGR_F_SetFieldDateTimeEx(cogr_feature, iField, nYear, nMonth, nDay, nHour, nMinute, fSecond, nTZFlag)


cdef (int, int, int, int, int, int, float, int) get_field_as_datetime(void *cogr_feature, int iField):
cdef int retval
cdef int nYear = 0
cdef int nMonth = 0
cdef int nDay = 0
cdef int nHour = 0
cdef int nMinute = 0
cdef float fSecond = 0.0
cdef int nTZFlag = 0

retval = OGR_F_GetFieldAsDateTimeEx(cogr_feature, iField, &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond, &nTZFlag)

return (retval, nYear, nMonth, nDay, nHour, nMinute, fSecond, nTZFlag)
39 changes: 19 additions & 20 deletions fiona/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
from fiona._env import get_gdal_release_name, get_gdal_version_tuple
from fiona.env import env_ctx_if_needed
from fiona.errors import FionaDeprecationWarning
from fiona.drvsupport import supported_drivers, driver_mode_mingdal
from fiona.drvsupport import (supported_drivers, driver_mode_mingdal, driver_converts_field_type_silently_to_str,
driver_supports_field)
from fiona.path import Path, vsi_path, parse_path
from six import string_types, binary_type

Expand Down Expand Up @@ -412,25 +413,23 @@ def _check_schema_driver_support(self):

for field in self._schema["properties"].values():
field_type = field.split(":")[0]
if self._driver == "ESRI Shapefile":
if field_type == "datetime":
raise DriverSupportError("ESRI Shapefile does not support datetime fields")
elif field_type == "time":
raise DriverSupportError("ESRI Shapefile does not support time fields")
elif self._driver == "GPKG":
if field_type == "time":
raise DriverSupportError("GPKG does not support time fields")
elif gdal_version_major == 1:
if field_type == "datetime":
raise DriverSupportError("GDAL 1.x GPKG driver does not support datetime fields")
elif self._driver == "GeoJSON":
if gdal_version_major == 1:
if field_type == "date":
warnings.warn("GeoJSON driver in GDAL 1.x silently converts date to string in non-standard format")
elif field_type == "datetime":
warnings.warn("GeoJSON driver in GDAL 1.x silently converts datetime to string in non-standard format")
elif field_type == "time":
warnings.warn("GeoJSON driver in GDAL 1.x silently converts time to string")

if not driver_supports_field(self.driver, field_type):
if self.driver == 'GPKG' and gdal_version_major < 2 and field_type == "datetime":
raise DriverSupportError("GDAL 1.x GPKG driver does not support datetime fields")
else:
raise DriverSupportError("{driver} does not support {field_type} "
"fields".format(driver=self.driver,
field_type=field_type))
elif field_type in {'time', 'datetime', 'date'} and driver_converts_field_type_silently_to_str(self.driver,
field_type):
if self._driver == "GeoJSON" and gdal_version_major < 2 and field_type in {'datetime', 'date'}:
warnings.warn("GeoJSON driver in GDAL 1.x silently converts {} to string"
" in non-standard format".format(field_type))
else:
warnings.warn("{driver} driver silently converts {field_type} "
"to string".format(driver=self.driver,
field_type=field_type))

def flush(self):
"""Flush the buffer."""
Expand Down
91 changes: 85 additions & 6 deletions fiona/drvsupport.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-

from fiona.env import Env
from fiona.env import Env, GDALVersion

gdal_version = GDALVersion.runtime()

# Here is the list of available drivers as (name, modes) tuples. Currently,
# we only expose the defaults (excepting FileGDB). We also don't expose
Expand Down Expand Up @@ -43,14 +44,14 @@
("OpenFileGDB", "r"),
# ESRI Personal GeoDatabase PGeo No Yes No, needs ODBC library
# ESRI ArcSDE SDE No Yes No, needs ESRI SDE
# ESRIJSON ESRIJSON No Yes Yes
# ESRIJSON ESRIJSON No Yes Yes
("ESRIJSON", "r"),
# ESRI Shapefile ESRI Shapefile Yes Yes Yes
("ESRI Shapefile", "raw"),
# FMEObjects Gateway FMEObjects Gateway No Yes No, needs FME
# GeoJSON GeoJSON Yes Yes Yes
("GeoJSON", "raw"),
# GeoJSONSeq GeoJSON sequences Yes Yes Yes
# GeoJSONSeq GeoJSON sequences Yes Yes Yes
("GeoJSONSeq", "rw"),
# Géoconcept Export Geoconcept Yes Yes Yes
# multi-layers
Expand Down Expand Up @@ -118,7 +119,7 @@
# SUA SUA No Yes Yes
("SUA", "r"),
# SVG SVG No Yes No, needs libexpat
# TopoJSON TopoJSON No Yes Yes
# TopoJSON TopoJSON No Yes Yes
("TopoJSON", "r"),
# UK .NTF UK. NTF No Yes Yes
# multi-layer
Expand All @@ -141,7 +142,7 @@
])


# Mininmal gdal version for different modes
# Minimal gdal version for different modes
driver_mode_mingdal = {

'r': {'GPKG': (1, 11, 0),
Expand All @@ -155,7 +156,7 @@
'GPKG': (1, 11, 0),
'GeoJSON': (2, 1, 0),
'MapInfo File': (2, 0, 0),
'PCIDSK': (2, 0, 0)}
'PCIDSK': (2, 0, 0)}
}


Expand All @@ -176,3 +177,81 @@ def _filter_supported_drivers():


_filter_supported_drivers()

# driver_converts_to_str contains field type, driver combinations that are silently converted to string
# None: field type is always converted to str
# GDALVersion(2, 0): starting from gdal 2.0 field type is not converted to string
driver_converts_to_str = {
'time': {
'CSV': None,
'PCIDSK': None,
'GeoJSON': GDALVersion(2, 0),
'GPKG': None,
'GMT': None,
},
'datetime': {
'CSV': None,
'PCIDSK': None,
'GeoJSON': GDALVersion(2, 0),
'GML': GDALVersion(3, 1),
},
'date': {
'CSV': None,
'PCIDSK': None,
'GeoJSON': GDALVersion(2, 0),
'GMT': None,
'GML': GDALVersion(3, 1),
}
}


def driver_converts_field_type_silently_to_str(driver, field_type):
""" Returns True if the driver converts the field_type silently to str, False otherwise """

if field_type in driver_converts_to_str and driver in driver_converts_to_str[field_type]:
if driver_converts_to_str[field_type][driver] is None:
return True
elif gdal_version < driver_converts_to_str[field_type][driver]:
return True
return False


# None: field type is never supported, GDALVersion(2, 0) field type is supported starting with gdal 2.0
driver_field_type_unsupported = {
'time': {
'ESRI Shapefile': None,
'GPKG': GDALVersion(2, 0),
'GPX': None,
'GPSTrackMaker': None,
'GML': GDALVersion(3, 1),
'DGN': None,
'BNA': None,
'DXF': None
},
'datetime': {
'ESRI Shapefile': None,
'GPKG': GDALVersion(2, 0),
'DGN': None,
'BNA': None,
'DXF': None
},
'date': {
'GPX': None,
'GPSTrackMaker': None,
'DGN': None,
'BNA': None,
'DXF': None
}
}


def driver_supports_field(driver, field_type):
""" Returns True if driver supports the field_type, False otherwise"""

if field_type in driver_field_type_unsupported and driver in driver_field_type_unsupported[field_type]:
if driver_field_type_unsupported[field_type][driver] is None:
return False
elif driver_field_type_unsupported[field_type][driver] > gdal_version:
return False

return True
Loading