-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change Parameter capabilities to allow new subsetting options (#85)
* Updated to work with new interval and series parameters * Updated parameters. * Got series working for time and level * Added TimeComponentsParameter: - for selecting date/times by specific components, such as: - year: 2000, 2001 - month: "feb", "mar" - day: 28, 29, 30 - hour 6 - it will allow subsetting/filtering in clisops/daops/rook * Added a test * Updated parameter parsing if class instance provided * Updated `.asdict()` method on TimeComponentsParameter. * Added `get_bounds()` method to TimeParameter. * Updated import in time_parameter.py * Linted * Updated CollectionParameter to take FileMapper as input * Updated: open_xr_dataset * Updated: open_xr_dataset - now ensures time.encoding["units"] is preserved. * Updated open_xr_dataset * Updated arg management in: open_xr_dataset * Updated HISTORY.rst * Updated inspection of xr.open_dataset kwargs * adjust error message to include FileMapper * use AnyCalendarDateTime to parse datetimes * update behaviour when dt is none * extended time and level parameter for string input * fixed import for daops * added time parameter get_bounds tests * update tests * update tests * added get_bounds for time_components_parameter * black * updated get_bounds (non 360 day calendar) * update time parameter end value * update get_bounds tests * Updated to ensure branch `fix-time-encoding-for-mfdataset` is merged * Updated HISTORY.rst * linting * make small changes to prepare for release * update history Co-authored-by: Eleanor Smith <esmith88@sci4.jasmin.ac.uk> Co-authored-by: Carsten Ehbrecht <ehbrecht@dkrz.de> Co-authored-by: MacPingu <cehbrecht@users.noreply.github.com> Co-authored-by: ellesmith88 <e.s.smith@hotmail.co.uk> Co-authored-by: Elle Smith <40183561+ellesmith88@users.noreply.github.com>
- Loading branch information
1 parent
62fb87c
commit 053eb57
Showing
23 changed files
with
1,122 additions
and
394 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,93 @@ | ||
from collections.abc import Sequence | ||
from pydoc import locate | ||
|
||
from roocs_utils.exceptions import InvalidParameterValue | ||
from roocs_utils.exceptions import MissingParameterValue | ||
from roocs_utils.utils.file_utils import FileMapper | ||
from roocs_utils.parameter.param_utils import interval, series | ||
|
||
|
||
class _BaseParameter(object): | ||
""" | ||
Base class for parameters used in operations (e.g. subset, average etc.) | ||
""" | ||
|
||
parser_method = "UNDEFINED" | ||
allowed_input_types = None | ||
|
||
def __init__(self, input): | ||
self.input = input | ||
self._result = self._parse() | ||
self._validate() | ||
|
||
def _validate(self): | ||
raise NotImplementedError | ||
|
||
@property | ||
def raw(self): | ||
return self.input | ||
|
||
def _parse(self): | ||
self.input = self.raw = input | ||
|
||
# If the input is already an instance of this class, call its parse method | ||
if isinstance(self.input, self.__class__): | ||
return self.input._parse() | ||
|
||
self.value = self.input.value | ||
self.type = getattr(self.input, "type", "undefined") | ||
else: | ||
return getattr(self, self.parse_method)() | ||
|
||
def _parse_range(self): | ||
if self.input in ("/", None, ""): | ||
start = None | ||
end = None | ||
|
||
elif isinstance(self.input, str): | ||
if "/" not in self.input: | ||
raise InvalidParameterValue( | ||
f"{self.__class__.__name__} should be passed in as a range separated by /" | ||
) | ||
self._check_input_type() | ||
self.value = self._parse() | ||
|
||
# empty string either side of '/' is converted to None | ||
start, end = [x.strip() or None for x in self.input.split("/")] | ||
def _check_input_type(self): | ||
if not self.allowed_input_types: | ||
return | ||
if not isinstance(self.input, tuple(self.allowed_input_types)): | ||
raise InvalidParameterValue( | ||
f"Input type of {type(self.input)} not allowed. " | ||
f"Must be one of: {self.allowed_input_types}" | ||
) | ||
|
||
elif isinstance(self.input, Sequence): | ||
if len(self.input) != 2: | ||
raise InvalidParameterValue( | ||
f"{self.__class__.__name__} should be a range. Expected 2 values, " | ||
f"received {len(self.input)}" | ||
) | ||
def _parse(self): | ||
raise NotImplementedError | ||
|
||
start, end = self.input | ||
def get_bounds(self): | ||
"""Returns a tuple of the (start, end) times, calculated from | ||
the value of the parameter. Either will default to None.""" | ||
raise NotImplementedError | ||
|
||
else: | ||
raise InvalidParameterValue( | ||
f"{self.__class__.__name__} is not in an accepted format" | ||
) | ||
return start, end | ||
def __str__(self): | ||
raise NotImplementedError | ||
|
||
def _parse_sequence(self): | ||
def __repr__(self): | ||
return str(self) | ||
|
||
if self.input in (None, ""): | ||
sequence = None | ||
def __unicode__(self): | ||
return str(self) | ||
|
||
# check str or bytes | ||
elif isinstance(self.input, (str, bytes)): | ||
sequence = [x.strip() for x in self.input.split(",")] | ||
|
||
elif isinstance(self.input, FileMapper): | ||
return [self.input] | ||
class _BaseIntervalOrSeriesParameter(_BaseParameter): | ||
""" | ||
A base class for a parameter that can be instantiated from either and | ||
`Interval` or `Series` class instance. It has a `type` and a `value` | ||
reflecting the type. E.g.: | ||
type: "interval" --> value: (start, end) | ||
type: "series" --> value: [item1, item2, ..., item_n] | ||
""" | ||
|
||
elif isinstance(self.input, Sequence): | ||
sequence = self.input | ||
allowed_input_types = [interval, series, type(None), type("")] | ||
|
||
else: | ||
raise InvalidParameterValue( | ||
f"{self.__class__.__name__} is not in an accepted format" | ||
) | ||
def _parse(self): | ||
|
||
return sequence | ||
if isinstance(self.input, interval): | ||
self.type = "interval" | ||
return self._parse_as_interval() | ||
elif isinstance(self.input, series): | ||
self.type = "series" | ||
return self._parse_as_series() | ||
elif isinstance(self.input, type(None)): | ||
self.type = "none" | ||
return None | ||
elif isinstance(self.input, type("")): | ||
if "/" in self.input: | ||
self.type = "interval" | ||
self.input = interval(self.input) | ||
return self._parse_as_interval() | ||
else: | ||
self.type = "series" | ||
self.input = series(self.input) | ||
return self._parse_as_series() | ||
|
||
def _parse_as_interval(self): | ||
raise NotImplementedError | ||
|
||
def __str__(self): | ||
def _parse_as_series(self): | ||
raise NotImplementedError | ||
|
||
def __repr__(self): | ||
return str(self) | ||
def _value_as_tuple(self): | ||
value = self.value | ||
if value is None: | ||
value = None, None | ||
|
||
def __unicode__(self): | ||
return str(self) | ||
return value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.