Repository: opendatacube/datacube-core

Issue:
`dc.load` should not need product when datasets are supplied via `datasets=` 
One should be able to do the following:

```python
dss = dc.find_datasets(product='some-product', limit=1)
xx = dc.load(datasets=dss)
```

Yet this will currently abort with an exception because `dc.load` expects to find `product=` argument. Product is used for two things:

1. Query (this is not being done when datasets are already supplied)
2. To check if product has GridSpec (used of output_crs, resolution, alignment)

Since user already supplied datasets we can get product from the first dataset, and assume that the rest have the same.





Discussion:

Resolving patch:
diff --git a/datacube/api/core.py b/datacube/api/core.py
--- a/datacube/api/core.py
+++ b/datacube/api/core.py
@@ -1,4 +1,5 @@
 import uuid
+import collections
 from itertools import groupby
 from typing import Union, Optional, Dict, Tuple
 import datetime
@@ -292,18 +293,27 @@ def load(self, product=None, measurements=None, output_crs=None, resolution=None
         if use_threads is not None:
             legacy_args['use_threads'] = use_threads
 
-        observations = datasets or self.find_datasets(product=product, like=like, ensure_location=True, **query)
-        if not observations:
+        if product is None and datasets is None:
+            raise ValueError("Must specify a product or supply datasets")
+
+        if datasets is None:
+            datasets = self.find_datasets(product=product, like=like, ensure_location=True, **query)
+        elif isinstance(datasets, collections.Iterator):
+            datasets = list(datasets)
+
+        if len(datasets) == 0:
             return xarray.Dataset()
 
+        ds, *_ = datasets
+        datacube_product = ds.type
+
         geobox = output_geobox(like=like, output_crs=output_crs, resolution=resolution, align=align,
-                               grid_spec=self.index.products.get_by_name(product).grid_spec,
-                               datasets=observations, **query)
+                               grid_spec=datacube_product.grid_spec,
+                               datasets=datasets, **query)
 
         group_by = query_group_by(**query)
-        grouped = self.group_datasets(observations, group_by)
+        grouped = self.group_datasets(datasets, group_by)
 
-        datacube_product = self.index.products.get_by_name(product)
         measurement_dicts = datacube_product.lookup_measurements(measurements)
 
         result = self.load_data(grouped, geobox,


Test patch:
diff --git a/integration_tests/test_end_to_end.py b/integration_tests/test_end_to_end.py
--- a/integration_tests/test_end_to_end.py
+++ b/integration_tests/test_end_to_end.py
@@ -105,6 +105,7 @@ def test_end_to_end(clirunner, index, testdata_dir, ingest_configs, datacube_env
 
     check_open_with_dc(index)
     check_open_with_grid_workflow(index)
+    check_load_via_dss(index)
 
     if datacube_env_name == "s3aio_env":
         check_legacy_open(index)
@@ -241,6 +242,31 @@ def check_open_with_grid_workflow(index):
     assert all(m in dataset_cell for m in ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'])
 
 
+def check_load_via_dss(index):
+    from datacube.api.core import Datacube
+    dc = Datacube(index=index)
+
+    dss = dc.find_datasets(product='ls5_nbar_albers')
+    assert len(dss) > 0
+
+    xx1 = dc.load(product='ls5_nbar_albers', measurements=['blue'])
+    xx2 = dc.load(datasets=dss, measurements=['blue'])
+    assert xx1.blue.shape
+    assert (xx1.blue != -999).any()
+    assert (xx1.blue == xx2.blue).all()
+
+    xx2 = dc.load(datasets=iter(dss), measurements=['blue'])
+    assert xx1.blue.shape
+    assert (xx1.blue != -999).any()
+    assert (xx1.blue == xx2.blue).all()
+
+    with pytest.raises(ValueError):
+        dc.load(measurements=['blue'])
+
+    with pytest.raises(DeprecationWarning):
+        dc.load(product='ls5_nbar_albers', stack=True)
+
+
 def check_legacy_open(index):
     from datacube.api.core import Datacube
     dc = Datacube(index=index)