[Git][debian-gis-team/rasterio][master] 4 commits: New upstream version 1.0.4
Bas Couwenberg
gitlab at salsa.debian.org
Mon Sep 17 17:33:20 BST 2018
Bas Couwenberg pushed to branch master at Debian GIS Project / rasterio
Commits:
afa80682 by Bas Couwenberg at 2018-09-17T16:00:25Z
New upstream version 1.0.4
- - - - -
acba39c2 by Bas Couwenberg at 2018-09-17T16:00:31Z
Merge tag 'upstream/1.0.4'
Upstream version 1.0.4
- - - - -
853c1d26 by Bas Couwenberg at 2018-09-17T16:00:46Z
New upstream release.
- - - - -
064055af by Bas Couwenberg at 2018-09-17T16:17:04Z
Set distribution to unstable.
- - - - -
25 changed files:
- CHANGES.txt
- debian/changelog
- rasterio/__init__.py
- rasterio/_crs.pyx
- rasterio/_io.pxd
- rasterio/_io.pyx
- rasterio/_warp.pyx
- rasterio/coords.py
- rasterio/enums.py
- rasterio/env.py
- rasterio/io.py
- rasterio/rio/env.py
- rasterio/rio/main.py
- rasterio/rio/overview.py
- + rasterio/session.py
- rasterio/vrt.py
- rasterio/windows.py
- + tests/data/issue1446.geojson
- tests/test_coords.py
- tests/test_env.py
- tests/test_overviews.py
- + tests/test_session.py
- tests/test_warp.py
- tests/test_windows.py
- tests/test_write.py
Changes:
=====================================
CHANGES.txt
=====================================
@@ -1,6 +1,34 @@
Changes
=======
+1.0.4 (2018-09-17)
+------------------
+
+Bug fixes:
+
+- Boundless reads of datasets without a coordinate reference system have been
+ fixed (#1448).
+- A y-directional error in disjoint_bounds (#1459) has been fixed.
+- Prevent geometries from being thrown near projection singularities (#1446).
+- Missing --aws-no-sign-requests and --aws-requester-pays options added to
+ the main rio command (#1460).
+- Add missing bilinear, cubic spline, lanczos resampling modes for overviews
+ (#1457).
+- Raise ValueError if get_writer_for_driver() is called without a driver
+ name.
+- Windows are now frozen so that they are hashable (#1452).
+
+Refactoring:
+
+- Use of InMemoryRaster eliminates redundant code in the _warp module (#1427,
+ #816).
+- Generalize sessions to support cloud providers other than AWS (#1429).
+
+1.0.3.post1 (2018-09-07)
+------------------------
+
+This version corrects errors made in building binary wheels for 1.0.3. There
+are no bug fixes or new features in this version.
1.0.3 (2018-08-01)
------------------
=====================================
debian/changelog
=====================================
@@ -1,11 +1,13 @@
-rasterio (1.0.3-2) UNRELEASED; urgency=medium
+rasterio (1.0.4-1) unstable; urgency=medium
+ * Team upload.
+ * New upstream release.
* Bump Standards-Version to 4.2.1, no changes.
* Drop autopkgtests to test installability & module import.
* Add lintian override for testsuite-autopkgtest-missing.
* Update watch file to limit matches to archive path.
- -- Bas Couwenberg <sebastic at debian.org> Sun, 05 Aug 2018 20:56:12 +0200
+ -- Bas Couwenberg <sebastic at debian.org> Mon, 17 Sep 2018 18:01:27 +0200
rasterio (1.0.3-1) unstable; urgency=medium
=====================================
rasterio/__init__.py
=====================================
@@ -43,7 +43,7 @@ import rasterio.path
__all__ = ['band', 'open', 'pad', 'Env']
-__version__ = "1.0.3"
+__version__ = "1.0.4"
__gdal_version__ = gdal_version()
# Rasterio attaches NullHandler to the 'rasterio' logger and its
=====================================
rasterio/_crs.pyx
=====================================
@@ -65,6 +65,12 @@ class _CRS(UserDict):
cdef int retval
try:
+ if (
+ isinstance(other, self.__class__) and
+ self.data == other.data
+ ):
+ return True
+
if not self or not other:
return not self and not other
=====================================
rasterio/_io.pxd
=====================================
@@ -29,7 +29,7 @@ cdef class WarpedVRTReaderBase(DatasetReaderBase):
cdef class InMemoryRaster:
cdef GDALDatasetH _hds
cdef double gdal_transform[6]
- cdef int band_ids[1]
+ cdef int* band_ids
cdef np.ndarray _image
cdef object crs
cdef object transform # this is an Affine object.
=====================================
rasterio/_io.pyx
=====================================
@@ -1540,7 +1540,10 @@ cdef class DatasetWriterBase(DatasetReaderBase):
# (no corresponding member in the warp enum).
resampling_map = {
0: 'NEAREST',
+ 1: 'BILINEAR',
2: 'CUBIC',
+ 3: 'CUBICSPLINE',
+ 4: 'LANCZOS',
5: 'AVERAGE',
6: 'MODE',
7: 'GAUSS'}
@@ -1619,7 +1622,6 @@ cdef class InMemoryRaster:
This class is only intended for internal use within rasterio to support
IO with GDAL. Other memory based operations should use numpy arrays.
"""
-
def __cinit__(self, image=None, dtype='uint8', count=1, width=None,
height=None, transform=None, gcps=None, crs=None):
"""
@@ -1634,9 +1636,6 @@ cdef class InMemoryRaster:
(see rasterio.dtypes.dtype_rev)
:param transform: Affine transform object
"""
-
- self._image = image
-
cdef int i = 0 # avoids Cython warning in for loop below
cdef const char *srcwkt = NULL
cdef OGRSpatialReferenceH osr = NULL
@@ -1644,9 +1643,9 @@ cdef class InMemoryRaster:
cdef GDAL_GCP *gcplist = NULL
if image is not None:
- if len(image.shape) == 3:
+ if image.ndim == 3:
count, height, width = image.shape
- elif len(image.shape) == 2:
+ elif image.ndim == 2:
count = 1
height, width = image.shape
dtype = image.dtype.name
@@ -1657,9 +1656,18 @@ cdef class InMemoryRaster:
if width is None or width == 0:
raise ValueError("width must be > 0")
- self.band_ids[0] = 1
+ self.band_ids = <int *>CPLMalloc(count*sizeof(int))
+ for i in range(1, count + 1):
+ self.band_ids[i-1] = i
+
+ try:
+ memdriver = exc_wrap_pointer(GDALGetDriverByName("MEM"))
+ except Exception:
+ raise DriverRegistrationError(
+ "'MEM' driver not found. Check that this call is contained "
+ "in a `with rasterio.Env()` or `with rasterio.open()` "
+ "block.")
- memdriver = exc_wrap_pointer(GDALGetDriverByName("MEM"))
datasetname = str(uuid.uuid4()).encode('utf-8')
self._hds = exc_wrap_pointer(
GDALCreate(memdriver, <const char *>datasetname, width, height,
@@ -1670,39 +1678,42 @@ cdef class InMemoryRaster:
gdal_transform = transform.to_gdal()
for i in range(6):
self.gdal_transform[i] = gdal_transform[i]
- err = GDALSetGeoTransform(self._hds, self.gdal_transform)
- if err:
- raise ValueError("transform not set: %s" % transform)
-
+ exc_wrap_int(GDALSetGeoTransform(self._hds, self.gdal_transform))
if crs:
osr = _osr_from_crs(crs)
- OSRExportToWkt(osr, <char**>&srcwkt)
- GDALSetProjection(self._hds, srcwkt)
- log.debug("Set CRS on temp source dataset: %s", srcwkt)
- CPLFree(<void *>srcwkt)
- _safe_osr_release(osr)
+ try:
+ OSRExportToWkt(osr, &srcwkt)
+ exc_wrap_int(GDALSetProjection(self._hds, srcwkt))
+ log.debug("Set CRS on temp dataset: %s", srcwkt)
+ finally:
+ CPLFree(srcwkt)
+ _safe_osr_release(osr)
elif gcps and crs:
- gcplist = <GDAL_GCP *>CPLMalloc(len(gcps) * sizeof(GDAL_GCP))
- for i, obj in enumerate(gcps):
- ident = str(i).encode('utf-8')
- info = "".encode('utf-8')
- gcplist[i].pszId = ident
- gcplist[i].pszInfo = info
- gcplist[i].dfGCPPixel = obj.col
- gcplist[i].dfGCPLine = obj.row
- gcplist[i].dfGCPX = obj.x
- gcplist[i].dfGCPY = obj.y
- gcplist[i].dfGCPZ = obj.z or 0.0
+ try:
+ gcplist = <GDAL_GCP *>CPLMalloc(len(gcps) * sizeof(GDAL_GCP))
+ for i, obj in enumerate(gcps):
+ ident = str(i).encode('utf-8')
+ info = "".encode('utf-8')
+ gcplist[i].pszId = ident
+ gcplist[i].pszInfo = info
+ gcplist[i].dfGCPPixel = obj.col
+ gcplist[i].dfGCPLine = obj.row
+ gcplist[i].dfGCPX = obj.x
+ gcplist[i].dfGCPY = obj.y
+ gcplist[i].dfGCPZ = obj.z or 0.0
- osr = _osr_from_crs(crs)
- OSRExportToWkt(osr, <char**>&srcwkt)
- GDALSetGCPs(self._hds, len(gcps), gcplist, srcwkt)
- CPLFree(gcplist)
- CPLFree(<void *>srcwkt)
+ osr = _osr_from_crs(crs)
+ OSRExportToWkt(osr, &srcwkt)
+ exc_wrap_int(GDALSetGCPs(self._hds, len(gcps), gcplist, srcwkt))
+ finally:
+ CPLFree(gcplist)
+ CPLFree(srcwkt)
+ _safe_osr_release(osr)
- if self._image is not None:
- self.write(self._image)
+ self._image = None
+ if image is not None:
+ self.write(image)
def __enter__(self):
return self
@@ -1710,6 +1721,9 @@ cdef class InMemoryRaster:
def __exit__(self, *args, **kwargs):
self.close()
+ def __dealloc__(self):
+ CPLFree(self.band_ids)
+
cdef GDALDatasetH handle(self) except NULL:
"""Return the object's GDAL dataset handle"""
return self._hds
@@ -1735,11 +1749,22 @@ cdef class InMemoryRaster:
self._hds = NULL
def read(self):
- io_auto(self._image, self.band(1), False)
+ if self._image is None:
+ raise IOError("You need to write data before you can read the data.")
+
+ if self._image.ndim == 2:
+ exc_wrap_int(io_auto(self._image, self.band(1), False))
+ else:
+ exc_wrap_int(io_auto(self._image, self._hds, False))
return self._image
- def write(self, image):
- io_auto(image, self.band(1), True)
+ def write(self, np.ndarray image):
+ self._image = image
+ if image.ndim == 2:
+ exc_wrap_int(io_auto(self._image, self.band(1), True))
+ else:
+ exc_wrap_int(io_auto(self._image, self._hds, True))
+
cdef class BufferedDatasetWriterBase(DatasetWriterBase):
=====================================
rasterio/_warp.pyx
=====================================
@@ -17,6 +17,7 @@ from rasterio._err import (
from rasterio import dtypes
from rasterio.control import GroundControlPoint
from rasterio.enums import Resampling, MaskFlags, ColorInterp
+from rasterio.env import GDALVersion
from rasterio.crs import CRS
from rasterio.errors import (
DriverRegistrationError, CRSError, RasterioIOError,
@@ -67,11 +68,15 @@ def _transform_geom(
_safe_osr_release(dst)
raise
- # Transform options.
- valb = str(antimeridian_offset).encode('utf-8')
- options = CSLSetNameValue(options, "DATELINEOFFSET", <const char *>valb)
- if antimeridian_cutting:
- options = CSLSetNameValue(options, "WRAPDATELINE", "YES")
+ if GDALVersion().runtime() < GDALVersion.parse('2.2'):
+ valb = str(antimeridian_offset).encode('utf-8')
+ options = CSLSetNameValue(options, "DATELINEOFFSET", <const char *>valb)
+ if antimeridian_cutting:
+ options = CSLSetNameValue(options, "WRAPDATELINE", "YES")
+ else:
+ # GDAL cuts on the antimeridian by default and using different
+ # logic in versions >= 2.2.
+ pass
try:
factory = new OGRGeometryFactory()
@@ -286,48 +291,17 @@ def _reproject(
out: None
Output is written to destination.
"""
- cdef int retval
- cdef int rows
- cdef int cols
cdef int src_count
- cdef GDALDriverH driver = NULL
cdef GDALDatasetH src_dataset = NULL
cdef GDALDatasetH dst_dataset = NULL
- cdef GDALAccess GA
- cdef double gt[6]
- cdef char *srcwkt = NULL
- cdef char *dstwkt= NULL
- cdef OGRSpatialReferenceH src_osr = NULL
- cdef OGRSpatialReferenceH dst_osr = NULL
cdef char **warp_extras = NULL
cdef const char* pszWarpThread = NULL
cdef int i
cdef double tolerance = 0.125
- cdef GDAL_GCP *gcplist = NULL
cdef void *hTransformArg = NULL
cdef GDALTransformerFunc pfnTransformer = NULL
cdef GDALWarpOptions *psWOptions = NULL
- # If working with identity transform, assume it is crs-less data
- # and that translating the matrix very slightly will avoid #674
- eps = 1e-100
-
- if src_transform:
-
- src_transform = guard_transform(src_transform)
- # if src_transform is like `identity` with positive or negative `e`,
- # translate matrix very slightly to avoid #674 and #1272.
- if src_transform.almost_equals(identity) or src_transform.almost_equals(Affine(1, 0, 0, 0, -1, 0)):
- src_transform = src_transform.translation(eps, eps)
- src_transform = src_transform.to_gdal()
-
- if dst_transform:
-
- dst_transform = guard_transform(dst_transform)
- if dst_transform.almost_equals(identity) or dst_transform.almost_equals(Affine(1, 0, 0, 0, -1, 0)):
- dst_transform = dst_transform.translation(eps, eps)
- dst_transform = dst_transform.to_gdal()
-
# Validate nodata values immediately.
if src_nodata is not None:
if not in_dtype_range(src_nodata, source.dtype):
@@ -338,91 +312,43 @@ def _reproject(
if not in_dtype_range(dst_nodata, destination.dtype):
raise ValueError("dst_nodata must be in valid range for "
"destination dtype")
+
+ def format_transform(in_transform):
+ if not in_transform:
+ return in_transform
+ in_transform = guard_transform(in_transform)
+ # If working with identity transform, assume it is crs-less data
+ # and that translating the matrix very slightly will avoid #674 and #1272
+ eps = 1e-100
+ if in_transform.almost_equals(identity) or in_transform.almost_equals(Affine(1, 0, 0, 0, -1, 0)):
+ in_transform = in_transform.translation(eps, eps)
+ return in_transform
# If the source is an ndarray, we copy to a MEM dataset.
# We need a src_transform and src_dst in this case. These will
# be copied to the MEM dataset.
if dtypes.is_ndarray(source):
+ if not src_crs:
+ raise CRSError("Missing src_crs.")
+ if src_nodata is None and hasattr(source, 'fill_value'):
+ # source is a masked array
+ src_nodata = source.fill_value
# Convert 2D single-band arrays to 3D multi-band.
if len(source.shape) == 2:
source = source.reshape(1, *source.shape)
src_count = source.shape[0]
src_bidx = range(1, src_count + 1)
- rows = source.shape[1]
- cols = source.shape[2]
- dtype = np.dtype(source.dtype).name
-
- if src_nodata is None and hasattr(source, 'fill_value'):
- # source is a masked array
- src_nodata = source.fill_value
-
- try:
- driver = exc_wrap_pointer(GDALGetDriverByName("MEM"))
- except:
- raise DriverRegistrationError(
- "'MEM' driver not found. Check that this call is contained "
- "in a `with rasterio.Env()` or `with rasterio.open()` "
- "block.")
-
- datasetname = str(uuid.uuid4()).encode('utf-8')
- src_dataset = exc_wrap_pointer(
- GDALCreate(driver, <const char *>datasetname, cols, rows,
- src_count, dtypes.dtype_rev[dtype], NULL))
-
- GDALSetDescription(
- src_dataset, "Temporary source dataset for _reproject()")
-
- log.debug("Created temp source dataset")
-
- try:
- src_osr = _osr_from_crs(src_crs)
- OSRExportToWkt(src_osr, &srcwkt)
-
- if src_transform:
- for i in range(6):
- gt[i] = src_transform[i]
-
- exc_wrap_int(GDALSetGeoTransform(src_dataset, gt))
-
- exc_wrap_int(GDALSetProjection(src_dataset, srcwkt))
-
- log.debug("Set CRS on temp source dataset: %s", srcwkt)
-
- elif gcps:
- gcplist = <GDAL_GCP *>CPLMalloc(len(gcps) * sizeof(GDAL_GCP))
- try:
- for i, obj in enumerate(gcps):
- ident = str(i).encode('utf-8')
- info = "".encode('utf-8')
- gcplist[i].pszId = ident
- gcplist[i].pszInfo = info
- gcplist[i].dfGCPPixel = obj.col
- gcplist[i].dfGCPLine = obj.row
- gcplist[i].dfGCPX = obj.x
- gcplist[i].dfGCPY = obj.y
- gcplist[i].dfGCPZ = obj.z or 0.0
-
- exc_wrap_int(GDALSetGCPs(src_dataset, len(gcps), gcplist, srcwkt))
- finally:
- CPLFree(gcplist)
-
- finally:
- CPLFree(srcwkt)
- _safe_osr_release(src_osr)
-
- # Copy arrays to the dataset.
- exc_wrap_int(io_auto(source, src_dataset, 1))
-
- log.debug("Wrote array to temp source dataset")
-
+ src_dataset = InMemoryRaster(image=source,
+ transform=format_transform(src_transform),
+ gcps=gcps,
+ crs=src_crs).handle()
# If the source is a rasterio MultiBand, no copy necessary.
- # A MultiBand is a tuple: (dataset, bidx, dtype, shape(2d)).
+ # A MultiBand is a tuple: (dataset, bidx, dtype, shape(2d))
elif isinstance(source, tuple):
rdr, src_bidx, dtype, shape = source
if isinstance(src_bidx, int):
src_bidx = [src_bidx]
src_count = len(src_bidx)
- rows, cols = shape
src_dataset = (<DatasetReaderBase?>rdr).handle()
if src_nodata is None:
src_nodata = rdr.nodata
@@ -431,6 +357,8 @@ def _reproject(
# Next, do the same for the destination raster.
if dtypes.is_ndarray(destination):
+ if not dst_crs:
+ raise CRSError("Missing dst_crs.")
if len(destination.shape) == 2:
destination = destination.reshape(1, *destination.shape)
@@ -443,21 +371,9 @@ def _reproject(
raise ValueError("Invalid destination shape")
dst_bidx = src_bidx
- try:
- driver = exc_wrap_pointer(GDALGetDriverByName("MEM"))
- except:
- raise DriverRegistrationError(
- "'MEM' driver not found. Check that this call is contained "
- "in a `with rasterio.Env()` or `with rasterio.open()` "
- "block.")
-
- count, rows, cols = destination.shape
-
- datasetname = str(uuid.uuid4()).encode('utf-8')
- dst_dataset = exc_wrap_pointer(
- GDALCreate(driver, <const char *>datasetname, cols, rows, count,
- dtypes.dtype_rev[np.dtype(destination.dtype).name], NULL))
-
+ dst_dataset = InMemoryRaster(image=destination,
+ transform=format_transform(dst_transform),
+ crs=dst_crs).handle()
if dst_alpha:
for i in range(destination.shape[0]):
try:
@@ -472,26 +388,6 @@ def _reproject(
log.debug("Created temp destination dataset.")
- for i in range(6):
- gt[i] = dst_transform[i]
-
- exc_wrap_int(GDALSetGeoTransform(dst_dataset, gt))
-
- try:
- dst_osr = _osr_from_crs(dst_crs)
- OSRExportToWkt(dst_osr, &dstwkt)
-
- log.debug("CRS for temp destination dataset: %s.", dstwkt)
-
- exc_wrap_int(GDALSetProjection(dst_dataset, dstwkt))
- finally:
- CPLFree(dstwkt)
- _safe_osr_release(dst_osr)
-
- exc_wrap_int(io_auto(destination, dst_dataset, 1))
-
- log.debug("Wrote array to temp output dataset")
-
if dst_nodata is None:
if hasattr(destination, "fill_value"):
# destination is a masked array
@@ -503,7 +399,6 @@ def _reproject(
udr, dst_bidx, _, _ = destination
if isinstance(dst_bidx, int):
dst_bidx = [dst_bidx]
- udr = destination.ds
dst_dataset = (<DatasetReaderBase?>udr).handle()
if dst_nodata is None:
dst_nodata = udr.nodata
@@ -581,6 +476,8 @@ def _reproject(
# Now that the transformer and warp options are set up, we init
# and run the warper.
cdef GDALWarpOperation oWarper
+ cdef int rows
+ cdef int cols
try:
exc_wrap_int(oWarper.Initialize(psWOptions))
rows, cols = destination.shape[-2:]
=====================================
rasterio/coords.py
=====================================
@@ -52,7 +52,7 @@ def disjoint_bounds(bounds1, bounds2):
if bounds1_north_up:
return (bounds1[0] > bounds2[2] or bounds2[0] > bounds1[2] or
- bounds1[1] > bounds2[3] or bounds2[1] > bounds2[3])
+ bounds1[1] > bounds2[3] or bounds2[1] > bounds1[3])
else:
return (bounds1[0] > bounds2[2] or bounds2[0] > bounds1[2] or
- bounds1[3] > bounds2[1] or bounds2[3] > bounds2[1])
+ bounds1[3] > bounds2[1] or bounds2[3] > bounds1[1])
=====================================
rasterio/enums.py
=====================================
@@ -94,4 +94,4 @@ class PhotometricInterp(Enum):
class MergeAlg(Enum):
"""Available rasterization algorithms"""
replace = 'REPLACE'
- add = 'ADD'
\ No newline at end of file
+ add = 'ADD'
=====================================
rasterio/env.py
=====================================
@@ -1,19 +1,21 @@
"""Rasterio's GDAL/AWS environment"""
+import attr
from functools import wraps, total_ordering
import logging
-import threading
import re
-import attr
-
+import threading
+import warnings
import rasterio
from rasterio._env import (
GDALEnv, del_gdal_config, get_gdal_config, set_gdal_config)
from rasterio.compat import string_types, getargspec
from rasterio.dtypes import check_dtype
-from rasterio.errors import EnvError, GDALVersionError
-from rasterio.path import parse_path
+from rasterio.errors import (
+ EnvError, GDALVersionError, RasterioDeprecationWarning)
+from rasterio.path import parse_path, UnparsedPath, ParsedPath
+from rasterio.session import Session, AWSSession
from rasterio.transform import guard_transform
@@ -106,7 +108,8 @@ class Env(object):
def __init__(
self, session=None, aws_unsigned=False, aws_access_key_id=None,
aws_secret_access_key=None, aws_session_token=None,
- region_name=None, profile_name=None, **options):
+ region_name=None, profile_name=None, session_class=AWSSession,
+ **options):
"""Create a new GDAL/AWS environment.
Note: this class is a context manager. GDAL isn't configured
@@ -115,7 +118,7 @@ class Env(object):
Parameters
----------
session : optional
- A boto3 session object.
+ A Session object.
aws_unsigned : bool, optional (default: False)
If True, requests will be unsigned.
aws_access_key_id : str, optional
@@ -128,6 +131,8 @@ class Env(object):
A region name, as per boto3.
profile_name : str, optional
A shared credentials profile name, as per boto3.
+ session_class : Session, optional
+ A sub-class of Session.
**options : optional
A mapping of GDAL configuration options, e.g.,
`CPL_DEBUG=True, CHECK_WITH_INVERT_PROJ=False`.
@@ -142,25 +147,60 @@ class Env(object):
AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY are given. AWS
credentials are handled exclusively by boto3.
+ Examples
+ --------
+
+ >>> with Env(CPL_DEBUG=True, CPL_CURL_VERBOSE=True):
+ ... with rasterio.open("https://example.com/a.tif") as src:
+ ... print(src.profile)
+
+ For access to secured cloud resources, a Rasterio Session or a
+ foreign session object may be passed to the constructor.
+
+ >>> import boto3
+ >>> from rasterio.session import AWSSession
+ >>> boto3_session = boto3.Session(...)
+ >>> with Env(AWSSession(boto3_session)):
+ ... with rasterio.open("s3://mybucket/a.tif") as src:
+ ... print(src.profile)
+
"""
if ('AWS_ACCESS_KEY_ID' in options or
'AWS_SECRET_ACCESS_KEY' in options):
raise EnvError(
"GDAL's AWS config options can not be directly set. "
"AWS credentials are handled exclusively by boto3.")
- self.aws_unsigned = aws_unsigned
- self.aws_access_key_id = aws_access_key_id
- self.aws_secret_access_key = aws_secret_access_key
- self.aws_session_token = aws_session_token
- self.region_name = region_name
- self.profile_name = profile_name
- self.session = session
+
+ if session:
+ # Passing a session via keyword argument is the canonical
+ # way to configure access to secured cloud resources.
+ if not isinstance(session, Session):
+ warnings.warn(
+ "Passing a boto3 session is deprecated. Pass a Rasterio "
+ "AWSSession object instead.",
+ RasterioDeprecationWarning
+ )
+ session = AWSSession(session=session)
+ self.session = session
+ else:
+ # Before 1.0, Rasterio only supported AWS. We will special
+ # case AWS in 1.0.x. TODO: warn deprecation in 1.1.
+ warnings.warn(
+ "Passing abstract session keyword arguments is deprecated. "
+ "Pass a Rasterio AWSSession object instead.",
+ RasterioDeprecationWarning
+ )
+ self.session = AWSSession(
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ aws_session_token=aws_session_token,
+ region_name=region_name,
+ profile_name=profile_name,
+ aws_unsigned=aws_unsigned)
self.options = options.copy()
self.context_options = {}
- self._creds = None
-
@classmethod
def from_defaults(cls, *args, **kwargs):
"""Create an environment with default config options
@@ -193,7 +233,7 @@ class Env(object):
-------
bool
"""
- return bool(self._creds)
+ return hascreds() # bool(self.session)
def credentialize(self):
"""Get credentials and configure GDAL
@@ -204,54 +244,21 @@ class Env(object):
Returns
-------
None
+
"""
if hascreds():
pass
-
else:
- import boto3
- if not self.session and not self.aws_access_key_id and not self.profile_name:
- self.session = boto3.Session()
- elif not self.session:
- self.session = boto3.Session(
- aws_access_key_id=self.aws_access_key_id,
- aws_secret_access_key=self.aws_secret_access_key,
- aws_session_token=self.aws_session_token,
- region_name=self.region_name,
- profile_name=self.profile_name)
- else:
- # use self.session
- pass
- self._creds = self.session._session.get_credentials()
-
- # Pass these credentials to the GDAL environment.
- cred_opts = {}
-
- if self.aws_unsigned:
- cred_opts['AWS_NO_SIGN_REQUEST'] = 'YES'
- else:
- if self._creds.access_key: # pragma: no branch
- cred_opts['AWS_ACCESS_KEY_ID'] = self._creds.access_key
- if self._creds.secret_key: # pragma: no branch
- cred_opts['AWS_SECRET_ACCESS_KEY'] = self._creds.secret_key
- if self._creds.token:
- cred_opts['AWS_SESSION_TOKEN'] = self._creds.token
- if self.session.region_name:
- cred_opts['AWS_REGION'] = self.session.region_name
-
+ cred_opts = self.session.get_credential_options()
self.options.update(**cred_opts)
setenv(**cred_opts)
- def can_credentialize_on_enter(self):
- return bool(self.session or self.aws_access_key_id or self.profile_name)
-
def drivers(self):
"""Return a mapping of registered drivers."""
return local._env.drivers()
def __enter__(self):
log.debug("Entering env context: %r", self)
- # No parent Rasterio environment exists.
if local._env is None:
log.debug("Starting outermost env")
self._has_parent_env = False
@@ -274,8 +281,7 @@ class Env(object):
self.context_options = getenv()
setenv(**self.options)
- if self.can_credentialize_on_enter():
- self.credentialize()
+ self.credentialize()
log.debug("Entered env context: %r", self)
return self
@@ -389,17 +395,14 @@ def ensure_env_credentialled(f):
env_ctor = Env
else:
env_ctor = Env.from_defaults
- with env_ctor() as wrapper_env:
- if isinstance(args[0], str):
- path = parse_path(args[0])
- scheme = getattr(path, 'scheme', None)
- if scheme == 's3':
- wrapper_env.credentialize()
- log.debug("Credentialized: {!r}".format(getenv()))
- else:
- pass
- else:
- pass
+
+ if isinstance(args[0], str):
+ session = Session.from_path(args[0])
+ else:
+ session = Session.from_path(None)
+
+ with env_ctor(session=session):
+ log.debug("Credentialized: {!r}".format(getenv()))
return f(*args, **kwds)
return wrapper
=====================================
rasterio/io.py
=====================================
@@ -175,6 +175,8 @@ class ZipMemoryFile(MemoryFile):
def get_writer_for_driver(driver):
"""Return the writer class appropriate for the specified driver."""
+ if not driver:
+ raise ValueError("'driver' is required to write dataset.")
cls = None
if driver_can_create(driver):
cls = DatasetWriter
=====================================
rasterio/rio/env.py
=====================================
@@ -11,7 +11,7 @@ import rasterio
@click.option('--formats', 'key', flag_value='formats', default=True,
help="Enumerate the available formats.")
@click.option('--credentials', 'key', flag_value='credentials', default=False,
- help="Print AWS credentials.")
+ help="Print credentials.")
@click.pass_context
def env(ctx, key):
"""Print information about the Rasterio environment."""
@@ -20,7 +20,4 @@ def env(ctx, key):
for k, v in sorted(env.drivers().items()):
click.echo("{0}: {1}".format(k, v))
elif key == 'credentials':
- click.echo(json.dumps({
- 'aws_access_key_id': env._creds.access_key,
- 'aws_secret_access_key': env._creds.secret_key,
- 'aws_session_token': env._creds.token}))
+ click.echo(json.dumps(env.session.credentials))
=====================================
rasterio/rio/main.py
=====================================
@@ -41,6 +41,7 @@ import cligj
from . import options
import rasterio
+from rasterio.session import AWSSession
def configure_logging(verbosity):
@@ -51,28 +52,50 @@ def configure_logging(verbosity):
def gdal_version_cb(ctx, param, value):
if not value or ctx.resilient_parsing:
return
+
click.echo("{0}".format(rasterio.__gdal_version__), color=ctx.color)
ctx.exit()
- at with_plugins(ep for ep in list(iter_entry_points('rasterio.rio_commands')) +
- list(iter_entry_points('rasterio.rio_plugins')))
+ at with_plugins(
+ ep
+ for ep in list(iter_entry_points("rasterio.rio_commands"))
+ + list(iter_entry_points("rasterio.rio_plugins"))
+)
@click.group()
@cligj.verbose_opt
@cligj.quiet_opt
- at click.option('--aws-profile',
- help="Selects a profile from your shared AWS credentials file")
- at click.version_option(version=rasterio.__version__, message='%(version)s')
- at click.option('--gdal-version', is_eager=True, is_flag=True,
- callback=gdal_version_cb)
+ at click.option(
+ "--aws-profile", help="Select a profile from the AWS credentials file"
+)
+ at click.option("--aws-no-sign-requests", is_flag=True, help="Make requests anonymously")
+ at click.option(
+ "--aws-requester-pays", is_flag=True, help="Requester pays data transfer costs"
+)
+ at click.version_option(version=rasterio.__version__, message="%(version)s")
+ at click.option("--gdal-version", is_eager=True, is_flag=True, callback=gdal_version_cb)
@click.pass_context
-def main_group(ctx, verbose, quiet, aws_profile, gdal_version):
+def main_group(
+ ctx,
+ verbose,
+ quiet,
+ aws_profile,
+ aws_no_sign_requests,
+ aws_requester_pays,
+ gdal_version,
+):
"""Rasterio command line interface.
"""
verbosity = verbose - quiet
configure_logging(verbosity)
ctx.obj = {}
- ctx.obj['verbosity'] = verbosity
- ctx.obj['aws_profile'] = aws_profile
- ctx.obj['env'] = rasterio.Env(CPL_DEBUG=(verbosity > 2),
- profile_name=aws_profile)
+ ctx.obj["verbosity"] = verbosity
+ ctx.obj["aws_profile"] = aws_profile
+ ctx.obj["env"] = rasterio.Env(
+ session=AWSSession(
+ profile_name=aws_profile,
+ aws_unsigned=aws_no_sign_requests,
+ requester_pays=aws_requester_pays,
+ ),
+ CPL_DEBUG=(verbosity > 2)
+ )
=====================================
rasterio/rio/overview.py
=====================================
@@ -38,7 +38,7 @@ def build_handler(ctx, param, value):
is_flag=True, default=False)
@click.option('--resampling', help="Resampling algorithm.",
type=click.Choice(
- [it.name for it in Resampling if it.value in [0, 2, 5, 6, 7]]),
+ [it.name for it in Resampling if it.value in [0, 1, 2, 3, 4, 5, 6, 7]]),
default='nearest', show_default=True)
@click.pass_context
def overview(ctx, input, build, ls, rebuild, resampling):
=====================================
rasterio/session.py
=====================================
@@ -0,0 +1,190 @@
+"""Abstraction for sessions in various clouds."""
+
+
+from rasterio.path import parse_path, UnparsedPath, ParsedPath
+
+
+class Session(object):
+ """Base for classes that configure access to secured resources.
+
+ Attributes
+ ----------
+ credentials : dict
+ Keys and values for session credentials.
+
+ Notes
+ -----
+ This class is not intended to be instantiated.
+
+ """
+
+ def get_credential_options(self):
+ """Get credentials as GDAL configuration options
+
+ Returns
+ -------
+ dict
+
+ """
+ return NotImplementedError
+
+ @staticmethod
+ def from_foreign_session(session, cls=None):
+ """Create a session object matching the foreign `session`.
+
+ Parameters
+ ----------
+ session : obj
+ A foreign session object.
+ cls : Session class, optional
+ The class to return.
+
+ Returns
+ -------
+ Session
+
+ """
+ if not cls:
+ return DummySession()
+ else:
+ return cls(session)
+
+ @staticmethod
+ def from_path(path, *args, **kwargs):
+ """Create a session object suited to the data at `path`.
+
+ 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 not path:
+ return DummySession()
+
+ path = parse_path(path)
+
+ if isinstance(path, UnparsedPath) or path.is_local:
+ return DummySession()
+
+ elif path.scheme == "s3" or "amazonaws.com" in path.path:
+ return AWSSession(*args, **kwargs)
+
+ # This factory can be extended to other cloud providers here.
+ # elif path.scheme == "cumulonimbus": # for example.
+ # return CumulonimbusSession(*args, **kwargs)
+
+ else:
+ return DummySession()
+
+
+class DummySession(Session):
+ """A dummy session.
+
+ Attributes
+ ----------
+ credentials : dict
+ The session credentials.
+
+ """
+
+ def __init__(self, *args, **kwargs):
+ self._session = None
+ self.credentials = {}
+
+ def get_credential_options(self):
+ """Get credentials as GDAL configuration options
+
+ Returns
+ -------
+ dict
+
+ """
+ return {}
+
+
+class AWSSession(Session):
+ """Configures access to secured resources stored in AWS S3.
+ """
+
+ def __init__(
+ self, session=None, aws_unsigned=False, aws_access_key_id=None,
+ aws_secret_access_key=None, aws_session_token=None,
+ region_name=None, profile_name=None, requester_pays=False):
+ """Create a new boto3 session
+
+ Parameters
+ ----------
+ session : optional
+ A boto3 session object.
+ aws_unsigned : bool, optional (default: False)
+ If True, requests will be unsigned.
+ aws_access_key_id : str, optional
+ An access key id, as per boto3.
+ aws_secret_access_key : str, optional
+ A secret access key, as per boto3.
+ aws_session_token : str, optional
+ A session token, as per boto3.
+ region_name : str, optional
+ A region name, as per boto3.
+ profile_name : str, optional
+ A shared credentials profile name, as per boto3.
+ requester_pays : bool, optional
+ True if the requester agrees to pay transfer costs (default:
+ False)
+ """
+ import boto3
+
+ if session:
+ self._session = session
+ else:
+ if not aws_access_key_id and not profile_name:
+ self._session = boto3.Session()
+ else:
+ self._session = boto3.Session(
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ aws_session_token=aws_session_token,
+ region_name=region_name,
+ profile_name=profile_name)
+
+ self.requester_pays = requester_pays
+ self.unsigned = aws_unsigned
+ self._creds = self._session._session.get_credentials()
+
+ @property
+ def credentials(self):
+ """The session credentials as a dict"""
+ creds = {}
+ if self._creds.access_key: # pragma: no branch
+ creds['aws_access_key_id'] = self._creds.access_key
+ if self._creds.secret_key: # pragma: no branch
+ creds['aws_secret_access_key'] = self._creds.secret_key
+ if self._creds.token:
+ creds['aws_session_token'] = self._creds.token
+ if self._session.region_name:
+ creds['aws_region'] = self._session.region_name
+ if self.requester_pays:
+ creds['aws_request_payer'] = 'requester'
+ return creds
+
+ def get_credential_options(self):
+ """Get credentials as GDAL configuration options
+
+ Returns
+ -------
+ dict
+
+ """
+ if self.unsigned:
+ return {'AWS_NO_SIGN_REQUEST': 'YES'}
+ else:
+ return {k.upper(): v for k, v in self.credentials.items()}
=====================================
rasterio/vrt.py
=====================================
@@ -81,7 +81,7 @@ def _boundless_vrt_doc(src_dataset, nodata=None, width=None, height=None, transf
vrtdataset.attrib['rasterYSize'] = str(height)
vrtdataset.attrib['rasterXSize'] = str(width)
srs = ET.SubElement(vrtdataset, 'SRS')
- srs.text = src_dataset.crs.wkt
+ srs.text = src_dataset.crs.wkt if src_dataset.crs else ""
geotransform = ET.SubElement(vrtdataset, 'GeoTransform')
geotransform.text = ','.join([str(v) for v in transform.to_gdal()])
=====================================
rasterio/windows.py
=====================================
@@ -475,7 +475,8 @@ def validate_length_value(instance, attribute, value):
raise ValueError("Number of columns or rows must be non-negative")
- at attr.s(slots=True)
+ at attr.s(slots=True,
+ frozen=True)
class Window(object):
"""Windows are rectangular subsets of rasters.
=====================================
tests/data/issue1446.geojson
=====================================
@@ -0,0 +1,14 @@
+{
+"type": "FeatureCollection",
+"name": "test_lines",
+"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
+"features": [
+{ "type": "Feature", "properties": { "fid": 183521, "uuid": "{2c66f90e-befb-49d5-8083-c5642194be06}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.146176034327512, 2.172296541854189 ], [ -9.146450423923667, 2.172488614571499 ], [ -9.146649356380882, 2.172845321046502 ], [ -9.146697374560208, 2.172989375584485 ], [ -9.146834569358287, 2.173099131422947 ], [ -9.146944325196749, 2.173380380759008 ], [ -9.146951184936654, 2.17349013659747 ], [ -9.146923745977038, 2.173757666453723 ], [ -9.146717953779921, 2.174196689807574 ], [ -9.146621917421266, 2.174395622264787 ], [ -9.146553320022226, 2.174553396282577 ], [ -9.146436704443861, 2.174704310560464 ], [ -9.146004540829914, 2.175074736515274 ], [ -9.145572377215966, 2.17541772351047 ], [ -9.145270548660195, 2.175644094927299 ] ] } },
+{ "type": "Feature", "properties": { "fid": 183518, "uuid": "{a84f6b24-082c-4e78-a39d-46f2d96582e4}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.148784450425975, 2.175074736515274 ], [ -9.148949084183668, 2.174889523537869 ], [ -9.149120577681266, 2.174807206659022 ], [ -9.149381247797615, 2.174642572901328 ], [ -9.149614478954348, 2.174457359923922 ], [ -9.149827130891369, 2.174299585906132 ], [ -9.150026063348584, 2.173936019691225 ], [ -9.150190697106277, 2.17349013659747 ], [ -9.150348471124067, 2.172996235324388 ], [ -9.150417068523106, 2.172783583387367 ], [ -9.150458226962529, 2.172399437952748 ], [ -9.15054740358128, 2.171994713298417 ], [ -9.150595421760608, 2.17175462240178 ], [ -9.150588562020706, 2.171617427603702 ], [ -9.150691458119262, 2.171349897747449 ], [ -9.150753195778398, 2.17112352633062 ] ] } },
+{ "type": "Feature", "properties": { "fid": 183519, "uuid": "{be89730e-95de-4744-a18c-406730800b73}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.147330185566345, 2.175877326084033 ], [ -9.147583995942789, 2.17557549752826 ], [ -9.147782928400003, 2.175355985851335 ], [ -9.147940702417793, 2.175198211833545 ], [ -9.148180793314429, 2.175019858596043 ], [ -9.148324847852413, 2.174834645618637 ], [ -9.148448323170683, 2.174670011860944 ], [ -9.148647255627896, 2.174532817062865 ], [ -9.148784450425975, 2.174340744345556 ], [ -9.148866767304822, 2.174100653448919 ], [ -9.148921645224053, 2.173977178130648 ], [ -9.149072559501938, 2.173750806713819 ], [ -9.14912743742117, 2.173558733996509 ], [ -9.149182315340401, 2.173195167781602 ], [ -9.149168595860594, 2.172982515844581 ], [ -9.149141156900978, 2.172824741826791 ], [ -9.14928521143896, 2.172673827548905 ], [ -9.149394967277424, 2.172612089889769 ], [ -9.149504723115886, 2.17257779119025 ] ] } },
+{ "type": "Feature", "properties": { "fid": 183517, "uuid": "{e02bf433-920a-4edd-a869-8bfabc832149}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.150869811356765, 2.174711170300367 ], [ -9.151041304854362, 2.174594554722001 ], [ -9.15117849965244, 2.174464219663826 ], [ -9.151267676271191, 2.174347604085459 ], [ -9.151329413930327, 2.174182970327766 ], [ -9.151349993150038, 2.174011476830168 ], [ -9.151281395750999, 2.173689069054684 ], [ -9.151226517831768, 2.173476417117663 ], [ -9.151130481473112, 2.173222606741218 ], [ -9.151048164594268, 2.173009954804196 ], [ -9.151034445114458, 2.17270126650852 ], [ -9.15105502433417, 2.172433736652267 ], [ -9.151164780172632, 2.172269102894574 ], [ -9.151205938612057, 2.172166206796015 ], [ -9.151233377571671, 2.171898676939762 ], [ -9.151247097051479, 2.171672305522933 ], [ -9.151315694450519, 2.171473373065719 ], [ -9.151391151589461, 2.171240141908986 ], [ -9.151446029508692, 2.171075508151293 ] ] } },
+{ "type": "Feature", "properties": { "fid": 183522, "uuid": "{662d526c-0ef9-4aab-b533-7ac0a64ee014}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.146133160953113, 2.172913918445542 ], [ -9.146194898612247, 2.173037393763812 ], [ -9.146332093410326, 2.173154009342179 ], [ -9.146421270029077, 2.17324318596093 ], [ -9.146441849248788, 2.17340095997872 ], [ -9.146359532369942, 2.173558733996509 ], [ -9.146284075230998, 2.173689069054684 ], [ -9.146105721993496, 2.174073214489303 ], [ -9.146043984334362, 2.174230988507093 ], [ -9.146043984334362, 2.174272146946516 ] ] } },
+{ "type": "Feature", "properties": { "fid": 183523, "uuid": "{d54434ff-2013-4897-bb9c-856468743b13}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.14416441560069, 2.172234804195054 ], [ -9.144377067537711, 2.172529773010922 ], [ -9.144438805196845, 2.172708126248424 ], [ -9.144589719474732, 2.172955076884965 ], [ -9.144651457133866, 2.173133430122467 ], [ -9.144802371411753, 2.173133430122467 ], [ -9.145008163608871, 2.173119710642659 ], [ -9.145138498667045, 2.17308541194314 ] ] } },
+{ "type": "Feature", "properties": { "fid": 183520, "uuid": "{8bfc07f0-8550-479b-9682-741a3c3b1c75}" }, "geometry": { "type": "LineString", "coordinates": [ [ -9.148954228988597, 2.171761482141684 ], [ -9.148981667948213, 2.172090749657072 ], [ -9.148967948468405, 2.172344560033517 ], [ -9.148871912109751, 2.172625809369577 ], [ -9.148576943293881, 2.172797302867175 ], [ -9.148350571877053, 2.173044253503716 ], [ -9.148336852397245, 2.17317458856189 ], [ -9.148398590056379, 2.173298063880161 ], [ -9.148357431616956, 2.17352443529699 ], [ -9.148206517339069, 2.173572453476317 ], [ -9.147987005662147, 2.174025196309976 ], [ -9.147808652424644, 2.174340744345556 ], [ -9.147630299187142, 2.174615133941712 ], [ -9.147417647250119, 2.174923822237389 ], [ -9.147150117393867, 2.1752942481922 ], [ -9.146868868057807, 2.175589217008068 ] ] } }
+]
+}
=====================================
tests/test_coords.py
=====================================
@@ -1,23 +1,41 @@
-import rasterio
import numpy as np
+import rasterio
+from rasterio.coords import BoundingBox, disjoint_bounds
+
+
def test_bounds():
with rasterio.open('tests/data/RGB.byte.tif') as src:
assert src.bounds == (101985.0, 2611485.0, 339315.0, 2826915.0)
+
def test_ul():
with rasterio.open('tests/data/RGB.byte.tif') as src:
assert src.xy(0, 0, offset='ul') == (101985.0, 2826915.0)
assert src.xy(1, 0, offset='ul') == (101985.0, 2826614.95821727)
assert src.xy(src.height, src.width, offset='ul') == (339315.0, 2611485.0)
+
def test_res():
with rasterio.open('tests/data/RGB.byte.tif') as src:
assert tuple(round(v, 6) for v in src.res) == (300.037927, 300.041783)
+
def test_rotated_bounds():
with rasterio.open('tests/data/rotated.tif') as src:
assert src.res == (20.0, 10.0)
np.testing.assert_almost_equal(
src.bounds,
(100.0, 70.0961894323342, 348.20508075688775, 300.0))
+
+
+def test_disjoint_bounds_issue1459():
+ a = BoundingBox(left=478038, bottom=57155, right=703888, top=266344)
+ b = BoundingBox(left=584184, bottom=469629, right=740727, top=626172)
+ assert disjoint_bounds(a, b)
+
+
+def test_disjoint_bounds_issue1459_south_up():
+ a = BoundingBox(left=0.0, bottom=1.0, right=1.0, top=0.0)
+ b = BoundingBox(left=0.0, bottom=2.0, right=1.0, top=1.01)
+ assert disjoint_bounds(a, b)
=====================================
tests/test_env.py
=====================================
@@ -167,10 +167,10 @@ def test_aws_session(gdalenv):
aws_access_key_id='id', aws_secret_access_key='key',
aws_session_token='token', region_name='null-island-1')
with rasterio.env.Env(session=aws_session) as s:
- assert s._creds.access_key == 'id'
- assert s._creds.secret_key == 'key'
- assert s._creds.token == 'token'
- assert s.session.region_name == 'null-island-1'
+ assert s.session._creds.access_key == 'id'
+ assert s.session._creds.secret_key == 'key'
+ assert s.session._creds.token == 'token'
+ assert s.session._session.region_name == 'null-island-1'
def test_aws_session_credentials(gdalenv):
=====================================
tests/test_overviews.py
=====================================
@@ -8,9 +8,9 @@ import pytest
import rasterio
from rasterio.enums import Resampling
+from rasterio.env import GDALVersion
-
-logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
+gdal_version = GDALVersion()
def test_count_overviews_zero(data):
@@ -40,6 +40,18 @@ def test_build_overviews_two(data):
assert src.overviews(2) == [2, 4]
assert src.overviews(3) == [2, 4]
+ at pytest.mark.xfail(
+ gdal_version < GDALVersion.parse('2.0'),
+ reason="Bilinear resampling not supported by GDAL < 2.0")
+def test_build_overviews_bilinear(data):
+ inputfile = str(data.join('RGB.byte.tif'))
+ with rasterio.open(inputfile, 'r+') as src:
+ overview_factors = [2, 4]
+ src.build_overviews(overview_factors, resampling=Resampling.bilinear)
+ assert src.overviews(1) == [2, 4]
+ assert src.overviews(2) == [2, 4]
+ assert src.overviews(3) == [2, 4]
+
def test_build_overviews_average(data):
inputfile = str(data.join('RGB.byte.tif'))
=====================================
tests/test_session.py
=====================================
@@ -0,0 +1,116 @@
+"""Tests of session module"""
+
+import pytest
+
+from rasterio.session import DummySession, AWSSession, Session
+
+
+def test_dummy_session():
+ """DummySession works"""
+ sesh = DummySession()
+ assert sesh._session is None
+ assert sesh.get_credential_options() == {}
+
+
+def test_aws_session_class():
+ """AWSSession works"""
+ sesh = AWSSession(aws_access_key_id='foo', aws_secret_access_key='bar')
+ assert sesh._session
+ assert sesh.get_credential_options()['AWS_ACCESS_KEY_ID'] == 'foo'
+ assert sesh.get_credential_options()['AWS_SECRET_ACCESS_KEY'] == 'bar'
+
+
+def test_aws_session_class_session():
+ """AWSSession works"""
+ boto3 = pytest.importorskip("boto3")
+ sesh = AWSSession(session=boto3.session.Session(aws_access_key_id='foo', aws_secret_access_key='bar'))
+ assert sesh._session
+ assert sesh.get_credential_options()['AWS_ACCESS_KEY_ID'] == 'foo'
+ assert sesh.get_credential_options()['AWS_SECRET_ACCESS_KEY'] == 'bar'
+
+
+def test_aws_session_class_unsigned():
+ """AWSSession works"""
+ pytest.importorskip("boto3")
+ sesh = AWSSession(aws_unsigned=True)
+ assert sesh._session
+ assert sesh.get_credential_options()['AWS_NO_SIGN_REQUEST'] == 'YES'
+
+
+def test_aws_session_class_profile(tmpdir, monkeypatch):
+ """Confirm that profile_name kwarg works."""
+ pytest.importorskip("boto3")
+ credentials_file = tmpdir.join('credentials')
+ credentials_file.write("[testing]\n"
+ "aws_access_key_id = foo\n"
+ "aws_secret_access_key = bar\n"
+ "aws_session_token = baz")
+ monkeypatch.setenv('AWS_SHARED_CREDENTIALS_FILE', str(credentials_file))
+ monkeypatch.setenv('AWS_SESSION_TOKEN', 'ignore_me')
+ sesh = AWSSession(profile_name='testing')
+ assert sesh._session
+ assert sesh.get_credential_options()['AWS_ACCESS_KEY_ID'] == 'foo'
+ assert sesh.get_credential_options()['AWS_SECRET_ACCESS_KEY'] == 'bar'
+ assert sesh.get_credential_options()['AWS_SESSION_TOKEN'] == 'baz'
+ monkeypatch.undo()
+
+
+def test_session_factory_unparsed():
+ """Get a DummySession for unparsed paths"""
+ sesh = Session.from_path("/vsicurl/lolwut")
+ assert isinstance(sesh, DummySession)
+
+
+def test_session_factory_empty():
+ """Get a DummySession for no path"""
+ sesh = Session.from_path("")
+ assert isinstance(sesh, DummySession)
+
+
+def test_session_factory_local():
+ """Get a DummySession for local paths"""
+ sesh = Session.from_path("file:///lolwut")
+ assert isinstance(sesh, DummySession)
+
+
+def test_session_factory_unknown():
+ """Get a DummySession for unknown paths"""
+ sesh = Session.from_path("https://fancy-cloud.com/lolwut")
+ assert isinstance(sesh, DummySession)
+
+
+def test_session_factory_s3():
+ """Get an AWSSession for s3:// paths"""
+ pytest.importorskip("boto3")
+ sesh = Session.from_path("s3://lol/wut")
+ assert isinstance(sesh, AWSSession)
+
+
+def test_session_factory_s3_kwargs():
+ """Get an AWSSession for s3:// paths with keywords"""
+ pytest.importorskip("boto3")
+ sesh = Session.from_path("s3://lol/wut", aws_access_key_id='foo', aws_secret_access_key='bar')
+ assert isinstance(sesh, AWSSession)
+ assert sesh._session.get_credentials().access_key == 'foo'
+ assert sesh._session.get_credentials().secret_key == 'bar'
+
+
+def test_foreign_session_factory_dummy():
+ sesh = Session.from_foreign_session(None)
+ assert isinstance(sesh, DummySession)
+
+
+def test_foreign_session_factory_s3():
+ boto3 = pytest.importorskip("boto3")
+ aws_session = boto3.Session(aws_access_key_id='foo', aws_secret_access_key='bar')
+ sesh = Session.from_foreign_session(aws_session, cls=AWSSession)
+ assert isinstance(sesh, AWSSession)
+ assert sesh._session.get_credentials().access_key == 'foo'
+ assert sesh._session.get_credentials().secret_key == 'bar'
+
+
+def test_requester_pays():
+ """GDAL is configured with requester pays"""
+ sesh = AWSSession(requester_pays=True)
+ assert sesh._session
+ assert sesh.get_credential_options()['AWS_REQUEST_PAYER'] == 'requester'
=====================================
tests/test_warp.py
=====================================
@@ -1,4 +1,4 @@
-
+import json
import logging
import sys
@@ -8,14 +8,20 @@ import numpy as np
import rasterio
from rasterio.control import GroundControlPoint
+from rasterio.crs import CRS
from rasterio.enums import Resampling
from rasterio.env import GDALVersion
-from rasterio.errors import (
- GDALBehaviorChangeException, CRSError, GDALVersionError)
+from rasterio.errors import (GDALBehaviorChangeException, CRSError, GDALVersionError)
from rasterio.warp import (
- reproject, transform_geom, transform, transform_bounds,
- calculate_default_transform, aligned_target, SUPPORTED_RESAMPLING,
- GDAL2_RESAMPLING)
+ reproject,
+ transform_geom,
+ transform,
+ transform_bounds,
+ calculate_default_transform,
+ aligned_target,
+ SUPPORTED_RESAMPLING,
+ GDAL2_RESAMPLING,
+)
from rasterio import windows
from .conftest import requires_gdal22
@@ -25,8 +31,7 @@ gdal_version = GDALVersion.runtime()
logging.basicConfig(level=logging.DEBUG)
-DST_TRANSFORM = Affine(300.0, 0.0, -8789636.708,
- 0.0, -300.0, 2943560.235)
+DST_TRANSFORM = Affine(300.0, 0.0, -8789636.708, 0.0, -300.0, 2943560.235)
def flatten_coords(coordinates):
@@ -34,21 +39,21 @@ def flatten_coords(coordinates):
for elem in coordinates:
if isinstance(elem, (float, int)):
yield elem
+
else:
for x in flatten_coords(elem):
yield x
reproj_expected = (
- ({'CHECK_WITH_INVERT_PROJ': False}, 7608),
- ({'CHECK_WITH_INVERT_PROJ': True}, 2216))
+ ({"CHECK_WITH_INVERT_PROJ": False}, 7608), ({"CHECK_WITH_INVERT_PROJ": True}, 2216)
+)
class ReprojectParams(object):
"""Class to assist testing reprojection by encapsulating parameters."""
- def __init__(self, left, bottom, right, top, width, height, src_crs,
- dst_crs):
+ def __init__(self, left, bottom, right, top, width, height, src_crs, dst_crs):
self.width = width
self.height = height
src_res = float(right - left) / float(width)
@@ -57,7 +62,8 @@ class ReprojectParams(object):
self.dst_crs = dst_crs
dt, dw, dh = calculate_default_transform(
- src_crs, dst_crs, width, height, left, bottom, right, top)
+ src_crs, dst_crs, width, height, left, bottom, right, top
+ )
self.dst_transform = dt
self.dst_width = dw
self.dst_height = dh
@@ -71,8 +77,9 @@ def default_reproject_params():
top=70,
width=80,
height=80,
- src_crs={'init': 'EPSG:4326'},
- dst_crs={'init': 'EPSG:2163'})
+ src_crs={"init": "EPSG:4326"},
+ dst_crs={"init": "EPSG:2163"},
+ )
def uninvertable_reproject_params():
@@ -83,11 +90,12 @@ def uninvertable_reproject_params():
top=70,
width=80,
height=80,
- src_crs={'init': 'EPSG:4326'},
- dst_crs={'init': 'EPSG:26836'})
+ src_crs={"init": "EPSG:4326"},
+ dst_crs={"init": "EPSG:26836"},
+ )
-WGS84_crs = {'init': 'EPSG:4326'}
+WGS84_crs = {"init": "EPSG:4326"}
def test_transform_src_crs_none():
@@ -122,96 +130,106 @@ def test_transform_geom_dst_crs_none():
def test_reproject_src_crs_none():
with pytest.raises(CRSError):
- reproject(np.ones((2, 2)), np.zeros((2, 2)),
- src_transform=Affine.identity(),
- dst_transform=Affine.identity(), dst_crs=WGS84_crs)
+ reproject(
+ np.ones((2, 2)),
+ np.zeros((2, 2)),
+ src_transform=Affine.identity(),
+ dst_transform=Affine.identity(),
+ dst_crs=WGS84_crs,
+ )
def test_reproject_dst_crs_none():
with pytest.raises(CRSError):
- reproject(np.ones((2, 2)), np.zeros((2, 2)),
- src_transform=Affine.identity(),
- dst_transform=Affine.identity(), src_crs=WGS84_crs)
+ reproject(
+ np.ones((2, 2)),
+ np.zeros((2, 2)),
+ src_transform=Affine.identity(),
+ dst_transform=Affine.identity(),
+ src_crs=WGS84_crs,
+ )
def test_transform():
"""2D and 3D."""
- WGS84_crs = {'init': 'EPSG:4326'}
+ WGS84_crs = {"init": "EPSG:4326"}
WGS84_points = ([12.492269], [41.890169], [48.])
- ECEF_crs = {'init': 'EPSG:4978'}
+ ECEF_crs = {"init": "EPSG:4978"}
ECEF_points = ([4642610.], [1028584.], [4236562.])
ECEF_result = transform(WGS84_crs, ECEF_crs, *WGS84_points)
assert np.allclose(np.array(ECEF_result), np.array(ECEF_points))
- UTM33_crs = {'init': 'EPSG:32633'}
+ UTM33_crs = {"init": "EPSG:32633"}
UTM33_points = ([291952], [4640623])
UTM33_result = transform(WGS84_crs, UTM33_crs, *WGS84_points[:2])
assert np.allclose(np.array(UTM33_result), np.array(UTM33_points))
def test_transform_bounds():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
l, b, r, t = src.bounds
assert np.allclose(
- transform_bounds(src.crs, {'init': 'EPSG:4326'}, l, b, r, t),
+ transform_bounds(src.crs, {"init": "EPSG:4326"}, l, b, r, t),
(
- -78.95864996545055, 23.564991210854686,
- -76.57492370013823, 25.550873767433984
- )
+ -78.95864996545055,
+ 23.564991210854686,
+ -76.57492370013823,
+ 25.550873767433984,
+ ),
)
def test_transform_bounds_densify():
# This transform is non-linear along the edges, so densification produces
# a different result than otherwise
- src_crs = {'init': 'EPSG:4326'}
- dst_crs = {'init': 'EPSG:2163'}
+ src_crs = {"init": "EPSG:4326"}
+ dst_crs = {"init": "EPSG:2163"}
assert np.allclose(
- transform_bounds(
- src_crs,
- dst_crs,
- -120, 40, -80, 64,
- densify_pts=0),
- (-1684649.41338, -350356.81377, 1684649.41338, 2234551.18559))
+ transform_bounds(src_crs, dst_crs, -120, 40, -80, 64, densify_pts=0),
+ (-1684649.41338, -350356.81377, 1684649.41338, 2234551.18559),
+ )
assert np.allclose(
- transform_bounds(
- src_crs,
- dst_crs,
- -120, 40, -80, 64,
- densify_pts=100),
- (-1684649.41338, -555777.79210, 1684649.41338, 2234551.18559))
+ transform_bounds(src_crs, dst_crs, -120, 40, -80, 64, densify_pts=100),
+ (-1684649.41338, -555777.79210, 1684649.41338, 2234551.18559),
+ )
def test_transform_bounds_no_change():
"""Make sure that going from and to the same crs causes no change."""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
l, b, r, t = src.bounds
- assert np.allclose(
- transform_bounds(src.crs, src.crs, l, b, r, t),
- src.bounds
- )
+ assert np.allclose(transform_bounds(src.crs, src.crs, l, b, r, t), src.bounds)
def test_transform_bounds_densify_out_of_bounds():
with pytest.raises(ValueError):
transform_bounds(
- {'init': 'EPSG:4326'},
- {'init': 'EPSG:32610'},
- -120, 40, -80, 64,
- densify_pts=-10
+ {"init": "EPSG:4326"},
+ {"init": "EPSG:32610"},
+ -120,
+ 40,
+ -80,
+ 64,
+ densify_pts=-10,
)
def test_calculate_default_transform():
target_transform = Affine(
- 0.0028535715391804096, 0.0, -78.95864996545055,
- 0.0, -0.0028535715391804096, 25.550873767433984)
+ 0.0028535715391804096,
+ 0.0,
+ -78.95864996545055,
+ 0.0,
+ -0.0028535715391804096,
+ 25.550873767433984,
+ )
- with rasterio.open('tests/data/RGB.byte.tif') as src:
- wgs84_crs = {'init': 'EPSG:4326'}
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
+ wgs84_crs = {"init": "EPSG:4326"}
dst_transform, width, height = calculate_default_transform(
- src.crs, wgs84_crs, src.width, src.height, *src.bounds)
+ src.crs, wgs84_crs, src.width, src.height, *src.bounds
+ )
assert dst_transform.almost_equals(target_transform)
assert width == 835
@@ -219,15 +237,23 @@ def test_calculate_default_transform():
def test_calculate_default_transform_single_resolution():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
target_resolution = 0.1
target_transform = Affine(
- target_resolution, 0.0, -78.95864996545055,
- 0.0, -target_resolution, 25.550873767433984
+ target_resolution,
+ 0.0,
+ -78.95864996545055,
+ 0.0,
+ -target_resolution,
+ 25.550873767433984,
)
dst_transform, width, height = calculate_default_transform(
- src.crs, {'init': 'EPSG:4326'}, src.width, src.height,
- *src.bounds, resolution=target_resolution
+ src.crs,
+ {"init": "EPSG:4326"},
+ src.width,
+ src.height,
+ *src.bounds,
+ resolution=target_resolution
)
assert dst_transform.almost_equals(target_transform)
@@ -236,16 +262,24 @@ def test_calculate_default_transform_single_resolution():
def test_calculate_default_transform_multiple_resolutions():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
target_resolution = (0.2, 0.1)
target_transform = Affine(
- target_resolution[0], 0.0, -78.95864996545055,
- 0.0, -target_resolution[1], 25.550873767433984
+ target_resolution[0],
+ 0.0,
+ -78.95864996545055,
+ 0.0,
+ -target_resolution[1],
+ 25.550873767433984,
)
dst_transform, width, height = calculate_default_transform(
- src.crs, {'init': 'EPSG:4326'}, src.width, src.height,
- *src.bounds, resolution=target_resolution
+ src.crs,
+ {"init": "EPSG:4326"},
+ src.width,
+ src.height,
+ *src.bounds,
+ resolution=target_resolution
)
assert dst_transform.almost_equals(target_transform)
@@ -254,16 +288,25 @@ def test_calculate_default_transform_multiple_resolutions():
def test_calculate_default_transform_dimensions():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
dst_width, dst_height = (113, 103)
target_transform = Affine(
- 0.02108612597535966, 0.0, -78.95864996545055,
- 0.0, -0.0192823863230055, 25.550873767433984
+ 0.02108612597535966,
+ 0.0,
+ -78.95864996545055,
+ 0.0,
+ -0.0192823863230055,
+ 25.550873767433984,
)
dst_transform, width, height = calculate_default_transform(
- src.crs, {'init': 'EPSG:4326'}, src.width, src.height,
- *src.bounds, dst_width=dst_width, dst_height=dst_height
+ src.crs,
+ {"init": "EPSG:4326"},
+ src.width,
+ src.height,
+ *src.bounds,
+ dst_width=dst_width,
+ dst_height=dst_height
)
assert dst_transform.almost_equals(target_transform)
@@ -272,11 +315,11 @@ def test_calculate_default_transform_dimensions():
def test_reproject_ndarray():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
dst_crs = dict(
- proj='merc',
+ proj="merc",
a=6378137,
b=6378137,
lat_ts=0.0,
@@ -284,10 +327,11 @@ def test_reproject_ndarray():
x_0=0.0,
y_0=0,
k=1.0,
- units='m',
- nadgrids='@null',
+ units="m",
+ nadgrids="@null",
wktext=True,
- no_defs=True)
+ no_defs=True,
+ )
out = np.empty(src.shape, dtype=np.uint8)
reproject(
source,
@@ -296,13 +340,14 @@ def test_reproject_ndarray():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
assert (out > 0).sum() == 438113
def test_reproject_view():
"""Source views are reprojected properly"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
window = windows.Window(100, 100, 500, 500)
@@ -314,7 +359,7 @@ def test_reproject_view():
assert reduced_array.base is source
dst_crs = dict(
- proj='merc',
+ proj="merc",
a=6378137,
b=6378137,
lat_ts=0.0,
@@ -322,10 +367,11 @@ def test_reproject_view():
x_0=0.0,
y_0=0,
k=1.0,
- units='m',
- nadgrids='@null',
+ units="m",
+ nadgrids="@null",
wktext=True,
- no_defs=True)
+ no_defs=True,
+ )
out = np.empty(src.shape, dtype=np.uint8)
@@ -336,16 +382,17 @@ def test_reproject_view():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
assert (out > 0).sum() == 299199
def test_reproject_epsg():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
- dst_crs = {'init': 'EPSG:3857'}
+ dst_crs = {"init": "EPSG:3857"}
out = np.empty(src.shape, dtype=np.uint8)
reproject(
source,
@@ -354,7 +401,8 @@ def test_reproject_epsg():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
assert (out > 0).sum() == 438113
@@ -363,10 +411,10 @@ def test_reproject_out_of_bounds():
Should return blank image.
"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
- dst_crs = {'init': 'EPSG:32619'}
+ dst_crs = {"init": "EPSG:32619"}
out = np.zeros(src.shape, dtype=np.uint8)
reproject(
source,
@@ -375,7 +423,8 @@ def test_reproject_out_of_bounds():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
assert not out.any()
@@ -386,8 +435,7 @@ def test_reproject_nodata(options, expected):
with rasterio.Env(**options):
params = uninvertable_reproject_params()
source = np.ones((params.width, params.height), dtype=np.uint8)
- out = np.zeros((params.dst_width, params.dst_height),
- dtype=source.dtype)
+ out = np.zeros((params.dst_width, params.dst_height), dtype=source.dtype)
out.fill(120) # Fill with arbitrary value
reproject(
@@ -398,12 +446,13 @@ def test_reproject_nodata(options, expected):
src_nodata=nodata,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=nodata
+ dst_nodata=nodata,
)
assert (out == 1).sum() == expected
- assert (out == nodata).sum() == (params.dst_width *
- params.dst_height - expected)
+ assert (out == nodata).sum() == (
+ params.dst_width * params.dst_height - expected
+ )
@pytest.mark.parametrize("options, expected", reproj_expected)
@@ -412,8 +461,7 @@ def test_reproject_nodata_nan(options, expected):
with rasterio.Env(**options):
params = uninvertable_reproject_params()
source = np.ones((params.width, params.height), dtype=np.float32)
- out = np.zeros((params.dst_width, params.dst_height),
- dtype=source.dtype)
+ out = np.zeros((params.dst_width, params.dst_height), dtype=source.dtype)
out.fill(120) # Fill with arbitrary value
reproject(
@@ -424,12 +472,11 @@ def test_reproject_nodata_nan(options, expected):
src_nodata=np.nan,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=np.nan
+ dst_nodata=np.nan,
)
assert (out == 1).sum() == expected
- assert np.isnan(out).sum() == (params.dst_width *
- params.dst_height - expected)
+ assert np.isnan(out).sum() == (params.dst_width * params.dst_height - expected)
@pytest.mark.parametrize("options, expected", reproj_expected)
@@ -439,8 +486,7 @@ def test_reproject_dst_nodata_default(options, expected):
with rasterio.Env(**options):
params = uninvertable_reproject_params()
source = np.ones((params.width, params.height), dtype=np.uint8)
- out = np.zeros((params.dst_width, params.dst_height),
- dtype=source.dtype)
+ out = np.zeros((params.dst_width, params.dst_height), dtype=source.dtype)
out.fill(120) # Fill with arbitrary value
reproject(
@@ -449,12 +495,11 @@ def test_reproject_dst_nodata_default(options, expected):
src_transform=params.src_transform,
src_crs=params.src_crs,
dst_transform=params.dst_transform,
- dst_crs=params.dst_crs
+ dst_crs=params.dst_crs,
)
assert (out == 1).sum() == expected
- assert (out == 0).sum() == (params.dst_width *
- params.dst_height - expected)
+ assert (out == 0).sum() == (params.dst_width * params.dst_height - expected)
def test_reproject_invalid_dst_nodata():
@@ -473,7 +518,7 @@ def test_reproject_invalid_dst_nodata():
src_nodata=0,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=999999999
+ dst_nodata=999999999,
)
@@ -493,7 +538,7 @@ def test_reproject_invalid_src_nodata():
src_nodata=999999999,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=215
+ dst_nodata=215,
)
@@ -501,7 +546,7 @@ def test_reproject_init_nodata_tofile(tmpdir):
"""Test that nodata is being initialized."""
params = default_reproject_params()
- tiffname = str(tmpdir.join('foo.tif'))
+ tiffname = str(tmpdir.join("foo.tif"))
source1 = np.zeros((params.width, params.height), dtype=np.uint8)
source2 = source1.copy()
@@ -512,16 +557,16 @@ def test_reproject_init_nodata_tofile(tmpdir):
source2[rows // 2:, cols // 2:] = 100
kwargs = {
- 'count': 1,
- 'width': params.width,
- 'height': params.height,
- 'dtype': np.uint8,
- 'driver': 'GTiff',
- 'crs': params.dst_crs,
- 'transform': params.dst_transform
+ "count": 1,
+ "width": params.width,
+ "height": params.height,
+ "dtype": np.uint8,
+ "driver": "GTiff",
+ "crs": params.dst_crs,
+ "transform": params.dst_transform,
}
- with rasterio.open(tiffname, 'w', **kwargs) as dst:
+ with rasterio.open(tiffname, "w", **kwargs) as dst:
reproject(
source1,
rasterio.band(dst, 1),
@@ -530,7 +575,7 @@ def test_reproject_init_nodata_tofile(tmpdir):
src_nodata=0.0,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=0.0
+ dst_nodata=0.0,
)
# 200s should be overwritten by 100s
@@ -542,7 +587,7 @@ def test_reproject_init_nodata_tofile(tmpdir):
src_nodata=0.0,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=0.0
+ dst_nodata=0.0,
)
with rasterio.open(tiffname) as src:
@@ -553,7 +598,7 @@ def test_reproject_no_init_nodata_tofile(tmpdir):
"""Test that nodata is not being initialized."""
params = default_reproject_params()
- tiffname = str(tmpdir.join('foo.tif'))
+ tiffname = str(tmpdir.join("foo.tif"))
source1 = np.zeros((params.width, params.height), dtype=np.uint8)
source2 = source1.copy()
@@ -564,16 +609,16 @@ def test_reproject_no_init_nodata_tofile(tmpdir):
source2[rows // 2:, cols // 2:] = 100
kwargs = {
- 'count': 1,
- 'width': params.width,
- 'height': params.height,
- 'dtype': np.uint8,
- 'driver': 'GTiff',
- 'crs': params.dst_crs,
- 'transform': params.dst_transform
+ "count": 1,
+ "width": params.width,
+ "height": params.height,
+ "dtype": np.uint8,
+ "driver": "GTiff",
+ "crs": params.dst_crs,
+ "transform": params.dst_transform,
}
- with rasterio.open(tiffname, 'w', **kwargs) as dst:
+ with rasterio.open(tiffname, "w", **kwargs) as dst:
reproject(
source1,
rasterio.band(dst, 1),
@@ -582,7 +627,7 @@ def test_reproject_no_init_nodata_tofile(tmpdir):
src_nodata=0.0,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=0.0
+ dst_nodata=0.0,
)
reproject(
@@ -594,7 +639,7 @@ def test_reproject_no_init_nodata_tofile(tmpdir):
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
dst_nodata=0.0,
- init_dest_nodata=False
+ init_dest_nodata=False,
)
# 200s should remain along with 100s
@@ -625,7 +670,7 @@ def test_reproject_no_init_nodata_toarray():
src_nodata=0.0,
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
- dst_nodata=0.0
+ dst_nodata=0.0,
)
assert out.max() == 200
@@ -640,7 +685,7 @@ def test_reproject_no_init_nodata_toarray():
dst_transform=params.dst_transform,
dst_crs=params.dst_crs,
dst_nodata=0.0,
- init_dest_nodata=False
+ init_dest_nodata=False,
)
# 200s should NOT be overwritten by 100s
@@ -650,10 +695,10 @@ def test_reproject_no_init_nodata_toarray():
def test_reproject_multi():
"""Ndarry to ndarray."""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read()
dst_crs = dict(
- proj='merc',
+ proj="merc",
a=6378137,
b=6378137,
lat_ts=0.0,
@@ -661,10 +706,11 @@ def test_reproject_multi():
x_0=0.0,
y_0=0,
k=1.0,
- units='m',
- nadgrids='@null',
+ units="m",
+ nadgrids="@null",
wktext=True,
- no_defs=True)
+ no_defs=True,
+ )
destin = np.empty(source.shape, dtype=np.uint8)
reproject(
source,
@@ -673,15 +719,16 @@ def test_reproject_multi():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
assert destin.any()
def test_warp_from_file():
"""File to ndarray."""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
dst_crs = dict(
- proj='merc',
+ proj="merc",
a=6378137,
b=6378137,
lat_ts=0.0,
@@ -689,25 +736,24 @@ def test_warp_from_file():
x_0=0.0,
y_0=0,
k=1.0,
- units='m',
- nadgrids='@null',
+ units="m",
+ nadgrids="@null",
wktext=True,
- no_defs=True)
+ no_defs=True,
+ )
destin = np.empty(src.shape, dtype=np.uint8)
reproject(
- rasterio.band(src, 1),
- destin,
- dst_transform=DST_TRANSFORM,
- dst_crs=dst_crs)
+ rasterio.band(src, 1), destin, dst_transform=DST_TRANSFORM, dst_crs=dst_crs
+ )
assert destin.any()
def test_warp_from_to_file(tmpdir):
"""File to file."""
- tiffname = str(tmpdir.join('foo.tif'))
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ tiffname = str(tmpdir.join("foo.tif"))
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
dst_crs = dict(
- proj='merc',
+ proj="merc",
a=6378137,
b=6378137,
lat_ts=0.0,
@@ -715,25 +761,24 @@ def test_warp_from_to_file(tmpdir):
x_0=0.0,
y_0=0,
k=1.0,
- units='m',
- nadgrids='@null',
+ units="m",
+ nadgrids="@null",
wktext=True,
- no_defs=True)
+ no_defs=True,
+ )
kwargs = src.meta.copy()
- kwargs.update(
- transform=DST_TRANSFORM,
- crs=dst_crs)
- with rasterio.open(tiffname, 'w', **kwargs) as dst:
+ kwargs.update(transform=DST_TRANSFORM, crs=dst_crs)
+ with rasterio.open(tiffname, "w", **kwargs) as dst:
for i in (1, 2, 3):
reproject(rasterio.band(src, i), rasterio.band(dst, i))
def test_warp_from_to_file_multi(tmpdir):
"""File to file."""
- tiffname = str(tmpdir.join('foo.tif'))
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ tiffname = str(tmpdir.join("foo.tif"))
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
dst_crs = dict(
- proj='merc',
+ proj="merc",
a=6378137,
b=6378137,
lat_ts=0.0,
@@ -741,29 +786,26 @@ def test_warp_from_to_file_multi(tmpdir):
x_0=0.0,
y_0=0,
k=1.0,
- units='m',
- nadgrids='@null',
+ units="m",
+ nadgrids="@null",
wktext=True,
- no_defs=True)
+ no_defs=True,
+ )
kwargs = src.meta.copy()
- kwargs.update(
- transform=DST_TRANSFORM,
- crs=dst_crs)
- with rasterio.open(tiffname, 'w', **kwargs) as dst:
+ kwargs.update(transform=DST_TRANSFORM, crs=dst_crs)
+ with rasterio.open(tiffname, "w", **kwargs) as dst:
for i in (1, 2, 3):
- reproject(
- rasterio.band(src, i),
- rasterio.band(dst, i),
- num_threads=2)
+ reproject(rasterio.band(src, i), rasterio.band(dst, i), num_threads=2)
- at pytest.fixture(scope='function')
+ at pytest.fixture(scope="function")
def polygon_3373():
"""An EPSG:3373 polygon."""
return {
- 'type': 'Polygon',
- 'coordinates': (
- ((798842.3090855901, 6569056.500655151),
+ "type": "Polygon",
+ "coordinates": (
+ (
+ (798842.3090855901, 6569056.500655151),
(756688.2826828464, 6412397.888771972),
(755571.0617232556, 6408461.009397383),
(677605.2284582685, 6425600.39266733),
@@ -793,71 +835,75 @@ def polygon_3373():
(662054.7979028501, 6772962.86384242),
(841909.6014891531, 6731793.200435557),
(840726.455490463, 6727039.8672589315),
- (798842.3090855901, 6569056.500655151)),)}
+ (798842.3090855901, 6569056.500655151),
+ ),
+ ),
+ }
def test_transform_geom_polygon_cutting(polygon_3373):
geom = polygon_3373
- result = transform_geom(
- 'EPSG:3373', 'EPSG:4326', geom, antimeridian_cutting=True)
- assert result['type'] == 'MultiPolygon'
- assert len(result['coordinates']) == 2
+ result = transform_geom("EPSG:3373", "EPSG:4326", geom, antimeridian_cutting=True)
+ assert result["type"] == "MultiPolygon"
+ assert len(result["coordinates"]) == 2
def test_transform_geom_polygon_offset(polygon_3373):
geom = polygon_3373
result = transform_geom(
- 'EPSG:3373',
- 'EPSG:4326',
- geom,
- antimeridian_cutting=True,
- antimeridian_offset=0)
- assert result['type'] == 'MultiPolygon'
- assert len(result['coordinates']) == 2
+ "EPSG:3373", "EPSG:4326", geom, antimeridian_cutting=True, antimeridian_offset=0
+ )
+ assert result["type"] == "MultiPolygon"
+ assert len(result["coordinates"]) == 2
def test_transform_geom_polygon_precision(polygon_3373):
geom = polygon_3373
- result = transform_geom('EPSG:3373', 'EPSG:4326', geom, precision=1, antimeridian_cutting=True)
- assert all(round(x, 1) == x for x in flatten_coords(result['coordinates']))
+ result = transform_geom(
+ "EPSG:3373", "EPSG:4326", geom, precision=1, antimeridian_cutting=True
+ )
+ assert all(round(x, 1) == x for x in flatten_coords(result["coordinates"]))
def test_transform_geom_linestring_precision(polygon_3373):
- ring = polygon_3373['coordinates'][0]
- geom = {'type': 'LineString', 'coordinates': ring}
- result = transform_geom('EPSG:3373', 'EPSG:4326', geom, precision=1, antimeridian_cutting=True)
- assert all(round(x, 1) == x for x in flatten_coords(result['coordinates']))
+ ring = polygon_3373["coordinates"][0]
+ geom = {"type": "LineString", "coordinates": ring}
+ result = transform_geom(
+ "EPSG:3373", "EPSG:4326", geom, precision=1, antimeridian_cutting=True
+ )
+ assert all(round(x, 1) == x for x in flatten_coords(result["coordinates"]))
def test_transform_geom_linestring_precision_iso(polygon_3373):
- ring = polygon_3373['coordinates'][0]
- geom = {'type': 'LineString', 'coordinates': ring}
- result = transform_geom('EPSG:3373', 'EPSG:3373', geom, precision=1)
- assert int(result['coordinates'][0][0] * 10) == 7988423
+ ring = polygon_3373["coordinates"][0]
+ geom = {"type": "LineString", "coordinates": ring}
+ result = transform_geom("EPSG:3373", "EPSG:3373", geom, precision=1)
+ assert int(result["coordinates"][0][0] * 10) == 7988423
def test_transform_geom_linearring_precision(polygon_3373):
- ring = polygon_3373['coordinates'][0]
- geom = {'type': 'LinearRing', 'coordinates': ring}
- result = transform_geom('EPSG:3373', 'EPSG:4326', geom, precision=1, antimeridian_cutting=True)
- assert all(round(x, 1) == x for x in flatten_coords(result['coordinates']))
+ ring = polygon_3373["coordinates"][0]
+ geom = {"type": "LinearRing", "coordinates": ring}
+ result = transform_geom(
+ "EPSG:3373", "EPSG:4326", geom, precision=1, antimeridian_cutting=True
+ )
+ assert all(round(x, 1) == x for x in flatten_coords(result["coordinates"]))
def test_transform_geom_linestring_precision_z(polygon_3373):
- ring = polygon_3373['coordinates'][0]
+ ring = polygon_3373["coordinates"][0]
x, y = zip(*ring)
ring = list(zip(x, y, [0.0 for i in range(len(x))]))
- geom = {'type': 'LineString', 'coordinates': ring}
- result = transform_geom('EPSG:3373', 'EPSG:3373', geom, precision=1)
- assert int(result['coordinates'][0][0] * 10) == 7988423
- assert int(result['coordinates'][0][2] * 10) == 0
+ geom = {"type": "LineString", "coordinates": ring}
+ result = transform_geom("EPSG:3373", "EPSG:3373", geom, precision=1)
+ assert int(result["coordinates"][0][0] * 10) == 7988423
+ assert int(result["coordinates"][0][2] * 10) == 0
def test_transform_geom_multipolygon(polygon_3373):
- geom = {
- 'type': 'MultiPolygon', 'coordinates': [polygon_3373['coordinates']]}
- result = transform_geom('EPSG:3373', 'EPSG:4326', geom, precision=1)
- assert all(round(x, 1) == x for x in flatten_coords(result['coordinates']))
+ geom = {"type": "MultiPolygon", "coordinates": [polygon_3373["coordinates"]]}
+ result = transform_geom("EPSG:3373", "EPSG:4326", geom, precision=1)
+ assert all(round(x, 1) == x for x in flatten_coords(result["coordinates"]))
@pytest.mark.parametrize("method", SUPPORTED_RESAMPLING)
@@ -876,7 +922,7 @@ def test_reproject_resampling(path_rgb_byte_tif, method):
Resampling.min: 436397,
Resampling.med: 437194,
Resampling.q1: 436397,
- Resampling.q3: 438948
+ Resampling.q3: 438948,
}
with rasterio.open(path_rgb_byte_tif) as src:
@@ -889,8 +935,9 @@ def test_reproject_resampling(path_rgb_byte_tif, method):
src_transform=src.transform,
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
- dst_crs={'init': 'EPSG:3857'},
- resampling=method)
+ dst_crs={"init": "EPSG:3857"},
+ resampling=method,
+ )
assert np.count_nonzero(out) == expected[method]
@@ -912,10 +959,10 @@ def test_reproject_resampling_alpha(method):
Resampling.min: 436397,
Resampling.med: 437194,
Resampling.q1: 436397,
- Resampling.q3: 438948
+ Resampling.q3: 438948,
}
- with rasterio.open('tests/data/RGBA.byte.tif') as src:
+ with rasterio.open("tests/data/RGBA.byte.tif") as src:
source = src.read(1)
out = np.empty(src.shape, dtype=np.uint8)
@@ -925,22 +972,23 @@ def test_reproject_resampling_alpha(method):
src_transform=src.transform,
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
- dst_crs={'init': 'EPSG:3857'},
- resampling=method)
+ dst_crs={"init": "EPSG:3857"},
+ resampling=method,
+ )
assert np.count_nonzero(out) == expected[method]
@pytest.mark.skipif(
- gdal_version.at_least('2.0'),
- reason="Tests only applicable to GDAL < 2.0")
+ gdal_version.at_least("2.0"), reason="Tests only applicable to GDAL < 2.0"
+)
@pytest.mark.parametrize("method", GDAL2_RESAMPLING)
def test_reproject_not_yet_supported_resampling(method):
"""Test resampling methods not yet supported by this version of GDAL"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
- dst_crs = {'init': 'EPSG:32619'}
+ dst_crs = {"init": "EPSG:32619"}
out = np.empty(src.shape, dtype=np.uint8)
with pytest.raises(GDALVersionError):
reproject(
@@ -950,15 +998,16 @@ def test_reproject_not_yet_supported_resampling(method):
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=method)
+ resampling=method,
+ )
def test_reproject_unsupported_resampling():
"""Values not in enums. Resampling are not supported."""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
- dst_crs = {'init': 'EPSG:32619'}
+ dst_crs = {"init": "EPSG:32619"}
out = np.empty(src.shape, dtype=np.uint8)
with pytest.raises(ValueError):
reproject(
@@ -968,15 +1017,16 @@ def test_reproject_unsupported_resampling():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=99)
+ resampling=99,
+ )
def test_reproject_unsupported_resampling_guass():
"""Resampling.gauss is unsupported."""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
- dst_crs = {'init': 'EPSG:32619'}
+ dst_crs = {"init": "EPSG:32619"}
out = np.empty(src.shape, dtype=np.uint8)
with pytest.raises(ValueError):
reproject(
@@ -986,7 +1036,8 @@ def test_reproject_unsupported_resampling_guass():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.gauss)
+ resampling=Resampling.gauss,
+ )
@pytest.mark.parametrize("method", SUPPORTED_RESAMPLING)
@@ -995,18 +1046,19 @@ def test_resample_default_invert_proj(method):
with the default Env
"""
- with rasterio.open('tests/data/world.rgb.tif') as src:
+ with rasterio.open("tests/data/world.rgb.tif") as src:
source = src.read(1)
profile = src.profile.copy()
- dst_crs = {'init': 'EPSG:32619'}
+ dst_crs = {"init": "EPSG:32619"}
# Calculate the ideal dimensions and transformation in the new crs
dst_affine, dst_width, dst_height = calculate_default_transform(
- src.crs, dst_crs, src.width, src.height, *src.bounds)
+ src.crs, dst_crs, src.width, src.height, *src.bounds
+ )
- profile['height'] = dst_height
- profile['width'] = dst_width
+ profile["height"] = dst_height
+ profile["width"] = dst_width
out = np.empty(shape=(dst_height, dst_width), dtype=np.uint8)
@@ -1018,28 +1070,32 @@ def test_resample_default_invert_proj(method):
src_crs=src.crs,
dst_transform=dst_affine,
dst_crs=dst_crs,
- resampling=method)
+ resampling=method,
+ )
assert out.mean() > 0
def test_target_aligned_pixels():
"""Issue 853 has been resolved"""
- with rasterio.open('tests/data/world.rgb.tif') as src:
+ with rasterio.open("tests/data/world.rgb.tif") as src:
source = src.read(1)
profile = src.profile.copy()
- dst_crs = {'init': 'epsg:3857'}
+ dst_crs = {"init": "epsg:3857"}
with rasterio.Env(CHECK_WITH_INVERT_PROJ=False):
# Calculate the ideal dimensions and transformation in the new crs
dst_affine, dst_width, dst_height = calculate_default_transform(
- src.crs, dst_crs, src.width, src.height, *src.bounds)
+ src.crs, dst_crs, src.width, src.height, *src.bounds
+ )
- dst_affine, dst_width, dst_height = aligned_target(dst_affine, dst_width, dst_height, 100000.0)
+ dst_affine, dst_width, dst_height = aligned_target(
+ dst_affine, dst_width, dst_height, 100000.0
+ )
- profile['height'] = dst_height
- profile['width'] = dst_width
+ profile["height"] = dst_height
+ profile["width"] = dst_width
out = np.empty(shape=(dst_height, dst_width), dtype=np.uint8)
@@ -1050,7 +1106,8 @@ def test_target_aligned_pixels():
src_crs=src.crs,
dst_transform=dst_affine,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
# Check that there is no black borders
assert out[:, 0].all()
@@ -1065,25 +1122,31 @@ def test_resample_no_invert_proj(method):
CHECK_WITH_INVERT_PROJ = False
"""
- if method in (Resampling.bilinear, Resampling.cubic,
- Resampling.cubic_spline, Resampling.lanczos):
+ if method in (
+ Resampling.bilinear,
+ Resampling.cubic,
+ Resampling.cubic_spline,
+ Resampling.lanczos,
+ ):
pytest.xfail(
reason="Some resampling methods succeed but produce blank images. "
- "See https://github.com/mapbox/rasterio/issues/614")
+ "See https://github.com/mapbox/rasterio/issues/614"
+ )
with rasterio.Env(CHECK_WITH_INVERT_PROJ=False):
- with rasterio.open('tests/data/world.rgb.tif') as src:
+ with rasterio.open("tests/data/world.rgb.tif") as src:
source = src.read(1)
profile = src.profile.copy()
- dst_crs = {'init': 'EPSG:32619'}
+ dst_crs = {"init": "EPSG:32619"}
# Calculate the ideal dimensions and transformation in the new crs
dst_affine, dst_width, dst_height = calculate_default_transform(
- src.crs, dst_crs, src.width, src.height, *src.bounds)
+ src.crs, dst_crs, src.width, src.height, *src.bounds
+ )
- profile['height'] = dst_height
- profile['width'] = dst_width
+ profile["height"] = dst_height
+ profile["width"] = dst_width
out = np.empty(shape=(dst_height, dst_width), dtype=np.uint8)
@@ -1096,7 +1159,8 @@ def test_resample_no_invert_proj(method):
src_crs=src.crs,
dst_transform=dst_affine,
dst_crs=dst_crs,
- resampling=method)
+ resampling=method,
+ )
assert out.mean() > 0
@@ -1112,12 +1176,14 @@ def test_reproject_crs_none():
with pytest.raises(ValueError):
reproject(
- src, dst,
+ src,
+ dst,
src_transform=srcaff,
src_crs=srccrs,
dst_transform=dstaff,
dst_crs=dstcrs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
def test_reproject_identity_src():
@@ -1125,7 +1191,7 @@ def test_reproject_identity_src():
src = np.random.random(25).reshape((1, 5, 5))
dst = np.empty(shape=(1, 10, 10))
dstaff = Affine(0.5, 0.0, 0.0, 0.0, 0.5, 0.0)
- crs = {'init': 'epsg:3857'}
+ crs = {"init": "epsg:3857"}
src_affines = [
Affine(1.0, 0.0, 0.0, 0.0, 1.0, 0.0), # Identity both positive
@@ -1135,12 +1201,14 @@ def test_reproject_identity_src():
for srcaff in src_affines:
# reproject expected to not raise any error in any of the srcaff
reproject(
- src, dst,
+ src,
+ dst,
src_transform=srcaff,
src_crs=crs,
dst_transform=dstaff,
dst_crs=crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
def test_reproject_identity_dst():
@@ -1148,7 +1216,7 @@ def test_reproject_identity_dst():
src = np.random.random(100).reshape((1, 10, 10))
srcaff = Affine(0.5, 0.0, 0.0, 0.0, 0.5, 0.0)
dst = np.empty(shape=(1, 5, 5))
- crs = {'init': 'epsg:3857'}
+ crs = {"init": "epsg:3857"}
dst_affines = [
Affine(1.0, 0.0, 0.0, 0.0, 1.0, 0.0), # Identity both positive
@@ -1158,17 +1226,19 @@ def test_reproject_identity_dst():
for dstaff in dst_affines:
# reproject expected to not raise any error in any of the dstaff
reproject(
- src, dst,
+ src,
+ dst,
src_transform=srcaff,
src_crs=crs,
dst_transform=dstaff,
dst_crs=crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
- at pytest.fixture(scope='function')
+ at pytest.fixture(scope="function")
def rgb_byte_profile():
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
return src.profile
@@ -1181,20 +1251,24 @@ def test_reproject_gcps_transform_exclusivity():
def test_reproject_gcps(rgb_byte_profile):
"""Reproject using ground control points for the source"""
source = np.ones((3, 800, 800), dtype=np.uint8) * 255
- out = np.zeros((3, rgb_byte_profile['height'], rgb_byte_profile['height']), dtype=np.uint8)
+ out = np.zeros(
+ (3, rgb_byte_profile["height"], rgb_byte_profile["height"]), dtype=np.uint8
+ )
src_gcps = [
GroundControlPoint(row=0, col=0, x=156113, y=2818720, z=0),
GroundControlPoint(row=0, col=800, x=338353, y=2785790, z=0),
GroundControlPoint(row=800, col=800, x=297939, y=2618518, z=0),
- GroundControlPoint(row=800, col=0, x=115698, y=2651448, z=0)]
+ GroundControlPoint(row=800, col=0, x=115698, y=2651448, z=0),
+ ]
reproject(
source,
out,
- src_crs='epsg:32618',
+ src_crs="epsg:32618",
gcps=src_gcps,
- dst_transform=rgb_byte_profile['transform'],
- dst_crs=rgb_byte_profile['crs'],
- resampling=Resampling.nearest)
+ dst_transform=rgb_byte_profile["transform"],
+ dst_crs=rgb_byte_profile["crs"],
+ resampling=Resampling.nearest,
+ )
assert not out.all()
assert not out[:, 0, 0].any()
@@ -1204,26 +1278,23 @@ def test_reproject_gcps(rgb_byte_profile):
@requires_gdal22(
- reason="GDAL 2.2.0 and newer has different antimeridian cutting behavior.")
+ reason="GDAL 2.2.0 and newer has different antimeridian cutting behavior."
+)
def test_transform_geom_gdal22():
"""Enabling `antimeridian_cutting` has no effect on GDAL 2.2.0 or newer
where antimeridian cutting is always enabled. This could produce
unexpected geometries, so an exception is raised.
"""
- geom = {
- 'type': 'Point',
- 'coordinates': [0, 0]
- }
+ geom = {"type": "Point", "coordinates": [0, 0]}
with pytest.raises(GDALVersionError):
- transform_geom(
- 'EPSG:4326', 'EPSG:3857', geom, antimeridian_cutting=False)
+ transform_geom("EPSG:4326", "EPSG:3857", geom, antimeridian_cutting=False)
def test_issue1056():
"""Warp sucessfully from RGB's upper bands to an array"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
- dst_crs = {'init': 'EPSG:3857'}
+ dst_crs = {"init": "EPSG:3857"}
out = np.zeros(src.shape, dtype=np.uint8)
reproject(
rasterio.band(src, 2),
@@ -1232,15 +1303,16 @@ def test_issue1056():
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
def test_reproject_dst_nodata():
"""Affirm resolution of issue #1395"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
source = src.read(1)
- dst_crs = {'init': 'EPSG:3857'}
+ dst_crs = {"init": "EPSG:3857"}
out = np.empty(src.shape, dtype=np.float32)
reproject(
source,
@@ -1251,7 +1323,8 @@ def test_reproject_dst_nodata():
dst_crs=dst_crs,
src_nodata=0,
dst_nodata=np.nan,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
assert (out > 0).sum() == 438113
assert out[0, 0] != 0
@@ -1260,8 +1333,8 @@ def test_reproject_dst_nodata():
def test_issue1401():
"""The warp_mem_limit keyword argument is in effect"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
- dst_crs = {'init': 'EPSG:3857'}
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
+ dst_crs = {"init": "EPSG:3857"}
out = np.zeros(src.shape, dtype=np.uint8)
reproject(
rasterio.band(src, 2),
@@ -1271,7 +1344,8 @@ def test_issue1401():
dst_transform=DST_TRANSFORM,
dst_crs=dst_crs,
resampling=Resampling.nearest,
- warp_mem_limit=4000)
+ warp_mem_limit=4000,
+ )
def test_reproject_dst_alpha(path_rgb_msk_byte_tif):
@@ -1289,21 +1363,25 @@ def test_reproject_dst_alpha(path_rgb_msk_byte_tif):
src_transform=src.transform,
src_crs=src.crs,
dst_transform=DST_TRANSFORM,
- dst_crs={'init': 'EPSG:3857'},
- dst_alpha=4)
+ dst_crs={"init": "EPSG:3857"},
+ dst_alpha=4,
+ )
assert dst_arr[3].any()
@pytest.mark.xfail(
- rasterio.__gdal_version__ in ['2.2.0', '2.2.1', '2.2.2', '2.2.3'],
- reason=("GDAL had regression in 2.2.X series, fixed in 2.2.4,"
- " reproject used dst index instead of src index when destination was single band"))
+ rasterio.__gdal_version__ in ["2.2.0", "2.2.1", "2.2.2", "2.2.3"],
+ reason=(
+ "GDAL had regression in 2.2.X series, fixed in 2.2.4,"
+ " reproject used dst index instead of src index when destination was single band"
+ ),
+)
def test_issue1350():
"""Warp bands other than 1 or All"""
- with rasterio.open('tests/data/RGB.byte.tif') as src:
- dst_crs = {'init': 'EPSG:3857'}
+ with rasterio.open("tests/data/RGB.byte.tif") as src:
+ dst_crs = {"init": "EPSG:3857"}
reprojected = []
@@ -1315,9 +1393,45 @@ def test_issue1350():
out,
resampling=Resampling.nearest,
dst_transform=DST_TRANSFORM,
- dst_crs=dst_crs)
+ dst_crs=dst_crs,
+ )
reprojected.append(out)
for i in range(1, len(reprojected)):
assert not (reprojected[0] == reprojected[i]).all()
+
+
+def test_issue_1446():
+ """Confirm resolution of #1446"""
+ g = transform_geom(
+ CRS.from_epsg(4326),
+ CRS.from_epsg(32610),
+ {"type": "Point", "coordinates": (-122.51403808499907, 38.06106733107932)},
+ )
+ assert round(g["coordinates"][0], 1) == 542630.9
+ assert round(g["coordinates"][1], 1) == 4212702.1
+
+
+def test_issue_1446_b():
+ """Confirm that lines aren't thrown as reported in #1446"""
+ src_crs = CRS({"init": "EPSG:4326"})
+ dst_crs = CRS(
+ {
+ "proj": "sinu",
+ "lon_0": 350.85607029556,
+ "x_0": 0,
+ "y_0": 0,
+ "a": 3396190,
+ "b": 3396190,
+ "units": "m",
+ "no_defs": True,
+ }
+ )
+ collection = json.load(open("tests/data/issue1446.geojson"))
+ geoms = {f["properties"]["fid"]: f["geometry"] for f in collection["features"]}
+ transformed_geoms = {
+ k: transform_geom(src_crs, dst_crs, g) for k, g in geoms.items()
+ }
+ # Before the fix, this geometry was thrown eastward of 0.0. It should be between -350 and -250.
+ assert all([-350 < x < -150 for x, y in transformed_geoms[183519]["coordinates"]])
=====================================
tests/test_windows.py
=====================================
@@ -571,3 +571,11 @@ def test_round_lengths_no_op_error():
def test_round_offsets_no_op_error():
with pytest.raises(WindowError):
Window(0, 0, 1, 1).round_offsets(op='lolwut')
+
+
+def test_window_hashable():
+ a = Window(0, 0, 10, 10)
+ b = Window(0, 0, 10, 10)
+ c = Window(8, 8, 12, 12)
+ assert hash(a) == hash(b)
+ assert hash(a) != hash(c)
=====================================
tests/test_write.py
=====================================
@@ -320,3 +320,9 @@ def test_wplus_transform(tmpdir):
with rasterio.open(name, 'w+', driver='GTiff', crs='epsg:4326', transform=transform, height=10, width=10, count=1, dtype='uint8') as dst:
dst.write(np.ones((1, 10, 10), dtype='uint8'))
assert dst.transform == transform
+
+
+def test_write_no_driver__issue_1203(tmpdir):
+ name = str(tmpdir.join("test.tif"))
+ with pytest.raises(ValueError), rasterio.open(name, 'w', height=1, width=1, count=1, dtype='uint8'):
+ print("TEST FAILED IF THIS IS REACHED.")
View it on GitLab: https://salsa.debian.org/debian-gis-team/rasterio/compare/83a0a1c9b50520b183b72ef9af3e5649b1205e1e...064055af185912b4fb64b56e5068aec05df6cd6f
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/rasterio/compare/83a0a1c9b50520b183b72ef9af3e5649b1205e1e...064055af185912b4fb64b56e5068aec05df6cd6f
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/20180917/e7b4ad5a/attachment-0001.html>
More information about the Pkg-grass-devel
mailing list