From a77b63718c1f8f5d67de7a4e4b05b928de7a6a19 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 4 Mar 2022 20:00:33 +0100 Subject: [PATCH 1/3] remove deprecated interface options --- python/damask/_result.py | 65 ++++++++++++------------------------- python/tests/test_Result.py | 24 ++++++-------- 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 820e5d09f..2bd832aad 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -4,7 +4,6 @@ import fnmatch import os import copy import datetime -import warnings import xml.etree.ElementTree as ET # noqa import xml.dom.minidom from pathlib import Path @@ -28,12 +27,7 @@ h5py3 = h5py.__version__[0] == '3' chunk_size = 1024**2//8 # for compression in HDF5 -def _view_transition(what,datasets,increments,times,phases,homogenizations,fields): - if (datasets is not None and what is None) or (what is not None and datasets is None): - raise ValueError('"what" and "datasets" need to be used as a pair') - if datasets is not None or what is not None: - warnings.warn('arguments "what" and "datasets" will be removed in DAMASK v3.0.0-alpha7', DeprecationWarning,2) - return what,datasets +def _view_transition(increments,times,phases,homogenizations,fields): if sum(1 for _ in filter(None.__ne__, [increments,times,phases,homogenizations,fields])) > 1: raise ValueError('only one out of "increments", "times", "phases", "homogenizations", and "fields" can be used') else: @@ -213,14 +207,12 @@ class Result: choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \ [datasets] - what_ = what if what.endswith('s') else what+'s' - - if what_ == 'increments': + if what == 'increments': choice = [c if isinstance(c,str) and c.startswith('increment_') else self.increments[c] if isinstance(c,int) and c<0 else f'increment_{c}' for c in choice] - elif what_ == 'times': - what_ = 'increments' + elif what == 'times': + what = 'increments' if choice == ['*']: choice = self.increments else: @@ -234,18 +226,18 @@ class Result: elif np.isclose(c,self.times[idx+1]): choice.append(self.increments[idx+1]) - valid = _match(choice,getattr(self,what_)) - existing = set(self.visible[what_]) + valid = _match(choice,getattr(self,what)) + existing = set(self.visible[what]) dup = self.copy() if action == 'set': - dup.visible[what_] = sorted(set(valid), key=util.natural_sort) + dup.visible[what] = sorted(set(valid), key=util.natural_sort) elif action == 'add': add = existing.union(valid) - dup.visible[what_] = sorted(add, key=util.natural_sort) + dup.visible[what] = sorted(add, key=util.natural_sort) elif action == 'del': diff = existing.difference(valid) - dup.visible[what_] = sorted(diff, key=util.natural_sort) + dup.visible[what] = sorted(diff, key=util.natural_sort) return dup @@ -298,7 +290,7 @@ class Result: return selected - def view(self,what=None,datasets=None,*, + def view(self,*, increments=None, times=None, phases=None, @@ -313,11 +305,6 @@ class Result: Parameters ---------- - what : {'increments', 'times', 'phases', 'homogenizations', 'fields'} - Attribute to change. DEPRECATED. - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. DEPRECATED. - True is equivalent to '*', False is equivalent to []. increments: (list of) int, (list of) str, or bool, optional. Number(s) of increments to select. times: (list of) float, (list of) str, or bool, optional. @@ -351,24 +338,24 @@ class Result: >>> r_t10to40 = r.view(times=r.times_in_range(10.0,40.0)) """ - v = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) + v = _view_transition(increments,times,phases,homogenizations,fields) if protected is not None: if v is None: dup = self.copy() else: - what_,datasets_ = v - dup = self._manage_view('set',what_,datasets_) + what,datasets = v + dup = self._manage_view('set',what,datasets) if not protected: print(util.warn('Warning: Modification of existing datasets allowed!')) dup._protected = protected else: - what_,datasets_ = v - dup = self._manage_view('set',what_,datasets_) + what,datasets = v + dup = self._manage_view('set',what,datasets) return dup - def view_more(self,what=None,datasets=None,*, + def view_more(self,*, increments=None, times=None, phases=None, @@ -382,11 +369,6 @@ class Result: Parameters ---------- - what : {'increments', 'times', 'phases', 'homogenizations', 'fields'} - Attribute to change. DEPRECATED. - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. DEPRECATED. - True is equivalent to '*', False is equivalent to []. increments: (list of) int, (list of) str, or bool, optional. Number(s) of increments to select. times: (list of) float, (list of) str, or bool, optional. @@ -413,11 +395,11 @@ class Result: >>> r_first_and_last = r.first.view_more(increments=-1) """ - what_, datasets_ = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) - return self._manage_view('add',what_,datasets_) + what, datasets = _view_transition(increments,times,phases,homogenizations,fields) + return self._manage_view('add',what,datasets) - def view_less(self,what=None,datasets=None,*, + def view_less(self,*, increments=None, times=None, phases=None, @@ -431,11 +413,6 @@ class Result: Parameters ---------- - what : {'increments', 'times', 'phases', 'homogenizations', 'fields'} - Attribute to change. DEPRECATED. - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. DEPRECATED. - True is equivalent to '*', False is equivalent to []. increments: (list of) int, (list of) str, or bool, optional. Number(s) of increments to select. times: (list of) float, (list of) str, or bool, optional. @@ -461,8 +438,8 @@ class Result: >>> r_deformed = r_all.view_less(increments=0) """ - what_, datasets_ = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) - return self._manage_view('del',what_,datasets_) + what, datasets = _view_transition(increments,times,phases,homogenizations,fields) + return self._manage_view('del',what,datasets) def rename(self,name_src,name_dst): diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 18e09513f..9124cff99 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -69,8 +69,8 @@ class TestResult: @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations def test_view_none(self,default,what): - n0 = default.view(what,False) - n1 = default.view(what,[]) + n0 = default.view(**{what:False}) + n1 = default.view(**{what:[]}) label = 'increments' if what == 'times' else what @@ -79,29 +79,25 @@ class TestResult: @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations def test_view_more(self,default,what): - empty = default.view(what,False) + empty = default.view(**{what:False}) - a = empty.view_more(what,'*').get('F') - b = empty.view_more(what,True).get('F') + a = empty.view_more(**{what:'*'}).get('F') + b = empty.view_more(**{what:True}).get('F') assert dict_equal(a,b) @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations def test_view_less(self,default,what): - full = default.view(what,True) + full = default.view(**{what:True}) - n0 = full.view_less(what,'*') - n1 = full.view_less(what,True) + n0 = full.view_less(**{what:'*'}) + n1 = full.view_less(**{what:True}) label = 'increments' if what == 'times' else what assert n0.get('F') is n1.get('F') is None and \ len(n0.visible[label]) == len(n1.visible[label]) == 0 - def test_view_invalid(self,default): - with pytest.raises(AttributeError): - default.view('invalid',True) - def test_add_invalid(self,default): default.add_absolute('xxxx') @@ -469,7 +465,7 @@ class TestResult: def test_get(self,update,request,ref_path,view,output,flatten,prune): result = Result(ref_path/'4grains2x4x3_compressionY.hdf5') for key,value in view.items(): - result = result.view(key,value) + result = result.view(**{key:value}) fname = request.node.name cur = result.get(output,flatten,prune) @@ -494,7 +490,7 @@ class TestResult: def test_place(self,update,request,ref_path,view,output,flatten,prune,constituents): result = Result(ref_path/'4grains2x4x3_compressionY.hdf5') for key,value in view.items(): - result = result.view(key,value) + result = result.view(**{key:value}) fname = request.node.name cur = result.place(output,flatten,prune,constituents) From 20e056e26a20d07375a09976a137cf20a5be2e2d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Mar 2022 21:09:24 +0100 Subject: [PATCH 2/3] consistent interface also for internal functionality allows to change multiple 'what's at the same time --- python/damask/_result.py | 136 ++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 74 deletions(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 2bd832aad..0a1c1c825 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -27,16 +27,6 @@ h5py3 = h5py.__version__[0] == '3' chunk_size = 1024**2//8 # for compression in HDF5 -def _view_transition(increments,times,phases,homogenizations,fields): - if sum(1 for _ in filter(None.__ne__, [increments,times,phases,homogenizations,fields])) > 1: - raise ValueError('only one out of "increments", "times", "phases", "homogenizations", and "fields" can be used') - else: - if increments is not None: return "increments", increments - if times is not None: return "times", times - if phases is not None: return "phases", phases - if homogenizations is not None: return "homogenizations", homogenizations - if fields is not None: return "fields", fields - def _read(dataset): """Read a dataset and its metadata into a numpy.ndarray.""" metadata = {k:(v.decode() if not h5py3 and type(v) is bytes else v) for k,v in dataset.attrs.items()} @@ -179,7 +169,13 @@ class Result: return util.srepr([util.deemph(header)] + first + in_between + last) - def _manage_view(self,action,what,datasets): + def _manage_view(self, + action, + increments=None, + times=None, + phases=None, + homogenizations=None, + fields=None): """ Manages the visibility of the groups. @@ -187,11 +183,6 @@ class Result: ---------- action : str Select from 'set', 'add', and 'del'. - what : str - Attribute to change (must be from self.visible). - datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool - Name of datasets; supports '?' and '*' wildcards. - True is equivalent to '*', False is equivalent to []. Returns ------- @@ -199,45 +190,52 @@ class Result: Modified or new view on the DADF5 file. """ - # allow True/False and string arguments - if datasets is True: - datasets = '*' - elif datasets is False or datasets is None: - datasets = [] - choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \ - [datasets] - - if what == 'increments': - choice = [c if isinstance(c,str) and c.startswith('increment_') else - self.increments[c] if isinstance(c,int) and c<0 else - f'increment_{c}' for c in choice] - elif what == 'times': - what = 'increments' - if choice == ['*']: - choice = self.increments - else: - iterator = map(float,choice) - choice = [] - for c in iterator: - idx = np.searchsorted(self.times,c) - if idx >= len(self.times): continue - if np.isclose(c,self.times[idx]): - choice.append(self.increments[idx]) - elif np.isclose(c,self.times[idx+1]): - choice.append(self.increments[idx+1]) - - valid = _match(choice,getattr(self,what)) - existing = set(self.visible[what]) + if increments is not None and times is not None: + raise ValueError('cannot use "increments" and "times" at the same time to change view') dup = self.copy() - if action == 'set': - dup.visible[what] = sorted(set(valid), key=util.natural_sort) - elif action == 'add': - add = existing.union(valid) - dup.visible[what] = sorted(add, key=util.natural_sort) - elif action == 'del': - diff = existing.difference(valid) - dup.visible[what] = sorted(diff, key=util.natural_sort) + for what,datasets in zip(['increments','times','phases','homogenizations','fields'], + [ increments, times, phases, homogenizations, fields ]): + if datasets is None: + continue + # allow True/False and string arguments + elif datasets is True: + datasets = '*' + elif datasets is False: + datasets = [] + choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \ + [datasets] + + if what == 'increments': + choice = [c if isinstance(c,str) and c.startswith('increment_') else + self.increments[c] if isinstance(c,int) and c<0 else + f'increment_{c}' for c in choice] + elif what == 'times': + what = 'increments' + if choice == ['*']: + choice = self.increments + else: + iterator = map(float,choice) + choice = [] + for c in iterator: + idx = np.searchsorted(self.times,c) + if idx >= len(self.times): continue + if np.isclose(c,self.times[idx]): + choice.append(self.increments[idx]) + elif np.isclose(c,self.times[idx+1]): + choice.append(self.increments[idx+1]) + + valid = _match(choice,getattr(self,what)) + existing = set(self.visible[what]) + + if action == 'set': + dup.visible[what] = sorted(set(valid), key=util.natural_sort) + elif action == 'add': + add = existing.union(valid) + dup.visible[what] = sorted(add, key=util.natural_sort) + elif action == 'del': + diff = existing.difference(valid) + dup.visible[what] = sorted(diff, key=util.natural_sort) return dup @@ -291,12 +289,12 @@ class Result: def view(self,*, - increments=None, - times=None, - phases=None, - homogenizations=None, - fields=None, - protected=None): + increments=None, + times=None, + phases=None, + homogenizations=None, + fields=None, + protected=None): """ Set view. @@ -338,19 +336,11 @@ class Result: >>> r_t10to40 = r.view(times=r.times_in_range(10.0,40.0)) """ - v = _view_transition(increments,times,phases,homogenizations,fields) + dup = self._manage_view('set',increments,times,phases,homogenizations,fields) if protected is not None: - if v is None: - dup = self.copy() - else: - what,datasets = v - dup = self._manage_view('set',what,datasets) if not protected: print(util.warn('Warning: Modification of existing datasets allowed!')) dup._protected = protected - else: - what,datasets = v - dup = self._manage_view('set',what,datasets) return dup @@ -395,8 +385,7 @@ class Result: >>> r_first_and_last = r.first.view_more(increments=-1) """ - what, datasets = _view_transition(increments,times,phases,homogenizations,fields) - return self._manage_view('add',what,datasets) + return self._manage_view('add',increments,times,phases,homogenizations,fields) def view_less(self,*, @@ -438,8 +427,7 @@ class Result: >>> r_deformed = r_all.view_less(increments=0) """ - what, datasets = _view_transition(increments,times,phases,homogenizations,fields) - return self._manage_view('del',what,datasets) + return self._manage_view('del',increments,times,phases,homogenizations,fields) def rename(self,name_src,name_dst): @@ -1816,9 +1804,9 @@ class Result: d = obj.attrs['description'] if h5py3 else obj.attrs['description'].decode() if not Path(name).exists() or overwrite: with open(name,'w') as f_out: f_out.write(obj[0].decode()) - print(f"Exported {d} to '{name}'.") + print(f'Exported {d} to "{name}".') else: - print(f"'{name}' exists, {d} not exported.") + print(f'"{name}" exists, {d} not exported.') elif type(obj) == h5py.Group: os.makedirs(name, exist_ok=True) From 05541736a639dc2196e0766d4b0d45afdb0ed885 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 9 Mar 2022 15:18:18 +0100 Subject: [PATCH 3/3] clearer message --- python/damask/_result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_result.py b/python/damask/_result.py index 0a1c1c825..fb6ba2ae2 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -191,7 +191,7 @@ class Result: """ if increments is not None and times is not None: - raise ValueError('cannot use "increments" and "times" at the same time to change view') + raise ValueError('"increments" and "times" are mutually exclusive') dup = self.copy() for what,datasets in zip(['increments','times','phases','homogenizations','fields'],