[Git][debian-gis-team/rasterio][master] 4 commits: New upstream version 1.1.3

Bas Couwenberg gitlab at salsa.debian.org
Tue Feb 25 05:13:26 GMT 2020



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


Commits:
b02d934e by Bas Couwenberg at 2020-02-25T05:53:43+01:00
New upstream version 1.1.3
- - - - -
bf39f2d2 by Bas Couwenberg at 2020-02-25T05:54:18+01:00
Update upstream source from tag 'upstream/1.1.3'

Update to upstream version '1.1.3'
with Debian dir 0841f61ea6b098ddb95aebc64f5314fa3660e04e
- - - - -
34520a6f by Bas Couwenberg at 2020-02-25T05:55:35+01:00
New upstream release.

- - - - -
40d1d848 by Bas Couwenberg at 2020-02-25T05:56:32+01:00
Set distribution to unstable.

- - - - -


22 changed files:

- CHANGES.txt
- debian/changelog
- rasterio/__init__.py
- rasterio/_io.pyx
- rasterio/compat.py
- rasterio/env.py
- rasterio/errors.py
- rasterio/features.py
- rasterio/path.py
- rasterio/rio/options.py
- rasterio/session.py
- rasterio/vrt.py
- rasterio/windows.py
- tests/test_dataset_mask.py
- tests/test_env.py
- tests/test_features.py
- tests/test_path.py
- tests/test_rio_info.py
- tests/test_rio_options.py
- tests/test_session.py
- tests/test_windows.py
- tests/test_write.py


Changes:

=====================================
CHANGES.txt
=====================================
@@ -1,6 +1,24 @@
 Changes
 =======
 
+1.1.3 (2020-02-24)
+------------------
+
+Bug fixes:
+
+- Raise RasterioIOError when errors occur while creating a dataset (#1796).
+- Ensure the output of read_masks contains only 255 and 0 (#1721).
+- Filter more categories of invalid features in rasterize (#1815).
+- Fall back to use of a DummySession instead of failing when boto3 isn't
+  available (#1864).
+- A crashing bug involving boundless reads of VRTs (#1863) has been fixed.
+- The required transform argument of windows.from_bounds() was changed from a
+  positional arg to a keyword arg in commit 361112e but no guard against the
+  default value of None was added (#1857). The function now raises WindowError
+  if no transform is given.
+- dataset_mask returned in some cases an array with dtype "int64" (#1856). This
+  bug was introduced in 1.1.2 and has been fixed.
+
 1.1.2 (2019-12-18)
 ------------------
 


=====================================
debian/changelog
=====================================
@@ -1,9 +1,11 @@
-rasterio (1.1.2-2) UNRELEASED; urgency=medium
+rasterio (1.1.3-1) unstable; urgency=medium
 
+  * Team upload.
+  * New upstream release.
   * Bump Standards-Version to 4.5.0, no changes.
   * Update watch file to not match post releases.
 
- -- Bas Couwenberg <sebastic at debian.org>  Sat, 25 Jan 2020 11:12:11 +0100
+ -- Bas Couwenberg <sebastic at debian.org>  Tue, 25 Feb 2020 05:56:21 +0100
 
 rasterio (1.1.2-1) unstable; urgency=medium
 


=====================================
rasterio/__init__.py
=====================================
@@ -42,7 +42,7 @@ import rasterio.path
 
 
 __all__ = ['band', 'open', 'pad', 'Env']
-__version__ = "1.1.2"
+__version__ = "1.1.3"
 __gdal_version__ = gdal_version()
 
 # Rasterio attaches NullHandler to the 'rasterio' logger and its


=====================================
rasterio/_io.pyx
=====================================
@@ -1,4 +1,6 @@
 """Rasterio input/output."""
+
+
 # cython: boundscheck=False, c_string_type=unicode, c_string_encoding=utf8
 
 from __future__ import absolute_import
@@ -616,19 +618,6 @@ cdef class DatasetReaderBase(DatasetBase):
                         indexes, out, Window(0, 0, window.width, window.height),
                         None, resampling=resampling, masks=True)
 
-                    # TODO: we need to determine why `out` can contain data
-                    # that looks more like the source's band 1 when doing
-                    # this kind of boundless read. It looks like
-                    # hmask = GDALGetMaskBand(band) may be returning the
-                    # a pointer to the band instead of the mask band in 
-                    # this case.
-                    # 
-                    # Temporary solution: convert all non-zero pixels to
-                    # 255 and log that we have done so.
-
-                    out = np.where(out != 0, 255, 0)
-                    log.warning("Nonzero values in mask have been converted to 255, see note in rasterio/_io.pyx, read_masks()")
-
         if return2d:
             out.shape = out.shape[1:]
 
@@ -797,14 +786,13 @@ cdef class DatasetReaderBase(DatasetBase):
         elif out is not None:
             kwargs.pop("out", None)
             kwargs["out_shape"] = (self.count, out.shape[-2], out.shape[-1])
-            out = 255 * np.logical_or.reduce(self.read_masks(**kwargs))
+            out = np.logical_or.reduce(self.read_masks(**kwargs)) * np.uint8(255)
             return out
 
         elif out_shape is not None:
             kwargs["out_shape"] = (self.count, out_shape[-2], out_shape[-1])
 
-        return 255 * np.logical_or.reduce(self.read_masks(**kwargs))
-
+        return np.logical_or.reduce(self.read_masks(**kwargs)) * np.uint8(255)
 
     def sample(self, xy, indexes=None, masked=False):
         """Get the values of a dataset at certain positions
@@ -1191,6 +1179,8 @@ cdef class DatasetWriterBase(DatasetReaderBase):
                 self._hds = exc_wrap_pointer(
                     GDALCreate(drv, fname, width, height,
                                count, gdal_dtype, options))
+            except CPLE_BaseError as exc:
+                raise RasterioIOError(str(exc))
             finally:
                 if options != NULL:
                     CSLDestroy(options)


=====================================
rasterio/compat.py
=====================================
@@ -15,6 +15,8 @@ if sys.version_info[0] >= 3:   # pragma: no cover
     from collections import UserDict
     from collections.abc import Iterable, Mapping
     from inspect import getfullargspec as getargspec
+    from pathlib import Path
+
 else:  # pragma: no cover
     warnings.warn("Python 2 compatibility will be removed after version 1.1", DeprecationWarning)
     string_types = basestring,
@@ -26,3 +28,5 @@ else:  # pragma: no cover
     from UserDict import UserDict
     from inspect import getargspec
     from collections import Iterable, Mapping
+    class Path(object):
+        pass


=====================================
rasterio/env.py
=====================================
@@ -14,7 +14,7 @@ from rasterio._env import (
 from rasterio.compat import string_types, getargspec
 from rasterio.errors import (
     EnvError, GDALVersionError, RasterioDeprecationWarning)
-from rasterio.session import Session, AWSSession, DummySession
+from rasterio.session import Session, DummySession
 
 
 class ThreadEnv(threading.local):
@@ -51,12 +51,6 @@ local = ThreadEnv()
 
 log = logging.getLogger(__name__)
 
-try:
-    import boto3
-except ImportError:
-    log.info("failed to import boto3, continuing.")
-    boto3 = None
-
 
 class Env(object):
     """Abstraction for GDAL and AWS configuration
@@ -110,7 +104,7 @@ class Env(object):
         }
 
     def __init__(self, session=None, aws_unsigned=False, profile_name=None,
-                 session_class=AWSSession, **options):
+                 session_class=Session.aws_or_dummy, **options):
         """Create a new GDAL/AWS environment.
 
         Note: this class is a context manager. GDAL isn't configured
@@ -187,12 +181,12 @@ class Env(object):
                     "AWSSession object instead.",
                     RasterioDeprecationWarning
                 )
-                session = AWSSession(session=session)
+                session = Session.aws_or_dummy(session=session)
 
             self.session = session
 
         elif aws_access_key_id or profile_name or aws_unsigned:
-            self.session = AWSSession(
+            self.session = Session.aws_or_dummy(
                 aws_access_key_id=aws_access_key_id,
                 aws_secret_access_key=aws_secret_access_key,
                 aws_session_token=aws_session_token,
@@ -200,13 +194,8 @@ class Env(object):
                 profile_name=profile_name,
                 aws_unsigned=aws_unsigned)
 
-        elif 'AWS_ACCESS_KEY_ID' in os.environ and 'AWS_SECRET_ACCESS_KEY' in os.environ and boto3 is not None:
-            try:
-                self.session = AWSSession()
-                self.session.credentials
-            except RuntimeError as exc:
-                log.info("No AWS session created. Credentials in environment have expired.")
-                self.session = DummySession()
+        elif 'AWS_ACCESS_KEY_ID' in os.environ and 'AWS_SECRET_ACCESS_KEY' in os.environ:
+            self.session = Session.from_environ()
 
         else:
             self.session = DummySession()


=====================================
rasterio/errors.py
=====================================
@@ -110,3 +110,7 @@ class OverviewCreationError(RasterioError):
 
 class DatasetAttributeError(RasterioError, NotImplementedError):
     """Raised when dataset attributes are misused"""
+
+
+class PathError(RasterioError):
+    """Raised when a dataset path is malformed or invalid"""


=====================================
rasterio/features.py
=====================================
@@ -76,11 +76,11 @@ def geometry_mask(
 
 @ensure_env
 def shapes(source, mask=None, connectivity=4, transform=IDENTITY):
-    """Yield (polygon, value for each set of adjacent pixels of the same value.
+    """Get shapes and values of connected regions in a dataset or array.
 
     Parameters
     ----------
-    source : array or dataset object opened in 'r' mode or Band or tuple(dataset, bidx)
+    source : array, dataset object, Band, or tuple(dataset, bidx)
         Data type must be one of rasterio.int16, rasterio.int32,
         rasterio.uint8, rasterio.uint16, or rasterio.float32.
     mask : numpy ndarray or rasterio Band object, optional
@@ -93,25 +93,30 @@ def shapes(source, mask=None, connectivity=4, transform=IDENTITY):
     connectivity : int, optional
         Use 4 or 8 pixel connectivity for grouping pixels into features
     transform : Affine transformation, optional
-        If not provided, feature coordinates will be generated based on pixel
-        coordinates
+        If not provided, feature coordinates will be generated based on
+        pixel coordinates
 
     Yields
     -------
-    tuple
+    polygon, value
         A pair of (polygon, value) for each feature found in the image.
-        Polygons are GeoJSON-like dicts and the values are the associated value
-        from the image, in the data type of the image.
-        Note: due to floating point precision issues, values returned from a
-        floating point image may not exactly match the original values.
+        Polygons are GeoJSON-like dicts and the values are the
+        associated value from the image, in the data type of the image.
+        Note: due to floating point precision issues, values returned
+        from a floating point image may not exactly match the original
+        values.
 
     Notes
     -----
-    The amount of memory used by this algorithm is proportional to the number
-    and complexity of polygons produced.  This algorithm is most appropriate
-    for simple thematic data.  Data with high pixel-to-pixel variability, such
-    as imagery, may produce one polygon per pixel and consume large amounts of
-    memory.
+    The amount of memory used by this algorithm is proportional to the
+    number and complexity of polygons produced.  This algorithm is most
+    appropriate for simple thematic data.  Data with high pixel-to-pixel
+    variability, such as imagery, may produce one polygon per pixel and
+    consume large amounts of memory.
+
+    Because the low-level implementation uses either an int32 or float32
+    buffer, uint32 and float64 data cannot be operated on without
+    truncation issues.
 
     """
     if hasattr(source, 'mask') and mask is None:
@@ -304,7 +309,7 @@ def rasterize(
 
         else:
             # invalid or empty geometries are skipped and raise a warning instead
-            warnings.warn('Invalid or empty shape at index {} will not be rasterized.'.format(index), ShapeSkipWarning)
+            warnings.warn('Invalid or empty shape {} at index {} will not be rasterized.'.format(geom, index), ShapeSkipWarning)
 
     if not valid_shapes:
         raise ValueError('No valid geometry objects found for rasterize')
@@ -482,15 +487,12 @@ def is_valid_geom(geom):
 
     geom = getattr(geom, '__geo_interface__', None) or geom
 
-    if 'type' not in geom:
-        return False
-
     try:
-        geom_type = geom['type']
+        geom_type = geom["type"]
         if geom_type not in geom_types.union({'GeometryCollection'}):
             return False
 
-    except TypeError:
+    except (KeyError, TypeError):
         return False
 
     if geom_type in geom_types:


=====================================
rasterio/path.py
=====================================
@@ -1,11 +1,14 @@
 """Dataset paths, identifiers, and filenames"""
 
+import os.path
 import re
 import sys
 
 import attr
 
-from rasterio.compat import urlparse
+from rasterio.compat import Path as PathlibPath
+from rasterio.compat import string_types, urlparse
+from rasterio.errors import PathError
 
 # Supported URI schemes and their mapping to GDAL's VSI suffix.
 # TODO: extend for other cloud plaforms.
@@ -121,26 +124,37 @@ def parse_path(path):
     -----
     When legacy GDAL filenames are encountered, they will be returned
     in a UnparsedPath.
+
     """
-    # Windows drive letters (e.g. "C:\") confuse `urlparse` as they look like
-    # URL schemes
-    if sys.platform == "win32" and re.match("^[a-zA-Z]\\:", path):
-        return UnparsedPath(path)
+    if isinstance(path, Path):
+        return path
 
-    elif path.startswith('/vsi'):
-        return UnparsedPath(path)
+    elif isinstance(path, PathlibPath):
+        return ParsedPath(path, None, None)
 
-    else:
-        parts = urlparse(path)
+    elif isinstance(path, string_types):
 
-        # if the scheme is not one of Rasterio's supported schemes, we
-        # return an UnparsedPath.
-        if parts.scheme and not all(p in SCHEMES for p in parts.scheme.split('+')):
+        if sys.platform == "win32" and re.match("^[a-zA-Z]\\:", path):
+            return UnparsedPath(path)
+
+        elif path.startswith('/vsi'):
             return UnparsedPath(path)
 
         else:
+            parts = urlparse(path)
+
+    else:
+        raise PathError("invalid path '{!r}'".format(path))
+
+    # if the scheme is not one of Rasterio's supported schemes, we
+    # return an UnparsedPath.
+    if parts.scheme:
+
+        if all(p in SCHEMES for p in parts.scheme.split('+')):
             return ParsedPath.from_uri(path)
 
+    return UnparsedPath(path)
+
 
 def vsi_path(path):
     """Convert a parsed path to a GDAL VSI path


=====================================
rasterio/rio/options.py
=====================================
@@ -111,8 +111,13 @@ def file_in_handler(ctx, param, value):
     """Normalize ordinary filesystem and VFS paths"""
     try:
         path = parse_path(value)
+
         if isinstance(path, UnparsedPath):
-            return path.name
+
+            if os.path.exists(path.path) and rasterio.shutil.exists(value):
+                return abspath_forward_slashes(path.path)
+            else:
+                return path.name
 
         elif path.scheme and path.is_remote:
             return path.name


=====================================
rasterio/session.py
=====================================
@@ -1,8 +1,19 @@
 """Abstraction for sessions in various clouds."""
 
+import logging
+
 from rasterio.path import parse_path, UnparsedPath
 
 
+log = logging.getLogger(__name__)
+
+try:
+    import boto3
+except ImportError:
+    log.debug("Could not import boto3, continuing with reduced functionality.")
+    boto3 = None
+
+
 class Session(object):
     """Base for classes that configure access to secured resources.
 
@@ -89,7 +100,11 @@ class Session(object):
             return DummySession
 
         elif path.scheme == "s3" or "amazonaws.com" in path.path:
-            return AWSSession
+            if boto3 is not None:
+                return AWSSession
+            else:
+                log.info("boto3 not available, falling back to a DummySession.")
+                return DummySession
 
         elif path.scheme == "oss" or "aliyuncs.com" in path.path:
             return OSSSession
@@ -124,6 +139,55 @@ class Session(object):
         """
         return Session.cls_from_path(path)(*args, **kwargs)
 
+    @staticmethod
+    def aws_or_dummy(*args, **kwargs):
+        """Create an AWSSession if boto3 is available, else DummySession
+
+        Parameters
+        ----------
+        path : str
+            A dataset path or identifier.
+        args : sequence
+            Positional arguments for the foreign session constructor.
+        kwargs : dict
+            Keyword arguments for the foreign session constructor.
+
+        Returns
+        -------
+        Session
+
+        """
+        if boto3 is not None:
+            return AWSSession(*args, **kwargs)
+        else:
+            return DummySession(*args, **kwargs)
+
+    @staticmethod
+    def from_environ(*args, **kwargs):
+        """Create a session object suited to the environment.
+
+        Parameters
+        ----------
+        path : str
+            A dataset path or identifier.
+        args : sequence
+            Positional arguments for the foreign session constructor.
+        kwargs : dict
+            Keyword arguments for the foreign session constructor.
+
+        Returns
+        -------
+        Session
+
+        """
+        try:
+            session = Session.aws_or_dummy(*args, **kwargs)
+            session.credentials
+        except RuntimeError as exc:
+            log.warning("Credentials in environment have expired. Creating a DummySession.")
+            session = DummySession(*args, **kwargs)
+        return session
+
 
 class DummySession(Session):
     """A dummy session.
@@ -177,7 +241,7 @@ class AWSSession(Session):
             aws_secret_access_key=None, aws_session_token=None,
             region_name=None, profile_name=None, endpoint_url=None,
             requester_pays=False):
-        """Create a new boto3 session
+        """Create a new AWS session
 
         Parameters
         ----------
@@ -201,8 +265,6 @@ class AWSSession(Session):
             True if the requester agrees to pay transfer costs (default:
             False)
         """
-        import boto3
-
         if session:
             self._session = session
         else:
@@ -240,7 +302,7 @@ class AWSSession(Session):
     def credentials(self):
         """The session credentials as a dict"""
         res = {}
-        if self._creds: # pragma: no branch
+        if self._creds:  # pragma: no branch
             frozen_creds = self._creds.get_frozen_credentials()
             if frozen_creds.access_key:  # pragma: no branch
                 res['aws_access_key_id'] = frozen_creds.access_key
@@ -294,7 +356,7 @@ class OSSSession(Session):
             "oss_secret_access_key": oss_secret_access_key,
             "oss_endpoint": oss_endpoint
         }
-    
+
     @classmethod
     def hascreds(cls, config):
         """Determine if the given configuration has proper credentials
@@ -383,14 +445,15 @@ class GSSession(Session):
 class SwiftSession(Session):
     """Configures access to secured resources stored in OpenStack Swift Object Storage.
     """
-    def __init__(self, session=None, 
-                swift_storage_url=None, swift_auth_token=None, 
+    def __init__(self, session=None,
+                swift_storage_url=None, swift_auth_token=None,
                 swift_auth_v1_url=None, swift_user=None, swift_key=None):
-        """Create new OpenStack Swift Object Storage Session.   
-        Three methods are possible:  
+        """Create new OpenStack Swift Object Storage Session.
+
+        Three methods are possible:
             1. Create session by the swiftclient library.
-            2. The SWIFT_STORAGE_URL and SWIFT_AUTH_TOKEN (this method is recommended by GDAL docs).  
-            3. The SWIFT_AUTH_V1_URL, SWIFT_USER and SWIFT_KEY (This depends on the swiftclient library).  
+            2. The SWIFT_STORAGE_URL and SWIFT_AUTH_TOKEN (this method is recommended by GDAL docs).
+            3. The SWIFT_AUTH_V1_URL, SWIFT_USER and SWIFT_KEY (This depends on the swiftclient library).
 
         Parameters
         ----------
@@ -439,7 +502,7 @@ class SwiftSession(Session):
                 "swift_storage_url": self._session.get_auth()[0],
                 "swift_auth_token": self._session.get_auth()[1]
             }
-            
+
     @classmethod
     def hascreds(cls, config):
         """Determine if the given configuration has proper credentials
@@ -467,4 +530,3 @@ class SwiftSession(Session):
         dict
         """
         return {k.upper(): v for k, v in self.credentials.items()}
-        


=====================================
rasterio/vrt.py
=====================================
@@ -179,7 +179,8 @@ def _boundless_vrt_doc(
             complexsource = ET.SubElement(vrtrasterband, 'ComplexSource')
             sourcefilename = ET.SubElement(complexsource, 'SourceFilename')
             sourcefilename.attrib['relativeToVRT'] = '1'
-            sourcefilename.text = 'dummy.tif'  # vsi_path(parse_path(background.name))
+            sourcefilename.attrib["shared"] = "0"
+            sourcefilename.text = "dummy.tif"
             sourceband = ET.SubElement(complexsource, 'SourceBand')
             sourceband.text = str(bidx)
             sourceproperties = ET.SubElement(complexsource, 'SourceProperties')
@@ -191,13 +192,13 @@ def _boundless_vrt_doc(
             srcrect = ET.SubElement(complexsource, 'SrcRect')
             srcrect.attrib['xOff'] = '0'
             srcrect.attrib['yOff'] = '0'
-            srcrect.attrib['xSize'] = '1'  # str(background.width)
-            srcrect.attrib['ySize'] = '1'  # str(background.height)
+            srcrect.attrib['xSize'] = '1'
+            srcrect.attrib['ySize'] = '1'
             dstrect = ET.SubElement(complexsource, 'DstRect')
             dstrect.attrib['xOff'] = '0'
             dstrect.attrib['yOff'] = '0'
-            dstrect.attrib['xSize'] = '1'  # str(width)
-            dstrect.attrib['ySize'] = '1'  # str(height)
+            dstrect.attrib['xSize'] = '1'
+            dstrect.attrib['ySize'] = '1'
             scaleratio = ET.SubElement(complexsource, 'ScaleRatio')
             scaleratio.text = '0'
             scaleoffset = ET.SubElement(complexsource, 'ScaleOffset')
@@ -206,6 +207,7 @@ def _boundless_vrt_doc(
         complexsource = ET.SubElement(vrtrasterband, 'ComplexSource')
         sourcefilename = ET.SubElement(complexsource, 'SourceFilename')
         sourcefilename.attrib['relativeToVRT'] = "0"
+        sourcefilename.attrib["shared"] = "0"
         sourcefilename.text = vsi_path(parse_path(src_dataset.name))
         sourceband = ET.SubElement(complexsource, 'SourceBand')
         sourceband.text = str(bidx)
@@ -247,6 +249,7 @@ def _boundless_vrt_doc(
         simplesource = ET.SubElement(vrtrasterband, 'SimpleSource')
         sourcefilename = ET.SubElement(simplesource, 'SourceFilename')
         sourcefilename.attrib['relativeToVRT'] = "0"
+        sourcefilename.attrib["shared"] = "0"
         sourcefilename.text = vsi_path(parse_path(src_dataset.name))
 
         sourceband = ET.SubElement(simplesource, 'SourceBand')


=====================================
rasterio/windows.py
=====================================
@@ -261,9 +261,9 @@ def from_bounds(left, bottom, right, top, transform=None,
     left, bottom, right, top: float
         Left (west), bottom (south), right (east), and top (north)
         bounding coordinates.
-    transform: Affine
+    transform: Affine, required
         Affine transform matrix.
-    height, width: int
+    height, width: int, required
         Number of rows and columns of the window.
     precision: int, optional
         Number of decimal points of precision when computing inverse
@@ -272,8 +272,17 @@ def from_bounds(left, bottom, right, top, transform=None,
     Returns
     -------
     Window
-        A new Window
+        A new Window.
+
+    Raises
+    ------
+    WindowError
+        If a window can't be calculated.
+
     """
+    if not isinstance(transform, Affine):  # TODO: RPCs?
+        raise WindowError("A transform object is required to calculate the window")
+
     row_start, col_start = rowcol(
         transform, left, top, op=float, precision=precision)
 


=====================================
tests/test_dataset_mask.py
=====================================
@@ -160,6 +160,8 @@ def test_no_ndv(tiffs):
 
 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):
@@ -194,13 +196,6 @@ def test_kwargs(tiffs, kwds, expected):
     with rasterio.open(str(tiffs.join('rgb_ndv.tif'))) as src:
         result = src.dataset_mask(**kwds)
         assert np.array_equal(expected, result)
-#
-#        other = src.dataset_mask(out_shape=(1, 5, 5))
-#        assert np.array_equal(resampmask, other)
-#
-#        out = np.zeros((1, 5, 5), dtype=np.uint8)
-#        other = src.dataset_mask(out=out)
-#        assert np.array_equal(resampmask, other)
 
 
 def test_indexes_not_supported(tiffs):


=====================================
tests/test_env.py
=====================================
@@ -323,6 +323,17 @@ def test_s3_open_with_implicit_env(gdalenv):
         assert dataset.count == 1
 
 
+ at requires_gdal21(reason="S3 access requires 2.1+")
+ at credentials
+ at pytest.mark.network
+def test_s3_open_with_implicit_env_no_boto3(monkeypatch, gdalenv):
+    """Read from S3 using default env."""
+    with monkeypatch.context() as mpctx:
+        mpctx.setattr("rasterio.session.boto3", None)
+        with rasterio.open(L8TIF) as dataset:
+            assert dataset.count == 1
+
+
 @requires_gdal21(reason="S3 access requires 2.1+")
 @credentials
 @pytest.mark.network
@@ -831,11 +842,12 @@ def test_swift_session_credentials(gdalenv):
 
 
 def test_swift_session_by_user_key():
-    def mock_init(self, session=None, 
-                swift_storage_url=None, swift_auth_token=None, 
-                swift_auth_v1_url=None, swift_user=None, swift_key=None):
-        self._creds = {'SWIFT_STORAGE_URL':'foo',
-                       'SWIFT_AUTH_TOKEN':'bar'}
+    def mock_init(
+            self, session=None,
+            swift_storage_url=None, swift_auth_token=None,
+            swift_auth_v1_url=None, swift_user=None, swift_key=None):
+        self._creds = {'SWIFT_STORAGE_URL': 'foo',
+                       'SWIFT_AUTH_TOKEN': 'bar'}
 
     with mock.patch('rasterio.session.SwiftSession.__init__', new=mock_init):
         swift_session = SwiftSession(
@@ -852,7 +864,7 @@ def test_dummy_session_without_boto3(monkeypatch, caplog):
     """Without boto3, always revert to dummy session"""
     # Confirm fix of #1708.
     with monkeypatch.context() as mpctx:
-        mpctx.setattr("rasterio.env.boto3", None)
+        mpctx.setattr("rasterio.session.boto3", None)
         mpctx.setenv('AWS_ACCESS_KEY_ID', 'lol')
         mpctx.setenv('AWS_SECRET_ACCESS_KEY', 'wut')
         assert isinstance(rasterio.env.Env().session, DummySession)


=====================================
tests/test_features.py
=====================================
@@ -354,13 +354,10 @@ def test_is_valid_geom_geomcollection(geojson_geomcollection):
     assert not is_valid_geom(geom)
 
 
-def test_is_valid_geom_invalid_inputs():
+ at pytest.mark.parametrize("geom", [None, 1, "foo", "type", ["type"], {"type": "Invalid"}, {"type": "Point"}])
+def test_is_valid_geom_invalid_inputs(geom):
     """Improperly formed GeoJSON objects should fail"""
-
-    assert not is_valid_geom('type')
-    assert not is_valid_geom(['type'])
-    assert not is_valid_geom({'type': 'Invalid'})  # wrong type
-    assert not is_valid_geom({'type': 'Point'})  # Missing coordinates
+    assert not is_valid_geom(geom)
 
 
 def test_rasterize_point(geojson_point):


=====================================
tests/test_path.py
=====================================
@@ -5,6 +5,7 @@ import sys
 import pytest
 
 import rasterio
+from rasterio.errors import PathError
 from rasterio.path import parse_path, vsi_path, ParsedPath, UnparsedPath
 
 
@@ -164,3 +165,20 @@ def test_vsi_path_zip_plus_https():
     """A zip+https:// URLs vsi path is correct (see #1151)"""
     url = 'zip+https://example.com/foo.zip!bar.tif'
     assert vsi_path(parse_path(url)) == '/vsizip/vsicurl/https://example.com/foo.zip/bar.tif'
+
+
+ at pytest.mark.parametrize("path", ["DRIVER:/vsifoo/bar:var", "SENTINEL2_L1C:S2A_OPER_MTD_SAFL1C_PDMC_20150818T101440_R022_V20150813T102406_20150813T102406.xml:10m:EPSG_32632"])
+def test_driver_prefixed_path(path):
+    parsed = parse_path(path)
+    assert isinstance(parsed, UnparsedPath)
+
+
+ at pytest.mark.parametrize("path", [0, -1.0, object()])
+def test_path_error(path):
+    with pytest.raises(PathError):
+        parse_path(path)
+
+
+def test_parse_path():
+    pathlib = pytest.importorskip("pathlib")
+    assert isinstance(parse_path(pathlib.Path("/foo/bar.tif")), ParsedPath)


=====================================
tests/test_rio_info.py
=====================================
@@ -32,8 +32,6 @@ def test_info_err():
         main_group, ['info', 'tests'])
     assert result.exit_code != 0
     assert result.exception
-    # Note: text of exception changed after 2.1, don't test on full string
-    assert 'not' in result.output and ' a valid input file' in result.output
 
 
 def test_info():


=====================================
tests/test_rio_options.py
=====================================
@@ -64,7 +64,7 @@ def test_file_in_handler_no_vfs_nonexistent():
     """file does not exist"""
     ctx = MockContext()
     with pytest.raises(click.BadParameter):
-        file_in_handler(ctx, 'INPUT', '{0}.tif'.format(uuid.uuid4()))
+        file_in_handler(ctx, 'INPUT', 'file://{0}.tif'.format(uuid.uuid4()))
 
 
 def test_file_in_handler_no_vfs():


=====================================
tests/test_session.py
=====================================
@@ -108,6 +108,15 @@ def test_session_factory_s3():
     assert isinstance(sesh, AWSSession)
 
 
+def test_session_factory_s3_no_boto3(monkeypatch):
+    """Get an AWSSession for s3:// paths"""
+    pytest.importorskip("boto3")
+    with monkeypatch.context() as mpctx:
+        mpctx.setattr("rasterio.session.boto3", None)
+        sesh = Session.from_path("s3://lol/wut")
+        assert isinstance(sesh, DummySession)
+
+
 def test_session_factory_s3_kwargs():
     """Get an AWSSession for s3:// paths with keywords"""
     pytest.importorskip("boto3")
@@ -202,4 +211,16 @@ def test_session_factory_swift_kwargs():
     sesh = Session.from_path("/vsiswift/lol/wut", swift_storage_url='foo', swift_auth_token='bar')
     assert isinstance(sesh, DummySession)
 
-    
+
+def test_session_aws_or_dummy_aws():
+    """Get an AWSSession when boto3 is available"""
+    boto3 = pytest.importorskip("boto3")
+    assert isinstance(Session.aws_or_dummy(), AWSSession)
+
+
+def test_session_aws_or_dummy_dummy(monkeypatch):
+    """Get a DummySession when boto3 is not available"""
+    boto3 = pytest.importorskip("boto3")
+    with monkeypatch.context() as mpctx:
+        mpctx.setattr("rasterio.session.boto3", None)
+        assert isinstance(Session.aws_or_dummy(), DummySession)


=====================================
tests/test_windows.py
=====================================
@@ -579,3 +579,9 @@ def test_window_hashable():
     c = Window(8, 8, 12, 12)
     assert hash(a) == hash(b)
     assert hash(a) != hash(c)
+
+
+def test_from_bounds_requires_transform():
+    """Test fix for issue 1857"""
+    with pytest.raises(WindowError):
+        from_bounds(-105, 40, -100, 45, height=100, width=100)


=====================================
tests/test_write.py
=====================================
@@ -365,3 +365,10 @@ def test_require_width(tmpdir, mode):
     with pytest.raises(TypeError):
         with rasterio.open(name, mode, driver="GTiff", height=1, count=1, dtype='uint8'):
             print("TEST FAILED IF THIS IS REACHED.")
+
+
+def test_too_big_for_tiff(tmpdir):
+    """RasterioIOError is raised when TIFF is too big"""
+    name = str(tmpdir.join("test.tif"))
+    with pytest.raises(RasterioIOError):
+        rasterio.open(name, 'w', driver='GTiff', height=100000, width=100000, count=1, dtype='uint8', BIGTIFF=False)



View it on GitLab: https://salsa.debian.org/debian-gis-team/rasterio/-/compare/2e4aa2ad551234ec3bb0e15865f6c66fb1277101...40d1d8481e2f7a3c31d98d2c0d93ccd90f8dfb87

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/rasterio/-/compare/2e4aa2ad551234ec3bb0e15865f6c66fb1277101...40d1d8481e2f7a3c31d98d2c0d93ccd90f8dfb87
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/20200225/dea2a1b7/attachment-0001.html>


More information about the Pkg-grass-devel mailing list