From 04d6d9ce89257b54f1aeb328288e6146dedcd1e5 Mon Sep 17 00:00:00 2001 From: poplarShift Date: Wed, 29 Apr 2020 17:53:34 -0400 Subject: [PATCH 1/4] draft xarray parameters --- param/__init__.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/param/__init__.py b/param/__init__.py index 99ccc861d..a064a7c7c 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -1658,6 +1658,120 @@ def _validate(self, val): self._length_bounds_check(self.rows, len(val), 'Row') +class _XrBase: + """ + Provides mixin methods for DataArray and Dataset. Not useful on its own. + """ + __slots__ = [] + + def _validate_dims_coords(self, val): + if self.dims is not None: + self._validate_property(self.dims, val.dims, 'dimensions') + + if self.coords is not None: + self._validate_property(self.coords, list(val.coords), + 'coordinates') + if isinstance(self.coords, dict): + self._coord_check(self.coords, val.coords) + + + def _validate_property(self, expected, property, name): + # if isinstance(expected, (list, set)): + difference = set(expected) - set([str(el) for el in property]) + if difference: + msg = ('Provided DataArray {name} {found} do not contain ' + 'required {name} {expected}') + raise ValueError(msg.format( + found=list(property), + expected=sorted(expected), + name=name, + )) + + if isinstance(expected, (list, tuple)): + if not set(expected) == set(property): + msg = ('Provided DataArray {name} {found} must ' + 'exactly match {expected}') + raise ValueError(msg.format( + found=list(property), + expected=sorted(expected)), + name=name, + ) + + + def _coord_check(self, expected, coords): + if not all (coords[k].values.tolist() == list(v) + for k, v in expected.items()): + msg = 'Provided DataArray does not have expected coordinates' + raise ValueError(msg) + + +class DataArray(ClassSelector, _XrBase): + """ + Parameter whose value is an xarray DataArray. + + dims: If specified, may be a tuple, list, or set. If a set is used, the supplied + DataArray must contain the specified dims and if a list or tuple is used, the + supplied DataArray must contain exactly the same dimensions and no other + dimensions. + + coords: If specified, may be a set, tuple, list, or dict. For a set, tuple, or + list, the same validation is conducted as for dims (see above). For a dict, keys + must be coordinate names present in the supplied DataArray, and values must + match the respective coordinates exactly. + """ + __slots__ = ['dims', 'coords'] + + def __init__(self, default=None, dims=None, coords=None, **params): + from xarray import DataArray as xrArray + self.dims = dims + self.coords = coords + super(DataArray, self).__init__(xrArray, allow_None=True, default=default, **params) + self._validate(self.default) + + + def _validate(self, val): + super(DataArray, self)._validate(val) + self._validate_dims_coords(val) + + +class Dataset(ClassSelector, _XrBase): + """ + Parameter whose value is an xarray Dataset. + + dims: If specified, may be a tuple, list, or set. If a set is used, the supplied + Dataset must contain the specified dims and if a list or tuple is used, the + supplied Dataset must contain exactly the same dimensions and no other + dimensions. + + coords: If specified, may be a set, tuple, list, or dict. For a set, tuple, or + list, the same validation is conducted as for dims (see above). For a dict, keys + must be coordinate names present in the supplied Dataset, and values must + match the respective coordinates exactly. + + data_vars: Analogous to dims (see above). + """ + __slots__ = ['dims', 'coords', 'data_vars'] + + def __init__(self, default=None, dims=None, coords=None, data_vars=None, + **params): + from xarray import Dataset as xrDataset + self.dims = dims + self.coords = coords + self.data_vars = data_vars + super(Dataset, self).__init__(xrDataset, allow_None=True, default=default, + **params) + self._validate(self.default) + + + def _validate(self, val): + super(Dataset, self)._validate(val) + + self._validate_dims_coords(val) + + if self.data_vars is not None: + self._validate_property(self.data_vars, val.data_vars, + 'data variables') + # For portable code: # - specify paths in unix (rather than Windows) style; From dbdc41594d5f4ab2adf83fcadae65516bd832c67 Mon Sep 17 00:00:00 2001 From: poplarShift Date: Wed, 29 Apr 2020 18:01:05 -0400 Subject: [PATCH 2/4] typos --- param/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/param/__init__.py b/param/__init__.py index a064a7c7c..87f6942c0 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -1676,7 +1676,6 @@ def _validate_dims_coords(self, val): def _validate_property(self, expected, property, name): - # if isinstance(expected, (list, set)): difference = set(expected) - set([str(el) for el in property]) if difference: msg = ('Provided DataArray {name} {found} do not contain ' @@ -1693,9 +1692,9 @@ def _validate_property(self, expected, property, name): 'exactly match {expected}') raise ValueError(msg.format( found=list(property), - expected=sorted(expected)), + expected=sorted(expected), name=name, - ) + )) def _coord_check(self, expected, coords): From b44c17ce60e556478776eb7f68ba7d49dc081c1a Mon Sep 17 00:00:00 2001 From: poplarShift Date: Wed, 29 Apr 2020 18:06:29 -0400 Subject: [PATCH 3/4] allow none --- param/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/param/__init__.py b/param/__init__.py index 87f6942c0..638c40e08 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -1729,6 +1729,9 @@ def __init__(self, default=None, dims=None, coords=None, **params): def _validate(self, val): + if self.allow_None and val is None: + return + super(DataArray, self)._validate(val) self._validate_dims_coords(val) @@ -1763,6 +1766,9 @@ def __init__(self, default=None, dims=None, coords=None, data_vars=None, def _validate(self, val): + if self.allow_None and val is None: + return + super(Dataset, self)._validate(val) self._validate_dims_coords(val) From 6ab5dc1186bf35cef471ff7a3984794741edc221 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 16 Jan 2023 17:34:03 +0100 Subject: [PATCH 4/4] Fix flakes --- param/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/param/__init__.py b/param/__init__.py index 638c40e08..83d4370c1 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -1670,7 +1670,7 @@ def _validate_dims_coords(self, val): if self.coords is not None: self._validate_property(self.coords, list(val.coords), - 'coordinates') + 'coordinates') if isinstance(self.coords, dict): self._coord_check(self.coords, val.coords) @@ -1768,14 +1768,14 @@ def __init__(self, default=None, dims=None, coords=None, data_vars=None, def _validate(self, val): if self.allow_None and val is None: return - + super(Dataset, self)._validate(val) self._validate_dims_coords(val) if self.data_vars is not None: self._validate_property(self.data_vars, val.data_vars, - 'data variables') + 'data variables') # For portable code: