[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