From 9beca4deefeb44a9b29d5a32ec139e939fb15f2c Mon Sep 17 00:00:00 2001 From: al-niessner <1130658+al-niessner@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:51:15 -0800 Subject: [PATCH] Issue 213: make db.reset() explicit (#222) * add prototype While the method was being used by dawige.db.view() there was no prototype that identified its existence. Added it with basic comments. * implementation for shelve While dawgie.db.post already implemented dawgie.db.reset(), needed dawgie.db.shelve to do the same thing. * test dawgie.db.reset() Both dawgie.db.post and dawgie.db.shelve behave the same. --- Python/dawgie/db/__init__.py | 17 ++++++++++++++- Python/dawgie/db/shelve/__init__.py | 25 +++++++++++++++++++-- Python/dawgie/db/shelve/util.py | 21 +++++++++++++----- Test/test_13.py | 34 +++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/Python/dawgie/db/__init__.py b/Python/dawgie/db/__init__.py index 8a6e77a1..ddd877ca 100644 --- a/Python/dawgie/db/__init__.py +++ b/Python/dawgie/db/__init__.py @@ -165,6 +165,21 @@ def reopen()->bool: ''' return _db_in_use().reopen() +def reset (runid:int, tn:str, tskn:str, alg:dawgie.Algorithm): + '''Reset the algorithm version + + The version of the algorithm may be different than the one recorded for + the given runID. The reset() alters the version of the algorithm to match + that recorded with the given runID. + + This reset then descends down into state vectors and values doing the same + version reset. + + Once the objects have the correct versions, the rest of the database calls + can be used to look up their correct content. + ''' + return _db_in_use().reset (runid, tn, tskn, alg) + def retreat (reg, ret)->dawgie.Timeline: '''Get a dawgie.Timeline from the database backend @@ -264,7 +279,7 @@ def view (visitor, runid, tn, tskn, algn, svn): visitor.add_declaration (msg) return - _db_in_use().reset (runid, tn, tskn, alg) # set the alg version + reset (runid, tn, tskn, alg) # set the alg version ds = connect (alg, bot, tn) ds.load() diff --git a/Python/dawgie/db/shelve/__init__.py b/Python/dawgie/db/shelve/__init__.py index 482d221f..74f3f66f 100644 --- a/Python/dawgie/db/shelve/__init__.py +++ b/Python/dawgie/db/shelve/__init__.py @@ -304,8 +304,29 @@ def reopen()->bool: ''' return DBI().reopen() -def reset (_runid:int, _tn:str, _tskn, _alg)->None: - log.warning('reset() is not implemented for shelve') +def reset (runid:int, tn:str, tskn, alg)->None: + # Need to set the version value which is a private function + # so, pylint: disable=protected-access + if not DBI().is_open: raise RuntimeError('called next before open') + if DBI().is_reopened: raise RuntimeError('called outside of Foreman context') + + pk = [runid, DBI().tables.target[tn], DBI().tables.task[tskn]] + ptab = util.subset (DBI().tables.prime, str(tuple(pk)).replace (')', ',')) + for algi in util.subset (DBI().tables.alg, alg.name(), [pk[-1]]).values(): + tab = util.subset(DBI().tables.prime, + str(tuple(pk + [algi])).replace (')', ',')) + if tab: + ptab = tab + break + pass + for pk in util.prime_keys(ptab): + aid,svid = pk[-3:-1] + alg._set_ver (util.dissect(DBI().indices.alg[aid])[-1]._get_ver()) + svn,ver = util.dissect(DBI().indices.state[svid])[1:] + if svn in alg.sv_as_dict(): + alg.sv_as_dict()[svn]._set_ver(ver._get_ver()) + pass + pass return def retreat (reg, ret)->dawgie.Timeline: diff --git a/Python/dawgie/db/shelve/util.py b/Python/dawgie/db/shelve/util.py index 2b19266d..33b36e03 100644 --- a/Python/dawgie/db/shelve/util.py +++ b/Python/dawgie/db/shelve/util.py @@ -118,12 +118,23 @@ def rotated_files(index=None): orig += glob.glob(f"{path}/{index:d}.{dawgie.context.db_name}.value") return orig -def subset (from_table:{str:int}, name:str, parents:[int])->{}: - '''extract a subset of table as a dictionary''' +def subset (from_table:{str:int}, name:str, parents:[int]=None)->{}: + '''extract a subset of table as a dictionary + + It behaves two different ways. If parnets is provided, then it will use + util.construct() to generate the full name given the parents. If parents is + not given, then it will simply use name. + ''' result = {} - for parent in parents: - surname = construct (name, parent) - result.update (dict(filter(lambda t,sn=surname:t[0].startswith (sn), + if parents: + for parent in parents: + surname = construct (name, parent) + result.update (dict(filter(lambda t,sn=surname:t[0].startswith (sn), + from_table.items()))) + pass + pass + else: + result.update (dict(filter(lambda t,sn=name:t[0].startswith (sn), from_table.items()))) pass return result diff --git a/Test/test_13.py b/Test/test_13.py index 6d96c56b..acd14e03 100644 --- a/Test/test_13.py +++ b/Test/test_13.py @@ -291,6 +291,40 @@ def test_reopen(self): self.assertFalse(True) return + def test_reset(self): + tgt,tsk,alg = dawgie.db.testdata.DATASETS[-1] + print (tgt, tsk._name(), alg.name()) + alg._set_ver(dawgie.VERSION(100,100,100)) + for sv in alg.state_vectors(): + sv._set_ver(dawgie.VERSION(200,200,200)) + for val in sv.values(): + val._set_ver(dawgie.VERSION(400,500,600)) + pass + pass + print (type(alg.design()),alg.design()) + dawgie.db.close() + self.assertRaises (RuntimeError, dawgie.db.reset, + dawgie.db.testdata.RUNID, tgt, tsk._name(), alg) + dawgie.db.open() + dawgie.db.reset (dawgie.db.testdata.RUNID, tgt, tsk._name(), alg) + dawgie.db.close() + print (type(alg.design()),alg.design()) + self.assertEqual (alg.design(), 1, 'design') + self.assertEqual (alg.implementation(), 1, 'implementation') + self.assertEqual (alg.bugfix(), 2, 'bugfix') + for sv in alg.state_vectors(): + self.assertEqual (sv.design(), 1, 'design') + self.assertEqual (sv.implementation(), 2, 'implementation') + self.assertEqual (sv.bugfix(), 3, 'bugfix') + # these should not have changed + for val in sv.values(): + self.assertEqual (val.design(), 400, 'design') + self.assertEqual (val.implementation(), 500, 'implementation') + self.assertEqual (val.bugfix(), 600, 'bugfix') + pass + pass + return + def test_retreat(self): ret,reg = dawgie.db.testdata.TIMELINES[0] dawgie.db.close()