mirror of
https://github.com/rasterio/rasterio.git
synced 2025-12-08 17:36:12 +00:00
Refactor and test improvements
Traded the `int_reshape` function for a `round_shape` method on the Window class with better docs and clearer semantics.
This commit is contained in:
parent
56a6eba992
commit
361112e825
@ -225,14 +225,14 @@ cdef class DatasetReaderBase(DatasetBase):
|
||||
if window:
|
||||
|
||||
if isinstance(window, tuple):
|
||||
windows.warn_window_deprecation()
|
||||
window = windows.coerce_and_warn(window)
|
||||
|
||||
if not boundless:
|
||||
window = windows.crop(
|
||||
windows.evaluate(window, self.height, self.width),
|
||||
self.height, self.width)
|
||||
|
||||
int_window = windows.int_reshape(window)
|
||||
int_window = window.round_shape()
|
||||
win_shape += (int(int_window.num_rows), int(int_window.num_cols))
|
||||
|
||||
else:
|
||||
@ -463,14 +463,14 @@ cdef class DatasetReaderBase(DatasetBase):
|
||||
if window:
|
||||
|
||||
if isinstance(window, tuple):
|
||||
windows.warn_window_deprecation()
|
||||
window = windows.coerce_and_warn(window)
|
||||
|
||||
if not boundless:
|
||||
window = windows.crop(
|
||||
windows.evaluate(window, self.height, self.width),
|
||||
self.height, self.width)
|
||||
|
||||
int_window = windows.int_reshape(window)
|
||||
int_window = window.round_shape()
|
||||
win_shape += (int(int_window.num_rows), int(int_window.num_cols))
|
||||
|
||||
else:
|
||||
|
||||
@ -30,7 +30,7 @@ class RasterioIOError(IOError):
|
||||
registered format drivers."""
|
||||
|
||||
|
||||
class NodataShadowWarning(Warning):
|
||||
class NodataShadowWarning(UserWarning):
|
||||
"""Warn that a dataset's nodata attribute is shadowing its alpha band."""
|
||||
|
||||
def __str__(self):
|
||||
@ -39,7 +39,7 @@ class NodataShadowWarning(Warning):
|
||||
"by the nodata attribute")
|
||||
|
||||
|
||||
class NotGeoreferencedWarning(Warning):
|
||||
class NotGeoreferencedWarning(UserWarning):
|
||||
"""Warn that a dataset isn't georeferenced."""
|
||||
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@ import warnings
|
||||
|
||||
import rasterio
|
||||
from rasterio.features import geometry_mask
|
||||
from rasterio.windows import int_reshape
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -103,9 +102,9 @@ def mask(raster, shapes, nodata=None, crop=False, all_touched=False,
|
||||
if crop:
|
||||
bounds_window = raster.window(*mask_bounds)
|
||||
|
||||
# Call int_reshape to get the window with integer height
|
||||
# Get the window with integer height
|
||||
# and width that contains the bounds window.
|
||||
out_window = int_reshape(bounds_window)
|
||||
out_window = bounds_window.round_shape()
|
||||
height = int(out_window.num_rows)
|
||||
width = int(out_window.num_cols)
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ def merge(sources, bounds=None, res=None, nodata=None, precision=7):
|
||||
boundless=True)
|
||||
logger.debug("Src %s window: %r", src.name, src_window)
|
||||
|
||||
src_window = windows.int_reshape(src_window)
|
||||
src_window = src_window.round_shape()
|
||||
|
||||
# 3. Compute the destination window.
|
||||
dst_window = windows.from_bounds(
|
||||
|
||||
@ -7,7 +7,6 @@ from .helpers import resolve_inout
|
||||
from . import options
|
||||
import rasterio
|
||||
from rasterio.coords import disjoint_bounds
|
||||
from rasterio.windows import int_reshape
|
||||
|
||||
|
||||
# Geographic (default), projected, or Mercator switch.
|
||||
@ -102,9 +101,9 @@ def clip(ctx, files, output, bounds, like, driver, projection,
|
||||
|
||||
bounds_window = src.window(*bounds)
|
||||
|
||||
# Call int_reshape to get the window with integer height
|
||||
# Get the window with integer height
|
||||
# and width that contains the bounds window.
|
||||
out_window = int_reshape(bounds_window)
|
||||
out_window = bounds_window.round_shape()
|
||||
|
||||
height = int(out_window.num_rows)
|
||||
width = int(out_window.num_cols)
|
||||
|
||||
@ -29,6 +29,15 @@ def warn_window_deprecation():
|
||||
DeprecationWarning)
|
||||
|
||||
|
||||
def coerce_and_warn(ranges):
|
||||
"""Coerce ranges to Window and warn"""
|
||||
warn_window_deprecation()
|
||||
if not (len(ranges) == 2 and len(ranges[0]) == 2 and len(ranges[1]) == 2):
|
||||
raise ValueError("Not a valid pair of ranges")
|
||||
|
||||
return Window.from_ranges(*ranges)
|
||||
|
||||
|
||||
def iter_args(function):
|
||||
"""Decorator to allow function to take either *args or
|
||||
a single iterable which gets expanded to *args.
|
||||
@ -172,7 +181,7 @@ def intersect(*windows):
|
||||
return True
|
||||
|
||||
|
||||
def from_bounds(left, bottom, right, top, transform,
|
||||
def from_bounds(left, bottom, right, top, transform=None,
|
||||
height=None, width=None, boundless=False, precision=6):
|
||||
"""Get the window corresponding to the bounding coordinates.
|
||||
|
||||
@ -213,33 +222,6 @@ def from_bounds(left, bottom, right, top, transform,
|
||||
return crop(window, height, width)
|
||||
|
||||
|
||||
def int_reshape(window, pixel_precision=3):
|
||||
"""Converts floating point value Windows to integer value Windows.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
window : Window
|
||||
Input window with floating point values.
|
||||
pixel_precision : int
|
||||
Rounding precision in decimal places.
|
||||
Returns
|
||||
-------
|
||||
Window
|
||||
A new Window
|
||||
"""
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
return Window.from_offlen(
|
||||
window[1][0], window[0][0],
|
||||
math.ceil(round(window[1][1] - window[1][0], pixel_precision)),
|
||||
math.ceil(round(window[0][1] - window[0][0], pixel_precision)))
|
||||
else:
|
||||
return Window.from_offlen(
|
||||
window.col_off, window.row_off,
|
||||
math.ceil(round(window.num_cols, pixel_precision)),
|
||||
math.ceil(round(window.num_rows, pixel_precision)))
|
||||
|
||||
|
||||
def transform(window, transform):
|
||||
"""Construct an affine transform matrix relative to a window.
|
||||
|
||||
@ -255,13 +237,12 @@ def transform(window, transform):
|
||||
Affine
|
||||
The affine transform matrix for the given window
|
||||
"""
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
r, c = window[0][0], window[1][0]
|
||||
else:
|
||||
r, c = window.row_off, window.col_off
|
||||
window = (coerce_and_warn(window) if isinstance(window, tuple) else
|
||||
window)
|
||||
|
||||
return transform * Affine.translation(c or 0, r or 0)
|
||||
x, y = transform * (window.col_off or 0.0, window.row_off or 0.0)
|
||||
return Affine.translation(
|
||||
x - transform.c, y - transform.f) * transform
|
||||
|
||||
|
||||
def bounds(window, transform):
|
||||
@ -269,28 +250,27 @@ def bounds(window, transform):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
window : a Window or window tuple
|
||||
window: a Window or window tuple
|
||||
The input window.
|
||||
transform: Affine
|
||||
an affine transform matrix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
x_min, y_min, x_max, y_max : float
|
||||
left, bottom, right, top: float
|
||||
A tuple of spatial coordinate bounding values.
|
||||
"""
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
(row_min, row_max), (col_min, col_max) = window
|
||||
else:
|
||||
row_min = window.row_off
|
||||
row_max = row_min + window.num_rows
|
||||
col_min = window.col_off
|
||||
col_max = col_min + window.num_cols
|
||||
window = (coerce_and_warn(window) if isinstance(window, tuple) else
|
||||
window)
|
||||
|
||||
row_min = window.row_off
|
||||
row_max = row_min + window.num_rows
|
||||
col_min = window.col_off
|
||||
col_max = col_min + window.num_cols
|
||||
|
||||
x_min, y_min = transform * (col_min, row_max)
|
||||
x_max, y_max = transform * (col_max, row_min)
|
||||
return x_min, y_min, x_max, y_max
|
||||
left, bottom = transform * (col_min, row_max)
|
||||
right, top = transform * (col_max, row_min)
|
||||
return left, bottom, right, top
|
||||
|
||||
|
||||
def crop(window, height, width):
|
||||
@ -309,18 +289,15 @@ def crop(window, height, width):
|
||||
A new Window object.
|
||||
"""
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
(row_min, row_max), (col_min, col_max) = window
|
||||
else:
|
||||
row_min = window.row_off
|
||||
row_max = row_min + window.num_rows
|
||||
col_min = window.col_off
|
||||
col_max = col_min + window.num_cols
|
||||
window = coerce_and_warn(window)
|
||||
|
||||
return Window.from_ranges(
|
||||
(min(max(row_min, 0), height), max(0, min(row_max, height))),
|
||||
(min(max(col_min, 0), width), max(0, min(col_max, width))))
|
||||
row_start = min(max(window.row_off, 0), height)
|
||||
col_start = min(max(window.col_off, 0), width)
|
||||
row_stop = max(0, min(window.row_off + window.num_rows, height))
|
||||
col_stop = max(0, min(window.col_off + window.num_cols, width))
|
||||
|
||||
return Window.from_ranges((row_start, row_stop), (col_start, col_stop))
|
||||
|
||||
|
||||
def evaluate(window, height, width):
|
||||
"""Evaluates a window tuple that may contain relative index values.
|
||||
@ -342,16 +319,9 @@ def evaluate(window, height, width):
|
||||
A new Window object with absolute index values.
|
||||
"""
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
try:
|
||||
r, c = window
|
||||
assert len(r) == 2
|
||||
assert len(c) == 2
|
||||
except (ValueError, TypeError, AssertionError):
|
||||
raise ValueError("invalid window structure; expecting ints"
|
||||
"((row_start, row_stop), (col_start, col_stop))")
|
||||
else:
|
||||
r, c = window.toranges()
|
||||
window = coerce_and_warn(window)
|
||||
|
||||
r, c = window.toranges()
|
||||
|
||||
r_start = r[0] or 0
|
||||
if r_start < 0:
|
||||
@ -408,6 +378,8 @@ def shape(window, height=-1, width=-1):
|
||||
def window_index(window):
|
||||
"""Construct a pair of slice objects for ndarray indexing
|
||||
|
||||
Starting indexes are rounded down, Stopping indexes are rounded up.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
window : a Window or window tuple
|
||||
@ -418,11 +390,13 @@ def window_index(window):
|
||||
row_slice, col_slice: slice
|
||||
A pair of slices in row, column order
|
||||
"""
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
return tuple(slice(*w) for w in window)
|
||||
else:
|
||||
return tuple(slice(*w) for w in window.toranges())
|
||||
window = (coerce_and_warn(window) if isinstance(window, tuple) else
|
||||
window)
|
||||
|
||||
r, c = window.toranges()
|
||||
return (
|
||||
slice(int(math.floor(r[0])), int(math.ceil(r[1]))),
|
||||
slice(int(math.floor(c[0])), int(math.ceil(c[1]))))
|
||||
|
||||
|
||||
def round_window_to_full_blocks(window, block_shapes):
|
||||
@ -441,17 +415,17 @@ def round_window_to_full_blocks(window, block_shapes):
|
||||
-------
|
||||
Window
|
||||
"""
|
||||
if len(set(block_shapes)) != 1:
|
||||
raise ValueError('All bands must have the same block/stripe structure')
|
||||
if len(set(block_shapes)) != 1: # pragma: no cover
|
||||
raise ValueError(
|
||||
"All bands must have the same block/stripe structure")
|
||||
|
||||
window = (coerce_and_warn(window) if isinstance(window, tuple) else
|
||||
window)
|
||||
|
||||
height_shape = block_shapes[0][0]
|
||||
width_shape = block_shapes[0][1]
|
||||
|
||||
if isinstance(window, tuple):
|
||||
warn_window_deprecation()
|
||||
row_range, col_range = window
|
||||
else:
|
||||
row_range, col_range = window.toranges()
|
||||
row_range, col_range = window.toranges()
|
||||
|
||||
row_min = int(row_range[0] // height_shape) * height_shape
|
||||
row_max = int(row_range[1] // height_shape) * height_shape + \
|
||||
@ -516,10 +490,11 @@ class Window(object):
|
||||
num_rows=self.num_rows)
|
||||
|
||||
def toranges(self):
|
||||
"""A pair of range tuples"""
|
||||
"""Makes an equivalent pair of range tuples"""
|
||||
row_stop = None if self.num_rows is None else self.row_off + self.num_rows
|
||||
col_stop = None if self.num_cols is None else self.col_off + self.num_cols
|
||||
return (
|
||||
(self.row_off, self.row_off + self.num_rows),
|
||||
(self.col_off, self.col_off + self.num_cols))
|
||||
(self.row_off, row_stop), (self.col_off, col_stop))
|
||||
|
||||
def toslices(self):
|
||||
"""Slice objects for use as an ndarray indexer.
|
||||
@ -553,9 +528,12 @@ class Window(object):
|
||||
-------
|
||||
Window
|
||||
"""
|
||||
return cls(col_range[0], row_range[0],
|
||||
col_range[1] - col_range[0],
|
||||
row_range[1] - row_range[0])
|
||||
col_off = col_range[0] or 0.0
|
||||
row_off = row_range[0] or 0.0
|
||||
num_cols = None if col_range[1] is None else col_range[1] - col_off
|
||||
num_rows = None if row_range[1] is None else row_range[1] - row_off
|
||||
return cls(col_off, row_off, num_cols, num_rows)
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_offlen(cls, col_off, row_off, num_cols, num_rows):
|
||||
@ -573,3 +551,28 @@ class Window(object):
|
||||
Window
|
||||
"""
|
||||
return cls(col_off, row_off, num_cols, num_rows)
|
||||
|
||||
def round_shape(self, op='ceil', pixel_precision=3):
|
||||
"""Return a copy with column and row numbers rounded
|
||||
|
||||
Numbers are rounded to the nearest whole number. The offsets
|
||||
are not changed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
op: str
|
||||
'ceil' or 'floor'
|
||||
pixel_precision: int
|
||||
Number of places of rounding precision.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Window
|
||||
"""
|
||||
operator = getattr(math, op, None)
|
||||
if not operator:
|
||||
raise ValueError("operator must be 'ceil' or 'floor'")
|
||||
|
||||
return Window(self.col_off, self.row_off,
|
||||
operator(round(self.num_cols, pixel_precision)),
|
||||
operator(round(self.num_rows, pixel_precision)))
|
||||
|
||||
@ -3,6 +3,7 @@ import pytest
|
||||
import rasterio
|
||||
from rasterio import transform
|
||||
from rasterio.transform import xy, rowcol
|
||||
from rasterio.windows import Window
|
||||
|
||||
|
||||
def test_window_transform():
|
||||
@ -59,7 +60,7 @@ def test_window_bounds():
|
||||
|
||||
# Test a small window in each corner, both in and slightly out of bounds
|
||||
p = 10
|
||||
for window in (
|
||||
for ranges in (
|
||||
# In bounds (UL, UR, LL, LR)
|
||||
((0, p), (0, p)),
|
||||
((0, p), (cols - p, p)),
|
||||
@ -74,7 +75,8 @@ def test_window_bounds():
|
||||
|
||||
# Alternate formula
|
||||
|
||||
((row_min, row_max), (col_min, col_max)) = window
|
||||
window = Window.from_ranges(*ranges)
|
||||
(row_min, row_max), (col_min, col_max) = ranges
|
||||
win_aff = src.window_transform(window)
|
||||
|
||||
x_min, y_max = win_aff.c, win_aff.f
|
||||
|
||||
@ -1,25 +1,26 @@
|
||||
from copy import copy
|
||||
import logging
|
||||
import math
|
||||
import sys
|
||||
|
||||
from affine import Affine
|
||||
from hypothesis import given
|
||||
from hypothesis.strategies import floats
|
||||
from hypothesis.strategies import floats, integers
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import rasterio
|
||||
from rasterio.windows import (
|
||||
from_bounds, bounds, transform, evaluate, window_index, shape, Window,
|
||||
intersect, intersection, get_data_window, union, round_window_to_full_blocks)
|
||||
|
||||
crop, from_bounds, bounds, transform, evaluate, window_index, shape, Window,
|
||||
intersect, intersection, get_data_window, union, round_window_to_full_blocks,
|
||||
toranges)
|
||||
|
||||
EPS = 1.0e-8
|
||||
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
||||
|
||||
|
||||
def assert_window_almost_equals(a, b, precision=6):
|
||||
def assert_window_almost_equals(a, b, precision=3):
|
||||
for pair_outer in zip(a, b):
|
||||
for x, y in zip(*pair_outer):
|
||||
assert round(x, precision) == round(y, precision)
|
||||
@ -37,6 +38,53 @@ def test_window_ctor(col_off, row_off, num_cols, num_rows):
|
||||
assert window.num_rows == num_rows
|
||||
|
||||
|
||||
|
||||
@given(col_off=floats(min_value=-1.0e+7, max_value=1.0e+7),
|
||||
row_off=floats(min_value=-1.0e+7, max_value=1.0e+7),
|
||||
num_cols=floats(min_value=0.0, max_value=1.0e+7),
|
||||
num_rows=floats(min_value=0.0, max_value=1.0e+7))
|
||||
def test_window_round_up(col_off, row_off, num_cols, num_rows):
|
||||
window = Window(col_off, row_off, num_cols, num_rows).round_shape()
|
||||
assert window.col_off == col_off
|
||||
assert window.row_off == row_off
|
||||
assert window.num_cols == math.ceil(round(num_cols, 3))
|
||||
assert window.num_rows == math.ceil(round(num_rows, 3))
|
||||
|
||||
|
||||
def test_round_shape_invalid_op():
|
||||
with pytest.raises(ValueError):
|
||||
Window(0, 0, 1, 1).round_shape(op='bogus')
|
||||
|
||||
|
||||
@given(col_off=floats(min_value=-1.0e+7, max_value=1.0e+7),
|
||||
row_off=floats(min_value=-1.0e+7, max_value=1.0e+7),
|
||||
num_cols=floats(min_value=0.0, max_value=1.0e+7),
|
||||
num_rows=floats(min_value=0.0, max_value=1.0e+7),
|
||||
height=integers(min_value=0, max_value=10000000),
|
||||
width=integers(min_value=0, max_value=10000000))
|
||||
def test_crop(col_off, row_off, num_cols, num_rows, height, width):
|
||||
window = crop(Window(col_off, row_off, num_cols, num_rows), height, width)
|
||||
assert 0.0 <= round(window.col_off, 3) <= width
|
||||
assert 0.0 <= round(window.row_off, 3) <= height
|
||||
assert round(window.num_cols, 3) <= round(width - window.col_off, 3)
|
||||
assert round(window.num_rows, 3) <= round(height - window.row_off, 3)
|
||||
|
||||
|
||||
def test_crop_coerce():
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert crop(((-10, 10), (-10, 10)), 5, 5).num_cols == 5
|
||||
|
||||
|
||||
def test_transform_coerce():
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert transform(((-10, 10), (-10, 10)), Affine.identity()).a == 1.0
|
||||
|
||||
|
||||
def test_window_index_coerce():
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert window_index(((-10, 10), (-10, 10)))[0].start == -10
|
||||
|
||||
|
||||
def test_window_function():
|
||||
# TODO: break this test up.
|
||||
with rasterio.open('tests/data/RGB.byte.tif') as src:
|
||||
@ -53,11 +101,6 @@ def test_window_function():
|
||||
left, top - 2 * dy - EPS, left + 2 * dx - EPS, top, src.transform,
|
||||
height, width), ((0, 2), (0, 2)))
|
||||
|
||||
# bounds cropped
|
||||
assert_window_almost_equals(from_bounds(
|
||||
left - 2 * dx, top - 2 * dy, left + 2 * dx, top + 2 * dy,
|
||||
src.transform, height, width), ((0, 2), (0, 2)))
|
||||
|
||||
# boundless
|
||||
assert_window_almost_equals(from_bounds(
|
||||
left - 2 * dx, top - 2 * dy, left + 2 * dx, top + 2 * dy,
|
||||
@ -84,10 +127,16 @@ def test_window_bounds_south_up():
|
||||
Window(0, 0, 10, 10),
|
||||
precision=5)
|
||||
|
||||
|
||||
def test_toranges():
|
||||
assert Window(0, 0, 1, 1).toranges() == ((0, 1), (0, 1))
|
||||
|
||||
|
||||
def test_toranges_warn():
|
||||
with pytest.warns(DeprecationWarning):
|
||||
toranges(((0, 1), (0, 1)))
|
||||
|
||||
|
||||
def test_window_function():
|
||||
# TODO: break this test up.
|
||||
with rasterio.open('tests/data/RGB.byte.tif') as src:
|
||||
@ -104,11 +153,6 @@ def test_window_function():
|
||||
left, top - 2 * dy - EPS, left + 2 * dx - EPS, top, src.transform,
|
||||
height, width), ((0, 2), (0, 2)))
|
||||
|
||||
# bounds cropped
|
||||
assert_window_almost_equals(from_bounds(
|
||||
left - 2 * dx, top - 2 * dy, left + 2 * dx, top + 2 * dy,
|
||||
src.transform, height, width), ((0, 2), (0, 2)))
|
||||
|
||||
# boundless
|
||||
assert_window_almost_equals(from_bounds(
|
||||
left - 2 * dx, top - 2 * dy, left + 2 * dx, top + 2 * dy,
|
||||
@ -155,6 +199,7 @@ def test_window_bounds_north_up():
|
||||
precision=5)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="feature eliminated")
|
||||
def test_window_function_valuerror():
|
||||
with rasterio.open('tests/data/RGB.byte.tif') as src:
|
||||
left, bottom, right, top = src.bounds
|
||||
@ -186,17 +231,27 @@ def test_window_bounds_function():
|
||||
assert bounds(((0, rows), (0, cols)), src.transform) == src.bounds
|
||||
|
||||
|
||||
bad_windows = (
|
||||
bad_value_windows = [
|
||||
(1, 2, 3),
|
||||
(1, 2),
|
||||
((1, 0), 2))
|
||||
((1, 0), (2,))]
|
||||
|
||||
@pytest.mark.parametrize("window", bad_windows)
|
||||
def test_eval_window_bad_structure(window):
|
||||
bad_type_windows = [
|
||||
(1, 2),
|
||||
((1, 0), 2)]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("window", bad_value_windows)
|
||||
def test_eval_window_bad_value(window):
|
||||
with pytest.raises(ValueError):
|
||||
evaluate(window, 10, 10)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("window", bad_type_windows)
|
||||
def test_eval_window_bad_type(window):
|
||||
with pytest.raises(TypeError):
|
||||
evaluate(window, 10, 10)
|
||||
|
||||
|
||||
bad_params = (
|
||||
(((-1, 10), (0, 10)), -1, 10),
|
||||
(((1, -1), (0, 10)), -1, 10),
|
||||
@ -257,6 +312,9 @@ def test_shape_positive():
|
||||
def test_shape_negative():
|
||||
assert shape(((-10, None), (-10, None)), 100, 90) == (10, 10)
|
||||
assert shape(((~0, None), (~0, None)), 100, 90) == (1, 1)
|
||||
|
||||
|
||||
def test_shape_negative_start():
|
||||
assert shape(((None, ~0), (None, ~0)), 100, 90) == (99, 89)
|
||||
|
||||
|
||||
@ -409,7 +467,7 @@ def test_intersection():
|
||||
|
||||
|
||||
def test_round_window_to_full_blocks():
|
||||
with rasterio.open('tests/data/alpha.tif') as src:
|
||||
with rasterio.open('tests/data/alpha.tif') as src, pytest.warns(DeprecationWarning):
|
||||
block_shapes = src.block_shapes
|
||||
test_window = ((321, 548), (432, 765))
|
||||
rounded_window = round_window_to_full_blocks(test_window, block_shapes)
|
||||
@ -421,6 +479,13 @@ def test_round_window_to_full_blocks():
|
||||
assert rounded_window[1][0] % width_shape == 0
|
||||
assert rounded_window[1][1] % width_shape == 0
|
||||
|
||||
|
||||
def test_round_window_to_full_blocks_error():
|
||||
with pytest.raises(ValueError):
|
||||
round_window_to_full_blocks(
|
||||
Window(0, 0, 10, 10), block_shapes=[(1, 1), (2, 2)])
|
||||
|
||||
|
||||
def test_round_window_already_at_edge():
|
||||
with rasterio.open('tests/data/alpha.tif') as src:
|
||||
block_shapes = src.block_shapes
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user