Repository: ecmwf/earthkit-data
Pull request #526 (2024-11-18 10:55:10)

Add array_backend property to field

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/ecmwf/earthkit-data/pull/526?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ecmwf) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 91.09%. Comparing base [(`64a9e3c`)](https://app.codecov.io/gh/ecmwf/earthkit-data/commit/64a9e3c9d1b2edaede9c9a1ca32c94bd6437bc82?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ecmwf) to head [(`fb9cef2`)](https://app.codecov.io/gh/ecmwf/earthkit-data/commit/fb9cef2362a39f8e849696af38490416804e904a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ecmwf).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff            @@
##           develop     #526   +/-   ##
========================================
  Coverage    91.08%   91.09%           
========================================
  Files          147      147           
  Lines        10740    10744    +4     
  Branches       510      510           
========================================
+ Hits          9783     9787    +4     
  Misses         794      794           
  Partials       163      163           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/ecmwf/earthkit-data/pull/526?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ecmwf).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ecmwf).


Patch:
diff --git a/src/earthkit/data/core/fieldlist.py b/src/earthkit/data/core/fieldlist.py
index a1e863f..4d8d0b5 100644
--- a/src/earthkit/data/core/fieldlist.py
+++ b/src/earthkit/data/core/fieldlist.py
@@ -21,6 +21,7 @@ from earthkit.data.decorators import detect_out_filename
 from earthkit.data.utils.array import array_namespace
 from earthkit.data.utils.array import array_to_numpy
 from earthkit.data.utils.array import convert_array
+from earthkit.data.utils.array import get_backend
 from earthkit.data.utils.metadata.args import metadata_argument
 
 
@@ -79,6 +80,11 @@ class FieldListIndices:
 class Field(Base):
     r"""Represent a Field."""
 
+    @property
+    def array_backend(self):
+        r""":obj:`ArrayBackend`: Return the array backend of the field."""
+        return get_backend(self._values())
+
     @abstractmethod
     def _values(self, dtype=None):
         r"""Return the raw values extracted from the underlying storage format


Test patch:
diff --git a/tests/grib/test_grib_backend.py b/tests/grib/test_grib_backend.py
index ea0ece1..7796813 100644
--- a/tests/grib/test_grib_backend.py
+++ b/tests/grib/test_grib_backend.py
@@ -31,6 +31,7 @@ def test_grib_file_numpy_backend(_kwargs):
     assert getattr(ds, "path", None) is None
     assert len(ds) == 6
 
+    assert ds[0].array_backend == _NUMPY
     assert isinstance(ds[0].values, np.ndarray)
     assert ds[0].values.shape == (84,)
 
@@ -58,6 +59,7 @@ def test_grib_file_numpy_backend(_kwargs):
     assert len(ds1) == len(ds)
     assert getattr(ds1, "path", None) is None
     assert get_backend(ds1[0].to_array()) == _NUMPY
+    assert ds1[0].array_backend == _NUMPY
 
 
 @pytest.mark.skipif(NO_PYTORCH, reason="No pytorch installed")
@@ -70,6 +72,7 @@ def test_grib_file_pytorch_backend():
 
     import torch
 
+    assert ds[0].array_backend == _PYTORCH
     assert torch.is_tensor(ds[0].values)
     assert ds[0].values.shape == (84,)
 
@@ -101,6 +104,7 @@ def test_grib_file_pytorch_backend():
     assert len(ds1) == len(ds)
     assert getattr(ds1, "path", None) is None
     assert get_backend(ds1[0].to_array()) == _PYTORCH
+    assert ds1[0].array_backend == _PYTORCH
 
 
 @pytest.mark.skipif(NO_CUPY, reason="No cupy installed")