[fiona] 01/04: Imported Upstream version 1.7.6
Johan Van de Wauw
johanvdw-guest at moszumanska.debian.org
Fri May 19 21:03:04 UTC 2017
This is an automated email from the git hooks/post-receive script.
johanvdw-guest pushed a commit to branch master
in repository fiona.
commit 70a9a0d22f1abb630812e4dbf5a499dbdad69291
Author: Johan Van de Wauw <johan.vandewauw at gmail.com>
Date: Fri May 19 22:46:35 2017 +0200
Imported Upstream version 1.7.6
---
.travis.yml | 2 +
CHANGES.txt | 14 ++++
CREDITS.txt | 1 +
fiona/__init__.py | 8 +--
fiona/_crs.pxd | 30 ++++----
fiona/_drivers.pyx | 27 +++++--
fiona/_err.pxd | 1 +
fiona/_err.pyx | 191 ++++++++++++++++++++++++++++++++++++++++++++++----
fiona/_transform.pyx | 31 ++++----
fiona/collection.py | 42 ++++++-----
fiona/compat.py | 2 +-
fiona/errors.py | 5 ++
fiona/ogrext1.pxd | 30 ++++----
fiona/ogrext1.pyx | 114 +++++++++++++++++-------------
fiona/ogrext2.pxd | 48 +++++++------
fiona/ogrext2.pyx | 184 +++++++++++++++++++++++++-----------------------
setup.py | 7 +-
tests/test_drivers.py | 2 +-
tests/test_geojson.py | 26 ++++++-
19 files changed, 519 insertions(+), 246 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 724cf8a..774f1ad 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,6 +35,8 @@ before_install:
- . ./scripts/travis_gdal_install.sh
- export PATH=$GDALINST/gdal-$GDALVERSION/bin:$PATH
- export LD_LIBRARY_PATH=$GDALINST/gdal-$GDALVERSION/lib:$LD_LIBRARY_PATH
+ - export GDAL_DATA=$GDALINST/gdal-$GDALVERSION/share/gdal
+ - export PROJ_LIB=/usr/share/proj
- gdal-config --version
install:
- "if [ $(gdal-config --version) == \"$GDALVERSION\" ]; then echo \"Using gdal $GDALVERSION\"; else echo \"NOT using gdal $GDALVERSION as expected; aborting\"; exit 1; fi"
diff --git a/CHANGES.txt b/CHANGES.txt
index ea759be..d5f451a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,6 +3,20 @@ Changes
All issue numbers are relative to https://github.com/Toblerity/Fiona/issues.
+1.7.6 (2017-04-26)
+------------------
+
+Bug fixes:
+
+- Fall back to `share/proj` for PROJ_LIB (#440).
+- Replace every call to `OSRDestroySpatialReference()` with `OSRRelease()`,
+ fixing the GPKG driver crasher reported in #441 (#443).
+- Add a `DriverIOError` derived from `IOError` to use for driver-specific
+ errors such as the GeoJSON driver's refusal to overwrite existing files.
+ Also we now ensure that when this error is raised by `fiona.open()` any
+ created read or write session is deleted, this eliminates spurious
+ exceptions on teardown of broken `Collection` objects (#437, #444).
+
1.7.5 (2017-03-20)
------------------
diff --git a/CREDITS.txt b/CREDITS.txt
index de41ed5..4012f96 100644
--- a/CREDITS.txt
+++ b/CREDITS.txt
@@ -32,6 +32,7 @@ Fiona is written by:
- Stefano Costa <steko at iosa.it>
- dimlev <dimlev at gmail.com>
- wilsaj <wilson.andrew.j+github at gmail.com>
+- Jesse Crocker <jesse at gaiagps.com>
Fiona would not be possible without the great work of Frank Warmerdam and other
GDAL/OGR developers.
diff --git a/fiona/__init__.py b/fiona/__init__.py
index 2ea320f..7c11959 100644
--- a/fiona/__init__.py
+++ b/fiona/__init__.py
@@ -81,14 +81,10 @@ import uuid
__all__ = ['bounds', 'listlayers', 'open', 'prop_type', 'prop_width']
-__version__ = "1.7.5"
+__version__ = "1.7.6"
__gdal_version__ = get_gdal_release_name().decode('utf-8')
-log = logging.getLogger('Fiona')
-class NullHandler(logging.Handler):
- def emit(self, record):
- pass
-log.addHandler(NullHandler())
+log = logging.getLogger(__name__)
def open(
diff --git a/fiona/_crs.pxd b/fiona/_crs.pxd
index 7329cb0..9646a89 100644
--- a/fiona/_crs.pxd
+++ b/fiona/_crs.pxd
@@ -1,20 +1,22 @@
# Coordinate system and transform API functions.
cdef extern from "ogr_srs_api.h":
+
+ ctypedef void * OGRSpatialReferenceH
+
void OSRCleanup ()
- void * OSRClone (void *srs)
- void OSRDestroySpatialReference (void *srs)
- int OSRExportToProj4 (void *srs, char **params)
- int OSRExportToWkt (void *srs, char **params)
- int OSRImportFromEPSG (void *srs, int code)
- int OSRImportFromProj4 (void *srs, char *proj)
- int OSRSetFromUserInput (void *srs, char *input)
- int OSRAutoIdentifyEPSG (void *srs)
- int OSRFixup(void *srs)
- const char * OSRGetAuthorityName (void *srs, const char *key)
- const char * OSRGetAuthorityCode (void *srs, const char *key)
- void * OSRNewSpatialReference (char *wkt)
- void OSRRelease (void *srs)
- void * OCTNewCoordinateTransformation (void *source, void *dest)
+ OGRSpatialReferenceH OSRClone (OGRSpatialReferenceH srs)
+ int OSRExportToProj4 (OGRSpatialReferenceH srs, char **params)
+ int OSRExportToWkt (OGRSpatialReferenceH srs, char **params)
+ int OSRImportFromEPSG (OGRSpatialReferenceH srs, int code)
+ int OSRImportFromProj4 (OGRSpatialReferenceH srs, char *proj)
+ int OSRSetFromUserInput (OGRSpatialReferenceH srs, char *input)
+ int OSRAutoIdentifyEPSG (OGRSpatialReferenceH srs)
+ int OSRFixup(OGRSpatialReferenceH srs)
+ const char * OSRGetAuthorityName (OGRSpatialReferenceH srs, const char *key)
+ const char * OSRGetAuthorityCode (OGRSpatialReferenceH srs, const char *key)
+ OGRSpatialReferenceH OSRNewSpatialReference (char *wkt)
+ void OSRRelease (OGRSpatialReferenceH srs)
+ void * OCTNewCoordinateTransformation (OGRSpatialReferenceH source, OGRSpatialReferenceH dest)
void OCTDestroyCoordinateTransformation (void *source)
int OCTTransform (void *ct, int nCount, double *x, double *y, double *z)
diff --git a/fiona/_drivers.pyx b/fiona/_drivers.pyx
index 7c49231..79d5b73 100644
--- a/fiona/_drivers.pyx
+++ b/fiona/_drivers.pyx
@@ -106,18 +106,35 @@ cdef class GDALEnv(object):
if OGRGetDriverCount() == 0:
raise ValueError("Drivers not registered")
- if 'GDAL_DATA' not in os.environ:
+ if 'GDAL_DATA' in os.environ:
+ log.debug("GDAL_DATA: %s", os.environ['GDAL_DATA'])
+ else:
whl_datadir = os.path.abspath(
os.path.join(os.path.dirname(__file__), "gdal_data"))
share_datadir = os.path.join(sys.prefix, 'share/gdal')
if os.path.exists(os.path.join(whl_datadir, 'pcs.csv')):
os.environ['GDAL_DATA'] = whl_datadir
+ log.debug("Set GDAL_DATA = %r", whl_datadir)
elif os.path.exists(os.path.join(share_datadir, 'pcs.csv')):
os.environ['GDAL_DATA'] = share_datadir
- if 'PROJ_LIB' not in os.environ:
+ log.debug("Set GDAL_DATA = %r", share_datadir)
+ else:
+ log.warn("GDAL data files not located, GDAL_DATA not set")
+
+ if 'PROJ_LIB' in os.environ:
+ log.debug("PROJ_LIB: %s", os.environ['PROJ_LIB'])
+ else:
whl_datadir = os.path.abspath(
os.path.join(os.path.dirname(__file__), "proj_data"))
- os.environ['PROJ_LIB'] = whl_datadir
+ share_datadir = os.path.join(sys.prefix, 'share/proj')
+ if os.path.exists(whl_datadir):
+ os.environ['PROJ_LIB'] = whl_datadir
+ log.debug("Set PROJ_LIB = %r", whl_datadir)
+ elif os.path.exists(share_datadir):
+ os.environ['PROJ_LIB'] = share_datadir
+ log.debug("Set PROJ_LIB = %r", share_datadir)
+ else:
+ log.warn("PROJ data files not located, PROJ_LIB not set")
for key, val in self.options.items():
key_b = key.upper().encode('utf-8')
@@ -141,8 +158,8 @@ cdef class GDALEnv(object):
def drivers(self):
cdef void *drv = NULL
- cdef char *key = NULL
- cdef char *val = NULL
+ cdef const char *key = NULL
+ cdef const char *val = NULL
cdef int i
result = {}
for i in range(OGRGetDriverCount()):
diff --git a/fiona/_err.pxd b/fiona/_err.pxd
new file mode 100644
index 0000000..5818e0e
--- /dev/null
+++ b/fiona/_err.pxd
@@ -0,0 +1 @@
+cdef void *exc_wrap_pointer(void *ptr) except NULL
diff --git a/fiona/_err.pyx b/fiona/_err.pyx
index 4ab0fdc..467e8ed 100644
--- a/fiona/_err.pyx
+++ b/fiona/_err.pyx
@@ -31,24 +31,140 @@ manager raises a more useful and informative error:
# CPL function declarations.
cdef extern from "cpl_error.h":
+
+ ctypedef enum CPLErr:
+ CE_None
+ CE_Debug
+ CE_Warning
+ CE_Failure
+ CE_Fatal
+
int CPLGetLastErrorNo()
const char* CPLGetLastErrorMsg()
int CPLGetLastErrorType()
void CPLErrorReset()
-# Map GDAL error numbers to Python exceptions.
+
+from enum import IntEnum
+
+# Python exceptions expressing the CPL error numbers.
+
+class CPLE_BaseError(Exception):
+ """Base CPL error class
+ Exceptions deriving from this class are intended for use only in
+ Rasterio's Cython code. Let's not expose API users to them.
+ """
+
+ def __init__(self, error, errno, errmsg):
+ self.error = error
+ self.errno = errno
+ self.errmsg = errmsg
+
+ def __str__(self):
+ return self.__unicode__()
+
+ def __unicode__(self):
+ return "{}".format(self.errmsg)
+
+ @property
+ def args(self):
+ return self.error, self.errno, self.errmsg
+
+
+class CPLE_AppDefinedError(CPLE_BaseError):
+ pass
+
+
+class CPLE_OutOfMemoryError(CPLE_BaseError):
+ pass
+
+
+class CPLE_FileIOError(CPLE_BaseError):
+ pass
+
+
+class CPLE_OpenFailedError(CPLE_BaseError):
+ pass
+
+
+class CPLE_IllegalArgError(CPLE_BaseError):
+ pass
+
+
+class CPLE_NotSupportedError(CPLE_BaseError):
+ pass
+
+
+class CPLE_AssertionFailedError(CPLE_BaseError):
+ pass
+
+
+class CPLE_NoWriteAccessError(CPLE_BaseError):
+ pass
+
+
+class CPLE_UserInterruptError(CPLE_BaseError):
+ pass
+
+
+class ObjectNullError(CPLE_BaseError):
+ pass
+
+
+class CPLE_HttpResponseError(CPLE_BaseError):
+ pass
+
+
+class CPLE_AWSBucketNotFoundError(CPLE_BaseError):
+ pass
+
+
+class CPLE_AWSObjectNotFoundError(CPLE_BaseError):
+ pass
+
+
+class CPLE_AWSAccessDeniedError(CPLE_BaseError):
+ pass
+
+
+class CPLE_AWSInvalidCredentialsError(CPLE_BaseError):
+ pass
+
+
+class CPLE_AWSSignatureDoesNotMatchError(CPLE_BaseError):
+ pass
+
+
+# Map of GDAL error numbers to the Python exceptions.
exception_map = {
- 1: RuntimeError, # CPLE_AppDefined
- 2: MemoryError, # CPLE_OutOfMemory
- 3: IOError, # CPLE_FileIO
- 4: IOError, # CPLE_OpenFailed
- 5: TypeError, # CPLE_IllegalArg
- 6: ValueError, # CPLE_NotSupported
- 7: AssertionError, # CPLE_AssertionFailed
- 8: IOError, # CPLE_NoWriteAccess
- 9: KeyboardInterrupt, # CPLE_UserInterrupt
- 10: ValueError # ObjectNull
- }
+ 1: CPLE_AppDefinedError,
+ 2: CPLE_OutOfMemoryError,
+ 3: CPLE_FileIOError,
+ 4: CPLE_OpenFailedError,
+ 5: CPLE_IllegalArgError,
+ 6: CPLE_NotSupportedError,
+ 7: CPLE_AssertionFailedError,
+ 8: CPLE_NoWriteAccessError,
+ 9: CPLE_UserInterruptError,
+ 10: ObjectNullError,
+
+ # error numbers 11-16 are introduced in GDAL 2.1. See
+ # https://github.com/OSGeo/gdal/pull/98.
+ 11: CPLE_HttpResponseError,
+ 12: CPLE_AWSBucketNotFoundError,
+ 13: CPLE_AWSObjectNotFoundError,
+ 14: CPLE_AWSAccessDeniedError,
+ 15: CPLE_AWSInvalidCredentialsError,
+ 16: CPLE_AWSSignatureDoesNotMatchError}
+
+
+# CPL Error types as an enum.
+class GDALError(IntEnum):
+ none = CE_None
+ debug = CE_Debug
+ warning = CE_Warning
+ failure = CE_Failure
+ fatal = CE_Fatal
cdef class GDALErrCtxManager:
@@ -61,10 +177,55 @@ cdef class GDALErrCtxManager:
def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
cdef int err_type = CPLGetLastErrorType()
cdef int err_no = CPLGetLastErrorNo()
- cdef char *msg = CPLGetLastErrorMsg()
+ cdef const char *msg = CPLGetLastErrorMsg()
# TODO: warn for err_type 2?
- if err_type >= 3:
+ if err_type >= 2:
raise exception_map[err_no](msg)
-cpl_errs = GDALErrCtxManager()
+cdef inline object exc_check():
+ """Checks GDAL error stack for fatal or non-fatal errors
+
+ Returns
+ -------
+ An Exception, SystemExit, or None
+ """
+ cdef const char *msg_c = NULL
+
+ err_type = CPLGetLastErrorType()
+ err_no = CPLGetLastErrorNo()
+ err_msg = CPLGetLastErrorMsg()
+
+ if err_msg == NULL:
+ msg = "No error message."
+ else:
+ # Reformat messages.
+ msg_b = err_msg
+ msg = msg_b.decode('utf-8')
+ msg = msg.replace("`", "'")
+ msg = msg.replace("\n", " ")
+
+ if err_type == 3:
+ CPLErrorReset()
+ return exception_map.get(
+ err_no, CPLE_BaseError)(err_type, err_no, msg)
+
+ if err_type == 4:
+ return SystemExit("Fatal error: {0}".format((err_type, err_no, msg)))
+
+ else:
+ return
+
+
+cdef void *exc_wrap_pointer(void *ptr) except NULL:
+ """Wrap a GDAL/OGR function that returns GDALDatasetH etc (void *)
+ Raises a Rasterio exception if a non-fatal error has be set.
+ """
+ if ptr == NULL:
+ exc = exc_check()
+ if exc:
+ raise exc
+ return NULL
+ return ptr
+
+cpl_errs = GDALErrCtxManager()
\ No newline at end of file
diff --git a/fiona/_transform.pyx b/fiona/_transform.pyx
index 6c5460b..bafdba5 100644
--- a/fiona/_transform.pyx
+++ b/fiona/_transform.pyx
@@ -9,6 +9,8 @@ cimport _crs
cimport _csl
cimport _geometry
+from _crs cimport OGRSpatialReferenceH
+
cdef extern from "ogr_geometry.h" nogil:
@@ -34,7 +36,7 @@ log.addHandler(NullHandler())
cdef void *_crs_from_crs(object crs):
cdef char *proj_c = NULL
- cdef void *osr = NULL
+ cdef OGRSpatialReferenceH osr = NULL
osr = _crs.OSRNewSpatialReference(NULL)
if osr == NULL:
raise ValueError("NULL spatial reference")
@@ -68,10 +70,12 @@ cdef void *_crs_from_crs(object crs):
def _transform(src_crs, dst_crs, xs, ys):
- cdef double *x, *y
+ cdef double *x
+ cdef double *y
cdef char *proj_c = NULL
- cdef void *src, *dst
- cdef void *transform
+ cdef OGRSpatialReferenceH src = NULL
+ cdef OGRSpatialReferenceH dst = NULL
+ cdef void *transform = NULL
cdef int i
assert len(xs) == len(ys)
@@ -99,8 +103,8 @@ def _transform(src_crs, dst_crs, xs, ys):
_cpl.CPLFree(x)
_cpl.CPLFree(y)
_crs.OCTDestroyCoordinateTransformation(transform)
- _crs.OSRDestroySpatialReference(src)
- _crs.OSRDestroySpatialReference(dst)
+ _crs.OSRRelease(src)
+ _crs.OSRRelease(dst)
return res_xs, res_ys
@@ -112,11 +116,12 @@ def _transform_geom(
cdef char *key_c = NULL
cdef char *val_c = NULL
cdef char **options = NULL
- cdef void *src, *dst
- cdef void *transform
- cdef OGRGeometryFactory *factory
- cdef void *src_ogr_geom
- cdef void *dst_ogr_geom
+ cdef OGRSpatialReferenceH src = NULL
+ cdef OGRSpatialReferenceH dst = NULL
+ cdef void *transform = NULL
+ cdef OGRGeometryFactory *factory = NULL
+ cdef void *src_ogr_geom = NULL
+ cdef void *dst_ogr_geom = NULL
cdef int i
if src_crs and dst_crs:
@@ -144,8 +149,8 @@ def _transform_geom(
_crs.OCTDestroyCoordinateTransformation(transform)
if options != NULL:
_csl.CSLDestroy(options)
- _crs.OSRDestroySpatialReference(src)
- _crs.OSRDestroySpatialReference(dst)
+ _crs.OSRRelease(src)
+ _crs.OSRRelease(dst)
else:
g = geom
if precision >= 0:
diff --git a/fiona/collection.py b/fiona/collection.py
index f19c1a7..ada8d6d 100644
--- a/fiona/collection.py
+++ b/fiona/collection.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Collections provide file-like access to feature data
-
+import logging
import os
import warnings
@@ -17,6 +17,9 @@ from fiona.drvsupport import supported_drivers
from six import string_types, binary_type
+log = logging.getLogger(__name__)
+
+
class Collection(object):
"""A file-like interface to features of a vector dataset
@@ -141,25 +144,24 @@ class Collection(object):
self.env = GDALEnv()
self.env.__enter__()
- if self.mode == "r":
- self._driver = driver
- self.encoding = encoding
- self.session = Session()
- self.session.start(self)
-
- # If encoding param is None, we'll use what the session
- # suggests.
- self.encoding = encoding or self.session.get_fileencoding().lower()
-
- elif self.mode in ("a", "w"):
- self._driver = driver
- self.encoding = encoding
- self.session = WritingSession()
- self.session.start(self, **kwargs)
- self.encoding = encoding or self.session.get_fileencoding().lower()
+ self._driver = driver
+ self.encoding = encoding
+
+ try:
+ if self.mode == 'r':
+ self.session = Session()
+ self.session.start(self)
+ elif self.mode in ('a', 'w'):
+ self.session = WritingSession()
+ self.session.start(self, **kwargs)
+ except IOError:
+ self.session = None
+ raise
- if self.session:
+ if self.session is not None:
self.guard_driver_mode()
+ if not self.encoding:
+ self.encoding = self.session.get_fileencoding().lower()
def __repr__(self):
return "<%s Collection '%s', mode '%s' at %s>" % (
@@ -399,7 +401,9 @@ class Collection(object):
if self.session is not None:
if self.mode in ('a', 'w'):
self.flush()
+ log.debug("Flushed buffer")
self.session.stop()
+ log.debug("Stopped session")
self.session = None
self.iterator = None
if self.env:
@@ -419,7 +423,7 @@ class Collection(object):
def __del__(self):
# Note: you can't count on this being called. Call close() explicitly
# or use the context manager protocol ("with").
- self.__exit__(None, None, None)
+ self.close()
def get_filetype(bytesbuf):
diff --git a/fiona/compat.py b/fiona/compat.py
index 28d761f..72b2791 100644
--- a/fiona/compat.py
+++ b/fiona/compat.py
@@ -2,7 +2,7 @@ import collections
from six.moves import UserDict
try:
from collections import OrderedDict
-except ImportError:
+except ImportError:
from ordereddict import OrderedDict
diff --git a/fiona/errors.py b/fiona/errors.py
index b868cea..489d2ea 100644
--- a/fiona/errors.py
+++ b/fiona/errors.py
@@ -21,8 +21,13 @@ class DataIOError(IOError):
"""IO errors involving driver registration or availability."""
+class DriverIOError(IOError):
+ """A format specific driver error."""
+
+
class FieldNameEncodeError(UnicodeEncodeError):
"""Failure to encode a field name."""
+
class UnsupportedGeometryTypeError(KeyError):
"""When a OGR geometry type isn't supported by Fiona."""
diff --git a/fiona/ogrext1.pxd b/fiona/ogrext1.pxd
index 752c85e..9a2ca4f 100644
--- a/fiona/ogrext1.pxd
+++ b/fiona/ogrext1.pxd
@@ -40,21 +40,23 @@ cdef extern from "ogr_core.h":
char * OGRGeometryTypeToName(int)
cdef extern from "ogr_srs_api.h":
+
+ ctypedef void * OGRSpatialReferenceH
+
void OSRCleanup ()
- void * OSRClone (void *srs)
- void OSRDestroySpatialReference (void *srs)
- int OSRExportToProj4 (void *srs, char **params)
- int OSRExportToWkt (void *srs, char **params)
- int OSRImportFromEPSG (void *srs, int code)
- int OSRImportFromProj4 (void *srs, char *proj)
- int OSRSetFromUserInput (void *srs, char *input)
- int OSRAutoIdentifyEPSG (void *srs)
- int OSRFixup(void *srs)
- const char * OSRGetAuthorityName (void *srs, const char *key)
- const char * OSRGetAuthorityCode (void *srs, const char *key)
- void * OSRNewSpatialReference (char *wkt)
- void OSRRelease (void *srs)
- void * OCTNewCoordinateTransformation (void *source, void *dest)
+ OGRSpatialReferenceH OSRClone (OGRSpatialReferenceH srs)
+ int OSRExportToProj4 (OGRSpatialReferenceH srs, char **params)
+ int OSRExportToWkt (OGRSpatialReferenceH srs, char **params)
+ int OSRImportFromEPSG (OGRSpatialReferenceH, int code)
+ int OSRImportFromProj4 (OGRSpatialReferenceH srs, const char *proj)
+ int OSRSetFromUserInput (OGRSpatialReferenceH srs, const char *input)
+ int OSRAutoIdentifyEPSG (OGRSpatialReferenceH srs)
+ int OSRFixup(OGRSpatialReferenceH srs)
+ const char * OSRGetAuthorityName (OGRSpatialReferenceH srs, const char *key)
+ const char * OSRGetAuthorityCode (OGRSpatialReferenceH srs, const char *key)
+ OGRSpatialReferenceH OSRNewSpatialReference (char *wkt)
+ void OSRRelease (OGRSpatialReferenceH srs)
+ void * OCTNewCoordinateTransformation (OGRSpatialReferenceH source, OGRSpatialReferenceH dest)
void OCTDestroyCoordinateTransformation (void *source)
int OCTTransform (void *ct, int nCount, double *x, double *y, double *z)
diff --git a/fiona/ogrext1.pyx b/fiona/ogrext1.pyx
index 442c3db..57d6c43 100644
--- a/fiona/ogrext1.pyx
+++ b/fiona/ogrext1.pyx
@@ -16,11 +16,13 @@ cimport ogrext1
from _geometry cimport (
GeomBuilder, OGRGeomBuilder, geometry_type_code,
normalize_geometry_type_code)
+from fiona._err cimport exc_wrap_pointer
+
from fiona._err import cpl_errs
from fiona._geometry import GEOMETRY_TYPES
from fiona import compat
from fiona.errors import (
- DriverError, SchemaError, CRSError, FionaValueError)
+ DriverError, DriverIOError, SchemaError, CRSError, FionaValueError)
from fiona.compat import OrderedDict
from fiona.rfc3339 import parse_date, parse_datetime, parse_time
from fiona.rfc3339 import FionaDateType, FionaDateTimeType, FionaTimeType
@@ -66,25 +68,25 @@ FIELD_TYPES_MAP = {
}
# OGR Driver capability
-ODrCCreateDataSource = b"CreateDataSource"
-ODrCDeleteDataSource = b"DeleteDataSource"
+cdef const char * ODrCCreateDataSource = "CreateDataSource"
+cdef const char * ODrCDeleteDataSource = "DeleteDataSource"
# OGR Layer capability
-OLC_RANDOMREAD = b"RandomRead"
-OLC_SEQUENTIALWRITE = b"SequentialWrite"
-OLC_RANDOMWRITE = b"RandomWrite"
-OLC_FASTSPATIALFILTER = b"FastSpatialFilter"
-OLC_FASTFEATURECOUNT = b"FastFeatureCount"
-OLC_FASTGETEXTENT = b"FastGetExtent"
-OLC_FASTSETNEXTBYINDEX = b"FastSetNextByIndex"
-OLC_CREATEFIELD = b"CreateField"
-OLC_CREATEGEOMFIELD = b"CreateGeomField"
-OLC_DELETEFIELD = b"DeleteField"
-OLC_REORDERFIELDS = b"ReorderFields"
-OLC_ALTERFIELDDEFN = b"AlterFieldDefn"
-OLC_DELETEFEATURE = b"DeleteFeature"
-OLC_STRINGSASUTF8 = b"StringsAsUTF8"
-OLC_TRANSACTIONS = b"Transactions"
+cdef const char * OLC_RANDOMREAD = "RandomRead"
+cdef const char * OLC_SEQUENTIALWRITE = "SequentialWrite"
+cdef const char * OLC_RANDOMWRITE = "RandomWrite"
+cdef const char * OLC_FASTSPATIALFILTER = "FastSpatialFilter"
+cdef const char * OLC_FASTFEATURECOUNT = "FastFeatureCount"
+cdef const char * OLC_FASTGETEXTENT = "FastGetExtent"
+cdef const char * OLC_FASTSETNEXTBYINDEX = "FastSetNextByIndex"
+cdef const char * OLC_CREATEFIELD = "CreateField"
+cdef const char * OLC_CREATEGEOMFIELD = "CreateGeomField"
+cdef const char * OLC_DELETEFIELD = "DeleteField"
+cdef const char * OLC_REORDERFIELDS = "ReorderFields"
+cdef const char * OLC_ALTERFIELDDEFN = "AlterFieldDefn"
+cdef const char * OLC_DELETEFEATURE = "DeleteFeature"
+cdef const char * OLC_STRINGSASUTF8 = "StringsAsUTF8"
+cdef const char * OLC_TRANSACTIONS = "Transactions"
# OGR integer error types.
@@ -217,7 +219,7 @@ cdef class FeatureBuilder:
props[key] = None
cdef void *cogr_geometry = ogrext1.OGR_F_GetGeometryRef(feature)
- if cogr_geometry is not NULL:
+ if cogr_geometry != NULL:
geom = GeomBuilder().build(cogr_geometry)
else:
geom = None
@@ -334,7 +336,7 @@ cdef class OGRFeatureBuilder:
cdef _deleteOgrFeature(void *cogr_feature):
"""Delete an OGR feature"""
- if cogr_feature is not NULL:
+ if cogr_feature != NULL:
ogrext1.OGR_F_Destroy(cogr_feature)
cogr_feature = NULL
@@ -360,7 +362,7 @@ def featureRT(feature, collection):
# Collection-related extension classes and functions
cdef class Session:
-
+
cdef void *cogr_ds
cdef void *cogr_layer
cdef object _fileencoding
@@ -451,7 +453,7 @@ cdef class Session:
def stop(self):
self.cogr_layer = NULL
- if self.cogr_ds is not NULL:
+ if self.cogr_ds != NULL:
ogrext1.OGR_DS_Destroy(self.cogr_ds)
self.cogr_ds = NULL
@@ -552,7 +554,7 @@ cdef class Session:
raise ValueError("Null layer")
cogr_crs = ogrext1.OGR_L_GetSpatialRef(self.cogr_layer)
crs = {}
- if cogr_crs is not NULL:
+ if cogr_crs != NULL:
log.debug("Got coordinate system")
retval = ogrext1.OSRAutoIdentifyEPSG(cogr_crs)
@@ -606,7 +608,7 @@ cdef class Session:
raise ValueError("Null layer")
cogr_crs = ogrext1.OGR_L_GetSpatialRef(self.cogr_layer)
crs_wkt = ""
- if cogr_crs is not NULL:
+ if cogr_crs != NULL:
log.debug("Got coordinate system")
ogrext1.OSRExportToWkt(cogr_crs, &proj_c)
if proj_c == NULL:
@@ -696,8 +698,8 @@ cdef class WritingSession(Session):
def start(self, collection):
cdef void *cogr_fielddefn
cdef void *cogr_driver
- cdef void *cogr_ds
- cdef void *cogr_layer
+ cdef void *cogr_ds = NULL
+ cdef void *cogr_layer = NULL
cdef void *cogr_srs = NULL
cdef char **options = NULL
self.collection = collection
@@ -751,29 +753,40 @@ cdef class WritingSession(Session):
except UnicodeError:
path_b = path
path_c = path_b
+
driver_b = collection.driver.encode()
driver_c = driver_b
+ # TODO: use exc_wrap_pointer()
cogr_driver = ogrext1.OGRGetDriverByName(driver_c)
if cogr_driver == NULL:
raise ValueError("Null driver")
+ # Our most common use case is the creation of a new data
+ # file and historically we've assumed that it's a file on
+ # the local filesystem and queryable via os.path.
+ #
+ # TODO: remove the assumption.
+ # TODO: use exc_wrap_pointer().
if not os.path.exists(path):
cogr_ds = ogrext1.OGR_Dr_CreateDataSource(
cogr_driver, path_c, NULL)
else:
- with cpl_errs:
- cogr_ds = ogrext1.OGROpen(path_c, 1, NULL)
+ cogr_ds = ogrext1.OGROpen(path_c, 1, NULL)
if cogr_ds == NULL:
- cogr_ds = ogrext1.OGR_Dr_CreateDataSource(
- cogr_driver, path_c, NULL)
+ try:
+ cogr_ds = exc_wrap_pointer(
+ ogrext1.OGR_Dr_CreateDataSource(
+ cogr_driver, path_c, NULL))
+ except Exception as exc:
+ raise DriverIOError(str(exc))
elif collection.name is None:
ogrext1.OGR_DS_Destroy(cogr_ds)
- cogr_ds == NULL
+ cogr_ds = NULL
log.debug("Deleted pre-existing data at %s", path)
-
+
cogr_ds = ogrext1.OGR_Dr_CreateDataSource(
cogr_driver, path_c, NULL)
@@ -866,21 +879,26 @@ cdef class WritingSession(Session):
# Create the named layer in the datasource.
name_b = collection.name.encode('utf-8')
name_c = name_b
- self.cogr_layer = ogrext1.OGR_DS_CreateLayer(
- self.cogr_ds,
- name_c,
- cogr_srs,
- geometry_type_code(
- collection.schema.get('geometry', 'Unknown')),
- options)
-
- if cogr_srs != NULL:
- ogrext1.OSRDestroySpatialReference(cogr_srs)
- if options != NULL:
- ogrext1.CSLDestroy(options)
-
- if self.cogr_layer == NULL:
- raise ValueError("Null layer")
+
+ try:
+ self.cogr_layer = exc_wrap_pointer(
+ ogrext1.OGR_DS_CreateLayer(
+ self.cogr_ds, name_c, cogr_srs,
+ geometry_type_code(
+ collection.schema.get('geometry', 'Unknown')),
+ options))
+ except Exception as exc:
+ raise DriverError(str(exc))
+ finally:
+ # Shapefile layers make a copy of the passed srs. GPKG
+ # layers, on the other hand, increment its reference
+ # count. OSRRelease() is the safe way to release
+ # OGRSpatialReferenceH.
+ if cogr_srs != NULL:
+ ogrext1.OSRRelease(cogr_srs)
+ if options != NULL:
+ ogrext1.CSLDestroy(options)
+
log.debug("Created layer")
# Next, make a layer definition from the given schema properties,
@@ -1240,7 +1258,7 @@ def _listlayers(path):
layer_names.append(name_b.decode('utf-8'))
# Close up data source.
- if cogr_ds is not NULL:
+ if cogr_ds != NULL:
ogrext1.OGR_DS_Destroy(cogr_ds)
cogr_ds = NULL
diff --git a/fiona/ogrext2.pxd b/fiona/ogrext2.pxd
index 0a3aa29..f3579f9 100644
--- a/fiona/ogrext2.pxd
+++ b/fiona/ogrext2.pxd
@@ -19,7 +19,6 @@ cdef extern from "gdal.h":
void * GDALDatasetGetLayer(void * hDS, int iLayer)
void * GDALDatasetGetLayerByName(void * hDS, char * pszName)
void GDALClose(void * hDS)
- void * GDALGetDatasetDriver(void * hDataset)
void * GDALCreate(void * hDriver,
const char * pszFilename,
int nXSize,
@@ -80,36 +79,43 @@ cdef extern from "cpl_vsi.h":
int take_ownership)
int VSIUnlink (const char * pathname)
-ctypedef int OGRErr
-ctypedef struct OGREnvelope:
- double MinX
- double MaxX
- double MinY
- double MaxY
cdef extern from "ogr_core.h":
+
+ ctypedef int OGRErr
+
+ ctypedef struct OGREnvelope:
+ double MinX
+ double MaxX
+ double MinY
+ double MaxY
+
char * OGRGeometryTypeToName(int)
+
cdef extern from "ogr_srs_api.h":
+
+ ctypedef void * OGRSpatialReferenceH
+
void OSRCleanup ()
- void * OSRClone (void *srs)
- void OSRDestroySpatialReference (void *srs)
- int OSRExportToProj4 (void *srs, char **params)
- int OSRExportToWkt (void *srs, char **params)
- int OSRImportFromEPSG (void *srs, int code)
- int OSRImportFromProj4 (void *srs, char *proj)
- int OSRSetFromUserInput (void *srs, char *input)
- int OSRAutoIdentifyEPSG (void *srs)
- int OSRFixup(void *srs)
- const char * OSRGetAuthorityName (void *srs, const char *key)
- const char * OSRGetAuthorityCode (void *srs, const char *key)
- void * OSRNewSpatialReference (char *wkt)
- void OSRRelease (void *srs)
- void * OCTNewCoordinateTransformation (void *source, void *dest)
+ OGRSpatialReferenceH OSRClone (OGRSpatialReferenceH srs)
+ int OSRExportToProj4 (OGRSpatialReferenceH srs, char **params)
+ int OSRExportToWkt (OGRSpatialReferenceH srs, char **params)
+ int OSRImportFromEPSG (OGRSpatialReferenceH, int code)
+ int OSRImportFromProj4 (OGRSpatialReferenceH srs, const char *proj)
+ int OSRSetFromUserInput (OGRSpatialReferenceH srs, const char *input)
+ int OSRAutoIdentifyEPSG (OGRSpatialReferenceH srs)
+ int OSRFixup(OGRSpatialReferenceH srs)
+ const char * OSRGetAuthorityName (OGRSpatialReferenceH srs, const char *key)
+ const char * OSRGetAuthorityCode (OGRSpatialReferenceH srs, const char *key)
+ OGRSpatialReferenceH OSRNewSpatialReference (char *wkt)
+ void OSRRelease (OGRSpatialReferenceH srs)
+ void * OCTNewCoordinateTransformation (OGRSpatialReferenceH source, OGRSpatialReferenceH dest)
void OCTDestroyCoordinateTransformation (void *source)
int OCTTransform (void *ct, int nCount, double *x, double *y, double *z)
cdef extern from "ogr_api.h":
+
char * OGR_Dr_GetName (void *driver)
void * OGR_Dr_CreateDataSource (void *driver, const char *path, char **options)
int OGR_Dr_DeleteDataSource (void *driver, char *)
diff --git a/fiona/ogrext2.pyx b/fiona/ogrext2.pyx
index 82eaec4..3a0d416 100644
--- a/fiona/ogrext2.pyx
+++ b/fiona/ogrext2.pyx
@@ -13,13 +13,17 @@ import uuid
from six import integer_types, string_types, text_type
cimport ogrext2
+from ogrext2 cimport OGREnvelope
from _geometry cimport (
GeomBuilder, OGRGeomBuilder, geometry_type_code,
normalize_geometry_type_code)
+from fiona._err cimport exc_wrap_pointer
+
from fiona._err import cpl_errs
from fiona._geometry import GEOMETRY_TYPES
from fiona import compat
-from fiona.errors import DriverError, SchemaError, CRSError, FionaValueError
+from fiona.errors import (
+ DriverError, DriverIOError, SchemaError, CRSError, FionaValueError)
from fiona.compat import OrderedDict
from fiona.rfc3339 import parse_date, parse_datetime, parse_time
from fiona.rfc3339 import FionaDateType, FionaDateTimeType, FionaTimeType
@@ -29,11 +33,6 @@ from libc.string cimport strcmp
log = logging.getLogger("Fiona")
-class NullHandler(logging.Handler):
- def emit(self, record):
- pass
-log.addHandler(NullHandler())
-
# Mapping of OGR integer field types to Fiona field type names.
#
@@ -68,25 +67,25 @@ FIELD_TYPES_MAP = {
}
# OGR Driver capability
-ODrCCreateDataSource = b"CreateDataSource"
-ODrCDeleteDataSource = b"DeleteDataSource"
+cdef const char * ODrCCreateDataSource = "CreateDataSource"
+cdef const char * ODrCDeleteDataSource = "DeleteDataSource"
# OGR Layer capability
-OLC_RANDOMREAD = b"RandomRead"
-OLC_SEQUENTIALWRITE = b"SequentialWrite"
-OLC_RANDOMWRITE = b"RandomWrite"
-OLC_FASTSPATIALFILTER = b"FastSpatialFilter"
-OLC_FASTFEATURECOUNT = b"FastFeatureCount"
-OLC_FASTGETEXTENT = b"FastGetExtent"
-OLC_FASTSETNEXTBYINDEX = b"FastSetNextByIndex"
-OLC_CREATEFIELD = b"CreateField"
-OLC_CREATEGEOMFIELD = b"CreateGeomField"
-OLC_DELETEFIELD = b"DeleteField"
-OLC_REORDERFIELDS = b"ReorderFields"
-OLC_ALTERFIELDDEFN = b"AlterFieldDefn"
-OLC_DELETEFEATURE = b"DeleteFeature"
-OLC_STRINGSASUTF8 = b"StringsAsUTF8"
-OLC_TRANSACTIONS = b"Transactions"
+cdef const char * OLC_RANDOMREAD = "RandomRead"
+cdef const char * OLC_SEQUENTIALWRITE = "SequentialWrite"
+cdef const char * OLC_RANDOMWRITE = "RandomWrite"
+cdef const char * OLC_FASTSPATIALFILTER = "FastSpatialFilter"
+cdef const char * OLC_FASTFEATURECOUNT = "FastFeatureCount"
+cdef const char * OLC_FASTGETEXTENT = "FastGetExtent"
+cdef const char * OLC_FASTSETNEXTBYINDEX = "FastSetNextByIndex"
+cdef const char * OLC_CREATEFIELD = "CreateField"
+cdef const char * OLC_CREATEGEOMFIELD = "CreateGeomField"
+cdef const char * OLC_DELETEFIELD = "DeleteField"
+cdef const char * OLC_REORDERFIELDS = "ReorderFields"
+cdef const char * OLC_ALTERFIELDDEFN = "AlterFieldDefn"
+cdef const char * OLC_DELETEFEATURE = "DeleteFeature"
+cdef const char * OLC_STRINGSASUTF8 = "StringsAsUTF8"
+cdef const char * OLC_TRANSACTIONS = "Transactions"
# OGR integer error types.
@@ -156,7 +155,7 @@ cdef class FeatureBuilder:
cdef int ss = 0
cdef int tz = 0
cdef int retval
- cdef char *key_c
+ cdef const char *key_c = NULL
props = OrderedDict()
for i in range(ogrext2.OGR_F_GetFieldCount(feature)):
fdefn = ogrext2.OGR_F_GetFieldDefnRef(feature, i)
@@ -239,7 +238,7 @@ cdef class OGRFeatureBuilder:
cdef void * build(self, feature, collection) except NULL:
cdef void *cogr_geometry = NULL
- cdef char *string_c
+ cdef const char *string_c = NULL
cdef WritingSession session
session = collection.session
cdef void *cogr_layer = session.cogr_layer
@@ -417,7 +416,7 @@ cdef class Session:
flags = ogrext2.GDAL_OF_VECTOR | ogrext2.GDAL_OF_READONLY
try:
self.cogr_ds = ogrext2.GDALOpenEx(
- path_c, flags, drvs, NULL, NULL)
+ path_c, flags, <const char *const *>drvs, NULL, NULL)
finally:
ogrext2.CSLDestroy(drvs)
@@ -458,7 +457,7 @@ cdef class Session:
def stop(self):
self.cogr_layer = NULL
- if self.cogr_ds is not NULL:
+ if self.cogr_ds != NULL:
ogrext2.GDALClose(self.cogr_ds)
self.cogr_ds = NULL
@@ -483,7 +482,7 @@ cdef class Session:
cdef void *cogr_driver = ogrext2.GDALGetDatasetDriver(self.cogr_ds)
if cogr_driver == NULL:
raise ValueError("Null driver")
- cdef char *name = ogrext2.OGR_Dr_GetName(cogr_driver)
+ cdef const char *name = ogrext2.OGR_Dr_GetName(cogr_driver)
driver_name = name
return driver_name.decode()
@@ -492,7 +491,7 @@ cdef class Session:
cdef int n
cdef void *cogr_featuredefn
cdef void *cogr_fielddefn
- cdef char *key_c
+ cdef const char *key_c
props = []
if self.cogr_layer == NULL:
@@ -552,8 +551,8 @@ cdef class Session:
def get_crs(self):
cdef char *proj_c = NULL
- cdef char *auth_key = NULL
- cdef char *auth_val = NULL
+ cdef const char *auth_key = NULL
+ cdef const char *auth_val = NULL
cdef void *cogr_crs = NULL
if self.cogr_layer == NULL:
raise ValueError("Null layer")
@@ -626,9 +625,11 @@ cdef class Session:
return crs_wkt
def get_extent(self):
+ cdef OGREnvelope extent
+
if self.cogr_layer == NULL:
raise ValueError("Null layer")
- cdef ogrext2.OGREnvelope extent
+
result = ogrext2.OGR_L_GetExtent(self.cogr_layer, &extent, 1)
return (extent.MinX, extent.MinY, extent.MaxX, extent.MaxY)
@@ -701,18 +702,18 @@ cdef class WritingSession(Session):
cdef object _schema_mapping
def start(self, collection):
- cdef void *cogr_fielddefn
- cdef void *cogr_driver
- cdef void *cogr_ds
- cdef void *cogr_layer
+ cdef void *cogr_fielddefn = NULL
+ cdef void *cogr_driver = NULL
+ cdef void *cogr_ds = NULL
+ cdef void *cogr_layer = NULL
cdef void *cogr_srs = NULL
cdef char **options = NULL
self.collection = collection
- cdef char *path_c
- cdef char *driver_c
- cdef char *name_c
- cdef char *proj_c
- cdef char *fileencoding_c
+ cdef const char *path_c = NULL
+ cdef const char *driver_c = NULL
+ cdef const char *name_c = NULL
+ cdef const char *proj_c = NULL
+ cdef const char *fileencoding_c = NULL
path = collection.path
if collection.mode == 'a':
@@ -722,15 +723,10 @@ cdef class WritingSession(Session):
except UnicodeDecodeError:
path_b = path
path_c = path_b
- with cpl_errs:
- self.cogr_ds = ogrext2.GDALOpenEx(path_c,
- ogrext2.GDAL_OF_VECTOR | ogrext2.GDAL_OF_UPDATE,
- NULL,
- NULL,
- NULL)
-# self.cogr_ds = ogrext2.OGROpen(path_c, 1, NULL)
- if self.cogr_ds == NULL:
- raise RuntimeError("Failed to open %s" % path)
+ self.cogr_ds = ogrext2.GDALOpenEx(path_c,
+ ogrext2.GDAL_OF_VECTOR | ogrext2.GDAL_OF_UPDATE,
+ NULL, NULL, NULL)
+
cogr_driver = ogrext2.GDALGetDatasetDriver(self.cogr_ds)
if cogr_driver == NULL:
raise ValueError("Null driver")
@@ -763,6 +759,7 @@ cdef class WritingSession(Session):
except UnicodeDecodeError:
path_b = path
path_c = path_b
+
driver_b = collection.driver.encode()
driver_c = driver_b
@@ -770,27 +767,32 @@ cdef class WritingSession(Session):
if cogr_driver == NULL:
raise ValueError("Null driver")
+ # Our most common use case is the creation of a new data
+ # file and historically we've assumed that it's a file on
+ # the local filesystem and queryable via os.path.
+ #
+ # TODO: remove the assumption.
if not os.path.exists(path):
-# cogr_ds = ogrext2.OGR_Dr_CreateDataSource(
-# cogr_driver, path_c, NULL)
- cogr_ds = ogrext2.GDALCreate(
+ cogr_ds = exc_wrap_pointer(ogrext2.GDALCreate(
cogr_driver,
path_c,
0,
0,
0,
ogrext2.GDT_Unknown,
- NULL)
- pass
+ NULL))
+ # TODO: revisit the logic in the following blocks when we
+ # change the assumption above.
+ # TODO: use exc_wrap_pointer()
else:
- with cpl_errs:
- cogr_ds = ogrext2.GDALOpenEx(path_c,
- ogrext2.GDAL_OF_VECTOR | ogrext2.GDAL_OF_UPDATE,
- NULL,
- NULL,
- NULL)
-# cogr_ds = ogrext2.OGROpen(path_c, 1, NULL)
+ cogr_ds = ogrext2.GDALOpenEx(path_c,
+ ogrext2.GDAL_OF_VECTOR | ogrext2.GDAL_OF_UPDATE,
+ NULL,
+ NULL,
+ NULL)
+
+ # TODO: use exc_wrap_pointer()
if cogr_ds == NULL:
cogr_ds = ogrext2.GDALCreate(
cogr_driver,
@@ -800,12 +802,10 @@ cdef class WritingSession(Session):
0,
ogrext2.GDT_Unknown,
NULL)
-# cogr_ds = ogrext2.OGR_Dr_CreateDataSource(
-# cogr_driver, path_c, NULL)
elif collection.name is None:
ogrext2.GDALClose(cogr_ds)
- cogr_ds == NULL
+ cogr_ds = NULL
log.debug("Deleted pre-existing data at %s", path)
cogr_ds = ogrext2.GDALCreate(
cogr_driver,
@@ -815,8 +815,6 @@ cdef class WritingSession(Session):
0,
ogrext2.GDT_Unknown,
NULL)
-# cogr_ds = ogrext2.OGR_Dr_CreateDataSource(
-# cogr_driver, path_c, NULL)
else:
pass
@@ -877,11 +875,14 @@ cdef class WritingSession(Session):
collection.driver == "ESRI Shapefile" and
'ISO-8859-1') or sysencoding).upper()
+ # The ENCODING option makes no sense for some drivers and
+ # will result in a warning. Fixing is a TODO.
fileencoding = self.get_fileencoding()
if fileencoding:
fileencoding_b = fileencoding.encode()
fileencoding_c = fileencoding_b
- options = ogrext2.CSLSetNameValue(options, "ENCODING", fileencoding_c)
+ with cpl_errs:
+ options = ogrext2.CSLSetNameValue(options, "ENCODING", fileencoding_c)
# Does the layer exist already? If so, we delete it.
layer_count = ogrext2.GDALDatasetGetLayerCount(self.cogr_ds)
@@ -906,22 +907,31 @@ cdef class WritingSession(Session):
# Create the named layer in the datasource.
name_b = collection.name.encode('utf-8')
name_c = name_b
- self.cogr_layer = ogrext2.GDALDatasetCreateLayer(
- self.cogr_ds,
- name_c,
- cogr_srs,
- geometry_type_code(
- collection.schema.get('geometry', 'Unknown')),
- options)
-
- if cogr_srs != NULL:
- ogrext2.OSRDestroySpatialReference(cogr_srs)
- if options != NULL:
- ogrext2.CSLDestroy(options)
+
+ try:
+ self.cogr_layer = exc_wrap_pointer(
+ ogrext2.GDALDatasetCreateLayer(
+ self.cogr_ds, name_c, cogr_srs,
+ geometry_type_code(
+ collection.schema.get('geometry', 'Unknown')),
+ options))
+ except Exception as exc:
+ raise DriverIOError(str(exc))
+ finally:
+ if options != NULL:
+ ogrext2.CSLDestroy(options)
+
+ # Shapefile layers make a copy of the passed srs. GPKG
+ # layers, on the other hand, increment its reference
+ # count. OSRRelease() is the safe way to release
+ # OGRSpatialReferenceH.
+ if cogr_srs != NULL:
+ ogrext2.OSRRelease(cogr_srs)
if self.cogr_layer == NULL:
raise ValueError("Null layer")
- log.debug("Created layer")
+
+ log.debug("Created layer %s", collection.name)
# Next, make a layer definition from the given schema properties,
# which are an ordered dict since Fiona 1.0.1.
@@ -1028,10 +1038,12 @@ cdef class WritingSession(Session):
cdef void *cogr_layer = self.cogr_layer
if cogr_ds == NULL:
raise ValueError("Null data source")
- log.debug("Syncing OGR to disk")
- ogrext2.GDALFlushCache(cogr_ds)
+ with cpl_errs:
+ ogrext2.GDALFlushCache(cogr_ds)
+
+ log.debug("Flushed data source cache")
cdef class Iterator:
@@ -1261,8 +1273,8 @@ def _listlayers(path):
cdef void *cogr_ds
cdef void *cogr_layer
- cdef char *path_c
- cdef char *name_c
+ cdef const char *path_c
+ cdef const char *name_c
# Open OGR data source.
try:
@@ -1290,7 +1302,7 @@ def _listlayers(path):
layer_names.append(name_b.decode('utf-8'))
# Close up data source.
- if cogr_ds is not NULL:
+ if cogr_ds != NULL:
ogrext2.GDALClose(cogr_ds)
cogr_ds = NULL
diff --git a/setup.py b/setup.py
index e3fac13..f794f60 100644
--- a/setup.py
+++ b/setup.py
@@ -222,12 +222,15 @@ requirements = [
'cligj',
'click-plugins',
'six',
- 'munch'
-]
+ 'munch']
+
if sys.version_info < (2, 7):
requirements.append('argparse')
requirements.append('ordereddict')
+if sys.version_info < (3, 4):
+ requirements.append('enum34')
+
setup_args = dict(
cmdclass={'sdist': sdist_multi_gdal},
metadata_version='1.2',
diff --git a/tests/test_drivers.py b/tests/test_drivers.py
index 63f3e28..9d88aa9 100644
--- a/tests/test_drivers.py
+++ b/tests/test_drivers.py
@@ -8,7 +8,7 @@ import unittest
import fiona
-logging.basicConfig(stream=sys.stderr, level=logging.INFO)
+logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
FIXME_WINDOWS = sys.platform.startswith('win')
diff --git a/tests/test_geojson.py b/tests/test_geojson.py
index 60d95cd..b7d2d7f 100644
--- a/tests/test_geojson.py
+++ b/tests/test_geojson.py
@@ -10,7 +10,10 @@ import fiona
from fiona.collection import supported_drivers
from fiona.errors import FionaValueError, DriverError, SchemaError, CRSError
-logging.basicConfig(stream=sys.stderr, level=logging.INFO)
+
+# logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
+
+log = logging.getLogger(__name__)
class ReadingTest(unittest.TestCase):
@@ -46,3 +49,24 @@ class WritingTest(unittest.TestCase):
with fiona.open(path) as c:
self.assertEqual(c.schema['geometry'], 'Unknown')
self.assertEqual(len(c), 2)
+
+ def test_json_overwrite(self):
+ path = os.path.join(self.tempdir, 'foo.json')
+
+ with fiona.drivers(), fiona.open(path, 'w',
+ driver='GeoJSON',
+ schema={'geometry': 'Unknown', 'properties': [('title', 'str')]}) as c:
+ c.writerecords([{
+ 'geometry': {'type': 'Point', 'coordinates': [0.0, 0.0]},
+ 'properties': {'title': 'One'}}])
+ c.writerecords([{
+ 'geometry': {'type': 'MultiPoint', 'coordinates': [[0.0, 0.0]]},
+ 'properties': {'title': 'Two'}}])
+
+ # Overwrite should raise DriverIOError.
+ try:
+ with fiona.drivers(), fiona.open(path, 'w', driver='GeoJSON',
+ schema={'geometry': 'Unknown', 'properties': [('title', 'str')]}) as c:
+ pass
+ except IOError:
+ pass
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/fiona.git
More information about the Pkg-grass-devel
mailing list