[Git][debian-gis-team/rasterio][upstream] New upstream version 1.3.6

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Mon Feb 13 19:27:54 GMT 2023



Bas Couwenberg pushed to branch upstream at Debian GIS Project / rasterio


Commits:
0c69a8a2 by Bas Couwenberg at 2023-02-13T20:14:52+01:00
New upstream version 1.3.6
- - - - -


14 changed files:

- CHANGES.txt
- rasterio/__init__.py
- rasterio/_base.pyx
- rasterio/_features.pyx
- rasterio/_io.pyx
- rasterio/_transform.pyx
- rasterio/errors.py
- rasterio/transform.py
- + tests/data/all-nodata.tif
- tests/test_dataset.py
- tests/test_dataset_mask.py
- tests/test_plot.py
- + tests/test_statistics.py
- tests/test_warp.py


Changes:

=====================================
CHANGES.txt
=====================================
@@ -1,7 +1,29 @@
 Changes
 =======
 
-1.3.5 (2023-01-24)
+1.3.6 (2014-02-13)
+------------------
+
+- Tests that use matplotlib have been cleaned up and the one in test_warp.py
+  which uses our vendored rangehttpserver has been marked as needing a network
+  (#).
+- When computing the bounds of a sequence of feature or geometry objects, we
+  dodge empty "features" and "geometries" sequences that could be provided by,
+  e.g., Fiona 1.9.0 (#2745).
+- Decouple our Affine transformer from GDAL environments, fixing a performance
+  regression introduced in 1.3.0 (#2754).
+- StatisticsError is raised when dataset statistics cannot be computed (#2760).
+- In DatasetBase.__enter__ an Env is added to the dataset's context stack if
+  needed, making an explicit `with Env():` optional when using an opened
+  dataset as a context manager (#2760).
+
+1.3.5.post1 (2023-02-02)
+------------------------
+
+There are no code changes in this release. This is only to create new wheels as
+the 1.3.5 macosx 10.15 wheels are defective.
+
+1.3.5 (2023-01-25)
 ------------------
 
 Bug fixes:


=====================================
rasterio/__init__.py
=====================================
@@ -81,7 +81,7 @@ except ImportError:
     have_vsi_plugin = False
 
 __all__ = ['band', 'open', 'pad', 'Env', 'CRS']
-__version__ = "1.3.5"
+__version__ = "1.3.6"
 __gdal_version__ = gdal_version()
 __proj_version__ = ".".join([str(version) for version in get_proj_version()])
 __geos_version__ = ".".join([str(version) for version in get_geos_version()])


=====================================
rasterio/_base.pyx
=====================================
@@ -24,6 +24,7 @@ from rasterio.coords import BoundingBox
 from rasterio.crs import CRS
 from rasterio.enums import (
     ColorInterp, Compression, Interleaving, MaskFlags, PhotometricInterp)
+from rasterio.env import env_ctx_if_needed
 from rasterio.errors import (
     DatasetAttributeError,
     RasterioIOError, CRSError, DriverRegistrationError, NotGeoreferencedWarning,
@@ -439,6 +440,7 @@ cdef class DatasetBase:
         self._closed = True
 
     def __enter__(self):
+        self._env.enter_context(env_ctx_if_needed())
         return self
 
     def __exit__(self, *exc_details):


=====================================
rasterio/_features.pyx
=====================================
@@ -397,35 +397,17 @@ def _bounds(geometry, north_up=True, transform=None):
     TODO: add to Fiona.
     """
 
-    if 'features' in geometry:
-        # Input is a FeatureCollection
-        xmins = []
-        ymins = []
-        xmaxs = []
-        ymaxs = []
-        for feature in geometry['features']:
-            xmin, ymin, xmax, ymax = _bounds(feature['geometry'])
-            xmins.append(xmin)
-            ymins.append(ymin)
-            xmaxs.append(xmax)
-            ymaxs.append(ymax)
+    if 'features' in geometry and geometry["features"]:
+        xmins, ymins, xmaxs, ymaxs = zip(
+            *[_bounds(feat["geometry"]) for feat in geometry["features"]]
+        )
         if north_up:
             return min(xmins), min(ymins), max(xmaxs), max(ymaxs)
         else:
             return min(xmins), max(ymaxs), max(xmaxs), min(ymins)
 
-    elif 'geometries' in geometry:
-        # Input is a geometry collection
-        xmins = []
-        ymins = []
-        xmaxs = []
-        ymaxs = []
-        for geometry in geometry['geometries']:
-            xmin, ymin, xmax, ymax = _bounds(geometry)
-            xmins.append(xmin)
-            ymins.append(ymin)
-            xmaxs.append(xmax)
-            ymaxs.append(ymax)
+    elif 'geometries' in geometry and geometry['geometries']:
+        xmins, ymins, xmaxs, ymaxs = zip(*[_bounds(geom) for geom in geometry["geometries"]])
         if north_up:
             return min(xmins), min(ymins), max(xmaxs), max(ymaxs)
         else:


=====================================
rasterio/_io.pyx
=====================================
@@ -18,14 +18,16 @@ from rasterio._base import tastes_like_gdal
 from rasterio._base cimport open_dataset
 from rasterio._env import catch_errors
 from rasterio._err import (
-    GDALError, CPLE_OpenFailedError, CPLE_IllegalArgError, CPLE_BaseError, CPLE_AWSObjectNotFoundError, CPLE_HttpResponseError)
+    GDALError, CPLE_AppDefinedError, CPLE_OpenFailedError, CPLE_IllegalArgError, CPLE_BaseError,
+    CPLE_AWSObjectNotFoundError, CPLE_HttpResponseError)
 from rasterio.crs import CRS
 from rasterio import dtypes
 from rasterio.enums import ColorInterp, MaskFlags, Resampling
 from rasterio.errors import (
     CRSError, DriverRegistrationError, RasterioIOError,
     NotGeoreferencedWarning, NodataShadowWarning, WindowError,
-    UnsupportedOperation, OverviewCreationError, RasterBlockError, InvalidArrayError
+    UnsupportedOperation, OverviewCreationError, RasterBlockError, InvalidArrayError,
+    StatisticsError
 )
 from rasterio.dtypes import is_ndarray, _is_complex_int, _getnpdtype, _gdal_typename, _get_gdal_dtype
 from rasterio.sample import sample_gen
@@ -1107,8 +1109,8 @@ cdef class DatasetReaderBase(DatasetBase):
             exc_wrap_int(
                 GDALGetRasterStatistics(band, int(approx), 1, &min, &max, &mean, &std)
             )
-        except CPLE_BaseError:
-            raise
+        except CPLE_AppDefinedError as exc:
+            raise StatisticsError("No valid pixels found in sampling.") from exc
         else:
             return Statistics(min, max, mean, std)
 


=====================================
rasterio/_transform.pyx
=====================================
@@ -92,6 +92,7 @@ cdef class RPCTransformerBase:
                Consider using RPC_DEM to supply a DEM to sample accurate height measurements
                from.
         """
+        super().__init__()
         cdef char **papszMD = NULL
         cdef char **options = NULL
         cdef int bReversed = 1
@@ -125,8 +126,6 @@ cdef class RPCTransformerBase:
             CSLDestroy(options)
             CSLDestroy(papszMD)
 
-        self._env = ExitStack()
-
     def _transform(self, xs, ys, zs, transform_direction):
         """
         General computation of dataset pixel/line <-> lon/lat/height coordinates using RPCs
@@ -251,6 +250,7 @@ cdef class GCPTransformerBase:
         gcps : a sequence of GroundControlPoint
             Ground Control Points for a dataset.
         """
+        super().__init__()
         cdef int bReversed = 1
         cdef int nReqOrder = 0  # let GDAL determine polynomial order
         cdef GDAL_GCP *gcplist = <GDAL_GCP *>CPLMalloc(len(gcps) * sizeof(GDAL_GCP))
@@ -272,8 +272,6 @@ cdef class GCPTransformerBase:
         finally:
             CPLFree(gcplist)
 
-        self._env = ExitStack()
-
     def _transform(self, xs, ys, zs, transform_direction):
         """
         General computation of dataset pixel/line <-> lon/lat/height coordinates using GCPs


=====================================
rasterio/errors.py
=====================================
@@ -158,3 +158,7 @@ class DatasetIOShapeError(RasterioError):
 
 class WarpOperationError(RasterioError):
     """Raised when a warp operation fails."""
+
+
+class StatisticsError(RasterioError):
+    """Raised when dataset statistics cannot be computed."""


=====================================
rasterio/transform.py
=====================================
@@ -1,16 +1,13 @@
 """Geospatial transforms"""
 
-from collections.abc import Iterable
 from contextlib import ExitStack
 from functools import partial
 import math
 import numpy as np
-import sys
 import warnings
 
 from affine import Affine
 
-import rasterio
 from rasterio.env import env_ctx_if_needed
 from rasterio._transform import (
     _transform_from_gcps,
@@ -60,13 +57,13 @@ class TransformMethodsMixin:
         col : int
             Pixel column.
         z : float, optional
-            Height associated with coordinates. Primarily used for RPC based 
-            coordinate transformations. Ignored for affine based 
+            Height associated with coordinates. Primarily used for RPC based
+            coordinate transformations. Ignored for affine based
             transformations. Default: 0.
         offset : str, optional
             Determines if the returned coordinates are for the center of the
             pixel or for a corner.
-        transform_method: TransformMethod, optional 
+        transform_method: TransformMethod, optional
             The coordinate transformation method. Default: `TransformMethod.affine`.
         rpc_options: dict, optional
             Additional arguments passed to GDALCreateRPCTransformer
@@ -103,13 +100,13 @@ class TransformMethodsMixin:
         y : float
             y value in coordinate reference system
         z : float, optional
-            Height associated with coordinates. Primarily used for RPC based 
-            coordinate transformations. Ignored for affine based 
+            Height associated with coordinates. Primarily used for RPC based
+            coordinate transformations. Ignored for affine based
             transformations. Default: 0.
         op : function, optional (default: math.floor)
             Function to convert fractional pixels to whole numbers (floor,
             ceiling, round)
-        transform_method: TransformMethod, optional 
+        transform_method: TransformMethod, optional
             The coordinate transformation method. Default: `TransformMethod.affine`.
         rpc_options: dict, optional
             Additional arguments passed to GDALCreateRPCTransformer
@@ -210,20 +207,20 @@ def xy(transform, rows, cols, zs=None, offset='center', **rpc_options):
     The pixel's center is returned by default, but a corner can be returned
     by setting `offset` to one of `ul, ur, ll, lr`.
 
-    Supports affine, Ground Control Point (GCP), or Rational Polynomial 
+    Supports affine, Ground Control Point (GCP), or Rational Polynomial
     Coefficients (RPC) based coordinate transformations.
 
     Parameters
     ----------
     transform : Affine or sequence of GroundControlPoint or RPC
-        Transform suitable for input to AffineTransformer, GCPTransformer, or RPCTransformer. 
+        Transform suitable for input to AffineTransformer, GCPTransformer, or RPCTransformer.
     rows : list or int
         Pixel rows.
     cols : int or sequence of ints
         Pixel columns.
     zs : list or float, optional
-        Height associated with coordinates. Primarily used for RPC based 
-        coordinate transformations. Ignored for affine based 
+        Height associated with coordinates. Primarily used for RPC based
+        coordinate transformations. Ignored for affine based
         transformations. Default: 0.
     offset : str, optional
         Determines if the returned coordinates are for the center of the
@@ -256,8 +253,8 @@ def rowcol(transform, xs, ys, zs=None, op=math.floor, precision=None, **rpc_opti
     ys : list or float
         y values in coordinate reference system.
     zs : list or float, optional
-        Height associated with coordinates. Primarily used for RPC based 
-        coordinate transformations. Ignored for affine based 
+        Height associated with coordinates. Primarily used for RPC based
+        coordinate transformations. Ignored for affine based
         transformations. Default: 0.
     op : function
         Function to convert fractional pixels to whole numbers (floor, ceiling,
@@ -303,7 +300,7 @@ def from_gcps(gcps):
     return Affine.from_gdal(*_transform_from_gcps(gcps))
 
 
-class TransformerBase():
+class TransformerBase:
     """Generic GDAL transformer base class
 
     Notes
@@ -312,17 +309,12 @@ class TransformerBase():
 
     """
     def __init__(self):
-        self._env = ExitStack()
         self._transformer = None
-        self.closed = True
-
-    def close(self):
-        self.closed = True
 
     @staticmethod
     def _ensure_arr_input(xs, ys, zs=None):
         """Ensure all input coordinates are mapped to array-like objects
-        
+
         Raises
         ------
         TransformError
@@ -337,13 +329,11 @@ class TransformerBase():
         return np.atleast_1d(xs), np.atleast_1d(ys), np.atleast_1d(zs)
 
     def __enter__(self):
-        self._env.enter_context(env_ctx_if_needed())
         return self
 
     def __exit__(self, *args):
-        self.close()
-        self._env.close()
-    
+        pass
+
     def rowcol(self, xs, ys, zs=None, op=math.floor, precision=None):
         """Get rows and cols coordinates given geographic coordinates.
 
@@ -352,8 +342,8 @@ class TransformerBase():
         xs, ys : float or list of float
             Geographic coordinates
         zs : float or list of float, optional
-            Height associated with coordinates. Primarily used for RPC based 
-            coordinate transformations. Ignored for affine based 
+            Height associated with coordinates. Primarily used for RPC based
+            coordinate transformations. Ignored for affine based
             transformations. Default: 0.
         op : function, optional (default: math.floor)
             Function to convert fractional pixels to whole numbers (floor,
@@ -380,7 +370,7 @@ class TransformerBase():
 
         AS_ARR = True if hasattr(xs, "__iter__") else False
         xs, ys, zs = self._ensure_arr_input(xs, ys, zs=zs)
-        
+
         try:
             new_cols, new_rows = self._transform(
                 xs, ys, zs, transform_direction=TransformDirection.reverse
@@ -402,8 +392,8 @@ class TransformerBase():
         rows, cols : int or list of int
             Image pixel coordinates
         zs : float or list of float, optional
-            Height associated with coordinates. Primarily used for RPC based 
-            coordinate transformations. Ignored for affine based 
+            Height associated with coordinates. Primarily used for RPC based
+            coordinate transformations. Ignored for affine based
             transformations. Default: 0.
         offset : str, optional
             Determines if the returned coordinates are for the center of the
@@ -420,7 +410,7 @@ class TransformerBase():
         """
         AS_ARR = True if hasattr(rows, "__iter__") else False
         rows, cols, zs = self._ensure_arr_input(rows, cols, zs=zs)
-        
+
         if offset == 'center':
             coff, roff = (0.5, 0.5)
         elif offset == 'ul':
@@ -433,7 +423,7 @@ class TransformerBase():
             coff, roff = (1, 1)
         else:
             raise TransformError("Invalid offset")
-        
+
         # shift input coordinates according to offset
         T = IDENTITY.translation(coff, roff)
         offset_rows = []
@@ -454,11 +444,28 @@ class TransformerBase():
                 return (new_xs, new_ys)
         except TypeError:
             raise TransformError("Invalid inputs")
-    
+
     def _transform(self, xs, ys, zs, transform_direction):
         raise NotImplementedError
 
 
+class GDALTransformerBase(TransformerBase):
+    def __init__(self):
+        super().__init__()
+        self._env = ExitStack()
+
+    def close(self):
+        pass
+
+    def __enter__(self):
+        self._env.enter_context(env_ctx_if_needed())
+        return self
+
+    def __exit__(self, *args):
+        self.close()
+        self._env.close()
+
+
 class AffineTransformer(TransformerBase):
     """A pure Python class related to affine based coordinate transformations."""
     def __init__(self, affine_transform):
@@ -467,13 +474,10 @@ class AffineTransformer(TransformerBase):
             raise ValueError("Not an affine transform")
         self._transformer = affine_transform
 
-    def close(self):
-        pass
-    
     def _transform(self, xs, ys, zs, transform_direction):
         resxs = []
         resys = []
-        
+
         if transform_direction is TransformDirection.forward:
             transform = self._transformer
         elif transform_direction is TransformDirection.reverse:
@@ -483,21 +487,21 @@ class AffineTransformer(TransformerBase):
             resx, resy = transform * (x, y)
             resxs.append(resx)
             resys.append(resy)
-        
+
         return (resxs, resys)
-    
+
     def __repr__(self):
         return "<AffineTransformer>"
 
 
-class RPCTransformer(RPCTransformerBase, TransformerBase):
+class RPCTransformer(RPCTransformerBase, GDALTransformerBase):
     """
     Class related to Rational Polynomial Coeffecients (RPCs) based
     coordinate transformations.
 
     Uses GDALCreateRPCTransformer and GDALRPCTransform for computations. Options
     for GDALCreateRPCTransformer may be passed using `rpc_options`.
-    Ensure that GDAL transformer objects are destroyed by calling `close()` 
+    Ensure that GDAL transformer objects are destroyed by calling `close()`
     method or using context manager interface.
 
     """
@@ -511,13 +515,13 @@ class RPCTransformer(RPCTransformerBase, TransformerBase):
             self.closed and 'closed' or 'open')
 
 
-class GCPTransformer(GCPTransformerBase, TransformerBase):
+class GCPTransformer(GCPTransformerBase, GDALTransformerBase):
     """
     Class related to Ground Control Point (GCPs) based
     coordinate transformations.
 
     Uses GDALCreateGCPTransformer and GDALGCPTransform for computations.
-    Ensure that GDAL transformer objects are destroyed by calling `close()` 
+    Ensure that GDAL transformer objects are destroyed by calling `close()`
     method or using context manager interface.
 
     """


=====================================
tests/data/all-nodata.tif
=====================================
Binary files /dev/null and b/tests/data/all-nodata.tif differ


=====================================
tests/test_dataset.py
=====================================
@@ -2,12 +2,8 @@
 
 
 from pathlib import Path
-try:
-    from unittest.mock import MagicMock
-except ImportError:
-    from mock import MagicMock
+from unittest.mock import MagicMock
 
-from numpy.testing import assert_almost_equal
 import pytest
 
 import rasterio
@@ -72,16 +68,6 @@ def test_dataset_readonly_attributes(path_rgb_byte_tif):
             dataset.crs = "foo"
 
 
-def test_statistics(path_rgb_byte_tif):
-    """Compute, store, and return basic statistics."""
-    with rasterio.open(path_rgb_byte_tif) as dataset:
-        stats = dataset.statistics(1)
-        assert stats.min == 0
-        assert stats.max == 255
-        assert_almost_equal(stats.mean, 29.947726688477)
-        assert_almost_equal(stats.std, 52.340921626611)
-
-
 @pytest.mark.parametrize("blockysize", [1, 2, 3, 7, 61, 62])
 def test_creation_untiled_blockysize(tmp_path, blockysize):
     """Check for fix of gh-2599"""


=====================================
tests/test_dataset_mask.py
=====================================
@@ -1,25 +1,14 @@
-import logging
-import sys
+"""Dataset mask test."""
 
+from affine import Affine
 import numpy as np
 import pytest
 
-try:
-    import matplotlib as mpl
-    mpl.use('agg')
-    import matplotlib.pyplot as plt
-except ImportError:
-    plt = None
-
-from affine import Affine
-
 import rasterio
 from rasterio.enums import Resampling
 from rasterio.errors import NodataShadowWarning
 from rasterio.crs import CRS
 
-logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
-
 
 # Setup test arrays
 red = np.array([[0, 0, 0],
@@ -131,7 +120,7 @@ def tiffs(tmpdir):
     # 6. RGB with msk (internal)
     prof = _profile.copy()
     prof['count'] = 3
-    with rasterio.Env(GDAL_TIFF_INTERNAL_MASK=True) as env:
+    with rasterio.Env(GDAL_TIFF_INTERNAL_MASK=True):
         with rasterio.open(str(tmpdir.join('rgb_msk_internal.tif')),
                            'w', **prof) as dst:
             dst.write(red, 1)
@@ -156,22 +145,26 @@ def test_no_ndv(tiffs):
     with rasterio.open(str(tiffs.join('rgb_no_ndv.tif'))) as src:
         assert np.array_equal(src.dataset_mask(), alldata)
 
+
 def test_rgb_ndv(tiffs):
     with rasterio.open(str(tiffs.join('rgb_ndv.tif'))) as src:
         res = src.dataset_mask()
         assert res.dtype.name == "uint8"
         assert np.array_equal(src.dataset_mask(), alp)
 
+
 def test_rgba_no_ndv(tiffs):
     with rasterio.open(str(tiffs.join('rgba_no_ndv.tif'))) as src:
         assert np.array_equal(src.dataset_mask(), alp)
 
+
 def test_rgba_ndv(tiffs):
     with rasterio.open(str(tiffs.join('rgba_ndv.tif'))) as src:
         with pytest.warns(NodataShadowWarning):
             res = src.dataset_mask()
         assert np.array_equal(res, alp)
 
+
 def test_rgb_msk(tiffs):
     with rasterio.open(str(tiffs.join('rgb_msk.tif'))) as src:
         assert np.array_equal(src.dataset_mask(), msk)
@@ -179,10 +172,12 @@ def test_rgb_msk(tiffs):
         for bmask in src.read_masks():
             assert np.array_equal(bmask, msk)
 
+
 def test_rgb_msk_int(tiffs):
     with rasterio.open(str(tiffs.join('rgb_msk_internal.tif'))) as src:
         assert np.array_equal(src.dataset_mask(), msk)
 
+
 def test_rgba_msk(tiffs):
     with rasterio.open(str(tiffs.join('rgba_msk.tif'))) as src:
         # mask takes precendent over alpha


=====================================
tests/test_plot.py
=====================================
@@ -1,50 +1,47 @@
 """Unittests for rasterio.plot"""
 
-
-import numpy as np
 import pytest
 
-try:
-    import matplotlib as mpl
-    mpl.use('agg')
-    import matplotlib.pyplot as plt
-    plt.show = lambda :None
-except ImportError:
-    plt = None
+plt = pytest.importorskip("matplotlib.pyplot")
+
+import matplotlib
+import numpy as np
 
 import rasterio
-from rasterio.plot import (show, show_hist, get_plt,
-                           plotting_extent, adjust_band)
+from rasterio.plot import show, show_hist, get_plt, plotting_extent, adjust_band
 from rasterio.enums import ColorInterp
 
 
+matplotlib.use("agg")
+plt.show = lambda: None
+
+
 def test_show_raster_band():
     """Test plotting a single raster band."""
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         show((src, 1))
         fig = plt.gcf()
         plt.close(fig)
 
+
 def test_show_raster_mult_bands():
     """Test multiple bands plotting."""
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         show((src, (1, 2, 3)))
         fig = plt.gcf()
         plt.close(fig)
 
+
 def test_show_raster_object():
     """Test plotting a raster object."""
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         show(src)
         fig = plt.gcf()
         plt.close(fig)
 
+
 def test_show_raster_float():
     """Test plotting a raster object with float data."""
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/float.tif') as src:
         show(src)
         fig = plt.gcf()
@@ -53,7 +50,6 @@ def test_show_raster_float():
 
 def test_show_cmyk_interp(tmpdir):
     """A CMYK TIFF has cyan, magenta, yellow, black bands."""
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         profile = src.profile
 
@@ -84,7 +80,6 @@ def test_show_raster_no_bounds():
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show((src, 1), with_bounds=False)
@@ -99,7 +94,6 @@ def test_show_raster_title():
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show((src, 1), title="insert title here")
@@ -108,12 +102,12 @@ def test_show_raster_title():
         except ImportError:
             pass
 
+
 def test_show_hist_large():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     try:
         rand_arr = np.random.randn(10, 718, 791)
         show_hist(rand_arr)
@@ -122,12 +116,12 @@ def test_show_hist_large():
     except ImportError:
         pass
 
+
 def test_show_raster_cmap():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show((src, 1), cmap='jet')
@@ -136,12 +130,12 @@ def test_show_raster_cmap():
         except ImportError:
             pass
 
+
 def test_show_raster_ax():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             fig, ax = plt.subplots(1)
@@ -151,12 +145,12 @@ def test_show_raster_ax():
         except ImportError:
             pass
 
+
 def test_show_array():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show(src.read(1))
@@ -171,7 +165,6 @@ def test_show_array3D():
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show(src.read((1, 2, 3)))
@@ -180,12 +173,12 @@ def test_show_array3D():
         except ImportError:
             pass
 
+
 def test_show_hist():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show_hist((src, 1), bins=256)
@@ -209,12 +202,12 @@ def test_show_hist():
         except ImportError:
             pass
 
+
 def test_show_hist_mplargs():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show_hist(src, bins=50, lw=0.0, stacked=False, alpha=0.3,
@@ -224,12 +217,12 @@ def test_show_hist_mplargs():
         except ImportError:
             pass
 
+
 def test_show_contour():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show((src, 1), contour=True)
@@ -238,12 +231,12 @@ def test_show_contour():
         except ImportError:
             pass
 
+
 def test_show_contour_mplargs():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         try:
             show((src, 1), contour=True,
@@ -254,24 +247,25 @@ def test_show_contour_mplargs():
         except ImportError:
             pass
 
+
 def test_get_plt():
     """
     This test only verifies that code up to the point of plotting with
     matplotlib works correctly.  Tests do not exercise matplotlib.
     """
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif'):
         try:
             assert plt == get_plt()
         except ImportError:
             pass
 
+
 def test_plt_transform():
-    matplotlib = pytest.importorskip('matplotlib')
     with rasterio.open('tests/data/RGB.byte.tif') as src:
         show(src.read(), transform=src.transform)
         show(src.read(1), transform=src.transform)
 
+
 def test_plotting_extent():
     from rasterio.plot import reshape_as_image
     expected = (101985.0, 339315.0, 2611485.0, 2826915.0)
@@ -285,6 +279,7 @@ def test_plotting_extent():
         with pytest.raises(ValueError):
             plotting_extent(src.read(1))
 
+
 def test_plot_normalize():
     a = np.linspace(1, 6, 10)
     b = adjust_band(a, 'linear')


=====================================
tests/test_statistics.py
=====================================
@@ -0,0 +1,27 @@
+"""Test of a dataset's statistics method."""
+
+from numpy.testing import assert_almost_equal
+import pytest
+
+import rasterio
+from rasterio.errors import RasterioError
+
+
+def test_statistics(path_rgb_byte_tif):
+    """Compute, store, and return basic statistics."""
+    with rasterio.open(path_rgb_byte_tif) as dataset:
+        stats = dataset.statistics(1)
+        assert stats.min == 0
+        assert stats.max == 255
+        assert_almost_equal(stats.mean, 29.947726688477)
+        assert_almost_equal(stats.std, 52.340921626611)
+
+
+def test_statistics_all_invalid(capsys):
+    """Raise an exception for stats of an invalid dataset."""
+    with rasterio.open("tests/data/all-nodata.tif") as dataset:
+        with pytest.raises(RasterioError):
+            _ = dataset.statistics(1)
+
+    captured = capsys.readouterr()
+    assert "ERROR 1" not in captured.err


=====================================
tests/test_warp.py
=====================================
@@ -1959,6 +1959,7 @@ def test_reproject_rpcs_approx_transformer(caplog):
         assert "Created approximate transformer" in caplog.text
 
 
+ at pytest.mark.network
 @pytest.fixture
 def http_error_server(data):
     """Serves files from the test data directory, poorly."""



View it on GitLab: https://salsa.debian.org/debian-gis-team/rasterio/-/commit/0c69a8a2f0f4a135edce9b4a3843e485231372ad

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/rasterio/-/commit/0c69a8a2f0f4a135edce9b4a3843e485231372ad
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20230213/e3978364/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list