We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
python 3.8/3.9 doesn't support entry_points with either group or select
As title.

https://github.com/opendatacube/datacube-core/blob/5fed4a688c85c198c5d25f2570b0c92ef91dfc04/datacube/drivers/driver_cache.py#L50

Ref: https://docs.python.org/3/library/importlib.metadata.html
>Compatibility Note: The “selectable” entry points were introduced in importlib_metadata 3.6 and Python 3.10. Prior to those changes, entry_points accepted no parameters and always returned a dictionary of entry points, keyed by group. For compatibility, if no parameters are passed to entry_points, a SelectableGroups object is returned, implementing that dict interface. In the future, calling entry_points with no parameters will return an EntryPoints object. Users should rely on the selection interface to retrieve entry points by group.

--- 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/drivers/driver_cache.py`
Content:
```
1 # This file is part of the Open Data Cube, see https://opendatacube.org for more information
2 #
3 # Copyright (c) 2015-2023 ODC Contributors
4 # SPDX-License-Identifier: Apache-2.0
5 import logging
6 from typing import Dict, Any, Tuple, Iterable
7 
8 _LOG = logging.getLogger(__name__)
9 
10 
11 def load_drivers(group: str) -> Dict[str, Any]:
12     """
13     Load available drivers for a given group name.
14 
15     Gracefully handles:
16 
17      - Driver module not able to be imported
18      - Driver init function throwing an exception or returning None
19 
20      By having driver entry_points pointing to a function, we defer loading the driver
21      module or running any code until required.
22 
23     :param group: Name of the entry point group e.g. "datacube.plugins.io.read"
24 
25     :returns: Dictionary String -> Driver Object
26     """
27 
28     def safe_load(ep):
29         # pylint: disable=broad-except,bare-except
30         try:
31             driver_init = ep.load()
32         except Exception as e:
33             _LOG.warning('Failed to resolve driver %s::%s', group, ep.name)
34             _LOG.warning('Error was: %s', repr(e))
35             return None
36 
37         try:
38             driver = driver_init()
39         except Exception:
40             _LOG.warning('Exception during driver init, driver name: %s::%s', group, ep.name)
41             return None
42 
43         if driver is None:
44             _LOG.warning('Driver init returned None, driver name: %s::%s', group, ep.name)
45 
46         return driver
47 
48     def resolve_all(group: str) -> Iterable[Tuple[str, Any]]:
49         from importlib.metadata import entry_points
50         for ep in entry_points(group=group):
51             driver = safe_load(ep)
52             if driver is not None:
53                 yield (ep.name, driver)
54 
55     return dict((name, driver) for name, driver in resolve_all(group))
56
```

Path: `setup.py`
Content:
```
1 #!/usr/bin/env python
2 
3 from setuptools import setup, find_packages
4 
5 tests_require = [
6     'hypothesis',
7     'pycodestyle',
8     'pylint',
9     'pytest',
10     'pytest-cov',
11     'pytest-timeout',
12     'pytest-httpserver',
13     'moto',
14 ]
15 doc_require = [
16     'Sphinx',
17     'sphinx_autodoc_typehints',  # Propagate mypy info into docs
18     'sphinx-click',
19     'recommonmark',
20     'autodocsumm',
21     'beautifulsoup4',
22     'nbsphinx',
23     'pydata-sphinx-theme==0.9.0',
24 ]
25 
26 extras_require = {
27     'performance': ['ciso8601', 'bottleneck'],
28     'distributed': ['distributed', 'dask[distributed]'],
29     'doc': doc_require,
30     's3': ['boto3', 'botocore'],
31     'test': tests_require,
32     'cf': ['compliance-checker>=4.0.0'],
33 }
34 
35 extras_require['dev'] = sorted(set(sum([extras_require[k] for k in [
36     'test',
37     'doc',
38     'performance',
39     's3',
40     'distributed',
41 ]], [])))
42 
43 # An 'all' option, following ipython naming conventions.
44 extras_require['all'] = sorted(set(sum(extras_require.values(), [])))
45 
46 extra_plugins = dict(read=[], write=[], index=[])
47 
48 setup(
49     name='datacube',
50     python_requires='>=3.8.0',
51 
52     url='https://github.com/opendatacube/datacube-core',
53     author='Open Data Cube',
54     maintainer='Open Data Cube',
55     maintainer_email='',
56     description='An analysis environment for satellite and other earth observation data',
57     long_description=open('README.rst').read(),
58     long_description_content_type='text/x-rst',
59     license='Apache License 2.0',
60     classifiers=[
61         "Development Status :: 4 - Beta",
62         "Intended Audience :: Developers",
63         "Intended Audience :: Science/Research",
64         "License :: OSI Approved :: Apache Software License",
65         "Natural Language :: English",
66         "Operating System :: MacOS :: MacOS X",
67         "Operating System :: POSIX",
68         "Operating System :: POSIX :: BSD",
69         "Operating System :: POSIX :: Linux",
70         "Operating System :: Microsoft :: Windows",
71         "Programming Language :: Python",
72         "Programming Language :: Python :: 3",
73         "Programming Language :: Python :: 3.8",
74         "Programming Language :: Python :: 3.9",
75         "Programming Language :: Python :: 3.10",
76         "Topic :: Scientific/Engineering :: GIS",
77         "Topic :: Scientific/Engineering :: Information Analysis",
78     ],
79 
80     packages=find_packages(
81         exclude=('tests', 'tests.*',
82                  'integration_tests', 'integration_tests.*')
83     ),
84     package_data={
85         '': ['*.yaml', '*/*.yaml'],
86         'datacube': ['py.typed'],
87     },
88     scripts=[],
89     install_requires=[
90         'affine',
91         'attrs>=18.1',
92         'pyproj>=2.5',
93         'shapely>=2.0',
94         'cachetools',
95         'click>=5.0',
96         'cloudpickle>=0.4',
97         'dask[array]',
98         'distributed',
99         'jsonschema',
100         'netcdf4',
101         'numpy',
102         'psycopg2',
103         'lark',
104         'pandas',
105         'python-dateutil',
106         'pyyaml',
107         'rasterio>=1.3.2',  # Warping broken in 1.3.0 and 1.3.1
108         'ruamel.yaml',
109         'sqlalchemy>=1.4,<2.0',  # GeoAlchemy2 requires >=1.4.  SqlAlchemy2 *may* work but has not been tested yet.
110         'GeoAlchemy2',
111         'toolz',
112         'xarray>=0.9',  # >0.9 fixes most problems with `crs` attributes being lost
113         'packaging',
114         'deprecat',
115     ],
116     extras_require=extras_require,
117     tests_require=tests_require,
118 
119     entry_points={
120         'console_scripts': [
121             'datacube = datacube.scripts.cli_app:cli',
122             'datacube-search = datacube.scripts.search_tool:cli',
123             'datacube-worker = datacube.execution.worker:main',
124         ],
125         'datacube.plugins.io.read': [
126             'netcdf = datacube.drivers.netcdf.driver:reader_driver_init',
127             *extra_plugins['read'],
128         ],
129         'datacube.plugins.io.write': [
130             'netcdf = datacube.drivers.netcdf.driver:writer_driver_init',
131             *extra_plugins['write'],
132         ],
133         'datacube.plugins.index': [
134             'default = datacube.index.postgres.index:index_driver_init',
135             'null = datacube.index.null.index:index_driver_init',
136             'memory = datacube.index.memory.index:index_driver_init',
137             'postgis = datacube.index.postgis.index:index_driver_init',
138             *extra_plugins['index'],
139         ],
140     },
141 )
142
```

Path: `docs/click_utils.py`
Content:
```
1 # This file is part of the Open Data Cube, see https://opendatacube.org for more information
2 #
3 # Copyright (c) 2015-2023 ODC Contributors
4 # SPDX-License-Identifier: Apache-2.0
5 from importlib.metadata import entry_points
6 from docutils.nodes import literal_block, section, title, make_id
7 from sphinx.domains import Domain
8 from docutils.parsers.rst import Directive
9 import importlib
10 
11 import click
12 
13 
14 class ClickHelpDirective(Directive):
15     has_content = True
16     required_arguments = 1
17 
18     def run(self):
19         root_cmd = self.arguments[0]
20 
21         env = self.state.document.settings.env
22 
23         group = find_script_callable_from_env(root_cmd, env)
24 
25         return [generate_help_text(group, [root_cmd])]
26 
27 
28 def find_script_callable_from_env(name, env):
29     commands = env.config.click_utils_commands
30 
31     module, function_name = commands[name].split(':')
32     module = importlib.import_module(module)
33     return getattr(module, function_name)
34 
35 
36 def find_script_callable(name):
37     return list(entry_points(
38         group='console_scripts', name=name))[0].load()
39 
40 
41 def generate_help_text(command, prefix):
42     ctx = click.Context(command)
43     help_opts = command.get_help_option(ctx).opts
44     full_cmd = ' '.join(prefix)
45     block = section(None,
46                     title(None, full_cmd),
47                     ids=[make_id(full_cmd)], names=[full_cmd])
48     if help_opts:
49         h = "$ {} {}\n".format(full_cmd, help_opts[0]) + command.get_help(ctx)
50         block.append(literal_block(None, h, language='console'))
51 
52     if isinstance(command, click.core.MultiCommand):
53         for c in command.list_commands(ctx):
54             c = command.resolve_command(ctx, [c])[1]
55             block.append(generate_help_text(c, prefix+[c.name]))
56 
57     return block
58 
59 
60 def make_block(command, opt, content):
61     h = "$ {} {}\n".format(command, opt) + content
62     return section(None,
63                    title(None, command),
64                    literal_block(None, h, language='console'),
65                    ids=[make_id(command)], names=[command])
66 
67 
68 class DatacubeDomain(Domain):
69     name = 'datacube'
70     label = 'Data Cube'
71     directives = {
72         'click-help': ClickHelpDirective,
73     }
74 
75 
76 def setup(app):
77     app.add_config_value('click_utils_commands', {}, 'html')
78 
79     app.add_domain(DatacubeDomain)
80     return {
81         'parallel_read_safe': False,
82         'parallel_write_safe': False,
83     }
84
```
--- 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/drivers/driver_cache.py b/datacube/drivers/driver_cache.py
--- a/datacube/drivers/driver_cache.py
+++ b/datacube/drivers/driver_cache.py
@@ -46,7 +46,10 @@
         return driver
 
     def resolve_all(group: str) -> Iterable[Tuple[str, Any]]:
-        from importlib.metadata import entry_points
+        try:
+            from importlib_metadata import entry_points
+        except ModuleNotFoundError:
+            from importlib.metadata import entry_points
         for ep in entry_points(group=group):
             driver = safe_load(ep)
             if driver is not None:
diff --git a/docs/click_utils.py b/docs/click_utils.py
--- a/docs/click_utils.py
+++ b/docs/click_utils.py
@@ -2,7 +2,6 @@
 #
 # Copyright (c) 2015-2023 ODC Contributors
 # SPDX-License-Identifier: Apache-2.0
-from importlib.metadata import entry_points
 from docutils.nodes import literal_block, section, title, make_id
 from sphinx.domains import Domain
 from docutils.parsers.rst import Directive
@@ -34,6 +33,10 @@
 
 
 def find_script_callable(name):
+    try:
+        from importlib_metadata import entry_points
+    except ModuleNotFoundError:
+        from importlib.metadata import entry_points
     return list(entry_points(
         group='console_scripts', name=name))[0].load()
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -112,6 +112,7 @@
         'xarray>=0.9',  # >0.9 fixes most problems with `crs` attributes being lost
         'packaging',
         'deprecat',
+        'importlib_metadata>3.5;python_version<"3.10"',
     ],
     extras_require=extras_require,
     tests_require=tests_require,

{"golden_diff": "diff --git a/datacube/drivers/driver_cache.py b/datacube/drivers/driver_cache.py\n--- a/datacube/drivers/driver_cache.py\n+++ b/datacube/drivers/driver_cache.py\n@@ -46,7 +46,10 @@\n         return driver\n \n     def resolve_all(group: str) -> Iterable[Tuple[str, Any]]:\n-        from importlib.metadata import entry_points\n+        try:\n+            from importlib_metadata import entry_points\n+        except ModuleNotFoundError:\n+            from importlib.metadata import entry_points\n         for ep in entry_points(group=group):\n             driver = safe_load(ep)\n             if driver is not None:\ndiff --git a/docs/click_utils.py b/docs/click_utils.py\n--- a/docs/click_utils.py\n+++ b/docs/click_utils.py\n@@ -2,7 +2,6 @@\n #\n # Copyright (c) 2015-2023 ODC Contributors\n # SPDX-License-Identifier: Apache-2.0\n-from importlib.metadata import entry_points\n from docutils.nodes import literal_block, section, title, make_id\n from sphinx.domains import Domain\n from docutils.parsers.rst import Directive\n@@ -34,6 +33,10 @@\n \n \n def find_script_callable(name):\n+    try:\n+        from importlib_metadata import entry_points\n+    except ModuleNotFoundError:\n+        from importlib.metadata import entry_points\n     return list(entry_points(\n         group='console_scripts', name=name))[0].load()\n \ndiff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -112,6 +112,7 @@\n         'xarray>=0.9',  # >0.9 fixes most problems with `crs` attributes being lost\n         'packaging',\n         'deprecat',\n+        'importlib_metadata>3.5;python_version<\"3.10\"',\n     ],\n     extras_require=extras_require,\n     tests_require=tests_require,\n", "issue": "python 3.8/3.9 doesn't support entry_points with either group or select\nAs title.\r\n\r\nhttps://github.com/opendatacube/datacube-core/blob/5fed4a688c85c198c5d25f2570b0c92ef91dfc04/datacube/drivers/driver_cache.py#L50\r\n\r\nRef: https://docs.python.org/3/library/importlib.metadata.html\r\n>Compatibility Note: The \u201cselectable\u201d entry points were introduced in importlib_metadata 3.6 and Python 3.10. Prior to those changes, entry_points accepted no parameters and always returned a dictionary of entry points, keyed by group. For compatibility, if no parameters are passed to entry_points, a SelectableGroups object is returned, implementing that dict interface. In the future, calling entry_points with no parameters will return an EntryPoints object. Users should rely on the selection interface to retrieve entry points by group.\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-2023 ODC Contributors\n# SPDX-License-Identifier: Apache-2.0\nimport logging\nfrom typing import Dict, Any, Tuple, Iterable\n\n_LOG = logging.getLogger(__name__)\n\n\ndef load_drivers(group: str) -> Dict[str, Any]:\n    \"\"\"\n    Load available drivers for a given group name.\n\n    Gracefully handles:\n\n     - Driver module not able to be imported\n     - Driver init function throwing an exception or returning None\n\n     By having driver entry_points pointing to a function, we defer loading the driver\n     module or running any code until required.\n\n    :param group: Name of the entry point group e.g. \"datacube.plugins.io.read\"\n\n    :returns: Dictionary String -> Driver Object\n    \"\"\"\n\n    def safe_load(ep):\n        # pylint: disable=broad-except,bare-except\n        try:\n            driver_init = ep.load()\n        except Exception as e:\n            _LOG.warning('Failed to resolve driver %s::%s', group, ep.name)\n            _LOG.warning('Error was: %s', repr(e))\n            return None\n\n        try:\n            driver = driver_init()\n        except Exception:\n            _LOG.warning('Exception during driver init, driver name: %s::%s', group, ep.name)\n            return None\n\n        if driver is None:\n            _LOG.warning('Driver init returned None, driver name: %s::%s', group, ep.name)\n\n        return driver\n\n    def resolve_all(group: str) -> Iterable[Tuple[str, Any]]:\n        from importlib.metadata import entry_points\n        for ep in entry_points(group=group):\n            driver = safe_load(ep)\n            if driver is not None:\n                yield (ep.name, driver)\n\n    return dict((name, driver) for name, driver in resolve_all(group))\n", "path": "datacube/drivers/driver_cache.py"}, {"content": "#!/usr/bin/env python\n\nfrom setuptools import setup, find_packages\n\ntests_require = [\n    'hypothesis',\n    'pycodestyle',\n    'pylint',\n    'pytest',\n    'pytest-cov',\n    'pytest-timeout',\n    'pytest-httpserver',\n    'moto',\n]\ndoc_require = [\n    'Sphinx',\n    'sphinx_autodoc_typehints',  # Propagate mypy info into docs\n    'sphinx-click',\n    'recommonmark',\n    'autodocsumm',\n    'beautifulsoup4',\n    'nbsphinx',\n    'pydata-sphinx-theme==0.9.0',\n]\n\nextras_require = {\n    'performance': ['ciso8601', 'bottleneck'],\n    'distributed': ['distributed', 'dask[distributed]'],\n    'doc': doc_require,\n    's3': ['boto3', 'botocore'],\n    'test': tests_require,\n    'cf': ['compliance-checker>=4.0.0'],\n}\n\nextras_require['dev'] = sorted(set(sum([extras_require[k] for k in [\n    'test',\n    'doc',\n    'performance',\n    's3',\n    'distributed',\n]], [])))\n\n# An 'all' option, following ipython naming conventions.\nextras_require['all'] = sorted(set(sum(extras_require.values(), [])))\n\nextra_plugins = dict(read=[], write=[], index=[])\n\nsetup(\n    name='datacube',\n    python_requires='>=3.8.0',\n\n    url='https://github.com/opendatacube/datacube-core',\n    author='Open Data Cube',\n    maintainer='Open Data Cube',\n    maintainer_email='',\n    description='An analysis environment for satellite and other earth observation data',\n    long_description=open('README.rst').read(),\n    long_description_content_type='text/x-rst',\n    license='Apache License 2.0',\n    classifiers=[\n        \"Development Status :: 4 - Beta\",\n        \"Intended Audience :: Developers\",\n        \"Intended Audience :: Science/Research\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Natural Language :: English\",\n        \"Operating System :: MacOS :: MacOS X\",\n        \"Operating System :: POSIX\",\n        \"Operating System :: POSIX :: BSD\",\n        \"Operating System :: POSIX :: Linux\",\n        \"Operating System :: Microsoft :: Windows\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 3\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Programming Language :: Python :: 3.10\",\n        \"Topic :: Scientific/Engineering :: GIS\",\n        \"Topic :: Scientific/Engineering :: Information Analysis\",\n    ],\n\n    packages=find_packages(\n        exclude=('tests', 'tests.*',\n                 'integration_tests', 'integration_tests.*')\n    ),\n    package_data={\n        '': ['*.yaml', '*/*.yaml'],\n        'datacube': ['py.typed'],\n    },\n    scripts=[],\n    install_requires=[\n        'affine',\n        'attrs>=18.1',\n        'pyproj>=2.5',\n        'shapely>=2.0',\n        'cachetools',\n        'click>=5.0',\n        'cloudpickle>=0.4',\n        'dask[array]',\n        'distributed',\n        'jsonschema',\n        'netcdf4',\n        'numpy',\n        'psycopg2',\n        'lark',\n        'pandas',\n        'python-dateutil',\n        'pyyaml',\n        'rasterio>=1.3.2',  # Warping broken in 1.3.0 and 1.3.1\n        'ruamel.yaml',\n        'sqlalchemy>=1.4,<2.0',  # GeoAlchemy2 requires >=1.4.  SqlAlchemy2 *may* work but has not been tested yet.\n        'GeoAlchemy2',\n        'toolz',\n        'xarray>=0.9',  # >0.9 fixes most problems with `crs` attributes being lost\n        'packaging',\n        'deprecat',\n    ],\n    extras_require=extras_require,\n    tests_require=tests_require,\n\n    entry_points={\n        'console_scripts': [\n            'datacube = datacube.scripts.cli_app:cli',\n            'datacube-search = datacube.scripts.search_tool:cli',\n            'datacube-worker = datacube.execution.worker:main',\n        ],\n        'datacube.plugins.io.read': [\n            'netcdf = datacube.drivers.netcdf.driver:reader_driver_init',\n            *extra_plugins['read'],\n        ],\n        'datacube.plugins.io.write': [\n            'netcdf = datacube.drivers.netcdf.driver:writer_driver_init',\n            *extra_plugins['write'],\n        ],\n        'datacube.plugins.index': [\n            'default = datacube.index.postgres.index:index_driver_init',\n            'null = datacube.index.null.index:index_driver_init',\n            'memory = datacube.index.memory.index:index_driver_init',\n            'postgis = datacube.index.postgis.index:index_driver_init',\n            *extra_plugins['index'],\n        ],\n    },\n)\n", "path": "setup.py"}, {"content": "# This file is part of the Open Data Cube, see https://opendatacube.org for more information\n#\n# Copyright (c) 2015-2023 ODC Contributors\n# SPDX-License-Identifier: Apache-2.0\nfrom importlib.metadata import entry_points\nfrom docutils.nodes import literal_block, section, title, make_id\nfrom sphinx.domains import Domain\nfrom docutils.parsers.rst import Directive\nimport importlib\n\nimport click\n\n\nclass ClickHelpDirective(Directive):\n    has_content = True\n    required_arguments = 1\n\n    def run(self):\n        root_cmd = self.arguments[0]\n\n        env = self.state.document.settings.env\n\n        group = find_script_callable_from_env(root_cmd, env)\n\n        return [generate_help_text(group, [root_cmd])]\n\n\ndef find_script_callable_from_env(name, env):\n    commands = env.config.click_utils_commands\n\n    module, function_name = commands[name].split(':')\n    module = importlib.import_module(module)\n    return getattr(module, function_name)\n\n\ndef find_script_callable(name):\n    return list(entry_points(\n        group='console_scripts', name=name))[0].load()\n\n\ndef generate_help_text(command, prefix):\n    ctx = click.Context(command)\n    help_opts = command.get_help_option(ctx).opts\n    full_cmd = ' '.join(prefix)\n    block = section(None,\n                    title(None, full_cmd),\n                    ids=[make_id(full_cmd)], names=[full_cmd])\n    if help_opts:\n        h = \"$ {} {}\\n\".format(full_cmd, help_opts[0]) + command.get_help(ctx)\n        block.append(literal_block(None, h, language='console'))\n\n    if isinstance(command, click.core.MultiCommand):\n        for c in command.list_commands(ctx):\n            c = command.resolve_command(ctx, [c])[1]\n            block.append(generate_help_text(c, prefix+[c.name]))\n\n    return block\n\n\ndef make_block(command, opt, content):\n    h = \"$ {} {}\\n\".format(command, opt) + content\n    return section(None,\n                   title(None, command),\n                   literal_block(None, h, language='console'),\n                   ids=[make_id(command)], names=[command])\n\n\nclass DatacubeDomain(Domain):\n    name = 'datacube'\n    label = 'Data Cube'\n    directives = {\n        'click-help': ClickHelpDirective,\n    }\n\n\ndef setup(app):\n    app.add_config_value('click_utils_commands', {}, 'html')\n\n    app.add_domain(DatacubeDomain)\n    return {\n        'parallel_read_safe': False,\n        'parallel_write_safe': False,\n    }\n", "path": "docs/click_utils.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-2023 ODC Contributors\n# SPDX-License-Identifier: Apache-2.0\nimport logging\nfrom typing import Dict, Any, Tuple, Iterable\n\n_LOG = logging.getLogger(__name__)\n\n\ndef load_drivers(group: str) -> Dict[str, Any]:\n    \"\"\"\n    Load available drivers for a given group name.\n\n    Gracefully handles:\n\n     - Driver module not able to be imported\n     - Driver init function throwing an exception or returning None\n\n     By having driver entry_points pointing to a function, we defer loading the driver\n     module or running any code until required.\n\n    :param group: Name of the entry point group e.g. \"datacube.plugins.io.read\"\n\n    :returns: Dictionary String -> Driver Object\n    \"\"\"\n\n    def safe_load(ep):\n        # pylint: disable=broad-except,bare-except\n        try:\n            driver_init = ep.load()\n        except Exception as e:\n            _LOG.warning('Failed to resolve driver %s::%s', group, ep.name)\n            _LOG.warning('Error was: %s', repr(e))\n            return None\n\n        try:\n            driver = driver_init()\n        except Exception:\n            _LOG.warning('Exception during driver init, driver name: %s::%s', group, ep.name)\n            return None\n\n        if driver is None:\n            _LOG.warning('Driver init returned None, driver name: %s::%s', group, ep.name)\n\n        return driver\n\n    def resolve_all(group: str) -> Iterable[Tuple[str, Any]]:\n        try:\n            from importlib_metadata import entry_points\n        except ModuleNotFoundError:\n            from importlib.metadata import entry_points\n        for ep in entry_points(group=group):\n            driver = safe_load(ep)\n            if driver is not None:\n                yield (ep.name, driver)\n\n    return dict((name, driver) for name, driver in resolve_all(group))\n", "path": "datacube/drivers/driver_cache.py"}, {"content": "#!/usr/bin/env python\n\nfrom setuptools import setup, find_packages\n\ntests_require = [\n    'hypothesis',\n    'pycodestyle',\n    'pylint',\n    'pytest',\n    'pytest-cov',\n    'pytest-timeout',\n    'pytest-httpserver',\n    'moto',\n]\ndoc_require = [\n    'Sphinx',\n    'sphinx_autodoc_typehints',  # Propagate mypy info into docs\n    'sphinx-click',\n    'recommonmark',\n    'autodocsumm',\n    'beautifulsoup4',\n    'nbsphinx',\n    'pydata-sphinx-theme==0.9.0',\n]\n\nextras_require = {\n    'performance': ['ciso8601', 'bottleneck'],\n    'distributed': ['distributed', 'dask[distributed]'],\n    'doc': doc_require,\n    's3': ['boto3', 'botocore'],\n    'test': tests_require,\n    'cf': ['compliance-checker>=4.0.0'],\n}\n\nextras_require['dev'] = sorted(set(sum([extras_require[k] for k in [\n    'test',\n    'doc',\n    'performance',\n    's3',\n    'distributed',\n]], [])))\n\n# An 'all' option, following ipython naming conventions.\nextras_require['all'] = sorted(set(sum(extras_require.values(), [])))\n\nextra_plugins = dict(read=[], write=[], index=[])\n\nsetup(\n    name='datacube',\n    python_requires='>=3.8.0',\n\n    url='https://github.com/opendatacube/datacube-core',\n    author='Open Data Cube',\n    maintainer='Open Data Cube',\n    maintainer_email='',\n    description='An analysis environment for satellite and other earth observation data',\n    long_description=open('README.rst').read(),\n    long_description_content_type='text/x-rst',\n    license='Apache License 2.0',\n    classifiers=[\n        \"Development Status :: 4 - Beta\",\n        \"Intended Audience :: Developers\",\n        \"Intended Audience :: Science/Research\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Natural Language :: English\",\n        \"Operating System :: MacOS :: MacOS X\",\n        \"Operating System :: POSIX\",\n        \"Operating System :: POSIX :: BSD\",\n        \"Operating System :: POSIX :: Linux\",\n        \"Operating System :: Microsoft :: Windows\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 3\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Programming Language :: Python :: 3.10\",\n        \"Topic :: Scientific/Engineering :: GIS\",\n        \"Topic :: Scientific/Engineering :: Information Analysis\",\n    ],\n\n    packages=find_packages(\n        exclude=('tests', 'tests.*',\n                 'integration_tests', 'integration_tests.*')\n    ),\n    package_data={\n        '': ['*.yaml', '*/*.yaml'],\n        'datacube': ['py.typed'],\n    },\n    scripts=[],\n    install_requires=[\n        'affine',\n        'attrs>=18.1',\n        'pyproj>=2.5',\n        'shapely>=2.0',\n        'cachetools',\n        'click>=5.0',\n        'cloudpickle>=0.4',\n        'dask[array]',\n        'distributed',\n        'jsonschema',\n        'netcdf4',\n        'numpy',\n        'psycopg2',\n        'lark',\n        'pandas',\n        'python-dateutil',\n        'pyyaml',\n        'rasterio>=1.3.2',  # Warping broken in 1.3.0 and 1.3.1\n        'ruamel.yaml',\n        'sqlalchemy>=1.4,<2.0',  # GeoAlchemy2 requires >=1.4.  SqlAlchemy2 *may* work but has not been tested yet.\n        'GeoAlchemy2',\n        'toolz',\n        'xarray>=0.9',  # >0.9 fixes most problems with `crs` attributes being lost\n        'packaging',\n        'deprecat',\n        'importlib_metadata>3.5;python_version<\"3.10\"',\n    ],\n    extras_require=extras_require,\n    tests_require=tests_require,\n\n    entry_points={\n        'console_scripts': [\n            'datacube = datacube.scripts.cli_app:cli',\n            'datacube-search = datacube.scripts.search_tool:cli',\n            'datacube-worker = datacube.execution.worker:main',\n        ],\n        'datacube.plugins.io.read': [\n            'netcdf = datacube.drivers.netcdf.driver:reader_driver_init',\n            *extra_plugins['read'],\n        ],\n        'datacube.plugins.io.write': [\n            'netcdf = datacube.drivers.netcdf.driver:writer_driver_init',\n            *extra_plugins['write'],\n        ],\n        'datacube.plugins.index': [\n            'default = datacube.index.postgres.index:index_driver_init',\n            'null = datacube.index.null.index:index_driver_init',\n            'memory = datacube.index.memory.index:index_driver_init',\n            'postgis = datacube.index.postgis.index:index_driver_init',\n            *extra_plugins['index'],\n        ],\n    },\n)\n", "path": "setup.py"}, {"content": "# This file is part of the Open Data Cube, see https://opendatacube.org for more information\n#\n# Copyright (c) 2015-2023 ODC Contributors\n# SPDX-License-Identifier: Apache-2.0\nfrom docutils.nodes import literal_block, section, title, make_id\nfrom sphinx.domains import Domain\nfrom docutils.parsers.rst import Directive\nimport importlib\n\nimport click\n\n\nclass ClickHelpDirective(Directive):\n    has_content = True\n    required_arguments = 1\n\n    def run(self):\n        root_cmd = self.arguments[0]\n\n        env = self.state.document.settings.env\n\n        group = find_script_callable_from_env(root_cmd, env)\n\n        return [generate_help_text(group, [root_cmd])]\n\n\ndef find_script_callable_from_env(name, env):\n    commands = env.config.click_utils_commands\n\n    module, function_name = commands[name].split(':')\n    module = importlib.import_module(module)\n    return getattr(module, function_name)\n\n\ndef find_script_callable(name):\n    try:\n        from importlib_metadata import entry_points\n    except ModuleNotFoundError:\n        from importlib.metadata import entry_points\n    return list(entry_points(\n        group='console_scripts', name=name))[0].load()\n\n\ndef generate_help_text(command, prefix):\n    ctx = click.Context(command)\n    help_opts = command.get_help_option(ctx).opts\n    full_cmd = ' '.join(prefix)\n    block = section(None,\n                    title(None, full_cmd),\n                    ids=[make_id(full_cmd)], names=[full_cmd])\n    if help_opts:\n        h = \"$ {} {}\\n\".format(full_cmd, help_opts[0]) + command.get_help(ctx)\n        block.append(literal_block(None, h, language='console'))\n\n    if isinstance(command, click.core.MultiCommand):\n        for c in command.list_commands(ctx):\n            c = command.resolve_command(ctx, [c])[1]\n            block.append(generate_help_text(c, prefix+[c.name]))\n\n    return block\n\n\ndef make_block(command, opt, content):\n    h = \"$ {} {}\\n\".format(command, opt) + content\n    return section(None,\n                   title(None, command),\n                   literal_block(None, h, language='console'),\n                   ids=[make_id(command)], names=[command])\n\n\nclass DatacubeDomain(Domain):\n    name = 'datacube'\n    label = 'Data Cube'\n    directives = {\n        'click-help': ClickHelpDirective,\n    }\n\n\ndef setup(app):\n    app.add_config_value('click_utils_commands', {}, 'html')\n\n    app.add_domain(DatacubeDomain)\n    return {\n        'parallel_read_safe': False,\n        'parallel_write_safe': False,\n    }\n", "path": "docs/click_utils.py"}]}