def test_write_does_not_work_when_gdal_smaller_mingdal(tmpdir, driver, testdata_generator, monkeypatch): """ Test if driver really can't write for gdal < driver_mode_mingdal If this test fails, it should be considered to update driver_mode_mingdal in drvsupport.py. """ if driver == "BNA" and GDALVersion.runtime() < GDALVersion(2, 0): pytest.skip("BNA driver segfaults with gdal 1.11") if (driver == 'FlatGeobuf' and calc_gdal_version_num(3, 1, 0) <= get_gdal_version_num() < calc_gdal_version_num(3, 1, 3)): pytest.skip("See https://github.com/Toblerity/Fiona/pull/924") schema, crs, records1, _, test_equal, create_kwargs = testdata_generator( driver, range(0, 10), []) path = str(tmpdir.join(get_temp_filename(driver))) if (driver in driver_mode_mingdal['w'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['w'][driver])): monkeypatch.delitem(fiona.drvsupport.driver_mode_mingdal['w'], driver) with pytest.raises(Exception): with fiona.open(path, 'w', driver=driver, crs=crs, schema=schema, **create_kwargs) as c: c.writerecords(records1)
def test_append_or_driver_error(tmpdir, testdata_generator, driver): """ Test if driver supports append mode. Some driver only allow a specific schema. These drivers can be excluded by adding them to blacklist_append_drivers. """ if driver == "DGN": pytest.xfail("DGN schema has changed") if driver == "BNA" and GDALVersion.runtime() < GDALVersion(2, 0): pytest.skip("BNA driver segfaults with gdal 1.11") path = str(tmpdir.join(get_temp_filename(driver))) schema, crs, records1, records2, test_equal, create_kwargs = testdata_generator( driver, range(0, 5), range(5, 10)) # If driver is not able to write, we cannot test append if (driver in driver_mode_mingdal['w'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['w'][driver])): return # Create test file to append to with fiona.open(path, 'w', driver=driver, crs=crs, schema=schema, **create_kwargs) as c: c.writerecords(records1) if (driver in driver_mode_mingdal['a'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['a'][driver])): # Test if DriverError is raised for gdal < driver_mode_mingdal with pytest.raises(DriverError): with fiona.open(path, 'a', driver=driver) as c: c.writerecords(records2) else: # Test if we can append with fiona.open(path, 'a', driver=driver) as c: c.writerecords(records2) if driver in {'FileGDB', 'OpenFileGDB'}: open_driver = driver else: open_driver = None with fiona.open(path, driver=open_driver) as c: assert c.driver == driver items = list(c) assert len(items) == len(records1) + len(records2) for val_in, val_out in zip(records1 + records2, items): assert test_equal( driver, val_in, val_out), "in: {val_in}, out: {val_out}".format( val_in=val_in, val_out=val_out)
def test_append_does_not_work_when_gdal_smaller_mingdal( tmpdir, driver, testdata_generator, monkeypatch): """ Test if driver supports append mode. If this test fails, it should be considered to update driver_mode_mingdal in drvsupport.py. """ if driver == "BNA" and GDALVersion.runtime() < GDALVersion(2, 0): pytest.skip("BNA driver segfaults with gdal 1.11") path = str(tmpdir.join(get_temp_filename(driver))) schema, crs, records1, records2, test_equal, create_kwargs = testdata_generator( driver, range(0, 5), range(5, 10)) # If driver is not able to write, we cannot test append if (driver in driver_mode_mingdal['w'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['w'][driver])): return # Create test file to append to with fiona.open(path, 'w', driver=driver, crs=crs, schema=schema, **create_kwargs) as c: c.writerecords(records1) if (driver in driver_mode_mingdal['a'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['a'][driver])): # Test if driver really can't append for gdal < driver_mode_mingdal monkeypatch.delitem(fiona.drvsupport.driver_mode_mingdal['a'], driver) with pytest.raises(Exception): with fiona.open(path, 'a', driver=driver) as c: c.writerecords(records2) if driver in {'FileGDB', 'OpenFileGDB'}: open_driver = driver else: open_driver = None with fiona.open(path, driver=open_driver) as c: assert c.driver == driver items = list(c) assert len(items) == len(records1) + len(records2) for val_in, val_out in zip(records1 + records2, items): assert test_equal(driver, val_in, val_out)
def _validate(val, val_exp, field_type, driver): if (driver == 'MapInfo File' and field_type == 'time' and calc_gdal_version_num(2, 0, 0) <= get_gdal_version_num() < calc_gdal_version_num(3, 1, 1)): return val == '00:00:00' if val is None or val == '': return True return False
def _driver_supports_milliseconds(driver): """ Returns True if the driver supports milliseconds, False otherwise Note: this function is not part of Fiona's public API. """ # GDAL 2.0 introduced support for milliseconds if get_gdal_version_num() < calc_gdal_version_num(2, 0, 0): return False if driver in _drivers_not_supporting_milliseconds: if _drivers_not_supporting_milliseconds[driver] is None: return False elif calc_gdal_version_num( *_drivers_not_supporting_milliseconds[driver] ) < get_gdal_version_num(): return False return True
def test_no_append_driver_cannot_append(tmpdir, driver, testdata_generator, monkeypatch): """ Test if a driver that supports write and not append cannot also append If this test fails, it should be considered to enable append support for the respective driver in drvsupport.py. """ monkeypatch.setitem(fiona.drvsupport.supported_drivers, driver, 'raw') if driver == "BNA" and GDALVersion.runtime() < GDALVersion(2, 0): pytest.skip("BNA driver segfaults with gdal 1.11") path = str(tmpdir.join(get_temp_filename(driver))) schema, crs, records1, records2, test_equal, create_kwargs = testdata_generator( driver, range(0, 5), range(5, 10)) # If driver is not able to write, we cannot test append if (driver in driver_mode_mingdal['w'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['w'][driver])): return # Create test file to append to with fiona.open(path, 'w', driver=driver, crs=crs, schema=schema, **create_kwargs) as c: c.writerecords(records1) is_good = True try: with fiona.open(path, 'a', driver=driver) as c: c.writerecords(records2) if driver in {'FileGDB', 'OpenFileGDB'}: open_driver = driver else: open_driver = None with fiona.open(path, driver=open_driver) as c: assert c.driver == driver items = list(c) is_good = is_good and len(items) == len(records1) + len(records2) for val_in, val_out in zip(records1 + records2, items): is_good = is_good and test_equal(driver, val_in, val_out) except: is_good = False assert not is_good
def _driver_supports_timezones(driver, field_type): """ Returns True if the driver supports timezones for field_type, False otherwise Note: this function is not part of Fiona's public API. """ if field_type in _drivers_not_supporting_timezones and driver in _drivers_not_supporting_timezones[ field_type]: if _drivers_not_supporting_timezones[field_type][driver] is None: return False elif get_gdal_version_num() < calc_gdal_version_num( *_drivers_not_supporting_timezones[field_type][driver]): return False return True
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 Note: this function is not part of Fiona's public API. """ 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 get_gdal_version_num() < calc_gdal_version_num( *_driver_converts_to_str[field_type][driver]): return True return False
def test_write_or_driver_error(tmpdir, driver, testdata_generator): """ Test if write mode works. """ if driver == "BNA" and GDALVersion.runtime() < GDALVersion(2, 0): pytest.skip("BNA driver segfaults with gdal 1.11") schema, crs, records1, _, test_equal, create_kwargs = testdata_generator( driver, range(0, 10), []) path = str(tmpdir.join(get_temp_filename(driver))) if (driver in driver_mode_mingdal['w'] and get_gdal_version_num() < calc_gdal_version_num(*driver_mode_mingdal['w'][driver])): # Test if DriverError is raised for gdal < driver_mode_mingdal with pytest.raises(DriverError): with fiona.open(path, 'w', driver=driver, crs=crs, schema=schema, **create_kwargs) as c: c.writerecords(records1) else: # Test if we can write with fiona.open(path, 'w', driver=driver, crs=crs, schema=schema, **create_kwargs) as c: c.writerecords(records1) if driver in {'FileGDB', 'OpenFileGDB'}: open_driver = driver else: open_driver = None with fiona.open(path, driver=open_driver) as c: assert c.driver == driver items = list(c) assert len(items) == len(records1) for val_in, val_out in zip(records1, items): assert test_equal( driver, val_in, val_out), "in: {val_in}, out: {val_out}".format( val_in=val_in, val_out=val_out)
def _driver_supports_field(driver, field_type): """ Returns True if the driver supports the field_type, False otherwise Note: this function is not part of Fiona's public API. """ 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 get_gdal_version_num() < calc_gdal_version_num( *_driver_field_type_unsupported[field_type][driver]): return False return True
def _driver_supports_mode(driver, mode): """ Returns True if driver supports mode, False otherwise Note: this function is not part of Fiona's public API. """ if driver not in supported_drivers: return False if mode not in supported_drivers[driver]: return False if driver in driver_mode_mingdal[mode]: if get_gdal_version_num() < calc_gdal_version_num( *driver_mode_mingdal[mode][driver]): return False return True
def _check_schema_driver_support(self): """Check support for the schema against the driver See GH#572 for discussion. """ gdal_version_major = get_gdal_version_num() // 1000000 for field in self._schema["properties"]: 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" )
def __init__(self, path, mode='r', driver=None, schema=None, crs=None, encoding=None, layer=None, vsi=None, archive=None, enabled_drivers=None, crs_wkt=None, ignore_fields=None, ignore_geometry=False, **kwargs): """The required ``path`` is the absolute or relative path to a file, such as '/data/test_uk.shp'. In ``mode`` 'r', data can be read only. In ``mode`` 'a', data can be appended to a file. In ``mode`` 'w', data overwrites the existing contents of a file. In ``mode`` 'w', an OGR ``driver`` name and a ``schema`` are required. A Proj4 ``crs`` string is recommended. If both ``crs`` and ``crs_wkt`` keyword arguments are passed, the latter will trump the former. In 'w' mode, kwargs will be mapped to OGR layer creation options. """ if not isinstance(path, (string_types, Path)): raise TypeError("invalid path: %r" % path) if not isinstance(mode, string_types) or mode not in ('r', 'w', 'a'): raise TypeError("invalid mode: %r" % mode) if driver and not isinstance(driver, string_types): raise TypeError("invalid driver: %r" % driver) if schema and not hasattr(schema, 'get'): raise TypeError("invalid schema: %r" % schema) if crs and not isinstance(crs, compat.DICT_TYPES + string_types): raise TypeError("invalid crs: %r" % crs) if crs_wkt and not isinstance(crs_wkt, string_types): raise TypeError("invalid crs_wkt: %r" % crs_wkt) if encoding and not isinstance(encoding, string_types): raise TypeError("invalid encoding: %r" % encoding) if layer and not isinstance(layer, tuple(list(string_types) + [int])): raise TypeError("invalid name: %r" % layer) if vsi: if not isinstance(vsi, string_types) or not vfs.valid_vsi(vsi): raise TypeError("invalid vsi: %r" % vsi) if archive and not isinstance(archive, string_types): raise TypeError("invalid archive: %r" % archive) # Check GDAL version against drivers if (driver == "GPKG" and get_gdal_version_num() < calc_gdal_version_num(1, 11, 0)): raise DriverError( "GPKG driver requires GDAL 1.11.0, fiona was compiled " "against: {}".format(get_gdal_release_name())) self.session = None self.iterator = None self._len = 0 self._bounds = None self._driver = None self._schema = None self._crs = None self._crs_wkt = None self.env = None self.enabled_drivers = enabled_drivers self.ignore_fields = ignore_fields self.ignore_geometry = bool(ignore_geometry) if vsi: self.path = vfs.vsi_path(path, vsi, archive) path = parse_path(self.path) else: path = parse_path(path) self.path = vsi_path(path) if mode == 'w': if layer and not isinstance(layer, string_types): raise ValueError("in 'w' mode, layer names must be strings") if driver == 'GeoJSON': if layer is not None: raise ValueError("the GeoJSON format does not have layers") self.name = 'OgrGeoJSON' # TODO: raise ValueError as above for other single-layer formats. else: self.name = layer or os.path.basename( os.path.splitext(path.path)[0]) else: if layer in (0, None): self.name = 0 else: self.name = layer or os.path.basename( os.path.splitext(path)[0]) self.mode = mode if self.mode == 'w': if driver == 'Shapefile': driver = 'ESRI Shapefile' if not driver: raise DriverError("no driver") elif driver not in supported_drivers: raise DriverError("unsupported driver: %r" % driver) elif self.mode not in supported_drivers[driver]: raise DriverError("unsupported mode: %r" % self.mode) self._driver = driver if not schema: raise SchemaError("no schema") elif 'properties' not in schema: raise SchemaError("schema lacks: properties") elif 'geometry' not in schema: raise SchemaError("schema lacks: geometry") self._schema = schema self._check_schema_driver_support() if crs_wkt: self._crs_wkt = crs_wkt elif crs: if 'init' in crs or 'proj' in crs or 'epsg' in crs.lower(): self._crs = crs else: raise CRSError("crs lacks init or proj parameter") self._driver = driver kwargs.update(encoding=encoding or '') self.encoding = encoding try: if self.mode == 'r': self.session = Session() self.session.start(self, **kwargs) elif self.mode in ('a', 'w'): self.session = WritingSession() self.session.start(self, **kwargs) except IOError: self.session = None raise if self.session is not None: self.guard_driver_mode() if not self.encoding: self.encoding = self.session.get_fileencoding().lower() if self.mode in ("a", "w"): self._valid_geom_types = _get_valid_geom_types( self.schema, self.driver) self.field_skip_log_filter = FieldSkipLogFilter()