Repository: opendatacube/datacube-core

Issue:
Missing required dependencies in default install
### Expected behaviour

Default datacube-core install also installs required dependency packages.

### Actual behaviour

Default install is missing packages needed for core functionality.


### Steps to reproduce the behaviour

```
pip install datacube

datacube --help
```

Result: `ModuleNotFoundError: No module named 'botocore'`

### Environment information

Fresh Python 3.6.8 virtualenv with pip 21.2.3 

datacube==1.8.4

### Issue

76eb3508096ed94e50c341d1614ed9e6e022e39f - Added AWS packages as a dependency for the default install.

Current workaround is to install datacube-core with 's3' extras: `pip install datacube[s3]`


Discussion:
There is also this:

https://github.com/opendatacube/datacube-core/blob/e5471533ecb4541009c0cb512ea88fedc7685330/datacube/utils/dask.py#L17-L19

I guess we need to decide whether to keep boto dependency optional, in which case these imports need to be moved into function or guarded with `try:` blocks. Or whether to make botocore/boto3 a non-optional dependency.

@SpacemanPaul one way to fix IAM code is to move `obtain_new_iam_auth_token` out of `utils.aws.` and into db code.

Resolving patch:
diff --git a/datacube/drivers/postgres/_connections.py b/datacube/drivers/postgres/_connections.py
--- a/datacube/drivers/postgres/_connections.py
+++ b/datacube/drivers/postgres/_connections.py
@@ -27,7 +27,6 @@
 import datacube
 from datacube.index.exceptions import IndexSetupError
 from datacube.utils import jsonify_document
-from datacube.utils.aws import obtain_new_iam_auth_token
 
 from . import _api
 from . import _core
@@ -136,6 +135,7 @@ def _create_engine(url, application_name=None, iam_rds_auth=False, iam_rds_timeo
         )
 
         if iam_rds_auth:
+            from datacube.utils.aws import obtain_new_iam_auth_token
             handle_dynamic_token_authentication(engine, obtain_new_iam_auth_token, timeout=iam_rds_timeout, url=url)
 
         return engine
diff --git a/datacube/utils/dask.py b/datacube/utils/dask.py
--- a/datacube/utils/dask.py
+++ b/datacube/utils/dask.py
@@ -14,9 +14,6 @@
 import threading
 import logging
 import os
-from botocore.credentials import ReadOnlyCredentials
-from botocore.exceptions import BotoCoreError
-from .aws import s3_dump, s3_client
 
 
 __all__ = (
@@ -260,11 +257,14 @@ def _save_blob_to_file(data: Union[bytes, str],
 def _save_blob_to_s3(data: Union[bytes, str],
                      url: str,
                      profile: Optional[str] = None,
-                     creds: Optional[ReadOnlyCredentials] = None,
+                     creds = None,
                      region_name: Optional[str] = None,
                      with_deps=None,
                      **kw) -> Tuple[str, bool]:
     from botocore.errorfactory import ClientError
+    from botocore.credentials import ReadOnlyCredentials
+    from botocore.exceptions import BotoCoreError
+    from .aws import s3_dump, s3_client
 
     try:
         s3 = s3_client(profile=profile,
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -24,12 +24,10 @@
 
 extras_require = {
     'performance': ['ciso8601', 'bottleneck'],
-    'interactive': ['matplotlib', 'fiona'],
     'distributed': ['distributed', 'dask[distributed]'],
     'doc': doc_require,
-    'replicas': ['paramiko', 'sshtunnel', 'tqdm'],
-    'celery': ['celery>=4,<5', 'redis'],
-    's3': ['boto3'],
+    'celery': ['celery>=4,<5', 'redis', 'kombu'],
+    's3': ['boto3', 'botocore'],
     'test': tests_require,
     'cf': ['compliance-checker>=4.0.0'],
 }
@@ -37,7 +35,6 @@
 extras_require['dev'] = sorted(set(sum([extras_require[k] for k in [
     'test',
     'doc',
-    'replicas',
     'performance',
     's3',
     'distributed',
@@ -101,6 +98,7 @@
         'numpy',
         'psycopg2',
         'lark-parser>=0.6.7',
+        'pandas',
         'python-dateutil',
         'pyyaml',
         'rasterio>=1.0.2',  # Multi-band re-project fixed in that version


Test patch:
diff --git a/integration_tests/test_3d.py b/integration_tests/test_3d.py
--- a/integration_tests/test_3d.py
+++ b/integration_tests/test_3d.py
@@ -23,6 +23,7 @@
 from datacube.api.core import Datacube
 from datacube.utils import geometry
 
+pytest.importorskip("dcio_example.xarray_3d")  # skip this test if 3d driver is not installed
 _LOG = logging.getLogger(__name__)
 _LOG.setLevel(logging.DEBUG)