diff --git a/src/finam/data/tools/info.py b/src/finam/data/tools/info.py
index 4d2eb1b942feb80d7868ff4e137715cd5d33889e..e609b4ec0b4eb7b0ec54c06fb400b468ea05db1c 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."""