This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository rasterio.
commit 3f08f964811ee2d77d2ef1956178c4ace7b9a411 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Sat May 7 14:28:11 2016 +0200 Imported Upstream version 0.35.1 --- CHANGES.txt | 13 +++++++++++ MANIFEST.in | 1 + docs/vsi.rst | 65 +++++++++++++++++++++++++--------------------------- rasterio/__init__.py | 12 ++++------ rasterio/env.py | 7 ++++++ rasterio/features.py | 13 ++++------- rasterio/fill.py | 5 ++-- rasterio/vfs.py | 18 ++++++++++++--- rasterio/warp.py | 11 +++++---- tests/test_env.py | 9 +++++++- tests/test_vfs.py | 8 +++---- 11 files changed, 97 insertions(+), 65 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 4a76f88..8df10f8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,19 @@ Changes ======= +0.35.1 (2016-05-06) +------------------- +- Bug fix: restore support for URI-like GDAL dataset names such as + 'NETCDF:foo:bar' (#695). +- Bug fix: ensure GDAL environment is initialized for `transform_bounds()` as + well as the other functions in `rasterio.warp` (#694). In implementation, we + have done this with a function decorator. + +0.35.0.post1 (2016-05-04) +------------------------- +- Bug fix: added rasterfill.cpp to MANIFEST.in so it is included in source + distributions no matter the build system's GDAL version (#690). + 0.35.0 (2016-05-04) ------------------- - Requirements: affine requirement upped to >=1.3.0 (#430). diff --git a/MANIFEST.in b/MANIFEST.in index 5fa402e..142cee1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ exclude *.rst *.txt *.py include CHANGES.txt AUTHORS.txt LICENSE.txt VERSION.txt README.rst setup.py +include rasterio/rasterfill.cpp recursive-include examples *.py recursive-include tests *.py *.rst recursive-exclude tests/data *.tif diff --git a/docs/vsi.rst b/docs/vsi.rst index a7ef9c8..94bfed0 100644 --- a/docs/vsi.rst +++ b/docs/vsi.rst @@ -1,7 +1,7 @@ Virtual Files ************* -.. todo:: +.. todo:: Support for URIs describing zip, s3, etc resources. Relationship to GDAL vsicurl et al. @@ -9,44 +9,41 @@ Virtual Files AWS S3 ====== +.. note:: + Requires GDAL 2.1.0 + +This is an extra feature that must be installed by executing + +.. code-block:: console + + pip install rasterio[s3] + After you have configured your AWS credentials as explained in the `boto3 guide <http://boto3.readthedocs.org/en/latest/guide/configuration.html>`__ you can -read metadata and imagery from TIFFs stored as S3 objects with little change to -your code. Add a `rasterio.aws.Session` as shown below. - -.. code-block:: pycon - - >>> import pprint - >>> from rasterio.aws import Session - >>> session = Session() - >>> with session.open('s3://landsat-pds/L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B1.TIF') as src: - ... pprint.pprint(src.profile) - ... - {'affine': Affine(30.0, 0.0, 381885.0, - 0.0, -30.0, 2512815.0), - 'blockxsize': 512, - 'blockysize': 512, - 'compress': 'deflate', - 'count': 1, - 'crs': {'init': u'epsg:32645'}, - 'driver': u'GTiff', - 'dtype': 'uint16', - 'height': 7791, - 'interleave': 'band', - 'nodata': None, - 'tiled': True, - 'transform': (381885.0, 30.0, 0.0, 2512815.0, 0.0, -30.0), - 'width': 7621} - -If you provide no arguments when creating a session, your environment will be -checked for credentials. Access keys may be explicitly provided when creating -a session. +read metadata and imagery from TIFFs stored as S3 objects with no change to +your code. .. code-block:: python - session = Session(aws_access_key_id='KEY', - aws_secret_access_key='SECRET', - aws_session_token='TOKEN') + with rasterio.open('s3://landsat-pds/L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B1.TIF') as src: + print(src.profile) + + # Printed: + # {'affine': Affine(30.0, 0.0, 381885.0, + # 0.0, -30.0, 2512815.0), + # 'blockxsize': 512, + # 'blockysize': 512, + # 'compress': 'deflate', + # 'count': 1, + # 'crs': {'init': u'epsg:32645'}, + # 'driver': u'GTiff', + # 'dtype': 'uint16', + # 'height': 7791, + # 'interleave': 'band', + # 'nodata': None, + # 'tiled': True, + # 'transform': (381885.0, 30.0, 0.0, 2512815.0, 0.0, -30.0), + # 'width': 7621} .. note:: AWS pricing concerns While this feature can reduce latency by reading fewer bytes from S3 diff --git a/rasterio/__init__.py b/rasterio/__init__.py index b0c758e..8581e8e 100644 --- a/rasterio/__init__.py +++ b/rasterio/__init__.py @@ -17,7 +17,7 @@ from rasterio._base import ( from rasterio.dtypes import ( bool_, ubyte, uint8, uint16, int16, uint32, int32, float32, float64, complex_, check_dtype) -from rasterio.env import defenv, Env +from rasterio.env import ensure_env, Env from rasterio.five import string_types from rasterio.profiles import default_gtiff_profile from rasterio.transform import Affine, guard_transform @@ -32,7 +32,7 @@ from rasterio import _err, coords, enums, vfs __all__ = [ 'band', 'open', 'copy', 'pad'] -__version__ = "0.35.0" +__version__ = "0.35.1" __gdal_version__ = gdal_version() # Rasterio attaches NullHandler to the 'rasterio' logger and its @@ -44,6 +44,7 @@ log = logging.getLogger(__name__) log.addHandler(NullHandler()) +@ensure_env def open(path, mode='r', driver=None, width=None, height=None, count=None, crs=None, transform=None, dtype=None, nodata=None, **kwargs): @@ -161,9 +162,6 @@ def open(path, mode='r', driver=None, width=None, height=None, affine = kwargs.pop('affine') transform = guard_transform(affine) - # If there is no currently active GDAL/AWS environment, create one. - defenv() - # Get AWS credentials if we're attempting to access a raster # on S3. pth, archive, scheme = parse_path(path) @@ -196,6 +194,7 @@ def open(path, mode='r', driver=None, width=None, height=None, return s +@ensure_env def copy(src, dst, **kw): """Copy a source raster to a new destination with driver specific creation options. @@ -224,9 +223,6 @@ def copy(src, dst, **kw): This is the one way to create write-once files like JPEGs. """ from rasterio._copy import RasterCopier - - # If there is no currently active GDAL/AWS environment, create one. - defenv() return RasterCopier()(src, dst, **kw) diff --git a/rasterio/env.py b/rasterio/env.py index c5b6300..e76702f 100644 --- a/rasterio/env.py +++ b/rasterio/env.py @@ -186,3 +186,10 @@ def delenv(): else: _env.clear_config_options() log.debug("Cleared existing %r options", _env) + + +def ensure_env(f): + """A decorator that ensures an env exists before a function + calls any GDAL C functions.""" + defenv() + return f diff --git a/rasterio/features.py b/rasterio/features.py index 0ba3d28..39eef1d 100644 --- a/rasterio/features.py +++ b/rasterio/features.py @@ -9,7 +9,7 @@ import numpy as np import rasterio from rasterio._features import _shapes, _sieve, _rasterize, _bounds -import rasterio.env +from rasterio.env import ensure_env from rasterio.transform import IDENTITY, guard_transform from rasterio.dtypes import validate_dtype, can_cast_dtype, get_minimum_dtype @@ -17,6 +17,7 @@ from rasterio.dtypes import validate_dtype, can_cast_dtype, get_minimum_dtype log = logging.getLogger(__name__) +@ensure_env def geometry_mask( geometries, out_shape, @@ -61,6 +62,7 @@ def geometry_mask( default_value=mask_value).astype('bool') +@ensure_env def shapes(image, mask=None, connectivity=4, transform=IDENTITY): """Yield (polygon, value for each set of adjacent pixels of the same value. @@ -98,11 +100,11 @@ def shapes(image, mask=None, connectivity=4, transform=IDENTITY): """ transform = guard_transform(transform) - rasterio.env.setenv() for s, v in _shapes(image, mask, connectivity, transform.to_gdal()): yield s, v +@ensure_env def sieve(image, size, out=None, output=None, mask=None, connectivity=4): """Replace small polygons in `image` with value of their largest neighbor. @@ -152,15 +154,13 @@ def sieve(image, size, out=None, output=None, mask=None, connectivity=4): stacklevel=2) # pragma: no cover out = out if out is not None else output - if out is None: out = np.zeros(image.shape, image.dtype) - - rasterio.env.setenv() _sieve(image, size, out, mask, connectivity) return out +@ensure_env def rasterize( shapes, out_shape=None, @@ -301,10 +301,7 @@ def rasterize( raise ValueError('Either an output shape or image must be provided') transform = guard_transform(transform) - - rasterio.env.setenv() _rasterize(valid_shapes, out, transform.to_gdal(), all_touched) - return out diff --git a/rasterio/fill.py b/rasterio/fill.py index 53811c0..998da5d 100644 --- a/rasterio/fill.py +++ b/rasterio/fill.py @@ -2,8 +2,10 @@ import rasterio from rasterio._fill import _fillnodata -from rasterio.env import setenv +from rasterio.env import ensure_env + +@ensure_env def fillnodata( image, mask=None, @@ -49,6 +51,5 @@ def fillnodata( """ max_search_distance = float(max_search_distance) smoothing_iterations = int(smoothing_iterations) - rasterio.env.setenv() return _fillnodata( image, mask, max_search_distance, smoothing_iterations) diff --git a/rasterio/vfs.py b/rasterio/vfs.py index 4503d8c..c5f057f 100644 --- a/rasterio/vfs.py +++ b/rasterio/vfs.py @@ -12,9 +12,14 @@ SCHEMES = {'gzip': 'gzip', 'zip': 'zip', 'tar': 'tar', 'https': 'curl', 'http': 'curl', 's3': 's3'} -def parse_path(path, vfs=None): - """Parse a file path or Apache VFS URL into its parts.""" +def parse_path(uri, vfs=None): + """Parse a URI or Apache VFS URL into its parts + + Returns: tuple + (path, archive, scheme) + """ archive = scheme = None + path = uri if vfs: parts = urlparse(vfs) scheme = parts.scheme @@ -27,14 +32,21 @@ def parse_path(path, vfs=None): path = parts.path if parts.netloc and parts.netloc != 'localhost': path = parts.netloc + path + # There are certain URI schemes we favor over GDAL's names. if scheme in SCHEMES: parts = path.split('!') path = parts.pop() if parts else None archive = parts.pop() if parts else None + # For filesystem paths. elif scheme in (None, '', 'file'): pass + # We permit GDAL's idiosyncratic URI-like dataset paths such as + # 'NETCDF:...' to fall right through with no parsed archive + # or scheme. else: - raise ValueError("VFS scheme {0} is unknown".format(scheme)) + archive = scheme = None + path = uri + return path, archive, scheme diff --git a/rasterio/warp.py b/rasterio/warp.py index 779b3bd..d824d5c 100644 --- a/rasterio/warp.py +++ b/rasterio/warp.py @@ -13,7 +13,7 @@ from rasterio._base import _transform from rasterio._warp import ( _transform_geom, _reproject, _calculate_default_transform) from rasterio.enums import Resampling -import rasterio.env +from rasterio.env import ensure_env from rasterio.transform import guard_transform @@ -22,6 +22,7 @@ warnings.warn( "RESAMPLING is deprecated, use Resampling instead.", DeprecationWarning) +@ensure_env def transform(src_crs, dst_crs, xs, ys, zs=None): """Transform vectors from source to target coordinate reference system. @@ -48,10 +49,10 @@ def transform(src_crs, dst_crs, xs, ys, zs=None): Tuple of x, y, and optionally z vectors, transformed into the target coordinate reference system. """ - rasterio.env.setenv() return _transform(src_crs, dst_crs, xs, ys, zs) +@ensure_env def transform_geom( src_crs, dst_crs, @@ -86,7 +87,6 @@ def transform_geom( out: GeoJSON like dict object Transformed geometry in GeoJSON dict format """ - rasterio.env.setenv() return _transform_geom( src_crs, dst_crs, @@ -96,6 +96,7 @@ def transform_geom( precision) +@ensure_env def transform_bounds( src_crs, dst_crs, @@ -162,6 +163,7 @@ def transform_bounds( return (min(xs), min(ys), max(xs), max(ys)) +@ensure_env def reproject( source, destination, @@ -247,7 +249,6 @@ def reproject( if dst_transform: dst_transform = guard_transform(dst_transform).to_gdal() - rasterio.env.setenv() _reproject( source, destination, @@ -261,6 +262,7 @@ def reproject( **kwargs) +@ensure_env def calculate_default_transform( src_crs, dst_crs, @@ -312,7 +314,6 @@ def calculate_default_transform( avoids visual artifacts and coordinate discontinuties. NO: reproject coordinates beyond valid bound limits """ - rasterio.env.setenv() dst_affine, dst_width, dst_height = _calculate_default_transform( src_crs, dst_crs, width, height, diff --git a/tests/test_env.py b/tests/test_env.py index 428ab1f..fffc8a7 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -11,7 +11,7 @@ import pytest import rasterio from rasterio._drivers import ( GDALEnv, del_gdal_config, get_gdal_config, set_gdal_config, driver_count) -from rasterio.env import defenv, delenv, getenv, setenv, Env +from rasterio.env import defenv, delenv, getenv, setenv, ensure_env, Env from rasterio.errors import EnvError from rasterio.rio.main import main_group @@ -64,6 +64,13 @@ def test_env_accessors(gdalenv): getenv() +def test_ensure_env_decorator(gdalenv): + def f(x): + return x + wrapper = ensure_env(f) + assert wrapper == f + + def test_no_aws_gdal_config(gdalenv): """Trying to set AWS-specific GDAL config options fails.""" with pytest.raises(EnvError): diff --git a/tests/test_vfs.py b/tests/test_vfs.py index 0e1de87..20875ce 100644 --- a/tests/test_vfs.py +++ b/tests/test_vfs.py @@ -35,10 +35,10 @@ def test_parse_path_file(): '/foo.tif', None, '') -def test_parse_unknown_scheme(): - """Raise exception for unknown WFS scheme""" - with pytest.raises(ValueError): - parse_path('gopher://foo.tif') +def test_parse_netcdf(): + """Annoying URI-like GDAL dataset names fall through properly""" + assert parse_path('NETCDF:filepath:varname') == ( + 'NETCDF:filepath:varname', None, None) def test_vsi_path_scheme(): -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/rasterio.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel