Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major documentation theme update and fixes #1676

Merged
merged 12 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
907 changes: 552 additions & 355 deletions datacube/api/core.py

Large diffs are not rendered by default.

11 changes: 4 additions & 7 deletions datacube/api/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,12 @@ def query_group_by(group_by='time', **kwargs):
"""
Group by function for loading datasets

:param group_by: group_by name, supported str are
::
:param group_by: group_by name, supported strings are

- time (default)
- solar_day, see :func:`datacube.api.query.solar_day`
- `time` (default)
- `solar_day`, see :func:`datacube.api.query.solar_day`

or ::

- :class:`datacube.api.query.GroupBy` object
or pass a :class:`datacube.api.query.GroupBy` object.

:return: :class:`datacube.api.query.GroupBy`
:raises LookupError: when group_by string is not a valid dictionary key.
Expand Down
133 changes: 87 additions & 46 deletions datacube/cfg/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@

from .cfg import find_config, parse_text
from .exceptions import ConfigException
from .opt import ODCOptionHandler, AliasOptionHandler, IndexDriverOptionHandler, BoolOptionHandler, IntOptionHandler
from .opt import (
ODCOptionHandler,
AliasOptionHandler,
IndexDriverOptionHandler,
BoolOptionHandler,
IntOptionHandler,
)
from .utils import ConfigDict, check_valid_env_name
from ..migration import ODC2DeprecationWarning

Expand All @@ -31,31 +37,48 @@ class ODCConfig:
"""
Configuration finder/reader/parser.

Attributes:
allow_envvar_overrides: bool If True, environment variables can override the values explicitly specified
in the supplied configuration.
**Attributes**

Note that environments not explicitly specified in the supplied
configuration (dynamic environments) can still be read from
environment variables, even if this attribute is False.
.. py:attribute:: allow_envvar_overrides
:type: bool
:value: True

raw_text: str | None The raw configuration text being used, as read from the configuration
file or supplied directly by the user. May be None if the user
directly supplied configuration as a dictionary. May be in ini or yaml
format. Does not include dynamic environments or values overridden by
environment variables.
If True, environment variables can override the values explicitly specified in the supplied configuration.

raw_config: dict[str, dict[str, Any]] The raw dictionary form of the configuration, as supplied directly
by the user, or as parsed from raw_text. Does not include dynamic
environments or values overridden by environment variables.
Note that environments not explicitly specified in the supplied configuration (dynamic environments) can
still be read from environment variables, even if this attribute is False.

known_environments: dict[str, "ODCEnvironment"] A dictionary containing all environments defined in raw_config,
plus any dynamic environments read so far.
Environment themselves are not validated until read from.
.. py:attribute:: raw_text
:type: str | None

The raw configuration text being used, as read from the configuration
file or supplied directly by the user. May be None if the user
directly supplied configuration as a dictionary. May be in ini or yaml
format. Does not include dynamic environments or values overridden by
environment variables.

.. py:attribute:: raw_config
:type: dict[str, dict[str, Any]]

The raw dictionary form of the configuration, as supplied directly
by the user, or as parsed from raw_text. Does not include dynamic
environments or values overridden by environment variables.

.. py:attribute:: known_environments
:type: dict[str, "ODCEnvironment"]

A dictionary containing all environments defined in raw_config,
plus any dynamic environments read so far.
Environment themselves are not validated until read from.

.. py:attribute:: canonical_names
:type: dict[str, list[str]]

A dictionary mapping canonical environment names to all aliases for
that environment.

canonical_names: dict[str, list[str]] A dictionary mapping canonical environment names to all aliases for
that environment.
"""

allow_envvar_overrides: bool = True
raw_text: str | None = None
raw_config: ConfigDict = {}
Expand All @@ -64,10 +87,11 @@ class ODCConfig:
is_default = False

def __init__(
self,
paths: GeneralisedPath | None = None,
raw_dict: ConfigDict | None = None,
text: str | None = None):
self,
paths: GeneralisedPath | None = None,
raw_dict: ConfigDict | None = None,
text: str | None = None,
):
"""
When called with no args, reads the first config file found in the config path list is used.
The config path list is taken from:
Expand Down Expand Up @@ -97,8 +121,10 @@ def __init__(
# Cannot supply both text AND paths.
args_supplied: int = sum(map(lambda x: int(bool(x)), (paths, raw_dict, text)))
if args_supplied > 1:
raise ConfigException("Can only supply one of configuration path(s), raw dictionary, "
"and explicit configuration text.")
raise ConfigException(
"Can only supply one of configuration path(s), raw dictionary, "
"and explicit configuration text."
)

# Suppress environment variable overrides if explicit config text or dictionary is supplied.
self.allow_envvar_overrides = not text and not raw_dict
Expand All @@ -118,8 +144,10 @@ def __init__(
self.raw_config = parse_text(cast(str, self.raw_text))

self._aliases: dict[str, str] = {}
self.known_environments: dict[str, ODCEnvironment] = {
section: ODCEnvironment(self, section, self.raw_config[section], self.allow_envvar_overrides)
self.known_environments: dict[str, "ODCEnvironment"] = {
section: ODCEnvironment(
self, section, self.raw_config[section], self.allow_envvar_overrides
)
for section in self.raw_config
}
self.canonical_names: dict[str, list[str]] = {}
Expand All @@ -131,10 +159,12 @@ def __init__(
self.canonical_names[canonical] = [canonical, alias]

@classmethod
def get_environment(cls,
env: GeneralisedEnv | None = None,
config: GeneralisedCfg | None = None,
raw_config: GeneralisedRawCfg | None = None) -> "ODCEnvironment":
def get_environment(
cls,
env: GeneralisedEnv | None = None,
config: GeneralisedCfg | None = None,
raw_config: GeneralisedRawCfg | None = None,
) -> "ODCEnvironment":
"""
Obtain an ODCConfig object from the most general possible arguments.

Expand Down Expand Up @@ -216,14 +246,17 @@ def __getitem__(self, item: str | None) -> "ODCEnvironment":
warnings.warn(
"Setting the default environment with $DATACUBE_ENVIRONMENT is deprecated. "
"Please use $ODC_ENVIRONMENT instead.",
ODC2DeprecationWarning)
ODC2DeprecationWarning,
)
item = os.environ["DATACUBE_ENVIRONMENT"]
elif "default" in self.known_environments:
item = "default"
elif "datacube" in self.known_environments:
warnings.warn("Defaulting to the 'datacube' environment - "
"this fallback behaviour is deprecated and may change in a future release.",
ODC2DeprecationWarning)
warnings.warn(
"Defaulting to the 'datacube' environment - "
"this fallback behaviour is deprecated and may change in a future release.",
ODC2DeprecationWarning,
)
item = "datacube"
else:
# No explicitly defined (known) environments - assume default and hope there's config
Expand All @@ -248,11 +281,14 @@ class ODCEnvironment:

ODCEnvironment objects should only be instantiated by and acquired from an ODCConfig object.
"""
def __init__(self,
cfg: ODCConfig,
name: str,
raw: dict[str, Any],
allow_env_overrides: bool = True):

def __init__(
self,
cfg: ODCConfig,
name: str,
raw: dict[str, Any],
allow_env_overrides: bool = True,
):
self._cfg: ODCConfig = cfg
check_valid_env_name(name)
self._name: str = name
Expand All @@ -262,19 +298,22 @@ def __init__(self,
self._normalised: dict[str, Any] = {}

if name == "user" and "default_environment" in raw:
warnings.warn("The 'default_environment' setting in the 'user' section is no longer supported - "
"please refer to the documentation for more information")
warnings.warn(
"The 'default_environment' setting in the 'user' section is no longer supported - "
"please refer to the documentation for more information"
)

self._env_overrides_applied = False
# Aliases are handled here, the alias OptionHandler is a place-holder.
if "alias" in self._raw:
alias = self._raw['alias']
alias = self._raw["alias"]
check_valid_env_name(alias)
self._cfg._add_alias(self._name, alias)
for opt in self._raw.keys():
if opt != "alias":
raise ConfigException(
f"Alias environments should only contain an alias option. Extra option {opt} found.")
f"Alias environments should only contain an alias option. Extra option {opt} found."
)

self._option_handlers: list[ODCOptionHandler] = [
AliasOptionHandler("alias", self),
Expand All @@ -295,7 +334,9 @@ def __getitem__(self, key: str) -> Any:
for handler in self._option_handlers:
self._handle_option(handler)
if self._cfg.is_default and not self._env_overrides_applied:
warnings.warn("No configuration file found - using default configuration and environment variables")
warnings.warn(
"No configuration file found - using default configuration and environment variables"
)

# Config already processed
# 1. From Normalised
Expand Down
1 change: 0 additions & 1 deletion datacube/cfg/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ class ConfigException(Exception):
"""
Exception raised in the configuration API
"""
pass
12 changes: 8 additions & 4 deletions datacube/drivers/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,31 @@ def __call__(self, name: str) -> AbstractIndexDriver:
return self._drivers.get(name, None)

def drivers(self) -> List[str]:
""" Returns list of driver names
"""
Returns list of driver names
"""
return list(self._drivers.keys())


def index_cache() -> IndexDriverCache:
""" Singleton for IndexDriverCache
"""
Singleton for IndexDriverCache
"""
return singleton_setup(index_cache, '_instance',
IndexDriverCache,
'datacube.plugins.index')


def index_drivers() -> List[str]:
""" Returns list driver names
"""
Returns list driver names
"""
return index_cache().drivers()


def index_driver_by_name(name: str) -> Optional[AbstractIndexDriver]:
""" Lookup index driver by name
"""
Lookup index driver by name

:returns: Initialised index driver instance
:returns: None if driver with this name doesn't exist
Expand Down
18 changes: 12 additions & 6 deletions datacube/drivers/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ def _find_driver(self, uri_scheme: str, fmt: str):

def __call__(self, uri_scheme: str, fmt: str,
fallback: Optional[DatasourceFactory] = None) -> DatasourceFactory:
"""Lookup `new_datasource` constructor method from the driver. Returns
"""
Lookup `new_datasource` constructor method from the driver. Returns
`fallback` method if no driver is found.

:param uri_scheme: Protocol part of the Dataset uri
Expand All @@ -47,27 +48,31 @@ def __call__(self, uri_scheme: str, fmt: str,
raise KeyError("No driver found and no fallback provided")

def drivers(self) -> List[str]:
""" Returns list of driver names
"""
Returns list of driver names
"""
return list(self._drivers.keys())


def rdr_cache() -> ReaderDriverCache:
""" Singleton for ReaderDriverCache
"""
Singleton for ReaderDriverCache
"""
return singleton_setup(rdr_cache, '_instance',
ReaderDriverCache,
'datacube.plugins.io.read')


def reader_drivers() -> List[str]:
""" Returns list driver names
"""
Returns list driver names
"""
return rdr_cache().drivers()


def choose_datasource(band: BandInfo) -> DatasourceFactory:
"""Returns appropriate `DataSource` class (or a constructor method) for loading
"""
Returns appropriate `DataSource` class (or a constructor method) for loading
given `dataset`.

An appropriate `DataSource` implementation is chosen based on:
Expand All @@ -85,7 +90,8 @@ def choose_datasource(band: BandInfo) -> DatasourceFactory:


def new_datasource(band: BandInfo) -> Optional[DataSource]:
"""Returns a newly constructed data source to read dataset band data.
"""
Returns a newly constructed data source to read dataset band data.

An appropriate `DataSource` implementation is chosen based on:

Expand Down
15 changes: 9 additions & 6 deletions datacube/drivers/writers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,32 @@ def __call__(self, name: str):
return self._drivers.get(name, None)

def drivers(self) -> List[str]:
""" Returns list of driver names
"""
Returns list of driver names
"""
return list(self._drivers.keys())


def writer_cache() -> WriterDriverCache:
""" Singleton for WriterDriverCache
"""
Singleton for WriterDriverCache
"""
return singleton_setup(writer_cache, '_instance',
WriterDriverCache,
'datacube.plugins.io.write')


def writer_drivers() -> List[str]:
""" Returns list driver names
"""
Returns list driver names
"""
return writer_cache().drivers()


def storage_writer_by_name(name):
""" Lookup writer driver by name
"""
Lookup writer driver by name

:returns: Initialised writer driver instance
:returns: None if driver with this name doesn't exist
:return: Initialised writer driver instance or None if driver with this name doesn't exist
"""
return writer_cache()(name)
Loading
Loading