From e0e76de83333f5b009878fed4cef00077f5ed19c Mon Sep 17 00:00:00 2001 From: Stephan Finkensieper Date: Fri, 22 May 2026 09:55:03 +0000 Subject: [PATCH 1/2] Add config switch for legacy sensor attribute --- doc/source/reading.rst | 8 +++--- satpy/_config.py | 3 ++- satpy/scene.py | 21 ++++++++++++++++ satpy/tests/scene_tests/test_data_access.py | 27 +++++++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/doc/source/reading.rst b/doc/source/reading.rst index 288bb3d6d4..de375ec6dc 100644 --- a/doc/source/reading.rst +++ b/doc/source/reading.rst @@ -222,9 +222,11 @@ time etc. The following attributes are standardized across all readers: :class:`~pyresample.geometry.SwathDefinition` if data is geolocated. Areas are used for gridded projected data and Swaths when data must be described by individual longitude/latitude coordinates. See the Coordinates section below. -* ``sensor``: The name of the sensor that recorded the data. For full support through Satpy this - should be all lowercase. If the dataset is the result of observations from multiple sensors a - ``set`` object can be used to specify more than one sensor name. +* ``instruments`` (previously ``sensor`` in Satpy < v1.0): Names of instruments that recorded the + data, stored in a ``set`` object. Starting with Satpy v1.0 the instrument names follow WMO OSCAR + naming conventions. To facilitate the transision, you can get the ``sensor`` attribute back by + setting ``satpy.config.set(legacy_sensor_attribute=True)``. This config switch will be removed + in Satpy v1.1. * ``reader``: The name of the Satpy reader that produced the dataset. * ``orbital_parameters``: Dictionary of orbital parameters describing the satellite's position. See the :ref:`orbital_parameters` section below for more information. diff --git a/satpy/_config.py b/satpy/_config.py index 0b2e6a57c0..b55a89bd18 100644 --- a/satpy/_config.py +++ b/satpy/_config.py @@ -54,7 +54,8 @@ "readers": { "clip_negative_radiances": False, }, - "instruments_key": "sensor" + "instruments_key": "sensor", + "legacy_sensor_attribute": False } # Satpy main configuration object diff --git a/satpy/scene.py b/satpy/scene.py index e26f2e363f..5fb0d02fcd 100644 --- a/satpy/scene.py +++ b/satpy/scene.py @@ -29,6 +29,7 @@ from pyresample.geometry import AreaDefinition, BaseDefinition, CoordinateDefinition, SwathDefinition from xarray import DataArray +import satpy import satpy._instruments as inst_utils from satpy.area import get_area_def from satpy.composites.config_loader import load_compositor_configs_for_sensors @@ -841,8 +842,28 @@ def __getitem__(self, key): """Get a dataset or create a new 'slice' of the Scene.""" if isinstance(key, tuple): return self.slice(key) + # 8< v1.1 + data_array = self._datasets[key] + if self._should_add_legacy_sensor_attribute(data_array): + self._set_legacy_sensor_attribute(data_array) + return data_array + # >8 v1.1 return self._datasets[key] + # 8< v1.1 + def _should_add_legacy_sensor_attribute(self, data_array: xr.DataArray) -> bool: + instruments = inst_utils.get_instruments_from_attrs(data_array.attrs) + return bool(instruments) and satpy.config.get("legacy_sensor_attribute") + + def _set_legacy_sensor_attribute(self, data_array: xr.DataArray) -> None: + instruments = inst_utils.get_instruments_from_attrs(data_array.attrs) + if len(instruments) == 1: + # In satpy < v1.0 single sensors are provided as string + data_array.attrs["sensor"] = inst_utils.wmo_to_internal(list(instruments)[0]) + else: + data_array.attrs["sensor"] = {inst_utils.wmo_to_internal(inst) for inst in instruments} + # >8 v1.1 + def __setitem__(self, key, value): """Add the item to the scene.""" self._datasets[key] = value diff --git a/satpy/tests/scene_tests/test_data_access.py b/satpy/tests/scene_tests/test_data_access.py index 60ada6c78b..6e4cdb8baf 100644 --- a/satpy/tests/scene_tests/test_data_access.py +++ b/satpy/tests/scene_tests/test_data_access.py @@ -21,6 +21,7 @@ import xarray as xr from dask import array as da +import satpy from satpy import Scene from satpy.dataset.dataid import default_id_keys_config from satpy.tests.utils import FAKE_FILEHANDLER_END, FAKE_FILEHANDLER_START, make_cid, make_dataid @@ -393,3 +394,29 @@ def test_chunk_pass_through(self): scene.load(["ds1"]) scene = scene.chunk(chunks=2) assert scene["ds1"].data.chunksize == (2, 2) + + +class TestLegacySensorAttribute: + """Tests for legacy sensor attribute.""" + + @pytest.mark.parametrize( + ("instruments", "expected"), + [ + ({"inst1"}, "inst1"), + ({"inst1", "inst2"}, {"inst1", "inst2"}) + ] + ) + def test_getting_dataset_with_sensor_attribute(self, instruments, expected): + """Test getting dataset with sensor attribute.""" + scene = Scene() + scene["ds"] = xr.DataArray(attrs={"instruments": instruments}) + assert "sensor" not in scene["ds"].attrs + with satpy.config.set(legacy_sensor_attribute=True): + assert scene["ds"].attrs["sensor"] == expected + + def test_no_instruments_no_sensor(self): + """Test setting sensor only if instruments are present.""" + scene = Scene() + scene["ds"] = xr.DataArray() + with satpy.config.set(legacy_sensor_attribute=True): + assert "sensor" not in scene["ds"].attrs From f6a5fee34eb59b47b719cb36afb7acc9ce6689d3 Mon Sep 17 00:00:00 2001 From: Stephan Finkensieper Date: Fri, 22 May 2026 10:15:58 +0000 Subject: [PATCH 2/2] Update documentation --- doc/source/reading.rst | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/doc/source/reading.rst b/doc/source/reading.rst index de375ec6dc..a7061a395f 100644 --- a/doc/source/reading.rst +++ b/doc/source/reading.rst @@ -222,11 +222,27 @@ time etc. The following attributes are standardized across all readers: :class:`~pyresample.geometry.SwathDefinition` if data is geolocated. Areas are used for gridded projected data and Swaths when data must be described by individual longitude/latitude coordinates. See the Coordinates section below. -* ``instruments`` (previously ``sensor`` in Satpy < v1.0): Names of instruments that recorded the - data, stored in a ``set`` object. Starting with Satpy v1.0 the instrument names follow WMO OSCAR - naming conventions. To facilitate the transision, you can get the ``sensor`` attribute back by - setting ``satpy.config.set(legacy_sensor_attribute=True)``. This config switch will be removed - in Satpy v1.1. +* ``sensor``: The name of the sensor that recorded the data. For full support through Satpy this + should be all lowercase. If the dataset is the result of observations from multiple sensors a + ``set`` object can be used to specify more than one sensor name. + + .. versionremoved:: 1.0 + + The ``sensor`` attribute has been replaced by ``instruments`` in Satpy v1.0. During + a transition phase the attribute can be restored by setting + + .. code-block:: python + + import satpy + satpy.config.set(legacy_sensor_attribute=True) + + This option will be removed in Satpy v1.1. + +* ``instruments``: Names of instruments that recorded the data, stored in a ``set`` object. + Instrument names follow the WMO OSCAR naming conventions. + + .. versionadded:: 1.0 + * ``reader``: The name of the Satpy reader that produced the dataset. * ``orbital_parameters``: Dictionary of orbital parameters describing the satellite's position. See the :ref:`orbital_parameters` section below for more information.