Skip to content

Commit

Permalink
Merge 024fc4b into ce6ac7c
Browse files Browse the repository at this point in the history
  • Loading branch information
sgillies committed Nov 13, 2018
2 parents ce6ac7c + 024fc4b commit d694c3c
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 157 deletions.
7 changes: 4 additions & 3 deletions fiona/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ class Path:
from fiona.env import ensure_env_with_credentials, Env
from fiona.errors import FionaDeprecationWarning
from fiona._env import driver_count
from fiona._env import (
calc_gdal_version_num, get_gdal_version_num, get_gdal_release_name,
get_gdal_version_tuple)
from fiona.compat import OrderedDict
from fiona.io import MemoryFile
from fiona.ogrext import _bounds, _listlayers, FIELD_TYPES_MAP, _remove, _remove_layer
from fiona.ogrext import (
calc_gdal_version_num, get_gdal_version_num, get_gdal_release_name,
get_gdal_version_tuple)
from fiona.path import ParsedPath, parse_path, vsi_path
from fiona.vfs import parse_paths as vfs_parse_paths

Expand All @@ -107,6 +107,7 @@ class Path:
gdal_version = get_gdal_version_tuple()

log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())


@ensure_env_with_credentials
Expand Down
60 changes: 53 additions & 7 deletions fiona/_env.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ option is set to a new value inside the thread.

include "gdal.pxi"

from collections import namedtuple
import logging
import os
import os.path
import sys
import threading

from fiona.ogrext import get_gdal_version_tuple


level_map = {
0: 0,
Expand Down Expand Up @@ -55,14 +54,61 @@ log = logging.getLogger(__name__)
cdef bint is_64bit = sys.maxsize > 2 ** 32


def calc_gdal_version_num(maj, min, rev):
"""Calculates the internal gdal version number based on major, minor and revision
GDAL Version Information macro changed with GDAL version 1.10.0 (April 2013)
"""
if (maj, min, rev) >= (1, 10, 0):
return int(maj * 1000000 + min * 10000 + rev * 100)
else:
return int(maj * 1000 + min * 100 + rev * 10)


def get_gdal_version_num():
"""Return current internal version number of gdal"""
return int(GDALVersionInfo("VERSION_NUM"))


def get_gdal_release_name():
"""Return release name of gdal"""
cdef const char *name_c = NULL
name_c = GDALVersionInfo("RELEASE_NAME")
name = name_c
return name


GDALVersion = namedtuple("GDALVersion", ["major", "minor", "revision"])


def get_gdal_version_tuple():
"""
Calculates gdal version tuple from gdal's internal version number.
GDAL Version Information macro changed with GDAL version 1.10.0 (April 2013)
"""
gdal_version_num = get_gdal_version_num()

if gdal_version_num >= calc_gdal_version_num(1, 10, 0):
major = gdal_version_num // 1000000
minor = (gdal_version_num - (major * 1000000)) // 10000
revision = (gdal_version_num - (major * 1000000) - (minor * 10000)) // 100
return GDALVersion(major, minor, revision)
else:
major = gdal_version_num // 1000
minor = (gdal_version_num - (major * 1000)) // 100
revision = (gdal_version_num - (major * 1000) - (minor * 100)) // 10
return GDALVersion(major, minor, revision)


cdef void log_error(CPLErr err_class, int err_no, const char* msg) with gil:
"""Send CPL debug messages and warnings to Python's logger."""
log = logging.getLogger(__name__)
if err_class < 3:
if err_no in code_map:
log.log(level_map[err_class], "%s in %s", code_map[err_no], msg)
else:
log.info("Unknown error number %r", err_no)
if err_no in code_map:
log.log(level_map[err_class], "%s", msg)
else:
log.info("Unknown error number %r", err_no)


# Definition of GDAL callback functions, one for Windows and one for
Expand Down
13 changes: 6 additions & 7 deletions fiona/_err.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,12 @@ 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
else:
# null pointer was passed, but no error message from GDAL
raise FionaNullPointerError(-1, -1, "NULL pointer error")
exc = exc_check()
if exc:
raise exc
elif ptr == NULL:
# null pointer was passed, but no error message from GDAL
raise FionaNullPointerError(-1, -1, "NULL pointer error")
return ptr


Expand Down
4 changes: 2 additions & 2 deletions fiona/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
from fiona import compat, vfs
from fiona.ogrext import Iterator, ItemsIterator, KeysIterator
from fiona.ogrext import Session, WritingSession
from fiona.ogrext import (
calc_gdal_version_num, get_gdal_version_num, get_gdal_release_name)
from fiona.ogrext import buffer_to_virtual_file, remove_virtual_file, GEOMETRY_TYPES
from fiona.errors import (DriverError, SchemaError, CRSError, UnsupportedGeometryTypeError, DriverSupportError)
from fiona.logutils import FieldSkipLogFilter
from fiona._env import driver_count
from fiona._env import (
calc_gdal_version_num, get_gdal_version_num, get_gdal_release_name)
from fiona.env import Env
from fiona.errors import FionaDeprecationWarning
from fiona.drvsupport import supported_drivers
Expand Down
97 changes: 68 additions & 29 deletions fiona/env.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Fiona's GDAL/AWS environment"""

from contextlib import contextmanager
from functools import wraps, total_ordering
import logging
import re
Expand All @@ -9,7 +10,8 @@
from six import string_types

from fiona._env import (
GDALEnv, get_gdal_config, set_gdal_config)
GDALEnv, calc_gdal_version_num, get_gdal_version_num, get_gdal_config,
set_gdal_config, get_gdal_release_name)
from fiona.compat import getargspec
from fiona.errors import EnvError, GDALVersionError
from fiona.session import Session, DummySession
Expand Down Expand Up @@ -160,15 +162,16 @@ def __init__(
self.context_options = {}

@classmethod
def from_defaults(cls, *args, **kwargs):
def from_defaults(cls, session=None, **options):
"""Create an environment with default config options
Parameters
----------
args : optional
Positional arguments for Env()
kwargs : optional
Keyword arguments for Env()
session : optional
A Session object.
**options : optional
A mapping of GDAL configuration options, e.g.,
`CPL_DEBUG=True, CHECK_WITH_INVERT_PROJ=False`.
Returns
-------
Expand All @@ -179,9 +182,9 @@ def from_defaults(cls, *args, **kwargs):
The items in kwargs will be overlaid on the default values.
"""
options = Env.default_options()
options.update(**kwargs)
return Env(*args, **options)
opts = Env.default_options()
opts.update(**options)
return Env(session=session, **opts)

@property
def is_credentialized(self):
Expand Down Expand Up @@ -313,16 +316,55 @@ def delenv():
local._env = None


class NullContextManager(object):
def __init__(self):
pass
def __enter__(self):
return self
def __exit__(self, *args):
pass


def env_ctx_if_needed():
"""Return an Env if one does not exist
Returns
-------
Env or a do-nothing context manager
"""
if local._env:
return NullContextManager()
else:
return Env.from_defaults()


def ensure_env(f):
"""A decorator that ensures an env exists before a function
calls any GDAL C functions."""
calls any GDAL C functions.
Parameters
----------
f : function
A function.
Returns
-------
A function wrapper.
Notes
-----
If there is already an existing environment, the wrapper does
nothing and immediately calls f with the given arguments.
"""
@wraps(f)
def wrapper(*args, **kwds):
def wrapper(*args, **kwargs):
if local._env:
return f(*args, **kwds)
return f(*args, **kwargs)
else:
with Env.from_defaults():
return f(*args, **kwds)
return f(*args, **kwargs)
return wrapper


Expand All @@ -344,25 +386,23 @@ def ensure_env_with_credentials(f):
credentializes the environment if the first argument is a URI with
scheme "s3".
If there is already an existing environment, the wrapper does
nothing and immediately calls f with the given arguments.
"""
@wraps(f)
def wrapper(*args, **kwds):
def wrapper(*args, **kwargs):
if local._env:
env_ctor = Env
else:
env_ctor = Env.from_defaults

if hascreds():
session = DummySession()
elif isinstance(args[0], str):
session = Session.from_path(args[0])
return f(*args, **kwargs)
else:
session = Session.from_path(None)

with env_ctor(session=session):
log.debug("Credentialized: {!r}".format(getenv()))
return f(*args, **kwds)

if isinstance(args[0], str):
session = Session.from_path(args[0])
else:
session = Session.from_path(None)

with Env.from_defaults(session=session):
log.debug("Credentialized: {!r}".format(getenv()))
return f(*args, **kwargs)
return wrapper


Expand Down Expand Up @@ -425,7 +465,6 @@ def parse(cls, input):
@classmethod
def runtime(cls):
"""Return GDALVersion of current GDAL runtime"""
from fiona.ogrext import get_gdal_release_name # to avoid circular import
return cls.parse(get_gdal_release_name())

def at_least(self, other):
Expand Down

0 comments on commit d694c3c

Please sign in to comment.