Source code for httk.db.storable

#
#    The high-throughput toolkit (httk)
#    Copyright (C) 2012-2015 Rickard Armiento
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#from store.trivialstore import TrivialStore
import sys

from httk.db.filteredcollection import *
from httk.core import reraise_from

[docs]def storable_types(name, *keyvals, **flags): index = flags.pop('index', []) return {'name': name, 'keys': keyvals, 'keydict': dict(keyvals), 'index': index}
[docs]def storable_props(*props): return props
[docs]class TrivialStore(object): """ Very simple storage class that just stores everything into an individual dictionary, just like regular python objects work """
[docs] def new(self, table, types, keyvals): d = dict(keyvals) d['sid'] = 0 return d
[docs] def retrieve(self, table, types, sid): raise Exception("TrivialStore.instance: You cannot load data from TrivialStore, sid must be = None.")
[docs]class Storable(object): """ Superclass for handling various forms of data storage, retreival, etc. Class object representing data should inherit from Storable. All public variables must be initalized in a call to storable_init() inside __init__(). Other member variables are OK, but must begin with '_', and all methods must handle these variables not being initialized. For private variables that needs to be preserved: let them start with '_' AND declare them in storable_init(). """ trivialstore = TrivialStore() # The store class used if no store is specified, store things in the usual dictionary way _storable_tables = [] def __init__(self, types=None, index=None): self.__dict__['types'] = types self.__dict__['index'] = index
[docs] def storable_init(self, store, updatesid=None, **keyvals): """ All Storable objects need to call this method in __init__(). Name should be a 'somewhat qualified' class name. """ if store is None: store = Storable.trivialstore if keyvals: self.__dict__['store'] = store.new(self.types['name'], self.types, keyvals, updatesid=updatesid) else: self.__dict__['store'] = store.new(self.types['name'], self.types, None, updatesid=updatesid) self.__dict__['store_keys'] = keyvals.keys()
# @classmethod # def instantiate_from_store(cls,store,sid): # """ # Instantiate the storable object from the data in the store # """ # name = cls.types['name'] # obj = cls.__new__(cls) # Creates a new object, avoids calling __init__ # obj.__dict__['store'] = store.retrieve(name,cls.types, sid) # return obj def __getattr__(self, name): #if name in self.__class__.types[2]: # return getattr(self.__class__,name) if name[0] == '_': try: return self.__dict__[name] except KeyError: info = sys.exc_info() reraise_from(AttributeError, "KeyError when accessing local dict: "+str(info[1]), info) return self.store[name] def __setattr__(self, name, val): if name in self.store_keys: self.store[name] = val elif name[0] == '_': self.__dict__[name] = val else: raise Exception("The class "+self.__class__+" inherits from Storable. Hence, all public variables must be " + "declared in a call to self.storable_init, and non-public variables must start with an underscore (_). " + "Offending variable name: "+name)
[docs] @classmethod def variable(cls, searcher, name, types, outid=None, parent=None): # The empty new triggers an e.g., create_table. I'm not sure it really should be here, but it is tricky to get the order correct when # bootstapping new tables, and by placing this here, one can just simply make a query into the non-existent table, discover # that some data is missing, and insert it into the newly created table. #print(searcher.variable()) raise Exception("Internal error.") searcher.store.new(types['name'], types) if outid is None: outid = name+"_"+str(len(cls._storable_tables)) table = TableOrColumn(searcher, types['name'], parent=parent, outid=outid, indirection=1, classref=cls) return table
[docs] @classmethod def find_all(cls, obj, store, member, value, types): """ Convinience method to do a very simple search of type: find all entries where member = value. """ search = store.searcher() p = search.variable(obj.__class__) #print("XXXXXXXXXX",obj.__class__) search.add(p.__getattr__(member) == value) search.output(p, 'object') results = list(search) if len(results) > 0: return results[0] else: return []
[docs] @classmethod def find_one(cls, obj, store, member, value, types): """ Convinience^2 method to do a very simple search of type: find one entry where member = value. """ allresults = cls.find_all(store, obj, member, value, types) if len(allresults) >= 1: return allresults[0][0] return None
def _sql(self): return str(self.store.sid)