prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Example PickleWriterDriver does not support URIs
  ### Expected behaviour
  Using the example `pickles` driver should allow to successfully run, e.g., `integration_tests/test_end_to_end`. This is assuming the example dcio driver has been installed first.
  
  ### Actual behaviour
  The test fails because a URI gets passed to `PickleWriterDriver.write_dataset_to_storage()` which still expects a filepath string. Also, this URI may contain intermediate directories that need creating.
  
  ### Steps to reproduce the behaviour
  - Set `pickles` as driver name in, e.g., `datacube-core/docs/config_samples/ingester/ls5_nbar_albers.yaml(106)`
  - Run `pytest integration_tests/test_end_to_end.py`
  - First error: `AttributeError: 'PickleWriterDriver' object has no attribute 'mk_uri'` but subsequent errors happen due to missing intermediate directories.
  
  ### Environment information
  - `Open Data Cube core, version 1.8.4.dev52+g07bc51a5.d20210222`
  - Docker image: `opendatacube/datacube-tests:latest`
  
  </issue>
  <code>
  [start of examples/io_plugin/dcio_example/pickles.py]
  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 """ Example reader plugin
  6 """
  7 from contextlib import contextmanager
  8 import pickle
  9 
  10 
  11 PROTOCOL = 'file'
  12 FORMAT = 'pickle'
  13 
  14 
  15 def uri_split(uri):
  16     loc = uri.find('://')
  17     if loc < 0:
  18         return uri, PROTOCOL
  19     return uri[loc+3:], uri[:loc]
  20 
  21 
  22 class PickleDataSource(object):
  23     class BandDataSource(object):
  24         def __init__(self, da):
  25             self._da = da
  26             self.nodata = da.nodata
  27 
  28         @property
  29         def crs(self):
  30             return self._da.crs
  31 
  32         @property
  33         def transform(self):
  34             return self._da.affine
  35 
  36         @property
  37         def dtype(self):
  38             return self._da.dtype
  39 
  40         @property
  41         def shape(self):
  42             return self._da.shape
  43 
  44         def read(self, window=None, out_shape=None):
  45             if window is None:
  46                 data = self._da.values
  47             else:
  48                 rows, cols = [slice(*w) for w in window]
  49                 data = self._da.values[rows, cols]
  50 
  51             if out_shape is None or out_shape == data.shape:
  52                 return data
  53 
  54             raise NotImplementedError('Native reading not supported for this data source')
  55 
  56     def __init__(self, band):
  57         self._band = band
  58         uri = band.uri
  59         self._filename, protocol = uri_split(uri)
  60 
  61         if protocol not in [PROTOCOL, 'pickle']:
  62             raise ValueError('Expected file:// or pickle:// url')
  63 
  64     @contextmanager
  65     def open(self):
  66         with open(self._filename, 'rb') as f:
  67             ds = pickle.load(f)
  68 
  69         yield PickleDataSource.BandDataSource(ds[self._band.name].isel(time=0))
  70 
  71 
  72 class PickleReaderDriver(object):
  73     def __init__(self):
  74         self.name = 'PickleReader'
  75         self.protocols = [PROTOCOL, 'pickle']
  76         self.formats = [FORMAT]
  77 
  78     def supports(self, protocol, fmt):
  79         return (protocol in self.protocols and
  80                 fmt in self.formats)
  81 
  82     def new_datasource(self, band):
  83         return PickleDataSource(band)
  84 
  85 
  86 def rdr_driver_init():
  87     return PickleReaderDriver()
  88 
  89 
  90 class PickleWriterDriver(object):
  91     def __init__(self):
  92         pass
  93 
  94     @property
  95     def aliases(self):
  96         return ['pickles']
  97 
  98     @property
  99     def format(self):
  100         return FORMAT
  101 
  102     @property
  103     def uri_scheme(self):
  104         return PROTOCOL
  105 
  106     def write_dataset_to_storage(self, dataset, filename,
  107                                  global_attributes=None,
  108                                  variable_params=None,
  109                                  storage_config=None,
  110                                  **kwargs):
  111         with open(filename, 'wb') as f:
  112             pickle.dump(dataset, f)
  113         return {}
  114 
  115 
  116 def writer_driver_init():
  117     return PickleWriterDriver()
  118
  [end of examples/io_plugin/dcio_example/pickles.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/examples/io_plugin/dcio_example/pickles.py b/examples/io_plugin/dcio_example/pickles.py
  --- a/examples/io_plugin/dcio_example/pickles.py
  +++ b/examples/io_plugin/dcio_example/pickles.py
  @@ -4,9 +4,12 @@
   # SPDX-License-Identifier: Apache-2.0
   """ Example reader plugin
   """
  -from contextlib import contextmanager
   import pickle
  +from contextlib import contextmanager
  +from pathlib import Path
  +from urllib.parse import urlsplit
   
  +from datacube.utils.uris import normalise_path
   
   PROTOCOL = 'file'
   FORMAT = 'pickle'
  @@ -103,12 +106,33 @@
       def uri_scheme(self):
           return PROTOCOL
   
  -    def write_dataset_to_storage(self, dataset, filename,
  +    def mk_uri(self, file_path, storage_config):
  +        """
  +        Constructs a URI from the file_path and storage config.
  +
  +        A typical implementation should return f'{scheme}://{file_path}'
  +
  +        Example:
  +            file_path = '/path/to/my_file.pickled'
  +            storage_config = {'driver': 'pickles'}
  +
  +            mk_uri(file_path, storage_config) should return 'file:///path/to/my_file.pickled'
  +
  +        :param Path file_path: The file path of the file to be converted into a URI.
  +        :param dict storage_config: The dict holding the storage config found in the ingest definition.
  +        :return: file_path as a URI that the Driver understands.
  +        :rtype: str
  +        """
  +        return normalise_path(file_path).as_uri()
  +
  +    def write_dataset_to_storage(self, dataset, file_uri,
                                    global_attributes=None,
                                    variable_params=None,
                                    storage_config=None,
                                    **kwargs):
  -        with open(filename, 'wb') as f:
  +        filepath = Path(urlsplit(file_uri).path)
  +        filepath.parent.mkdir(parents=True, exist_ok=True)
  +        with filepath.open('wb') as f:
               pickle.dump(dataset, f)
           return {}
  
verification_info: {"golden_diff": "diff --git a/examples/io_plugin/dcio_example/pickles.py b/examples/io_plugin/dcio_example/pickles.py\n--- a/examples/io_plugin/dcio_example/pickles.py\n+++ b/examples/io_plugin/dcio_example/pickles.py\n@@ -4,9 +4,12 @@\n # SPDX-License-Identifier: Apache-2.0\n \"\"\" Example reader plugin\n \"\"\"\n-from contextlib import contextmanager\n import pickle\n+from contextlib import contextmanager\n+from pathlib import Path\n+from urllib.parse import urlsplit\n \n+from datacube.utils.uris import normalise_path\n \n PROTOCOL = 'file'\n FORMAT = 'pickle'\n@@ -103,12 +106,33 @@\n     def uri_scheme(self):\n         return PROTOCOL\n \n-    def write_dataset_to_storage(self, dataset, filename,\n+    def mk_uri(self, file_path, storage_config):\n+        \"\"\"\n+        Constructs a URI from the file_path and storage config.\n+\n+        A typical implementation should return f'{scheme}://{file_path}'\n+\n+        Example:\n+            file_path = '/path/to/my_file.pickled'\n+            storage_config = {'driver': 'pickles'}\n+\n+            mk_uri(file_path, storage_config) should return 'file:///path/to/my_file.pickled'\n+\n+        :param Path file_path: The file path of the file to be converted into a URI.\n+        :param dict storage_config: The dict holding the storage config found in the ingest definition.\n+        :return: file_path as a URI that the Driver understands.\n+        :rtype: str\n+        \"\"\"\n+        return normalise_path(file_path).as_uri()\n+\n+    def write_dataset_to_storage(self, dataset, file_uri,\n                                  global_attributes=None,\n                                  variable_params=None,\n                                  storage_config=None,\n                                  **kwargs):\n-        with open(filename, 'wb') as f:\n+        filepath = Path(urlsplit(file_uri).path)\n+        filepath.parent.mkdir(parents=True, exist_ok=True)\n+        with filepath.open('wb') as f:\n             pickle.dump(dataset, f)\n         return {}\n", "issue": "Example PickleWriterDriver does not support URIs\n### Expected behaviour\r\nUsing the example `pickles` driver should allow to successfully run, e.g., `integration_tests/test_end_to_end`. This is assuming the example dcio driver has been installed first.\r\n\r\n### Actual behaviour\r\nThe test fails because a URI gets passed to `PickleWriterDriver.write_dataset_to_storage()` which still expects a filepath string. Also, this URI may contain intermediate directories that need creating.\r\n\r\n### Steps to reproduce the behaviour\r\n- Set `pickles` as driver name in, e.g., `datacube-core/docs/config_samples/ingester/ls5_nbar_albers.yaml(106)`\r\n- Run `pytest integration_tests/test_end_to_end.py`\r\n- First error: `AttributeError: 'PickleWriterDriver' object has no attribute 'mk_uri'` but subsequent errors happen due to missing intermediate directories.\r\n\r\n### Environment information\r\n- `Open Data Cube core, version 1.8.4.dev52+g07bc51a5.d20210222`\r\n- Docker image: `opendatacube/datacube-tests:latest`\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\"\"\" Example reader plugin\n\"\"\"\nfrom contextlib import contextmanager\nimport pickle\n\n\nPROTOCOL = 'file'\nFORMAT = 'pickle'\n\n\ndef uri_split(uri):\n    loc = uri.find('://')\n    if loc < 0:\n        return uri, PROTOCOL\n    return uri[loc+3:], uri[:loc]\n\n\nclass PickleDataSource(object):\n    class BandDataSource(object):\n        def __init__(self, da):\n            self._da = da\n            self.nodata = da.nodata\n\n        @property\n        def crs(self):\n            return self._da.crs\n\n        @property\n        def transform(self):\n            return self._da.affine\n\n        @property\n        def dtype(self):\n            return self._da.dtype\n\n        @property\n        def shape(self):\n            return self._da.shape\n\n        def read(self, window=None, out_shape=None):\n            if window is None:\n                data = self._da.values\n            else:\n                rows, cols = [slice(*w) for w in window]\n                data = self._da.values[rows, cols]\n\n            if out_shape is None or out_shape == data.shape:\n                return data\n\n            raise NotImplementedError('Native reading not supported for this data source')\n\n    def __init__(self, band):\n        self._band = band\n        uri = band.uri\n        self._filename, protocol = uri_split(uri)\n\n        if protocol not in [PROTOCOL, 'pickle']:\n            raise ValueError('Expected file:// or pickle:// url')\n\n    @contextmanager\n    def open(self):\n        with open(self._filename, 'rb') as f:\n            ds = pickle.load(f)\n\n        yield PickleDataSource.BandDataSource(ds[self._band.name].isel(time=0))\n\n\nclass PickleReaderDriver(object):\n    def __init__(self):\n        self.name = 'PickleReader'\n        self.protocols = [PROTOCOL, 'pickle']\n        self.formats = [FORMAT]\n\n    def supports(self, protocol, fmt):\n        return (protocol in self.protocols and\n                fmt in self.formats)\n\n    def new_datasource(self, band):\n        return PickleDataSource(band)\n\n\ndef rdr_driver_init():\n    return PickleReaderDriver()\n\n\nclass PickleWriterDriver(object):\n    def __init__(self):\n        pass\n\n    @property\n    def aliases(self):\n        return ['pickles']\n\n    @property\n    def format(self):\n        return FORMAT\n\n    @property\n    def uri_scheme(self):\n        return PROTOCOL\n\n    def write_dataset_to_storage(self, dataset, filename,\n                                 global_attributes=None,\n                                 variable_params=None,\n                                 storage_config=None,\n                                 **kwargs):\n        with open(filename, 'wb') as f:\n            pickle.dump(dataset, f)\n        return {}\n\n\ndef writer_driver_init():\n    return PickleWriterDriver()\n", "path": "examples/io_plugin/dcio_example/pickles.py"}]}