Skip to content
Commits on Source (4)
Changes
=======
1.0.19 (2019-02-26)
-------------------
- Do not set GDAL_DATA and PROJ_LIB when data files can be found at their built
in locations (#1631).
- Add linear_units property to CRS (#1638).
- Ensure that AWS_NO_SIGN_REQUESTS is sufficient for accessing public S3
datasets and that import of boto3 is not required (#1637).
- An out_dtype parameter has been added to DatasetReaderBase.read, enabling
on-the-fly casting of raster values to the desired type (#1637). This uses
the same latent feature used to get support for "int8" data.
- Restore pickle protocol for CRS, using WKT as state (#1625).
- Support for signed 8-bit integer datasets ("int8" dtype) has been added
(#1595).
1.0.18 (2019-02-07)
-------------------
......
rasterio (1.0.19-1) unstable; urgency=medium
* Team upload.
* New upstream release.
-- Bas Couwenberg <sebastic@debian.org> Wed, 27 Feb 2019 06:52:24 +0100
rasterio (1.0.18-1) unstable; urgency=medium
* Team upload.
......
......@@ -22,7 +22,7 @@ except ImportError: # pragma: no cover
from rasterio._base import gdal_version
from rasterio.drivers import is_blacklisted
from rasterio.dtypes import (
bool_, ubyte, uint8, uint16, int16, uint32, int32, float32, float64,
bool_, ubyte, sbyte, uint8, int8, uint16, int16, uint32, int32, float32, float64,
complex_, check_dtype)
from rasterio.env import ensure_env_with_credentials, Env
from rasterio.errors import RasterioIOError
......@@ -42,7 +42,7 @@ import rasterio.path
__all__ = ['band', 'open', 'pad', 'Env']
__version__ = "1.0.18"
__version__ = "1.0.19"
__gdal_version__ = gdal_version()
# Rasterio attaches NullHandler to the 'rasterio' logger and its
......
......@@ -9,6 +9,7 @@ import logging
import math
import os
import warnings
from libc.string cimport strncmp
from rasterio._err import (
GDALError, CPLE_BaseError, CPLE_IllegalArgError, CPLE_OpenFailedError,
......@@ -115,6 +116,20 @@ def driver_can_create_copy(drivername):
"""Return True if the driver has CREATE_COPY capability"""
return driver_supports_mode(drivername, 'DCAP_CREATECOPY')
cdef _band_dtype(GDALRasterBandH band):
"""Resolve dtype of a given band, deals with signed/unsigned byte ambiguity"""
cdef const char * ptype
cdef int gdal_dtype = GDALGetRasterDataType(band)
if gdal_dtype == GDT_Byte:
# Can be uint8 or int8, need to check PIXELTYPE property
ptype = GDALGetMetadataItem(band, 'PIXELTYPE', 'IMAGE_STRUCTURE')
if ptype and strncmp(ptype, 'SIGNEDBYTE', 10) == 0:
return 'int8'
else:
return 'uint8'
return dtypes.dtype_fwd[gdal_dtype]
cdef class DatasetBase(object):
"""Dataset base class
......@@ -363,8 +378,7 @@ cdef class DatasetBase(object):
if not self._dtypes:
for i in range(self._count):
band = self.band(i + 1)
self._dtypes.append(
dtypes.dtype_fwd[GDALGetRasterDataType(band)])
self._dtypes.append(_band_dtype(band))
return tuple(self._dtypes)
......@@ -402,7 +416,7 @@ cdef class DatasetBase(object):
for i in range(self._count):
band = self.band(i + 1)
dtype = dtypes.dtype_fwd[GDALGetRasterDataType(band)]
dtype = _band_dtype(band)
nodataval = GDALGetRasterNoDataValue(band, &success)
val = nodataval
# GDALGetRasterNoDataValue() has two ways of telling you that
......
......@@ -53,6 +53,26 @@ cdef class _CRS(object):
except CPLE_BaseError as exc:
raise CRSError("{}".format(exc))
@property
def linear_units(self):
"""Get linear units of the CRS
Returns
-------
str
"""
cdef char *units_c = NULL
cdef double fmeter
try:
fmeter = OSRGetLinearUnits(self._osr, &units_c)
except CPLE_BaseError as exc:
raise CRSError("{}".format(exc))
else:
units_b = units_c
return units_b.decode('utf-8')
def __eq__(self, other):
cdef OGRSpatialReferenceH osr_s = NULL
cdef OGRSpatialReferenceH osr_o = NULL
......
......@@ -16,6 +16,10 @@ import os.path
import sys
import threading
from rasterio._base cimport _safe_osr_release
from rasterio._err import CPLE_BaseError
from rasterio._err cimport exc_wrap_ogrerr, exc_wrap_int
level_map = {
0: 0,
......@@ -192,6 +196,21 @@ class GDALDataFinder(object):
Note: this is not part of the public API in 1.0.x.
"""
def find_file(self, basename):
"""Returns path of a GDAL data file or None
Parameters
----------
basename : str
Basename of a data file such as "header.dxf"
Returns
-------
str (on success) or None (on failure)
"""
path = CPLFindFile("gdal", basename.encode('utf-8'))
return path
def search(self, prefix=None):
"""Returns GDAL data directory
......@@ -203,6 +222,7 @@ class GDALDataFinder(object):
str or None
"""
#
path = self.search_wheel(prefix or __file__)
if not path:
path = self.search_prefix(prefix or sys.prefix)
......@@ -235,6 +255,25 @@ class PROJDataFinder(object):
Note: this is not part of the public API in 1.0.x.
"""
def has_data(self):
"""Returns True if PROJ's data files can be found
Returns
-------
bool
"""
cdef OGRSpatialReferenceH osr = OSRNewSpatialReference(NULL)
try:
exc_wrap_ogrerr(exc_wrap_int(OSRImportFromProj4(osr, "+init=epsg:4326")))
except CPLE_BaseError:
return False
else:
return True
finally:
_safe_osr_release(osr)
def search(self, prefix=None):
"""Returns PROJ data directory
......@@ -288,6 +327,10 @@ cdef class GDALEnv(ConfigEnv):
self.update_config_options(GDAL_DATA=os.environ['GDAL_DATA'])
log.debug("GDAL_DATA found in environment: %r.", os.environ['GDAL_DATA'])
# See https://github.com/mapbox/rasterio/issues/1631.
elif GDALDataFinder().find_file("header.dxf"):
log.debug("GDAL data files are available at built-in paths")
else:
path = GDALDataFinder().search()
......@@ -295,8 +338,13 @@ cdef class GDALEnv(ConfigEnv):
self.update_config_options(GDAL_DATA=path)
log.debug("GDAL_DATA not found in environment, set to %r.", path)
if 'PROJ_LIB' not in os.environ:
if 'PROJ_LIB' in os.environ:
log.debug("PROJ_LIB found in environment: %r.", os.environ['PROJ_LIB'])
elif PROJDataFinder().has_data():
log.debug("PROJ data files are available at built-in paths")
else:
path = PROJDataFinder().search()
if path:
......
......@@ -137,7 +137,7 @@ cdef class DatasetReaderBase(DatasetBase):
def read(self, indexes=None, out=None, window=None, masked=False,
out_shape=None, boundless=False, resampling=Resampling.nearest,
fill_value=None):
fill_value=None, out_dtype=None):
"""Read a dataset's raw pixels as an N-d array
This data is read from the dataset's band cache, which means
......@@ -163,6 +163,10 @@ cdef class DatasetReaderBase(DatasetBase):
This parameter cannot be combined with `out_shape`.
out_dtype : str or numpy dtype
The desired output data type. For example: 'uint8' or
rasterio.uint16.
out_shape : tuple, optional
A tuple describing the shape of a new output array. See
`out` (above) for notes on image decimation and
......@@ -266,6 +270,9 @@ cdef class DatasetReaderBase(DatasetBase):
else:
dtype = check_dtypes.pop()
if out_dtype is not None:
dtype = out_dtype
# Get the natural shape of the read window, boundless or not.
# The window can have float values. In this case, we round up
# when computing the shape.
......@@ -292,16 +299,14 @@ cdef class DatasetReaderBase(DatasetBase):
if out is not None and out_shape is not None:
raise ValueError("out and out_shape are exclusive")
# `out` takes precedence over `out_shape`.
# `out` takes precedence over `out_shape` and `out_dtype`.
elif out is not None:
if out.dtype != dtype:
raise ValueError(
"the array's dtype '%s' does not match "
"the file's dtype '%s'" % (out.dtype, dtype))
dtype == out.dtype
if out.shape[0] != win_shape[0]:
raise ValueError(
"'out' shape %s does not match window shape %s" %
(out.shape, win_shape))
raise ValueError("'out' shape {} does not match window shape {}".format(out.shape, win_shape))
else:
if out_shape is not None:
......@@ -1101,6 +1106,9 @@ cdef class DatasetWriterBase(DatasetReaderBase):
else:
gdal_dtype = dtypes.dtype_rev.get(self._init_dtype)
if self._init_dtype == 'int8':
options = CSLSetNameValue(options, 'PIXELTYPE', 'SIGNEDBYTE')
# Create a GDAL dataset handle.
try:
......
......@@ -13,6 +13,7 @@ if sys.version_info[0] >= 3: # pragma: no cover
from urllib.parse import urlparse
from collections import UserDict
from inspect import getfullargspec as getargspec
from unittest import mock
else: # pragma: no cover
string_types = basestring,
text_type = unicode
......@@ -22,3 +23,4 @@ else: # pragma: no cover
from urlparse import urlparse
from UserDict import UserDict
from inspect import getargspec
import mock
......@@ -89,6 +89,12 @@ class CRS(collections.Mapping):
other = CRS.from_user_input(other)
return (self._crs == other._crs)
def __getstate__(self):
return self.wkt
def __setstate__(self, state):
self._crs = _CRS.from_wkt(state)
def to_proj4(self):
"""Convert CRS to a PROJ4 string
......@@ -223,6 +229,19 @@ class CRS(collections.Mapping):
except CRSError:
return False
@property
def linear_units(self):
"""The linear units of the CRS
Possible values include "metre" and "US survey foot".
Returns
-------
str
"""
return self._crs.linear_units
def to_string(self):
"""Convert CRS to a PROJ4 or WKT string
......
......@@ -12,6 +12,7 @@ do something like this:
bool_ = 'bool'
ubyte = uint8 = 'uint8'
sbyte = int8 = 'int8'
uint16 = 'uint16'
int16 = 'int16'
uint32 = 'uint32'
......@@ -41,6 +42,7 @@ dtype_fwd = {
dtype_rev = dict((v, k) for k, v in dtype_fwd.items())
dtype_rev['uint8'] = 1
dtype_rev['int8'] = 1
typename_fwd = {
0: 'Unknown',
......@@ -59,6 +61,7 @@ typename_fwd = {
typename_rev = dict((v, k) for k, v in typename_fwd.items())
dtype_ranges = {
'int8': (-128, 127),
'uint8': (0, 255),
'uint16': (0, 65535),
'int16': (-32768, 32767),
......
......@@ -606,6 +606,11 @@ def require_gdal_version(version, param=None, values=None, is_max_version=False,
if 'GDAL_DATA' not in os.environ:
# See https://github.com/mapbox/rasterio/issues/1631.
if GDALDataFinder().find_file("header.dxf"):
log.debug("GDAL data files are available at built-in paths")
else:
path = GDALDataFinder().search()
if path:
......@@ -614,6 +619,11 @@ if 'GDAL_DATA' not in os.environ:
if 'PROJ_LIB' not in os.environ:
# See https://github.com/mapbox/rasterio/issues/1631.
if PROJDataFinder().has_data():
log.debug("PROJ data files are available at built-in paths")
else:
path = PROJDataFinder().search()
if path:
......
......@@ -10,6 +10,7 @@ cdef extern from "cpl_conv.h" nogil:
void CPLSetThreadLocalConfigOption(const char* key, const char* val)
void CPLSetConfigOption(const char* key, const char* val)
const char *CPLGetConfigOption(const char* key, const char* default)
const char *CPLFindFile(const char *pszClass, const char *pszBasename)
cdef extern from "cpl_error.h" nogil:
......@@ -103,6 +104,7 @@ cdef extern from "ogr_srs_api.h" nogil:
void OSRRelease(OGRSpatialReferenceH srs)
int OSRSetFromUserInput(OGRSpatialReferenceH srs, const char *input)
OGRErr OSRValidate(OGRSpatialReferenceH srs)
double OSRGetLinearUnits(OGRSpatialReferenceH srs, char **ppszName)
cdef extern from "gdal.h" nogil:
......
"""Abstraction for sessions in various clouds."""
from rasterio.path import parse_path, UnparsedPath
......@@ -34,7 +33,7 @@ class Session(object):
bool
"""
return NotImplementedError
return NotImplemented
def get_credential_options(self):
"""Get credentials as GDAL configuration options
......@@ -44,7 +43,7 @@ class Session(object):
dict
"""
return NotImplementedError
return NotImplemented
@staticmethod
def from_foreign_session(session, cls=None):
......@@ -200,6 +199,8 @@ class AWSSession(Session):
if session:
self._session = session
elif aws_unsigned:
self._session = None
else:
self._session = boto3.Session(
aws_access_key_id=aws_access_key_id,
......@@ -210,7 +211,7 @@ class AWSSession(Session):
self.requester_pays = requester_pays
self.unsigned = aws_unsigned
self._creds = self._session._session.get_credentials()
self._creds = self._session._session.get_credentials() if self._session else None
@classmethod
def hascreds(cls, config):
......@@ -228,13 +229,13 @@ class AWSSession(Session):
bool
"""
return 'AWS_ACCESS_KEY_ID' in config and 'AWS_SECRET_ACCESS_KEY' in config
return ('AWS_ACCESS_KEY_ID' in config and 'AWS_SECRET_ACCESS_KEY' in config) or 'AWS_NO_SIGN_REQUEST' in config
@property
def credentials(self):
"""The session credentials as a dict"""
res = {}
if self._creds:
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
......@@ -330,9 +331,10 @@ class GSSession(Session):
Path to the google application credentials JSON file.
"""
self._creds = {}
if google_application_credentials is not None:
self._creds['google_application_credentials'] = google_application_credentials
self._creds = {'google_application_credentials': google_application_credentials}
else:
self._creds = {}
@classmethod
def hascreds(cls, config):
......
......@@ -348,7 +348,7 @@ extra_reqs = {
# Add futures to 'test' for Python < 3.2.
if sys.version_info < (3, 2):
extra_reqs['test'].append('futures')
extra_reqs['test'].extend(['futures', 'mock'])
# Add all extra requirements
extra_reqs['all'] = list(set(itertools.chain(*extra_reqs.values())))
......
"""crs module tests"""
import json
import logging
import os
import subprocess
import pytest
import rasterio
from rasterio._crs import _CRS
from rasterio.env import env_ctx_if_needed, Env
from rasterio.errors import CRSError
from .conftest import requires_gdal21, requires_gdal22
# Items like "D_North_American_1983" characterize the Esri dialect
# of WKT SRS.
ESRI_PROJECTION_STRING = (
'PROJCS["USA_Contiguous_Albers_Equal_Area_Conic_USGS_version",'
'GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",'
'SPHEROID["GRS_1980",6378137.0,298.257222101]],'
'PRIMEM["Greenwich",0.0],'
'UNIT["Degree",0.0174532925199433]],'
'PROJECTION["Albers"],'
'PARAMETER["false_easting",0.0],'
'PARAMETER["false_northing",0.0],'
'PARAMETER["central_meridian",-96.0],'
'PARAMETER["standard_parallel_1",29.5],'
'PARAMETER["standard_parallel_2",45.5],'
'PARAMETER["latitude_of_origin",23.0],'
'UNIT["Meter",1.0],'
'VERTCS["NAVD_1988",'
'VDATUM["North_American_Vertical_Datum_1988"],'
'PARAMETER["Vertical_Shift",0.0],'
'PARAMETER["Direction",1.0],UNIT["Centimeter",0.01]]]')
def test_from_dict():
"""Can create a _CRS from a dict"""
crs = _CRS.from_dict({'init': 'epsg:3857'})
assert crs.to_dict()['proj'] == 'merc'
assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"' in crs.to_wkt()
def test_from_dict_keywords():
"""Can create a CRS from keyword args, ignoring unknowns"""
crs = _CRS.from_dict(init='epsg:3857', foo='bar')
assert crs.to_dict()['proj'] == 'merc'
assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"' in crs.to_wkt()
def test_from_epsg():
"""Can create a CRS from EPSG code"""
crs = _CRS.from_epsg(4326)
assert crs.to_dict()['proj'] == 'longlat'
@pytest.mark.parametrize('code', [0, -1, float('nan'), 1.3])
def test_from_epsg_error(code):
"""Raise exception with invalid EPSG code"""
with pytest.raises(ValueError):
assert _CRS.from_epsg(code)
@pytest.mark.parametrize('proj,expected', [({'init': 'epsg:4326'}, True), ({'init': 'epsg:3857'}, False)])
def test_is_geographic(proj, expected):
"""CRS is or is not geographic"""
assert _CRS.from_dict(proj).is_geographic is expected
@pytest.mark.parametrize('proj,expected', [({'init': 'epsg:4326'}, False), ({'init': 'epsg:3857'}, True)])
def test_is_projected(proj, expected):
"""CRS is or is not projected"""
assert _CRS.from_dict(proj).is_projected is expected
def test_equality():
"""CRS are or are not equal"""
_CRS.from_epsg(4326) == _CRS.from_proj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
def test_to_wkt():
"""CRS converts to WKT"""
assert _CRS.from_dict({'init': 'epsg:4326'}).to_wkt().startswith('GEOGCS["WGS 84",DATUM')
@pytest.mark.parametrize('proj_string', ['+init=epsg:4326', '+proj=longlat +datum=WGS84 +no_defs'])
def test_to_epsg(proj_string):
"""CRS has EPSG code"""
assert _CRS.from_proj4(proj_string).to_epsg() == 4326
@pytest.mark.parametrize('proj_string', [ESRI_PROJECTION_STRING])
def test_esri_wkt_to_epsg(proj_string):
"""CRS has no EPSG code"""
assert _CRS.from_wkt(proj_string, morph_from_esri_dialect=True).to_epsg() is None
def test_epsg_no_code_available():
"""CRS has no EPSG code"""
lcc_crs = _CRS.from_proj4('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
assert lcc_crs.to_epsg() is None
def test_from_wkt_invalid():
"""Raise exception if input WKT is invalid"""
with pytest.raises(CRSError):
_CRS.from_wkt('bogus')
@pytest.mark.parametrize('projection_string', [ESRI_PROJECTION_STRING])
def test_from_esri_wkt_no_fix(projection_string):
"""Test ESRI CRS morphing with no datum fixing"""
with Env():
crs = _CRS.from_wkt(projection_string)
assert 'DATUM["D_North_American_1983"' in crs.to_wkt()
@pytest.mark.parametrize('projection_string', [ESRI_PROJECTION_STRING])
def test_from_esri_wkt_fix_datum(projection_string):
"""Test ESRI CRS morphing with datum fixing"""
with Env(GDAL_FIX_ESRI_WKT='DATUM'):
crs = _CRS.from_wkt(projection_string, morph_from_esri_dialect=True)
assert 'DATUM["North_American_Datum_1983"' in crs.to_wkt()
def test_to_esri_wkt_fix_datum():
"""Morph to Esri form"""
assert 'DATUM["D_North_American_1983"' in _CRS.from_dict(init='epsg:26913').to_wkt(morph_to_esri_dialect=True)
def test_compound_crs():
"""Parse compound WKT"""
wkt = """COMPD_CS["unknown",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433],AUTHORITY["EPSG","4326"]],VERT_CS["unknown",VERT_DATUM["unknown",2005],UNIT["metre",1.0,AUTHORITY["EPSG","9001"]],AXIS["Up",UP]]]"""
assert _CRS.from_wkt(wkt).to_wkt().startswith('COMPD_CS')
def test_exception_proj4():
"""Get the exception message we expect"""
with pytest.raises(CRSError):
_CRS.from_proj4("+proj=bogus")
def test_linear_units():
"""CRS linear units can be had"""
assert _CRS.from_epsg(3857).linear_units == 'metre'
......@@ -3,6 +3,7 @@
import json
import logging
import os
import pickle
import subprocess
import pytest
......@@ -42,21 +43,21 @@ def test_crs_constructor_dict():
"""Can create a CRS from a dict"""
crs = CRS({'init': 'epsg:3857'})
assert crs['init'] == 'epsg:3857'
assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]' in crs.wkt
assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
def test_crs_constructor_keywords():
"""Can create a CRS from keyword args, ignoring unknowns"""
crs = CRS(init='epsg:3857', foo='bar')
assert crs['init'] == 'epsg:3857'
assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]' in crs.wkt
assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
def test_crs_constructor_crs_obj():
"""Can create a CRS from a CRS obj"""
crs = CRS(CRS(init='epsg:3857'))
assert crs['init'] == 'epsg:3857'
assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]' in crs.wkt
assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
@pytest.fixture(scope='session')
......@@ -431,3 +432,16 @@ def test_empty_crs_str():
def test_issue1620():
"""Different forms of EPSG:3857 are equal"""
assert CRS.from_wkt('PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]') == CRS.from_dict(init='epsg:3857')
@pytest.mark.parametrize('factory,arg', [(CRS.from_epsg, 3857), (CRS.from_dict, {'ellps': 'WGS84', 'proj': 'stere', 'lat_0': -90.0, 'lon_0': 0.0, 'x_0': 0.0, 'y_0': 0.0, 'lat_ts': -70, 'no_defs': True})])
def test_pickle(factory, arg):
"""A CRS is pickleable"""
crs1 = factory(arg)
crs2 = pickle.loads(pickle.dumps(crs1))
assert crs2 == crs1
def test_linear_units():
"""CRS linear units can be had"""
assert CRS.from_epsg(3857).linear_units == 'metre'
......@@ -16,12 +16,22 @@ def test_gdal_data():
assert GDALDataFinder().search() == os.path.join(os.path.dirname(rasterio.__file__), 'gdal_data')
def test_gdal_data_find_file():
"""Find_file shouldn't raise any exceptions"""
GDALDataFinder().find_file("header.dxf")
@pytest.mark.wheel
def test_proj_data():
"""Get GDAL data path from a wheel"""
assert PROJDataFinder().search() == os.path.join(os.path.dirname(rasterio.__file__), 'proj_data')
def test_proj_data_has_data():
"""has_data shouldn't raise any exceptions"""
PROJDataFinder().has_data()
@pytest.mark.wheel
def test_env_gdal_data():
runner = CliRunner()
......
......@@ -14,6 +14,7 @@ from rasterio._env import del_gdal_config, get_gdal_config, set_gdal_config
from rasterio.env import Env, defenv, delenv, getenv, setenv, ensure_env, ensure_env_credentialled
from rasterio.env import GDALVersion, require_gdal_version
from rasterio.errors import EnvError, RasterioIOError, GDALVersionError
from rasterio.compat import mock
from rasterio.rio.main import main_group
from rasterio.session import AWSSession, OSSSession
......@@ -124,13 +125,16 @@ def test_ensure_env_decorator_sets_gdal_data(gdalenv, monkeypatch):
assert f() == '/lol/wut'
def test_ensure_env_decorator_sets_gdal_data_prefix(gdalenv, monkeypatch, tmpdir):
@mock.patch("rasterio._env.GDALDataFinder.find_file")
def test_ensure_env_decorator_sets_gdal_data_prefix(find_file, gdalenv, monkeypatch, tmpdir):
"""ensure_env finds GDAL data under a prefix"""
@ensure_env
def f():
return getenv()['GDAL_DATA']
find_file.return_value = None
tmpdir.ensure("share/gdal/pcs.csv")
monkeypatch.delenv('GDAL_DATA', raising=False)
monkeypatch.setattr(sys, 'prefix', str(tmpdir))
......@@ -138,12 +142,15 @@ def test_ensure_env_decorator_sets_gdal_data_prefix(gdalenv, monkeypatch, tmpdir
assert f() == str(tmpdir.join("share").join("gdal"))
def test_ensure_env_decorator_sets_gdal_data_wheel(gdalenv, monkeypatch, tmpdir):
@mock.patch("rasterio._env.GDALDataFinder.find_file")
def test_ensure_env_decorator_sets_gdal_data_wheel(find_file, gdalenv, monkeypatch, tmpdir):
"""ensure_env finds GDAL data in a wheel"""
@ensure_env
def f():
return getenv()['GDAL_DATA']
find_file.return_value = None
tmpdir.ensure("gdal_data/pcs.csv")
monkeypatch.delenv('GDAL_DATA', raising=False)
monkeypatch.setattr(_env, '__file__', str(tmpdir.join(os.path.basename(_env.__file__))))
......
"""Profile tests"""
import pickle
import warnings
import pytest
......@@ -77,8 +80,8 @@ def test_blockysize_guard(tmpdir):
rasterio.open(tiffname, 'w', **profile)
def test_profile_overlay():
with rasterio.open('tests/data/RGB.byte.tif') as src:
def test_profile_overlay(path_rgb_byte_tif):
with rasterio.open(path_rgb_byte_tif) as src:
kwds = src.profile
kwds.update(**default_gtiff_profile)
assert kwds['tiled']
......@@ -94,9 +97,9 @@ def test_dataset_profile_property_tiled(data):
assert src.profile['tiled'] is True
def test_dataset_profile_property_untiled(data):
def test_dataset_profile_property_untiled(data, path_rgb_byte_tif):
"""An untiled dataset's profile has no block sizes"""
with rasterio.open('tests/data/RGB.byte.tif') as src:
with rasterio.open(path_rgb_byte_tif) as src:
assert 'blockxsize' not in src.profile
assert 'blockysize' not in src.profile
assert src.profile['tiled'] is False
......@@ -108,3 +111,14 @@ def test_profile_affine_set():
profile['transform'] = 'foo'
with pytest.raises(TypeError):
profile['affine'] = 'bar'
def test_profile_pickle():
"""Standard profile can be pickled"""
assert pickle.loads(pickle.dumps(DefaultGTiffProfile())) == DefaultGTiffProfile()
def test_dataset_profile_pickle(path_rgb_byte_tif):
"""Dataset profiles can be pickled"""
with rasterio.open(path_rgb_byte_tif) as src:
assert pickle.loads(pickle.dumps(src.profile)) == src.profile
......@@ -233,9 +233,6 @@ class ReaderContextTest(unittest.TestCase):
b = s.read(2, a, ((310, 330), (320, 330)), False)
self.assertEqual(id(a), id(b))
self.assertEqual(a.ndim, 2)
# different data types
a = np.empty((3, 718, 791), np.float64)
self.assertRaises(ValueError, s.read, out=a)
# different number of array dimensions
a = np.empty((20, 10), np.ubyte)
self.assertRaises(ValueError, s.read, [2], out=a)
......