Repository: corteva/geocube

Issue:
DEP: odc-geo
Migrate to https://github.com/opendatacube/odc-geo from opendatacube when it is released.

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/corteva/geocube/pull/95?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva) Report
> Merging [#95](https://codecov.io/gh/corteva/geocube/pull/95?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva) (21eb2f2) into [master](https://codecov.io/gh/corteva/geocube/commit/a7cdbe5993164bb02f6d3dd2c4dc69791cd0b71d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva) (a7cdbe5) will **increase** coverage by `2.99%`.
> The diff coverage is `88.23%`.

> :exclamation: Current head 21eb2f2 differs from pull request most recent head 4723454. Consider uploading reports for the commit 4723454 to get more accurate results

```diff
@@            Coverage Diff             @@
##           master      #95      +/-   ##
==========================================
+ Coverage   94.11%   97.11%   +2.99%     
==========================================
  Files          14       14              
  Lines         425      416       -9     
==========================================
+ Hits          400      404       +4     
+ Misses         25       12      -13     
```


| [Impacted Files](https://codecov.io/gh/corteva/geocube/pull/95?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva) | Coverage Δ | |
|---|---|---|
| [geocube/\_show\_versions.py](https://codecov.io/gh/corteva/geocube/pull/95/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva#diff-Z2VvY3ViZS9fc2hvd192ZXJzaW9ucy5weQ==) | `95.12% <ø> (+7.31%)` | :arrow_up: |
| [geocube/rasterize.py](https://codecov.io/gh/corteva/geocube/pull/95/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva#diff-Z2VvY3ViZS9yYXN0ZXJpemUucHk=) | `97.72% <ø> (ø)` | |
| [geocube/geo\_utils/geobox.py](https://codecov.io/gh/corteva/geocube/pull/95/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva#diff-Z2VvY3ViZS9nZW9fdXRpbHMvZ2VvYm94LnB5) | `91.42% <88.23%> (+11.68%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/corteva/geocube/pull/95?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/corteva/geocube/pull/95?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva). Last update [a7cdbe5...4723454](https://codecov.io/gh/corteva/geocube/pull/95?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corteva).


Patch:
diff --git a/.github/workflows/build_docs.yaml b/.github/workflows/build_docs.yaml
index a10e70d..7f7d9a5 100644
--- a/.github/workflows/build_docs.yaml
+++ b/.github/workflows/build_docs.yaml
@@ -27,7 +27,7 @@ jobs:
         run: |
           conda config --prepend channels conda-forge
           conda config --set channel_priority strict
-          conda create -n docs python=3.8 datacube geopandas rasterio scipy rioxarray xarray pandoc
+          conda create -n docs python=3.8 odc-geo geopandas rasterio scipy rioxarray xarray pandoc
           source activate docs
           python -m pip install -e .[doc]
           sphinx-build -b html docs/ docs/_build/
diff --git a/appveyor.yml b/appveyor.yml
index 9d2a038..4f6a155 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -17,7 +17,7 @@ install:
 #-----------------------------------------------------------------------------
 # Create conda environment for geocube
 #-----------------------------------------------------------------------------
-  - conda create -n test python=%PYTHON_VERSION% datacube geopandas rioxarray rasterio scipy xarray
+  - conda create -n test python=%PYTHON_VERSION% odc-geo geopandas rioxarray rasterio scipy xarray
   - activate test
 
 #-------------------------------------------------------------------------------
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
index 57fedb2..585d025 100644
--- a/docs/getting_started.rst
+++ b/docs/getting_started.rst
@@ -11,7 +11,7 @@ and is powered by `GDAL <https://github.com/osgeo/gdal>`__ using:
 
 - `rasterio <https://github.com/mapbox/rasterio>`__
 - `fiona <https://github.com/toblerity/fiona>`__
-- `datacube <https://github.com/opendatacube/datacube-core>`__
+- `odc-geo <https://github.com/opendatacube/odc-geo>`__
 
 
 When getting started, the API documentation to start reading would be :func:`geocube.api.core.make_geocube`.
diff --git a/environment.yml b/environment.yml
index 87262d3..8840211 100644
--- a/environment.yml
+++ b/environment.yml
@@ -8,7 +8,6 @@ channels:
 - defaults
 dependencies:
 - python=3.8
-- datacube
 - geopandas
 - rasterio
 - scipy
diff --git a/geocube/_show_versions.py b/geocube/_show_versions.py
index 108204a..b3fd240 100644
--- a/geocube/_show_versions.py
+++ b/geocube/_show_versions.py
@@ -57,8 +57,8 @@ def _get_deps_info():
     deps = [
         "appdirs",
         "click",
-        "datacube",
         "geopandas",
+        "odc_geo",
         "rioxarray",
         "pyproj",
         "xarray",
diff --git a/geocube/geo_utils/geobox.py b/geocube/geo_utils/geobox.py
index a4d6738..cdc3dd0 100644
--- a/geocube/geo_utils/geobox.py
+++ b/geocube/geo_utils/geobox.py
@@ -7,25 +7,15 @@ import os
 
 import geopandas
 import rioxarray  # noqa: F401 pylint: disable=unused-import
-from datacube.utils import geometry
-from packaging import version
+from odc.geo import resyx_, wh_
+from odc.geo.crs import CRS
+from odc.geo.geobox import GeoBox
+from odc.geo.geom import Geometry
 from shapely.geometry import box, mapping
 
 from geocube.exceptions import VectorDataError
 from geocube.logger import get_logger
 
-try:
-    from rioxarray.crs import crs_to_wkt
-except ImportError:
-    # rioxarray 0.3+
-    from rioxarray.crs import crs_from_user_input
-
-    def crs_to_wkt(input_crs):
-        """
-        Convert CRS input to WKT format
-        """
-        return crs_from_user_input(input_crs).to_wkt()
-
 
 def geobox_from_rio(xds):
     """This function retrieves the geobox using rioxarray extension.
@@ -37,7 +27,7 @@ def geobox_from_rio(xds):
 
     Returns
     -------
-    :obj:`datacube.utils.geometry.GeoBox`
+    :obj:`odc.geo.geobox.GeoBox`
 
     """
     height, width = xds.rio.shape
@@ -45,11 +35,10 @@ def geobox_from_rio(xds):
         transform = xds.rio.transform()
     except AttributeError:
         transform = xds[xds.rio.vars[0]].rio.transform()
-    return geometry.GeoBox(
-        width=width,
-        height=height,
+    return GeoBox(
+        shape=wh_(width, height),
         affine=transform,
-        crs=geometry.CRS(crs_to_wkt(xds.rio.crs)),
+        crs=CRS(xds.rio.crs),
     )
 
 
@@ -91,38 +80,6 @@ def load_vector_data(vector_data):
     return vector_data
 
 
-def _datacube_to_geopandas_crs(dc_crs):
-    """
-    This gets the best representation of the datacube CRS object
-    to be used by geopandas
-
-    Parameters
-    ----------
-    dc_crs: :class:`datacube.utils.geometry.CRS`
-        Input datacube CRS
-
-    Returns
-    -------
-    str:
-        Representation of CRS for geopandas.
-    """
-    # pylint: disable=protected-access
-    if version.parse(geopandas.__version__) >= version.parse("0.6.0"):
-        # this version of geopandas uses always_xy=True so WKT version is safe
-        try:
-            geo_crs = dc_crs.to_wkt()
-        except AttributeError:
-            geo_crs = dc_crs.wkt
-    else:
-        try:
-            # datacube version < 0.8 uses osgeo.osr SpatialReference
-            geo_crs = dc_crs._crs.ExportToProj4()
-        except AttributeError:
-            # datacube version 0.8+ uses pyproj.CRS
-            geo_crs = dc_crs._crs.to_proj4()
-    return geo_crs
-
-
 class GeoBoxMaker:
     """
     This class is meant for delayed GeoBox making. Stores partial information until
@@ -153,7 +110,9 @@ class GeoBoxMaker:
 
         """
         self.output_crs = output_crs
-        self.resolution = resolution
+        self.resolution = (
+            resolution if not isinstance(resolution, tuple) else resyx_(*resolution)
+        )
         self.align = align
         self.geom = geom
         self.like = like
@@ -169,7 +128,7 @@ class GeoBoxMaker:
 
         Returns
         -------
-        :obj:`datacube.utils.geometry.GeoBox`
+        :obj:`odc.geo.geobox.GeoBox`
             The geobox for the grid to be generated from the vector data.
 
         """
@@ -193,36 +152,25 @@ class GeoBoxMaker:
             raise RuntimeError("Must specify 'resolution' if 'like' not specified.")
 
         if self.output_crs:
-            crs = geometry.CRS(crs_to_wkt(self.output_crs))
+            crs = CRS(self.output_crs)
         else:
-            crs = geometry.CRS(crs_to_wkt(vector_data.crs))
+            crs = CRS(vector_data.crs)
 
         if self.geom is None and self.output_crs:
-            geopoly = geometry.Geometry(
-                mapping(
-                    box(
-                        *vector_data.to_crs(
-                            _datacube_to_geopandas_crs(crs)
-                        ).total_bounds
-                    )
-                ),
+            geopoly = Geometry(
+                mapping(box(*vector_data.to_crs(crs).total_bounds)),
                 crs=crs,
             )
         elif self.geom is None:
-            geopoly = geometry.Geometry(
-                mapping(box(*vector_data.total_bounds)), crs=crs
-            )
+            geopoly = Geometry(mapping(box(*vector_data.total_bounds)), crs=crs)
 
         else:
             geom_json = json.loads(self.geom)
-            geom_crs = geometry.CRS(
+            geom_crs = CRS(
                 geom_json["crs"]["properties"]["name"]
                 if "crs" in geom_json
                 else "epsg:4326"
             )
 
-            geopoly = geometry.Geometry(geom_json, crs=geom_crs)
-
-        return geometry.GeoBox.from_geopolygon(
-            geopoly, self.resolution, crs, self.align
-        )
+            geopoly = Geometry(geom_json, crs=geom_crs)
+        return GeoBox.from_geopolygon(geopoly, self.resolution, crs, self.align)
diff --git a/geocube/rasterize.py b/geocube/rasterize.py
index 89a9917..7772b29 100644
--- a/geocube/rasterize.py
+++ b/geocube/rasterize.py
@@ -72,7 +72,7 @@ def rasterize_image(
         A geometry array of points.
     data_values: list
         Data values associated with the list of geojson shapes
-    geobox: :obj:`datacube.utils.geometry.GeoBox`
+    geobox: :obj:`odc.geo.geobox.GeoBox`
         Transform of the resulting image.
     fill: float
         The value to fill in the grid with for nodata.
diff --git a/setup.py b/setup.py
index fa8fd93..0ef7ae9 100644
--- a/setup.py
+++ b/setup.py
@@ -12,9 +12,8 @@ with open("README.rst") as readme_file:
 requirements = [
     "appdirs",
     "Click>=6.0",
-    "datacube",
     "geopandas>=0.7",
-    "packaging",
+    "odc_geo",
     "rasterio",
     "rioxarray>=0.4",
     "scipy",
@@ -22,7 +21,7 @@ requirements = [
     "pyproj>=2",
 ]
 
-test_requirements = ["pytest>=3.6", "pytest-cov"]
+test_requirements = ["pytest>=3.6", "pytest-cov", "packaging", "netcdf4"]
 doc_requirements = ["sphinx-click", "nbsphinx", "sphinx_rtd_theme"]
 
 extras_require = {


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index d664e35..03b0858 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -40,7 +40,7 @@ jobs:
         run: |
           conda config --prepend channels conda-forge
           conda config --set channel_priority strict
-          conda create -n test python=${{ matrix.python-version }} datacube geopandas rasterio scipy rioxarray xarray pandoc
+          conda create -n test python=${{ matrix.python-version }} odc-geo geopandas rasterio scipy rioxarray xarray netcdf4 pandoc
           source activate test
           python -m pip install -e .[all]
 
diff --git a/test/unit/test_show_versions.py b/test/unit/test_show_versions.py
index 061abaf..c26c6d0 100644
--- a/test/unit/test_show_versions.py
+++ b/test/unit/test_show_versions.py
@@ -25,7 +25,7 @@ def test_get_deps_info():
     assert "geopandas" in deps_info
     assert "pyproj" in deps_info
     assert "xarray" in deps_info
-    assert "datacube" in deps_info
+    assert "odc_geo" in deps_info
     assert "click" in deps_info
     assert "appdirs" in deps_info