Skip to content
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
52 changes: 50 additions & 2 deletions src/earthkit/data/utils/metadata/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# nor does it submit to any jurisdiction.
#

import copy
import logging
from functools import cached_property
from math import prod
Expand Down Expand Up @@ -452,7 +453,26 @@ def geography(self):
return make_geography(self, values_shape=self._shape)

def override(self, *args, **kwargs):
raise NotImplementedError("override is not implemented for UserMetadata")
r"""Create a new metadata object by cloning the underlying metadata and setting the keys in it.

Parameters
----------
*args: tuple
Positional arguments. When present must be a dict with the keys to set in
the new metadata.
**kwargs: dict, optional
Other keyword arguments specifying the metadata keys to set.

Returns
-------
:class:`UserMetadata`
The new metadata object. A copy of the original metadata with the keys set in it.
"""
d = dict(*args, **kwargs)
existing = copy.deepcopy(self._data)
existing.update(d)

return UserMetadata(existing, shape=copy.deepcopy(self._shape))

def namespaces(self):
return []
Expand All @@ -461,7 +481,35 @@ def as_namespace(self, namespace=None):
return {}

def dump(self, **kwargs):
return None
r"""Generate dump with all the metadata keys.

In a Jupyter notebook it is represented as a tabbed interface.

Parameters
----------
**kwargs: dict, optional
Other keyword arguments used for testing only

Returns
-------
NamespaceDump
Dict-like object with one item per namespace. In a Jupyter notebook represented
as a tabbed interface to browse the dump contents.

Examples
--------
:ref:`/examples/grib_metadata.ipynb`

"""
from earthkit.data.utils.summary import format_namespace_dump

r = [
{
"title": "metadata",
"data": self._data,
}
]
return format_namespace_dump(r, selected="parameter", details=self.__class__.__name__, **kwargs)

def ls_keys(self):
return self.LS_KEYS
Expand Down
57 changes: 57 additions & 0 deletions tests/array_fieldlist/test_array_field_usermetadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# nor does it submit to any jurisdiction.
#

import copy
import datetime

import numpy as np
Expand Down Expand Up @@ -73,3 +74,59 @@ def test_array_field_usermetadata_geom(_kwargs):
assert np.allclose(lat, meta["latitudes"])
assert np.allclose(lon, meta["longitudes"])
assert np.allclose(f.values, vals)


@pytest.mark.parametrize(
"initial, update, expected",
[
({"shortName": "2t"}, {}, {"shortName": "2t"}), # No update
({"shortName": "2t"}, {"shortName": "msl"}, {"shortName": "msl"}), # Update existing key
(
{"shortName": "2t"},
{"longName": "Temperature"},
{"shortName": "2t", "longName": "Temperature"},
), # Add new key
({}, {"shortName": "2t"}, {"shortName": "2t"}), # Add key to empty metadata
(
{"shortName": "2t", "longName": "Temperature"},
{"shortName": "temperature"},
{"shortName": "temperature", "longName": "Temperature"},
), # Update one key, keep others
],
)
def test_array_field_usermetadata_override(initial, update, expected):

initial_copied = copy.deepcopy(initial)
update_copied = copy.deepcopy(update)

meta = UserMetadata(initial)
new_meta = meta.override(update)
_ = meta.override(**update) # Check that the override method works with keyword arguments

# Check that the updated metadata matches the expected result
for k, v in expected.items():
assert new_meta[k] == v

# Ensure the original metadata remains unchanged
for k, v in initial_copied.items():
assert meta[k] == v

# Check that the updated metadata contains all expected keys
for k in update_copied:
if k in initial:
assert meta[k] == initial[k]
else:
assert k not in meta


def test_array_field_usermetadata_override_shape():
meta = UserMetadata({}, shape=(10, 1))
new_meta = meta.override(
{
"shortName": "2t",
"longName": "Temperature",
}
)
new_meta._shape = None
assert new_meta._shape is None
assert meta._shape is not None
Loading