Source code for esmvalcore.io.protocol

"""Protocols for accessing data.

An input data source can be defined in the configuration by using :obj:`esmvalcore.config.CFG`

.. code-block:: python

    >>> from esmvalcore.config import CFG
    >>> CFG["projects"]["example-project"]["data"]["example-source-name"] = {
            "type": "example_module.ExampleDataSource"
            "argument1": "value1"
            "argument2": "value2"
        }

or as a :ref:`YAML configuration file <config_overview>`

.. code-block:: yaml

    projects:
      example-project:
        data:
          example-source-name
            type: example_module.ExampleDataSource
            argument1: value1
            argument2: value2


where ``example-project`` is a project, e.g. ``CMIP6``, and ``example-source-name``
is a unique name describing the data source. The datasource type, in the
example above called ``example_module.ExampleDataSource`` needs to implement the
:class:`esmvalcore.io.protocol.DataSource` protocol. Any remaining key-value pairs
in the configuration, ``argument1: value1`` and ``argument2: value2`` are
passed as keyword arguments to the data source when it is created.

Dedeplication of search results happens based on the
:attr:`esmvalcore.io.protocol.DataElement.name` attribute and the ``"version"``
facet in :attr:`esmvalcore.io.protocol.DataElement.facets` of the data elements
provided by the data sources. If there is a tie, the data element provided by
the data source with the lowest value of
:attr:`esmvalcore.io.protocol.DataSource.priority` is chosen.
"""

from collections.abc import Iterable
from typing import Any, Protocol, runtime_checkable

import iris.cube

from esmvalcore.typing import FacetValue


[docs] @runtime_checkable class DataElement(Protocol): """A data element represents some data that can be loaded. A file is an example of a data element. """ name: str """A unique name identifying the data.""" facets: dict[str, FacetValue] """Facets are key-value pairs that can be used for searching the data.""" attributes: dict[str, Any] """Attributes are key-value pairs describing the data.""" def __hash__(self) -> int: """Return a number uniquely representing the data element."""
[docs] def prepare(self) -> None: """Prepare the data for access."""
[docs] def to_iris( self, ignore_warnings: list[dict[str, Any]] | None = None, ) -> iris.cube.CubeList: """Load the data as Iris cubes. Parameters ---------- ignore_warnings: Keyword arguments passed to :func:`warnings.filterwarnings` used to ignore warnings issued by :func:`iris.load_raw`. Each list element corresponds to one call to :func:`warnings.filterwarnings`. Returns ------- iris.cube.CubeList The loaded data. """
[docs] @runtime_checkable class DataSource(Protocol): """A data source can be used to find data.""" name: str """A name identifying the data source.""" project: str """The project that the data source provides data for.""" priority: int """The priority of the data source. Lower values have priority.""" debug_info: str """A string containing debug information when no data is found."""
[docs] def find_data(self, **facets: FacetValue) -> Iterable[DataElement]: """Find data. Parameters ---------- **facets : Find data matching these facets. Returns ------- :obj:`typing.Iterable` of :obj:`esmvalcore.io.base.DataElement` The data elements that have been found. """