From c35b043e0fb56a4dafe98f74236d5502bee8bb70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20M=C3=BCller?= <mueller.seb@posteo.de>
Date: Mon, 18 Nov 2024 11:08:00 +0100
Subject: [PATCH] Info: create properties for time, grid and mask with proper
 setters

---
 src/finam/data/tools/info.py | 60 ++++++++++++++++++++++++++++++------
 1 file changed, 50 insertions(+), 10 deletions(-)

diff --git a/src/finam/data/tools/info.py b/src/finam/data/tools/info.py
index 4d2eb1b9..e609b4ec 100644
--- a/src/finam/data/tools/info.py
+++ b/src/finam/data/tools/info.py
@@ -47,25 +47,65 @@ class Info:
     """
 
     def __init__(self, time=None, grid=None, meta=None, mask=Mask.FLEX, **meta_kwargs):
-        if time is not None and not isinstance(time, datetime.datetime):
-            raise FinamMetaDataError("Time in Info must be either None or a datetime")
-        if grid is not None and not isinstance(grid, GridBase):
-            raise FinamMetaDataError(
-                "Grid in Info must be either None or of a sub-class of GridBase"
-            )
-
+        self._time = self._grid = self._mask = None
         self.time = time
         self.grid = grid
-        if mask_specified(mask) and mask is not None:
-            mask = np.ma.make_mask(mask, shrink=False)
         self.mask = mask
+        # set meta last (see __setattr__)
         self.meta = meta or {}
         self.meta.update(meta_kwargs)
-
+        # handle units
         units = self.meta.get("units", "")
         units = None if units is None else UNITS.Unit(units)
         self.meta["units"] = units
 
+    @property
+    def time(self):
+        """datetime: current time."""
+        return self._time
+
+    @time.setter
+    def time(self, time):
+        if time is not None and not isinstance(time, datetime.datetime):
+            msg = "Time in Info must be either None or a datetime"
+            raise FinamMetaDataError(msg)
+        self._time = time
+
+    @property
+    def grid(self):
+        """Grid: data grid."""
+        return self._grid
+
+    @grid.setter
+    def grid(self, grid):
+        if grid is not None and not isinstance(grid, GridBase):
+            msg = "Grid in Info must be either None or of a sub-class of GridBase"
+            raise FinamMetaDataError(msg)
+        self._grid = grid
+
+    @property
+    def mask(self):
+        """Mask or ndarray: data mask."""
+        return self._mask
+
+    @mask.setter
+    def mask(self, mask):
+        if mask_specified(mask) and mask is not None:
+            mask = np.ma.make_mask(mask, shrink=False)
+            if (
+                self.grid is not None
+                and mask is not np.ma.nomask
+                and not np.array_equal(self.grid_shape, np.shape(mask))
+            ):
+                msg = "Mask in Info not compatible with given grid."
+                raise FinamMetaDataError(msg)
+        self._mask = mask
+
+    @property
+    def grid_shape(self):
+        """tuple: shape of the data grid."""
+        return None if self.grid is None else self.grid.data_shape
+
     @property
     def is_masked(self):
         """bool: whether data is set to be masked."""
-- 
GitLab