Merge branch 'master' into vfs

Conflicts:
	rasterio/__init__.py
This commit is contained in:
Sean Gillies 2015-11-09 14:44:14 -07:00
commit dd15b4ae53
21 changed files with 572 additions and 115 deletions

13
.coveragerc Normal file
View File

@ -0,0 +1,13 @@
[run]
plugins = Cython.Coverage
source = rasterio
omit = *.pxd
[report]
show_missing = True
exclude_lines =
pragma: no cover
def __repr__
raise AssertionError
raise NotImplementedError
if __name__ == .__main__.:

View File

@ -10,10 +10,11 @@ env:
- PIP_FIND_LINKS=file://$HOME/.cache/pip/wheels
- GDALINST=$HOME/gdalinstall
- GDALBUILD=$HOME/gdalbuild
- CYTHON_COVERAGE=1
matrix:
- GDALVERSION = "1.9.2"
- GDALVERSION = "1.11.2"
#- GDALVERSION = "2.0.1"
- GDALVERSION = "2.0.1"
addons:
apt:
packages:
@ -37,9 +38,9 @@ install:
- "pip wheel -r requirements-dev.txt"
- "pip install -r requirements-dev.txt"
- "pip install --upgrade --force-reinstall --global-option=build_ext --global-option='-I$GDALINST/gdal-$GDALVERSION/include' --global-option='-L$GDALINST/gdal-$GDALVERSION/lib' --global-option='-R$GDALINST/gdal-$GDALVERSION/lib' -e ."
- "pip install coveralls"
- "pip install coveralls>=1.1"
- "pip install -e ."
script:
script:
- py.test --cov rasterio --cov-report term-missing
after_success:
- coveralls

View File

@ -1,6 +1,15 @@
Changes
=======
0.29.0 (2015-10-22)
-------------------
- Fill masked arrays in rio-calc when using Numpy 1.10.x as well as with 1.8.x
(#500).
- When a raster dataset is not tiled, blockxszie and blockysize items are no
longer included in its `profile` property. This prevents meaningless block
size parameters from stripped, not tiled, datasets from being used when
creating new datasets (#503).
0.28.0 (2015-10-06)
-------------------
- Ensure that tools module is packaged (#489, #490). The rio-merge command was

View File

@ -161,6 +161,55 @@ This example also demonstrates decimation.
:width: 500
:height: 300
Data windows
------------
Sometimes it is desirable to crop off an outer boundary of NODATA values around
a dataset:
.. code-block:: python
from rasterio import get_data_window
with rasterio.open('tests/data/RGB.byte.tif') as src:
window = get_data_window(src.read(1, masked=True))
# window = ((3, 714), (13, 770))
kwargs = src.meta.copy()
del kwargs['transform']
kwargs.update({
'height': window[0][1] - window[0][0],
'width': window[1][1] - window[1][0],
'affine': src.window_transform(window)
})
with rasterio.open('/tmp/cropped.tif', 'w', **kwargs) as dst:
dst.write(src.read(window=window))
Window utilities
----------------
Basic union and intersection operations are available for windows, to streamline
operations across dynamically created windows for a series of bands or datasets
with the same full extent.
.. code-block:: python
from rasterio import window_union, window_intersection
# Full window is ((0, 1000), (0, 500))
window1 = ((100, 500), (10, 500))
window2 = ((10, 150), (50, 250))
outer = window_union([window1, window2])
# outer = ((10, 500), (10, 500))
inner = window_intersection([window1, window2])
# inner = ((100, 150), (50, 250))
Blocks
------

View File

@ -23,7 +23,7 @@ from rasterio import _err, coords, enums
__all__ = [
'band', 'open', 'drivers', 'copy', 'pad']
__version__ = "0.28.0"
__version__ = "0.29.0"
log = logging.getLogger('rasterio')
class NullHandler(logging.Handler):
@ -40,7 +40,6 @@ def open(
crs=None, transform=None,
dtype=None,
nodata=None,
vfs=None,
**kwargs):
"""Open file at ``path`` in ``mode`` "r" (read), "r+" (read/write),
or "w" (write) and return a ``Reader`` or ``Updater`` object.
@ -95,11 +94,6 @@ def open(
raise TypeError("invalid mode: %r" % mode)
if driver and not isinstance(driver, string_types):
raise TypeError("invalid driver: %r" % driver)
if vfs and not isinstance(vfs, string_types):
raise TypeError("invalid vfs: %r" % vfs)
path, vsi, archive = parse_paths(path, vfs)
path = vsi_path(path, vsi=vsi, archive=archive)
if transform:
transform = guard_transform(transform)
@ -180,28 +174,81 @@ def pad(array, transform, pad_width, mode=None, **kwargs):
return padded_array, Affine(*padded_trans[:6])
def parse_paths(path, vfs=None):
archive = vsi = None
if vfs:
parts = vfs.split("://")
vsi = parts.pop(0) if parts else None
archive = parts.pop(0) if parts else None
else:
parts = path.split("://")
path = parts.pop() if parts else None
vsi = parts.pop() if parts else None
return path, vsi, archive
def get_data_window(arr, nodata=None):
"""
Returns a window for the non-nodata pixels within the input array.
Parameters
----------
arr: numpy ndarray, <= 3 dimensions
nodata: number
If None, will either return a full window if arr is not a masked
array, or will use the mask to determine non-nodata pixels.
If provided, it must be a number within the valid range of the dtype
of the input array.
Returns
-------
((row_start, row_stop), (col_start, col_stop))
"""
from rasterio._io import get_data_window
return get_data_window(arr, nodata)
def vsi_path(path, vsi=None, archive=None):
# If a VSF and archive file are specified, we convert the path to
# a GDAL VSI path (see cpl_vsi.h).
if vsi:
path = path.strip(os.path.sep)
if archive:
result = os.path.sep.join(['/vsi{0}'.format(vsi), archive, path])
else:
result = os.path.sep.join(['/vsi{0}'.format(vsi), path])
else:
result = path
return result
def window_union(windows):
"""
Union windows and return the outermost extent they cover.
Parameters
----------
windows: list-like of window objects
((row_start, row_stop), (col_start, col_stop))
Returns
-------
((row_start, row_stop), (col_start, col_stop))
"""
from rasterio._io import window_union
return window_union(windows)
def window_intersection(windows):
"""
Intersect windows and return the innermost extent they cover.
Will raise ValueError if windows do not intersect.
Parameters
----------
windows: list-like of window objects
((row_start, row_stop), (col_start, col_stop))
Returns
-------
((row_start, row_stop), (col_start, col_stop))
"""
from rasterio._io import window_intersection
return window_intersection(windows)
def windows_intersect(windows):
"""
Test if windows intersect.
Parameters
----------
windows: list-like of window objects
((row_start, row_stop), (col_start, col_stop))
Returns
-------
boolean:
True if all windows intersect.
"""
from rasterio._io import windows_intersect
return windows_intersect(windows)

View File

@ -4,6 +4,7 @@
import logging
import math
import os
import sys
import warnings
@ -30,6 +31,38 @@ else:
log.addHandler(NullHandler())
def parse_paths(url, vfs=None):
"""Parse a file path or Apache VFS URL into its parts."""
archive = scheme = None
if vfs:
parts = vfs.split("://")
vsi = parts.pop(0) if parts else None
archive = parts.pop(0) if parts else None
else:
parts = url.split("://")
path = parts.pop() if parts else None
scheme = parts.pop() if parts else None
if scheme in ('gzip', 'zip', 'tar'):
parts = path.split('!')
path = parts.pop() if parts else None
archive = parts.pop() if parts else None
return path, scheme, archive
def vsi_path(path, vsi=None, archive=None):
# If a VSF and archive file are specified, we convert the path to
# a GDAL VSI path (see cpl_vsi.h).
if vsi and vsi != 'file':
path = path.strip(os.path.sep)
if archive:
result = os.path.sep.join(['/vsi{0}'.format(vsi), archive, path])
else:
result = os.path.sep.join(['/vsi{0}'.format(vsi), path])
else:
result = path
return result
cdef class DatasetReader(object):
def __init__(self, path):
@ -62,7 +95,10 @@ cdef class DatasetReader(object):
self.env = GDALEnv(False)
self.env.start()
name_b = self.name.encode('utf-8')
path, vsi, archive = parse_paths(self.name)
path = vsi_path(path, vsi=vsi, archive=archive)
name_b = path.encode('utf-8')
cdef const char *fname = name_b
with cpl_errs:
self._hds = _gdal.GDALOpen(fname, 0)
@ -448,6 +484,10 @@ cdef class DatasetReader(object):
else:
return None
@property
def is_tiled(self):
return self.block_shapes[0][1] != self.width
property profile:
"""Basic metadata and creation options of this dataset.
@ -457,10 +497,13 @@ cdef class DatasetReader(object):
def __get__(self):
m = self.meta
m.update(self.tags(ns='rio_creation_kwds'))
m.update(
blockxsize=self.block_shapes[0][1],
blockysize=self.block_shapes[0][0],
tiled=self.block_shapes[0][1] != self.width)
if self.is_tiled:
m.update(
blockxsize=self.block_shapes[0][1],
blockysize=self.block_shapes[0][0],
tiled=True)
else:
m.update(tiled=False)
if self.compression:
m['compress'] = self.compression.name
if self.interleaving:

View File

@ -13,7 +13,8 @@ cimport numpy as np
from rasterio cimport _base, _gdal, _ogr, _io
from rasterio._base import (
crop_window, eval_window, window_shape, window_index, tastes_like_gdal)
crop_window, eval_window, window_shape, window_index, tastes_like_gdal,
parse_paths)
from rasterio._drivers import driver_count, GDALEnv
from rasterio._err import cpl_errs
from rasterio import dtypes
@ -1249,8 +1250,7 @@ cdef class RasterUpdater(RasterReader):
cdef void *drv = NULL
cdef void *hband = NULL
cdef int success
name_b = self.name.encode('utf-8')
cdef const char *fname = name_b
# Is there not a driver manager already?
if driver_count() == 0 and not self.env:
@ -1259,7 +1259,16 @@ cdef class RasterUpdater(RasterReader):
else:
self.env = GDALEnv(False)
self.env.start()
path, scheme, archive = parse_paths(self.name)
if scheme and scheme != 'file':
raise TypeError(
"VFS '{0}' datasets can not be created or updated.".format(
scheme))
name_b = self.name.encode('utf-8')
cdef const char *fname = name_b
kwds = []
if self.mode == 'w':
@ -2002,6 +2011,12 @@ def writer(path, mode, **kwargs):
cdef const char *drv_name = NULL
cdef const char *fname = NULL
path, scheme, archive = parse_paths(path)
if scheme and scheme != 'file':
raise TypeError(
"VFS '{0}' datasets can not be created or updated.".format(
scheme))
if mode == 'w' and 'driver' in kwargs:
if kwargs['driver'] == 'GTiff':
return RasterUpdater(path, mode, **kwargs)
@ -2041,3 +2056,133 @@ def virtual_file_to_buffer(filename):
log.debug("Buffer length: %d bytes", n)
cdef np.uint8_t[:] buff_view = <np.uint8_t[:n]>buff
return buff_view
def get_data_window(arr, nodata=None):
"""
Returns a window for the non-nodata pixels within the input array.
Parameters
----------
arr: numpy ndarray, <= 3 dimensions
nodata: number
If None, will either return a full window if arr is not a masked
array, or will use the mask to determine non-nodata pixels.
If provided, it must be a number within the valid range of the dtype
of the input array.
Returns
-------
((row_start, row_stop), (col_start, col_stop))
"""
num_dims = len(arr.shape)
if num_dims > 3:
raise ValueError('get_data_window input array must have no more than '
'3 dimensions')
if nodata is None:
if not hasattr(arr, 'mask'):
return ((0, arr.shape[-2]), (0, arr.shape[-1]))
else:
arr = np.ma.masked_array(arr, arr == nodata)
if num_dims == 2:
data_rows, data_cols = np.where(arr.mask == False)
else:
data_rows, data_cols = np.where(
np.any(np.rollaxis(arr.mask, 0, 3) == False, axis=2)
)
if data_rows.size:
row_range = (data_rows.min(), data_rows.max() + 1)
else:
row_range = (0, 0)
if data_cols.size:
col_range = (data_cols.min(), data_cols.max() + 1)
else:
col_range = (0, 0)
return (row_range, col_range)
def window_union(windows):
"""
Union windows and return the outermost extent they cover.
Parameters
----------
windows: list-like of window objects
((row_start, row_stop), (col_start, col_stop))
Returns
-------
((row_start, row_stop), (col_start, col_stop))
"""
stacked = np.dstack(windows)
return (
(stacked[0, 0].min(), stacked[0, 1].max()),
(stacked[1, 0].min(), stacked[1, 1]. max())
)
def window_intersection(windows):
"""
Intersect windows and return the innermost extent they cover.
Will raise ValueError if windows do not intersect.
Parameters
----------
windows: list-like of window objects
((row_start, row_stop), (col_start, col_stop))
Returns
-------
((row_start, row_stop), (col_start, col_stop))
"""
if not windows_intersect(windows):
raise ValueError('windows do not intersect')
stacked = np.dstack(windows)
return (
(stacked[0, 0].max(), stacked[0, 1].min()),
(stacked[1, 0].max(), stacked[1, 1]. min())
)
def windows_intersect(windows):
"""
Test if windows intersect.
Parameters
----------
windows: list-like of window objects
((row_start, row_stop), (col_start, col_stop))
Returns
-------
boolean:
True if all windows intersect.
"""
from itertools import combinations
def intersects(range1, range2):
return not (
range1[0] > range2[1] or range1[1] < range2[0]
)
windows = np.array(windows)
for i in (0, 1):
for c in combinations(windows[:, i], 2):
if not intersects(*c):
return False
return True

View File

@ -123,8 +123,9 @@ def calc(ctx, command, files, output, name, dtype, masked, creation_options):
res = snuggs.eval(command, **ctxkwds)
if (isinstance(res, np.ma.core.MaskedArray) and
tuple(LooseVersion(np.__version__).version) < (1, 9, 0)):
if (isinstance(res, np.ma.core.MaskedArray) and (
tuple(LooseVersion(np.__version__).version) < (1, 9) or
tuple(LooseVersion(np.__version__).version) > (1, 10))):
res = res.filled(kwargs['nodata'])
if len(res.shape) == 3:

View File

@ -26,9 +26,8 @@ def configure_logging(verbosity):
@cligj.verbose_opt
@cligj.quiet_opt
@click.version_option(version=rasterio.__version__, message='%(version)s')
@options.vfs_opt
@click.pass_context
def main_group(ctx, verbose, quiet, vfs):
def main_group(ctx, verbose, quiet):
"""
Rasterio command line interface.
@ -38,4 +37,3 @@ def main_group(ctx, verbose, quiet, vfs):
configure_logging(verbosity)
ctx.obj = {}
ctx.obj['verbosity'] = verbosity
ctx.obj['vfs'] = vfs

View File

@ -73,6 +73,7 @@ def merge(ctx, files, output, driver, bounds, res, nodata, force_overwrite,
profile['height'] = dest.shape[1]
profile['width'] = dest.shape[2]
profile['driver'] = driver
profile.update(**creation_options)
with rasterio.open(output, 'w', **profile) as dst:

View File

@ -50,7 +50,7 @@ import os.path
import click
from rasterio import parse_paths, vsi_path
from rasterio._base import parse_paths
def _cb_key_val(ctx, param, value):
@ -77,34 +77,27 @@ def _cb_key_val(ctx, param, value):
raise click.BadParameter("Invalid syntax for KEY=VAL arg: {}".format(pair))
else:
k, v = pair.split('=', 1)
k = k.lower()
v = v.lower()
out[k] = v
return out
def vfs_handler(ctx, param, value):
if value:
path, vsi, archive = parse_paths(None, value)
if not vsi in ('gzip', 'zip', 'tar'):
raise click.BadParameter(
"VFS type {0} is unknown".format(vsi))
if not os.path.exists(archive):
raise click.BadParameter(
"VFS archive {0} does not exist".format(archive))
value = "{0}://{1}".format(vsi, os.path.abspath(archive))
return value
def file_in_handler(ctx, param, value):
vfs = (ctx.obj and ctx.obj.get('vfs'))
if vfs:
path, vsi, archive = parse_paths(value, vfs)
path = vsi_path(path, vsi, archive)
"""Normalize ordinary filesystem and VFS paths"""
path, scheme, archive = parse_paths(value)
if scheme and not scheme in ('file', 'gzip', 'zip', 'tar'):
raise click.BadParameter(
"VFS type {0} is unknown".format(scheme))
path_to_check = archive or path
if not os.path.exists(path_to_check):
raise click.BadParameter(
"Input file {0} does not exist".format(path_to_check))
if archive and scheme:
archive = os.path.abspath(archive)
path = "{0}://{1}!{2}".format(scheme, archive, path)
else:
if not os.path.exists(value):
raise click.BadParameter(
"Input file {0} does not exist".format(value))
path = os.path.abspath(value)
path = os.path.abspath(path)
return path
@ -188,11 +181,3 @@ rgb_opt = click.option(
flag_value='rgb',
default=False,
help="Set RGB photometric interpretation.")
vfs_opt = click.option(
'--vfs', 'vfs',
default=None,
callback=vfs_handler,
help="Use a zip:// or tar:// archive as a virtual file system "
"('r' mode only).")

View File

@ -1,12 +1,11 @@
affine
cligj
coveralls>=0.4
cython>=0.23.1
cython>=0.23.4
delocate
enum34
numpy>=1.8.0
numpy>=1.8
snuggs>=1.2
pytest
pytest-cov
pytest-cov>=2.2.0
setuptools>=0.9.8
wheel

View File

@ -1,6 +1,6 @@
affine
cligj
enum34
numpy>=1.8.0
numpy>=1.8
snuggs>=1.2
setuptools

View File

@ -60,30 +60,30 @@ ls -l $GDALINST
if [ ! -d $GDALINST/gdal-1.9.2 ]; then
cd $GDALBUILD
wget http://download.osgeo.org/gdal/gdal-1.9.2.tar.gz
tar -xzvf gdal-1.9.2.tar.gz
tar -xzf gdal-1.9.2.tar.gz
cd gdal-1.9.2
./configure --prefix=$GDALINST/gdal-1.9.2 $GDALOPTS
make -j 2
make -s -j 2
make install
fi
if [ ! -d $GDALINST/gdal-1.11.2 ]; then
cd $GDALBUILD
wget http://download.osgeo.org/gdal/1.11.2/gdal-1.11.2.tar.gz
tar -xzvf gdal-1.11.2.tar.gz
tar -xzf gdal-1.11.2.tar.gz
cd gdal-1.11.2
./configure --prefix=$GDALINST/gdal-1.11.2 $GDALOPTS
make -j 2
make -s -j 2
make install
fi
if [ ! -d $GDALINST/gdal-2.0.1 ]; then
cd $GDALBUILD
wget http://download.osgeo.org/gdal/2.0.1/gdal-2.0.1.tar.gz
tar -xzvf gdal-2.0.1.tar.gz
tar -xzf gdal-2.0.1.tar.gz
cd gdal-2.0.1
./configure --prefix=$GDALINST/gdal-2.0.1 $GDALOPTS
make -j 2
make -s -j 2
make install
fi

View File

@ -1,8 +1,2 @@
[nosetests]
tests=rasterio/tests
nocapture=True
verbosity=3
logging-filter=rasterio
logging-level=DEBUG
with-coverage=1
cover-package=rasterio
[pytest]
testpaths = tests

View File

@ -19,12 +19,10 @@ import sys
from setuptools import setup
from setuptools.extension import Extension
logging.basicConfig()
log = logging.getLogger()
# python -W all setup.py ...
if 'all' in sys.warnoptions:
log.level = logging.DEBUG
def check_output(cmd):
# since subprocess.check_output doesn't exist in 2.6
@ -39,6 +37,7 @@ def check_output(cmd):
out, err = p.communicate()
return out
def copy_data_tree(datadir, destdir):
try:
shutil.rmtree(destdir)
@ -46,6 +45,11 @@ def copy_data_tree(datadir, destdir):
pass
shutil.copytree(datadir, destdir)
# python -W all setup.py ...
if 'all' in sys.warnoptions:
log.level = logging.DEBUG
# Parse the version from the rasterio module.
with open('rasterio/__init__.py') as f:
for line in f:
@ -135,6 +139,13 @@ if not os.name == "nt":
ext_options['extra_compile_args'] = ['-Wno-unused-parameter',
'-Wno-unused-function']
cythonize_options = {}
if os.environ.get('CYTHON_COVERAGE'):
cythonize_options['compiler_directives'] = {'linetrace': True}
cythonize_options['annotate'] = True
ext_options['define_macros'] = [('CYTHON_TRACE', '1'),
('CYTHON_TRACE_NOGIL', '1')]
log.debug('ext_options:\n%s', pprint.pformat(ext_options))
# When building from a repo, Cython is required.
@ -164,7 +175,7 @@ if os.path.exists("MANIFEST.in") and "clean" not in sys.argv:
'rasterio._err', ['rasterio/_err.pyx'], **ext_options),
Extension(
'rasterio._example', ['rasterio/_example.pyx'], **ext_options),
], quiet=True)
], quiet=True, **cythonize_options)
# If there's no manifest template, as in an sdist, we just specify .c files.
else:
@ -193,12 +204,7 @@ with open('README.rst') as f:
readme = f.read()
# Runtime requirements.
inst_reqs = [
'affine>=1.0',
'cligj>=0.2.0',
'Numpy>=1.7',
'snuggs>=1.3.1',
'click-plugins']
inst_reqs = ['affine', 'cligj', 'numpy', 'snuggs', 'click-plugins']
if sys.version_info < (3, 4):
inst_reqs.append('enum34')

Binary file not shown.

View File

@ -1,4 +1,13 @@
import numpy
import pytest
import rasterio
from rasterio import (
get_data_window, window_intersection, window_union, windows_intersect
)
DATA_WINDOW = ((3, 5), (2, 6))
def test_index():
@ -67,3 +76,119 @@ def test_window_full_cover():
win = src.window(*bounds)
bounds_calc = list(src.window_bounds(win))
assert bound_covers(bounds_calc, bounds)
@pytest.fixture
def data():
data = numpy.zeros((10, 10), dtype='uint8')
data[slice(*DATA_WINDOW[0]), slice(*DATA_WINDOW[1])] = 1
return data
def test_data_window_unmasked(data):
window = get_data_window(data)
assert window == ((0, data.shape[0]), (0, data.shape[1]))
def test_data_window_masked(data):
data = numpy.ma.masked_array(data, data == 0)
window = get_data_window(data)
assert window == DATA_WINDOW
def test_data_window_nodata(data):
window = get_data_window(data, nodata=0)
assert window == DATA_WINDOW
window = get_data_window(numpy.ones_like(data), nodata=0)
assert window == ((0, data.shape[0]), (0, data.shape[1]))
def test_data_window_nodata_disjunct():
data = numpy.zeros((3, 10, 10), dtype='uint8')
data[0, :4, 1:4] = 1
data[1, 2:5, 2:8] = 1
data[2, 1:6, 1:6] = 1
window = get_data_window(data, nodata=0)
assert window == ((0, 6), (1, 8))
def test_data_window_empty_result():
data = numpy.zeros((3, 10, 10), dtype='uint8')
window = get_data_window(data, nodata=0)
assert window == ((0, 0), (0, 0))
def test_data_window_masked_file():
with rasterio.open('tests/data/RGB.byte.tif') as src:
window = get_data_window(src.read(1, masked=True))
assert window == ((3, 714), (13, 770))
window = get_data_window(src.read(masked=True))
assert window == ((3, 714), (13, 770))
def test_window_union():
assert window_union([
((0, 6), (3, 6)),
((2, 4), (1, 5))
]) == ((0, 6), (1, 6))
def test_window_intersection():
assert window_intersection([
((0, 6), (3, 6)),
((2, 4), (1, 5))
]) == ((2, 4), (3, 5))
assert window_intersection([
((0, 6), (3, 6)),
((6, 10), (1, 5))
]) == ((6, 6), (3, 5))
assert window_intersection([
((0, 6), (3, 6)),
((2, 4), (1, 5)),
((3, 6), (0, 6))
]) == ((3, 4), (3, 5))
def test_window_intersection_disjunct():
with pytest.raises(ValueError):
window_intersection([
((0, 6), (3, 6)),
((100, 200), (0, 12)),
((7, 12), (7, 12))
])
def test_windows_intersect():
assert windows_intersect([
((0, 6), (3, 6)),
((2, 4), (1, 5))
]) == True
assert windows_intersect([
((0, 6), (3, 6)),
((2, 4), (1, 5)),
((3, 6), (0, 6))
]) == True
def test_windows_intersect_disjunct():
assert windows_intersect([
((0, 6), (3, 6)),
((10, 20), (0, 6))
]) == False
assert windows_intersect([
((0, 6), (3, 6)),
((2, 4), (1, 5)),
((5, 6), (0, 6))
]) == False
assert windows_intersect([
((0, 6), (3, 6)),
((2, 4), (1, 3)),
((3, 6), (4, 6))
]) == False

View File

@ -7,7 +7,7 @@ def test_cb_key_val():
pairs = ['KEY=val', '1==']
expected = {
'KEY': 'val',
'key': 'val',
'1': '=',
}
assert options._cb_key_val(None, None, pairs) == expected

View File

@ -79,11 +79,26 @@ def test_profile_overlay():
assert kwds['count'] == 3
def test_dataset_profile_property(data):
def test_dataset_profile_property_tiled(data):
"""An tiled dataset's profile has block sizes"""
with rasterio.open('tests/data/shade.tif') as src:
assert src.profile['blockxsize'] == 256
assert src.profile['blockysize'] == 256
assert src.profile['tiled'] == True
def test_dataset_profile_property_untiled(data):
"""An untiled dataset's profile has no block sizes"""
with rasterio.open('tests/data/RGB.byte.tif') as src:
assert 'blockxsize' not in src.profile
assert 'blockysize' not in src.profile
assert src.profile['tiled'] == False
def test_dataset_profile_creation_kwds(data):
"""Updated creation keyword tags appear in profile"""
tiffile = str(data.join('RGB.byte.tif'))
with rasterio.open(tiffile, 'r+') as src:
src.update_tags(ns='rio_creation_kwds', foo='bar')
assert src.profile['blockxsize'] == 791
assert src.profile['blockysize'] == 3
assert src.profile['tiled'] == False
assert src.profile['foo'] == 'bar'

View File

@ -1,15 +1,41 @@
import logging
import sys
import pytest
import rasterio
from rasterio.profiles import default_gtiff_profile
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
def test_read_zip():
def test_read_vfs_zip():
with rasterio.open(
'/RGB.byte.tif',
vfs='zip://tests/data/files.zip') as src:
assert src.name == '/vsizip/tests/data/files.zip/RGB.byte.tif'
'zip://tests/data/files.zip!/RGB.byte.tif') as src:
assert src.name == 'zip://tests/data/files.zip!/RGB.byte.tif'
assert src.count == 3
def test_read_vfs_file():
with rasterio.open(
'file://tests/data/RGB.byte.tif') as src:
assert src.name == 'file://tests/data/RGB.byte.tif'
assert src.count == 3
def test_read_vfs_none():
with rasterio.open(
'tests/data/RGB.byte.tif') as src:
assert src.name == 'tests/data/RGB.byte.tif'
assert src.count == 3
@pytest.mark.parametrize('mode', ['r+', 'w'])
def test_update_vfs(tmpdir, mode):
"""VFS datasets can not be created or updated"""
with pytest.raises(TypeError):
_ = rasterio.open(
'zip://{0}'.format(tmpdir), mode,
**default_gtiff_profile(
count=1, width=1, height=1))