We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Don't use rasterio.path
@Kirill888 exposing rasterio.path and its members in Rasterio's public API was a mistake (https://github.com/rasterio/rasterio/issues/2365). Can you change https://github.com/opendatacube/datacube-core/blob/95e72fdbff2707aa6f7abc837d9eab52c50258e1/datacube/storage/_rio.py#L16 to not use it and to just call rasterio.open() instead?

I would love to rename rasterio.path to rasterio._path. At the very least we will warning about this in 1.3.0.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `datacube/storage/_rio.py`
Content:
```
1 # This file is part of the Open Data Cube, see https://opendatacube.org for more information
2 #
3 # Copyright (c) 2015-2020 ODC Contributors
4 # SPDX-License-Identifier: Apache-2.0
5 """
6 Driver implementation for Rasterio based reader.
7 """
8 import logging
9 import warnings
10 import contextlib
11 from contextlib import contextmanager
12 from threading import RLock
13 import numpy as np
14 from affine import Affine
15 import rasterio
16 import rasterio.path
17 from urllib.parse import urlparse
18 from typing import Optional, Iterator
19 
20 from datacube.utils import geometry
21 from datacube.utils.math import num2numpy
22 from datacube.utils import uri_to_local_path, get_part_from_uri, is_vsipath
23 from datacube.utils.rio import activate_from_config
24 from ..drivers.datasource import DataSource, GeoRasterReader, RasterShape, RasterWindow
25 from ._base import BandInfo
26 from ._hdf5 import HDF5_LOCK
27 
28 _LOG = logging.getLogger(__name__)
29 
30 
31 def _rasterio_crs(src):
32     if src.crs is None:
33         raise ValueError('no CRS')
34 
35     return geometry.CRS(src.crs)
36 
37 
38 def maybe_lock(lock):
39     if lock is None:
40         return contextlib.suppress()
41     return lock
42 
43 
44 class BandDataSource(GeoRasterReader):
45     """
46     Wrapper for a :class:`rasterio.Band` object
47 
48     :type source: rasterio.Band
49     """
50 
51     def __init__(self, source, nodata=None,
52                  lock: Optional[RLock] = None):
53         self.source = source
54         if nodata is None:
55             nodata = self.source.ds.nodatavals[self.source.bidx-1]
56 
57         self._nodata = num2numpy(nodata, source.dtype)
58         self._lock = lock
59 
60     @property
61     def nodata(self):
62         return self._nodata
63 
64     @property
65     def crs(self) -> geometry.CRS:
66         return _rasterio_crs(self.source.ds)
67 
68     @property
69     def transform(self) -> Affine:
70         return self.source.ds.transform
71 
72     @property
73     def dtype(self) -> np.dtype:
74         return np.dtype(self.source.dtype)
75 
76     @property
77     def shape(self) -> RasterShape:
78         return self.source.shape
79 
80     def read(self, window: Optional[RasterWindow] = None,
81              out_shape: Optional[RasterShape] = None) -> Optional[np.ndarray]:
82         """Read data in the native format, returning a numpy array
83         """
84         with maybe_lock(self._lock):
85             return self.source.ds.read(indexes=self.source.bidx, window=window, out_shape=out_shape)
86 
87 
88 class OverrideBandDataSource(GeoRasterReader):
89     """Wrapper for a rasterio.Band object that overrides nodata, CRS and transform
90 
91     This is useful for files with malformed or missing properties.
92 
93 
94     :type source: rasterio.Band
95     """
96 
97     def __init__(self,
98                  source: rasterio.Band,
99                  nodata,
100                  crs: geometry.CRS,
101                  transform: Affine,
102                  lock: Optional[RLock] = None):
103         self.source = source
104         self._nodata = num2numpy(nodata, source.dtype)
105         self._crs = crs
106         self._transform = transform
107         self._lock = lock
108 
109     @property
110     def crs(self) -> geometry.CRS:
111         return self._crs
112 
113     @property
114     def transform(self) -> Affine:
115         return self._transform
116 
117     @property
118     def nodata(self):
119         return self._nodata
120 
121     @property
122     def dtype(self) -> np.dtype:
123         return np.dtype(self.source.dtype)
124 
125     @property
126     def shape(self) -> RasterShape:
127         return self.source.shape
128 
129     def read(self, window: Optional[RasterWindow] = None,
130              out_shape: Optional[RasterShape] = None) -> Optional[np.ndarray]:
131         """Read data in the native format, returning a native array
132         """
133         with maybe_lock(self._lock):
134             return self.source.ds.read(indexes=self.source.bidx, window=window, out_shape=out_shape)
135 
136 
137 class RasterioDataSource(DataSource):
138     """
139     Abstract class used by fuse_sources and :func:`read_from_source`
140 
141     """
142 
143     def __init__(self, filename, nodata, lock=None):
144         self.filename = filename
145         self.nodata = nodata
146         self._lock = lock
147 
148     def get_bandnumber(self, src):
149         raise NotImplementedError()
150 
151     def get_transform(self, shape):
152         raise NotImplementedError()
153 
154     def get_crs(self):
155         raise NotImplementedError()
156 
157     @contextmanager
158     def open(self) -> Iterator[GeoRasterReader]:
159         """Context manager which returns a :class:`BandDataSource`"""
160 
161         activate_from_config()  # check if settings changed and apply new
162 
163         lock = self._lock
164         locked = False if lock is None else lock.acquire(blocking=True)
165 
166         try:
167             _LOG.debug("opening %s", self.filename)
168             with rasterio.DatasetReader(rasterio.path.parse_path(str(self.filename)),
169                                         sharing=False) as src:
170                 override = False
171 
172                 transform = src.transform
173                 if transform.is_identity:
174                     override = True
175                     transform = self.get_transform(src.shape)
176 
177                 try:
178                     crs = _rasterio_crs(src)
179                 except ValueError:
180                     override = True
181                     crs = self.get_crs()
182 
183                 bandnumber = self.get_bandnumber(src)
184                 band = rasterio.band(src, bandnumber)
185                 nodata = src.nodatavals[band.bidx-1] if src.nodatavals[band.bidx-1] is not None else self.nodata
186                 nodata = num2numpy(nodata, band.dtype)
187 
188                 if locked:
189                     locked = False
190                     lock.release()
191 
192                 if override:
193                     warnings.warn(f"""Broken/missing geospatial data was found in file:
194 "{self.filename}"
195 Will use approximate metadata for backwards compatibility reasons (#673).
196 This behaviour is deprecated. Future versions will raise an error.""",
197                                   category=DeprecationWarning)
198                     yield OverrideBandDataSource(band, nodata=nodata, crs=crs, transform=transform, lock=lock)
199                 else:
200                     yield BandDataSource(band, nodata=nodata, lock=lock)
201 
202         except Exception as e:
203             _LOG.error("Error opening source dataset: %s", self.filename)
204             raise e
205         finally:
206             if locked:
207                 lock.release()
208 
209 
210 class RasterDatasetDataSource(RasterioDataSource):
211     """Data source for reading from a Data Cube Dataset"""
212 
213     def __init__(self, band: BandInfo):
214         """
215         Initialise for reading from a Data Cube Dataset.
216 
217         :param dataset: dataset to read from
218         :param measurement_id: measurement to read. a single 'band' or 'slice'
219         """
220         self._band_info = band
221         self._hdf = _is_hdf(band.format)
222         self._part = get_part_from_uri(band.uri)
223         filename = _url2rasterio(band.uri, band.format, band.layer)
224         lock = HDF5_LOCK if self._hdf else None
225         super(RasterDatasetDataSource, self).__init__(filename, nodata=band.nodata, lock=lock)
226 
227     def get_bandnumber(self, src=None) -> Optional[int]:
228 
229         # If `band` property is set to an integer it overrides any other logic
230         bi = self._band_info
231         if bi.band is not None:
232             return bi.band
233 
234         if not self._hdf:
235             return 1
236 
237         # Netcdf/hdf only below
238         if self._part is not None:
239             return self._part + 1  # Convert to rasterio 1-based indexing
240 
241         if src is None:
242             # File wasnt' open, could be unstacked file in a new format, or
243             # stacked/unstacked in old. We assume caller knows what to do
244             # (maybe based on some side-channel information), so just report
245             # undefined.
246             return None
247 
248         if src.count == 1:  # Single-slice netcdf file
249             return 1
250 
251         raise DeprecationWarning("Stacked netcdf without explicit time index is not supported anymore")
252 
253     def get_transform(self, shape: RasterShape) -> Affine:
254         return self._band_info.transform * Affine.scale(1 / shape[1], 1 / shape[0])
255 
256     def get_crs(self):
257         return self._band_info.crs
258 
259 
260 def _is_hdf(fmt: str) -> bool:
261     """ Check if format is of HDF type (this includes netcdf variants)
262     """
263     fmt = fmt.lower()
264     return any(f in fmt for f in ('netcdf', 'hdf'))
265 
266 
267 def _build_hdf_uri(url_str: str, fmt: str, layer: str) -> str:
268     if is_vsipath(url_str):
269         base = url_str
270     else:
271         url = urlparse(url_str)
272         if url.scheme in (None, ''):
273             raise ValueError("Expect either URL or /vsi path")
274 
275         if url.scheme != 'file':
276             raise RuntimeError("Can't access %s over %s" % (fmt, url.scheme))
277         base = str(uri_to_local_path(url_str))
278 
279     return '{}:"{}":{}'.format(fmt, base, layer)
280 
281 
282 def _url2rasterio(url_str: str, fmt: str, layer: Optional[str]) -> str:
283     """
284     turn URL into a string that could be passed to raterio.open
285     """
286     if _is_hdf(fmt):
287         if layer is None:
288             raise ValueError("Missing layer for hdf/netcdf format dataset")
289 
290         return _build_hdf_uri(url_str, fmt, layer)
291 
292     if is_vsipath(url_str):
293         return url_str
294 
295     url = urlparse(url_str)
296     if url.scheme in (None, ''):
297         raise ValueError("Expect either URL or /vsi path")
298 
299     if url.scheme == 'file':
300         # if local path strip scheme and other gunk
301         return str(uri_to_local_path(url_str))
302 
303     return url_str
304
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/datacube/storage/_rio.py b/datacube/storage/_rio.py
--- a/datacube/storage/_rio.py
+++ b/datacube/storage/_rio.py
@@ -13,7 +13,6 @@
 import numpy as np
 from affine import Affine
 import rasterio
-import rasterio.path
 from urllib.parse import urlparse
 from typing import Optional, Iterator
 
@@ -165,8 +164,7 @@
 
         try:
             _LOG.debug("opening %s", self.filename)
-            with rasterio.DatasetReader(rasterio.path.parse_path(str(self.filename)),
-                                        sharing=False) as src:
+            with rasterio.open(str(self.filename), sharing=False) as src:
                 override = False
 
                 transform = src.transform

{"golden_diff": "diff --git a/datacube/storage/_rio.py b/datacube/storage/_rio.py\n--- a/datacube/storage/_rio.py\n+++ b/datacube/storage/_rio.py\n@@ -13,7 +13,6 @@\n import numpy as np\n from affine import Affine\n import rasterio\n-import rasterio.path\n from urllib.parse import urlparse\n from typing import Optional, Iterator\n \n@@ -165,8 +164,7 @@\n \n         try:\n             _LOG.debug(\"opening %s\", self.filename)\n-            with rasterio.DatasetReader(rasterio.path.parse_path(str(self.filename)),\n-                                        sharing=False) as src:\n+            with rasterio.open(str(self.filename), sharing=False) as src:\n                 override = False\n \n                 transform = src.transform\n", "issue": "Don't use rasterio.path\n@Kirill888 exposing rasterio.path and its members in Rasterio's public API was a mistake (https://github.com/rasterio/rasterio/issues/2365). Can you change https://github.com/opendatacube/datacube-core/blob/95e72fdbff2707aa6f7abc837d9eab52c50258e1/datacube/storage/_rio.py#L16 to not use it and to just call rasterio.open() instead?\r\n\r\nI would love to rename rasterio.path to rasterio._path. At the very least we will warning about this in 1.3.0.\n", "before_files": [{"content": "# This file is part of the Open Data Cube, see https://opendatacube.org for more information\n#\n# Copyright (c) 2015-2020 ODC Contributors\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"\nDriver implementation for Rasterio based reader.\n\"\"\"\nimport logging\nimport warnings\nimport contextlib\nfrom contextlib import contextmanager\nfrom threading import RLock\nimport numpy as np\nfrom affine import Affine\nimport rasterio\nimport rasterio.path\nfrom urllib.parse import urlparse\nfrom typing import Optional, Iterator\n\nfrom datacube.utils import geometry\nfrom datacube.utils.math import num2numpy\nfrom datacube.utils import uri_to_local_path, get_part_from_uri, is_vsipath\nfrom datacube.utils.rio import activate_from_config\nfrom ..drivers.datasource import DataSource, GeoRasterReader, RasterShape, RasterWindow\nfrom ._base import BandInfo\nfrom ._hdf5 import HDF5_LOCK\n\n_LOG = logging.getLogger(__name__)\n\n\ndef _rasterio_crs(src):\n    if src.crs is None:\n        raise ValueError('no CRS')\n\n    return geometry.CRS(src.crs)\n\n\ndef maybe_lock(lock):\n    if lock is None:\n        return contextlib.suppress()\n    return lock\n\n\nclass BandDataSource(GeoRasterReader):\n    \"\"\"\n    Wrapper for a :class:`rasterio.Band` object\n\n    :type source: rasterio.Band\n    \"\"\"\n\n    def __init__(self, source, nodata=None,\n                 lock: Optional[RLock] = None):\n        self.source = source\n        if nodata is None:\n            nodata = self.source.ds.nodatavals[self.source.bidx-1]\n\n        self._nodata = num2numpy(nodata, source.dtype)\n        self._lock = lock\n\n    @property\n    def nodata(self):\n        return self._nodata\n\n    @property\n    def crs(self) -> geometry.CRS:\n        return _rasterio_crs(self.source.ds)\n\n    @property\n    def transform(self) -> Affine:\n        return self.source.ds.transform\n\n    @property\n    def dtype(self) -> np.dtype:\n        return np.dtype(self.source.dtype)\n\n    @property\n    def shape(self) -> RasterShape:\n        return self.source.shape\n\n    def read(self, window: Optional[RasterWindow] = None,\n             out_shape: Optional[RasterShape] = None) -> Optional[np.ndarray]:\n        \"\"\"Read data in the native format, returning a numpy array\n        \"\"\"\n        with maybe_lock(self._lock):\n            return self.source.ds.read(indexes=self.source.bidx, window=window, out_shape=out_shape)\n\n\nclass OverrideBandDataSource(GeoRasterReader):\n    \"\"\"Wrapper for a rasterio.Band object that overrides nodata, CRS and transform\n\n    This is useful for files with malformed or missing properties.\n\n\n    :type source: rasterio.Band\n    \"\"\"\n\n    def __init__(self,\n                 source: rasterio.Band,\n                 nodata,\n                 crs: geometry.CRS,\n                 transform: Affine,\n                 lock: Optional[RLock] = None):\n        self.source = source\n        self._nodata = num2numpy(nodata, source.dtype)\n        self._crs = crs\n        self._transform = transform\n        self._lock = lock\n\n    @property\n    def crs(self) -> geometry.CRS:\n        return self._crs\n\n    @property\n    def transform(self) -> Affine:\n        return self._transform\n\n    @property\n    def nodata(self):\n        return self._nodata\n\n    @property\n    def dtype(self) -> np.dtype:\n        return np.dtype(self.source.dtype)\n\n    @property\n    def shape(self) -> RasterShape:\n        return self.source.shape\n\n    def read(self, window: Optional[RasterWindow] = None,\n             out_shape: Optional[RasterShape] = None) -> Optional[np.ndarray]:\n        \"\"\"Read data in the native format, returning a native array\n        \"\"\"\n        with maybe_lock(self._lock):\n            return self.source.ds.read(indexes=self.source.bidx, window=window, out_shape=out_shape)\n\n\nclass RasterioDataSource(DataSource):\n    \"\"\"\n    Abstract class used by fuse_sources and :func:`read_from_source`\n\n    \"\"\"\n\n    def __init__(self, filename, nodata, lock=None):\n        self.filename = filename\n        self.nodata = nodata\n        self._lock = lock\n\n    def get_bandnumber(self, src):\n        raise NotImplementedError()\n\n    def get_transform(self, shape):\n        raise NotImplementedError()\n\n    def get_crs(self):\n        raise NotImplementedError()\n\n    @contextmanager\n    def open(self) -> Iterator[GeoRasterReader]:\n        \"\"\"Context manager which returns a :class:`BandDataSource`\"\"\"\n\n        activate_from_config()  # check if settings changed and apply new\n\n        lock = self._lock\n        locked = False if lock is None else lock.acquire(blocking=True)\n\n        try:\n            _LOG.debug(\"opening %s\", self.filename)\n            with rasterio.DatasetReader(rasterio.path.parse_path(str(self.filename)),\n                                        sharing=False) as src:\n                override = False\n\n                transform = src.transform\n                if transform.is_identity:\n                    override = True\n                    transform = self.get_transform(src.shape)\n\n                try:\n                    crs = _rasterio_crs(src)\n                except ValueError:\n                    override = True\n                    crs = self.get_crs()\n\n                bandnumber = self.get_bandnumber(src)\n                band = rasterio.band(src, bandnumber)\n                nodata = src.nodatavals[band.bidx-1] if src.nodatavals[band.bidx-1] is not None else self.nodata\n                nodata = num2numpy(nodata, band.dtype)\n\n                if locked:\n                    locked = False\n                    lock.release()\n\n                if override:\n                    warnings.warn(f\"\"\"Broken/missing geospatial data was found in file:\n\"{self.filename}\"\nWill use approximate metadata for backwards compatibility reasons (#673).\nThis behaviour is deprecated. Future versions will raise an error.\"\"\",\n                                  category=DeprecationWarning)\n                    yield OverrideBandDataSource(band, nodata=nodata, crs=crs, transform=transform, lock=lock)\n                else:\n                    yield BandDataSource(band, nodata=nodata, lock=lock)\n\n        except Exception as e:\n            _LOG.error(\"Error opening source dataset: %s\", self.filename)\n            raise e\n        finally:\n            if locked:\n                lock.release()\n\n\nclass RasterDatasetDataSource(RasterioDataSource):\n    \"\"\"Data source for reading from a Data Cube Dataset\"\"\"\n\n    def __init__(self, band: BandInfo):\n        \"\"\"\n        Initialise for reading from a Data Cube Dataset.\n\n        :param dataset: dataset to read from\n        :param measurement_id: measurement to read. a single 'band' or 'slice'\n        \"\"\"\n        self._band_info = band\n        self._hdf = _is_hdf(band.format)\n        self._part = get_part_from_uri(band.uri)\n        filename = _url2rasterio(band.uri, band.format, band.layer)\n        lock = HDF5_LOCK if self._hdf else None\n        super(RasterDatasetDataSource, self).__init__(filename, nodata=band.nodata, lock=lock)\n\n    def get_bandnumber(self, src=None) -> Optional[int]:\n\n        # If `band` property is set to an integer it overrides any other logic\n        bi = self._band_info\n        if bi.band is not None:\n            return bi.band\n\n        if not self._hdf:\n            return 1\n\n        # Netcdf/hdf only below\n        if self._part is not None:\n            return self._part + 1  # Convert to rasterio 1-based indexing\n\n        if src is None:\n            # File wasnt' open, could be unstacked file in a new format, or\n            # stacked/unstacked in old. We assume caller knows what to do\n            # (maybe based on some side-channel information), so just report\n            # undefined.\n            return None\n\n        if src.count == 1:  # Single-slice netcdf file\n            return 1\n\n        raise DeprecationWarning(\"Stacked netcdf without explicit time index is not supported anymore\")\n\n    def get_transform(self, shape: RasterShape) -> Affine:\n        return self._band_info.transform * Affine.scale(1 / shape[1], 1 / shape[0])\n\n    def get_crs(self):\n        return self._band_info.crs\n\n\ndef _is_hdf(fmt: str) -> bool:\n    \"\"\" Check if format is of HDF type (this includes netcdf variants)\n    \"\"\"\n    fmt = fmt.lower()\n    return any(f in fmt for f in ('netcdf', 'hdf'))\n\n\ndef _build_hdf_uri(url_str: str, fmt: str, layer: str) -> str:\n    if is_vsipath(url_str):\n        base = url_str\n    else:\n        url = urlparse(url_str)\n        if url.scheme in (None, ''):\n            raise ValueError(\"Expect either URL or /vsi path\")\n\n        if url.scheme != 'file':\n            raise RuntimeError(\"Can't access %s over %s\" % (fmt, url.scheme))\n        base = str(uri_to_local_path(url_str))\n\n    return '{}:\"{}\":{}'.format(fmt, base, layer)\n\n\ndef _url2rasterio(url_str: str, fmt: str, layer: Optional[str]) -> str:\n    \"\"\"\n    turn URL into a string that could be passed to raterio.open\n    \"\"\"\n    if _is_hdf(fmt):\n        if layer is None:\n            raise ValueError(\"Missing layer for hdf/netcdf format dataset\")\n\n        return _build_hdf_uri(url_str, fmt, layer)\n\n    if is_vsipath(url_str):\n        return url_str\n\n    url = urlparse(url_str)\n    if url.scheme in (None, ''):\n        raise ValueError(\"Expect either URL or /vsi path\")\n\n    if url.scheme == 'file':\n        # if local path strip scheme and other gunk\n        return str(uri_to_local_path(url_str))\n\n    return url_str\n", "path": "datacube/storage/_rio.py"}], "after_files": [{"content": "# This file is part of the Open Data Cube, see https://opendatacube.org for more information\n#\n# Copyright (c) 2015-2020 ODC Contributors\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"\nDriver implementation for Rasterio based reader.\n\"\"\"\nimport logging\nimport warnings\nimport contextlib\nfrom contextlib import contextmanager\nfrom threading import RLock\nimport numpy as np\nfrom affine import Affine\nimport rasterio\nfrom urllib.parse import urlparse\nfrom typing import Optional, Iterator\n\nfrom datacube.utils import geometry\nfrom datacube.utils.math import num2numpy\nfrom datacube.utils import uri_to_local_path, get_part_from_uri, is_vsipath\nfrom datacube.utils.rio import activate_from_config\nfrom ..drivers.datasource import DataSource, GeoRasterReader, RasterShape, RasterWindow\nfrom ._base import BandInfo\nfrom ._hdf5 import HDF5_LOCK\n\n_LOG = logging.getLogger(__name__)\n\n\ndef _rasterio_crs(src):\n    if src.crs is None:\n        raise ValueError('no CRS')\n\n    return geometry.CRS(src.crs)\n\n\ndef maybe_lock(lock):\n    if lock is None:\n        return contextlib.suppress()\n    return lock\n\n\nclass BandDataSource(GeoRasterReader):\n    \"\"\"\n    Wrapper for a :class:`rasterio.Band` object\n\n    :type source: rasterio.Band\n    \"\"\"\n\n    def __init__(self, source, nodata=None,\n                 lock: Optional[RLock] = None):\n        self.source = source\n        if nodata is None:\n            nodata = self.source.ds.nodatavals[self.source.bidx-1]\n\n        self._nodata = num2numpy(nodata, source.dtype)\n        self._lock = lock\n\n    @property\n    def nodata(self):\n        return self._nodata\n\n    @property\n    def crs(self) -> geometry.CRS:\n        return _rasterio_crs(self.source.ds)\n\n    @property\n    def transform(self) -> Affine:\n        return self.source.ds.transform\n\n    @property\n    def dtype(self) -> np.dtype:\n        return np.dtype(self.source.dtype)\n\n    @property\n    def shape(self) -> RasterShape:\n        return self.source.shape\n\n    def read(self, window: Optional[RasterWindow] = None,\n             out_shape: Optional[RasterShape] = None) -> Optional[np.ndarray]:\n        \"\"\"Read data in the native format, returning a numpy array\n        \"\"\"\n        with maybe_lock(self._lock):\n            return self.source.ds.read(indexes=self.source.bidx, window=window, out_shape=out_shape)\n\n\nclass OverrideBandDataSource(GeoRasterReader):\n    \"\"\"Wrapper for a rasterio.Band object that overrides nodata, CRS and transform\n\n    This is useful for files with malformed or missing properties.\n\n\n    :type source: rasterio.Band\n    \"\"\"\n\n    def __init__(self,\n                 source: rasterio.Band,\n                 nodata,\n                 crs: geometry.CRS,\n                 transform: Affine,\n                 lock: Optional[RLock] = None):\n        self.source = source\n        self._nodata = num2numpy(nodata, source.dtype)\n        self._crs = crs\n        self._transform = transform\n        self._lock = lock\n\n    @property\n    def crs(self) -> geometry.CRS:\n        return self._crs\n\n    @property\n    def transform(self) -> Affine:\n        return self._transform\n\n    @property\n    def nodata(self):\n        return self._nodata\n\n    @property\n    def dtype(self) -> np.dtype:\n        return np.dtype(self.source.dtype)\n\n    @property\n    def shape(self) -> RasterShape:\n        return self.source.shape\n\n    def read(self, window: Optional[RasterWindow] = None,\n             out_shape: Optional[RasterShape] = None) -> Optional[np.ndarray]:\n        \"\"\"Read data in the native format, returning a native array\n        \"\"\"\n        with maybe_lock(self._lock):\n            return self.source.ds.read(indexes=self.source.bidx, window=window, out_shape=out_shape)\n\n\nclass RasterioDataSource(DataSource):\n    \"\"\"\n    Abstract class used by fuse_sources and :func:`read_from_source`\n\n    \"\"\"\n\n    def __init__(self, filename, nodata, lock=None):\n        self.filename = filename\n        self.nodata = nodata\n        self._lock = lock\n\n    def get_bandnumber(self, src):\n        raise NotImplementedError()\n\n    def get_transform(self, shape):\n        raise NotImplementedError()\n\n    def get_crs(self):\n        raise NotImplementedError()\n\n    @contextmanager\n    def open(self) -> Iterator[GeoRasterReader]:\n        \"\"\"Context manager which returns a :class:`BandDataSource`\"\"\"\n\n        activate_from_config()  # check if settings changed and apply new\n\n        lock = self._lock\n        locked = False if lock is None else lock.acquire(blocking=True)\n\n        try:\n            _LOG.debug(\"opening %s\", self.filename)\n            with rasterio.open(str(self.filename), sharing=False) as src:\n                override = False\n\n                transform = src.transform\n                if transform.is_identity:\n                    override = True\n                    transform = self.get_transform(src.shape)\n\n                try:\n                    crs = _rasterio_crs(src)\n                except ValueError:\n                    override = True\n                    crs = self.get_crs()\n\n                bandnumber = self.get_bandnumber(src)\n                band = rasterio.band(src, bandnumber)\n                nodata = src.nodatavals[band.bidx-1] if src.nodatavals[band.bidx-1] is not None else self.nodata\n                nodata = num2numpy(nodata, band.dtype)\n\n                if locked:\n                    locked = False\n                    lock.release()\n\n                if override:\n                    warnings.warn(f\"\"\"Broken/missing geospatial data was found in file:\n\"{self.filename}\"\nWill use approximate metadata for backwards compatibility reasons (#673).\nThis behaviour is deprecated. Future versions will raise an error.\"\"\",\n                                  category=DeprecationWarning)\n                    yield OverrideBandDataSource(band, nodata=nodata, crs=crs, transform=transform, lock=lock)\n                else:\n                    yield BandDataSource(band, nodata=nodata, lock=lock)\n\n        except Exception as e:\n            _LOG.error(\"Error opening source dataset: %s\", self.filename)\n            raise e\n        finally:\n            if locked:\n                lock.release()\n\n\nclass RasterDatasetDataSource(RasterioDataSource):\n    \"\"\"Data source for reading from a Data Cube Dataset\"\"\"\n\n    def __init__(self, band: BandInfo):\n        \"\"\"\n        Initialise for reading from a Data Cube Dataset.\n\n        :param dataset: dataset to read from\n        :param measurement_id: measurement to read. a single 'band' or 'slice'\n        \"\"\"\n        self._band_info = band\n        self._hdf = _is_hdf(band.format)\n        self._part = get_part_from_uri(band.uri)\n        filename = _url2rasterio(band.uri, band.format, band.layer)\n        lock = HDF5_LOCK if self._hdf else None\n        super(RasterDatasetDataSource, self).__init__(filename, nodata=band.nodata, lock=lock)\n\n    def get_bandnumber(self, src=None) -> Optional[int]:\n\n        # If `band` property is set to an integer it overrides any other logic\n        bi = self._band_info\n        if bi.band is not None:\n            return bi.band\n\n        if not self._hdf:\n            return 1\n\n        # Netcdf/hdf only below\n        if self._part is not None:\n            return self._part + 1  # Convert to rasterio 1-based indexing\n\n        if src is None:\n            # File wasnt' open, could be unstacked file in a new format, or\n            # stacked/unstacked in old. We assume caller knows what to do\n            # (maybe based on some side-channel information), so just report\n            # undefined.\n            return None\n\n        if src.count == 1:  # Single-slice netcdf file\n            return 1\n\n        raise DeprecationWarning(\"Stacked netcdf without explicit time index is not supported anymore\")\n\n    def get_transform(self, shape: RasterShape) -> Affine:\n        return self._band_info.transform * Affine.scale(1 / shape[1], 1 / shape[0])\n\n    def get_crs(self):\n        return self._band_info.crs\n\n\ndef _is_hdf(fmt: str) -> bool:\n    \"\"\" Check if format is of HDF type (this includes netcdf variants)\n    \"\"\"\n    fmt = fmt.lower()\n    return any(f in fmt for f in ('netcdf', 'hdf'))\n\n\ndef _build_hdf_uri(url_str: str, fmt: str, layer: str) -> str:\n    if is_vsipath(url_str):\n        base = url_str\n    else:\n        url = urlparse(url_str)\n        if url.scheme in (None, ''):\n            raise ValueError(\"Expect either URL or /vsi path\")\n\n        if url.scheme != 'file':\n            raise RuntimeError(\"Can't access %s over %s\" % (fmt, url.scheme))\n        base = str(uri_to_local_path(url_str))\n\n    return '{}:\"{}\":{}'.format(fmt, base, layer)\n\n\ndef _url2rasterio(url_str: str, fmt: str, layer: Optional[str]) -> str:\n    \"\"\"\n    turn URL into a string that could be passed to raterio.open\n    \"\"\"\n    if _is_hdf(fmt):\n        if layer is None:\n            raise ValueError(\"Missing layer for hdf/netcdf format dataset\")\n\n        return _build_hdf_uri(url_str, fmt, layer)\n\n    if is_vsipath(url_str):\n        return url_str\n\n    url = urlparse(url_str)\n    if url.scheme in (None, ''):\n        raise ValueError(\"Expect either URL or /vsi path\")\n\n    if url.scheme == 'file':\n        # if local path strip scheme and other gunk\n        return str(uri_to_local_path(url_str))\n\n    return url_str\n", "path": "datacube/storage/_rio.py"}]}