Example #1
0
class TestAdvancedBag(unittest.TestCase):
    def setUp(self):
        self.bag = Bag()
        self.bag.setBackRef()
        self.bag["a.b.c.d"] = 4
        self.bag["a.b.e"] = 5

    def testparent(self):
        self.assertEqual(self.bag["a.b.c"].parent, self.bag["a.b"])
        c = self.bag["a.b.c"]
        self.assertEqual(c["../e"], 5)
        self.bag["a.b"].delParentRef()
        self.assertFalse(self.bag["a.b"].backref)

    def testformula(self):
        self.bag["product"] = self.bag.formula("$x*$y", x="a.b.c.d", y="a.b.e")
        self.assertEqual(self.bag["product"], self.bag["a.b.c.d"] * self.bag["a.b.e"])

        self.bag.defineFormula(calculate_perimeter="2*($base + $height)")
        self.bag.defineSymbol(base="a.b.c.d", height="a.b.e")
        self.bag["perimeter"] = self.bag.formula("calculate_perimeter")
        self.assertEqual(self.bag["perimeter"], 18)

    def testcallbackitem(self):
        def hello():
            return "Hello!"

        self.bag.setCallBackItem("say_hello", hello)
        self.assertEqual(self.bag["say_hello"], hello())

    def testnodetrigger(self):
        self.lastupdates = []

        def mycallback(node, info=None, evt=None):
            self.lastupdates.append((node.getLabel(), info, node.getValue()))

        self.bag.getNode("a.b.c.d").subscribe("lastupdates", mycallback)
        self.bag["a.b.c.d"] = 20
        self.assertEqual(self.lastupdates[-1], ("d", 4, 20))

    def testbagtriggers(self):
        self.log = []

        def log_upd(node, pathlist, oldvalue, evt):
            self.log.append((".".join(pathlist), node.getValue(), oldvalue, evt))

        def log_ins(node, pathlist, ind, evt):
            self.log.append((".".join(pathlist), node.getValue(), ind, evt))

        def log_del(node, pathlist, ind, evt):
            self.log.append((".".join(pathlist), node.getValue(), ind, evt))

        self.bag.subscribe("log", update=log_upd, insert=log_ins, delete=log_del)
        self.bag["a.b.t"] = 45
        self.assertEqual(self.log[-1], ("a.b", 45, 2, "ins"))
        self.bag["a.b.t"] = 56
        self.assertEqual(self.log[-1], ("a.b.t", 56, 45, "upd_value"))
        self.bag.delItem("a.b.t")
        self.assertEqual(self.log[-1], ("a.b", 56, 2, "del"))
Example #2
0
 def addRegisterItem(self,register_item,data=None):
     register_item_id = register_item['register_item_id']
     self.registerItems[register_item_id] = register_item
     register_item['datachanges'] = list()
     register_item['datachanges_idx'] = 0
     register_item['subscribed_paths'] = set()
     data = Bag(data)
     data.subscribe('datachanges', any=lambda **kwargs:  self._on_data_trigger(register_item=register_item,**kwargs))
     self.itemsData[register_item_id] = data
Example #3
0
 def register_item(self):
     if self._register_item != '*':
         return self._register_item
     self._register_item = register_item = self.parent.read(self.register_item_id)
     if not register_item:
         return
     data = register_item.get('data')
     if data is None:
         data = Bag()
         register_item['data'] = data
         register_item['datachanges'] = list()
         register_item['datachanges_idx'] = 0
         register_item['subscribed_paths'] = set()
     if self.triggered and register_item['subscribed_paths']:
         data.subscribe('datachanges', any=self._on_data_trigger)
     return register_item
Example #4
0
 def register_item(self):
     if self._register_item != '*':
         return self._register_item
     self._register_item = register_item = self.parent.read(
         self.register_item_id)
     if not register_item:
         return
     data = register_item.get('data')
     if data is None:
         data = Bag()
         register_item['data'] = data
         register_item['datachanges'] = list()
         register_item['datachanges_idx'] = 0
         register_item['subscribed_paths'] = set()
     if self.triggered and register_item['subscribed_paths']:
         data.subscribe('datachanges', any=self._on_data_trigger)
     return register_item
Example #5
0
class TestAdvancedBag(unittest.TestCase):
    def setUp(self):
        self.bag = Bag()
        self.bag.setBackRef()
        self.bag['a.b.c.d'] = 4
        self.bag['a.b.e'] = 5

    def testparent(self):
        self.assertEqual(self.bag['a.b.c'].parent, self.bag['a.b'])
        c = self.bag['a.b.c']
        self.assertEqual(c['../e'], 5)
        self.bag['a.b'].delParentRef()
        self.assertFalse(self.bag['a.b'].backref)

    def testformula(self):
        self.bag['product'] = self.bag.formula('$x*$y', x='a.b.c.d', y='a.b.e')
        self.assertEqual(self.bag['product'],
                         self.bag['a.b.c.d'] * self.bag['a.b.e'])

        self.bag.defineFormula(calculate_perimeter='2*($base + $height)')
        self.bag.defineSymbol(base='a.b.c.d', height='a.b.e')
        self.bag['perimeter'] = self.bag.formula('calculate_perimeter')
        self.assertEqual(self.bag['perimeter'], 18)

    def testcallbackitem(self):
        def hello():
            return 'Hello!'

        self.bag.setCallBackItem('say_hello', hello)
        self.assertEqual(self.bag['say_hello'], hello())

    def testnodetrigger(self):
        self.lastupdates = []

        def mycallback(node, info=None, evt=None):
            self.lastupdates.append((node.getLabel(), info, node.getValue()))

        self.bag.getNode('a.b.c.d').subscribe('lastupdates', mycallback)
        self.bag['a.b.c.d'] = 20
        self.assertEqual(self.lastupdates[-1], ('d', 4, 20))

    def testbagtriggers(self):
        self.log = []

        def log_upd(node, pathlist, oldvalue, evt):
            self.log.append(
                ('.'.join(pathlist), node.getValue(), oldvalue, evt))

        def log_ins(node, pathlist, ind, evt):
            self.log.append(('.'.join(pathlist), node.getValue(), ind, evt))

        def log_del(node, pathlist, ind, evt):
            self.log.append(('.'.join(pathlist), node.getValue(), ind, evt))

        self.bag.subscribe('log',
                           update=log_upd,
                           insert=log_ins,
                           delete=log_del)
        self.bag['a.b.t'] = 45
        self.assertEqual(self.log[-1], ('a.b', 45, 2, 'ins'))
        self.bag['a.b.t'] = 56
        self.assertEqual(self.log[-1], ('a.b.t', 56, 45, 'upd_value'))
        self.bag.delItem('a.b.t')
        self.assertEqual(self.log[-1], ('a.b', 56, 2, 'del'))
Example #6
0
class SharedObject(object):
    default_savedir = 'site:async/sharedobjects'
    def __init__(self,manager,shared_id,expire=None,startData=None,read_tags=None,write_tags=None,
                    filepath=None, dbSaveKw=None, saveInterval=None, autoSave=None, autoLoad=None,**kwargs):

        self.manager = manager
        self.lock=locks.Lock()
        self.server = manager.server
        self.shared_id = shared_id
        self._data = Bag(dict(root=Bag(startData)))
        self.read_tags = read_tags
        self.write_tags = write_tags
        self._data.subscribe('datachanges', any=self._on_data_trigger)
        self.subscribed_pages = dict()
        self.expire = expire or 0
        self.focusedPaths = {}
        if self.expire<0:
            self.expire = 365*24*60*60
        self.timeout=None
        self.autoSave=autoSave
        self.saveInterval=saveInterval
        self.autoLoad=autoLoad
        self.changes=False
        self.dbSaveKw=dbSaveKw
        self.onInit(**kwargs)


    @property
    def savepath(self):
        return self.server.gnrsite.getStaticPath(self.default_savedir,'%s.xml' %self.shared_id)

    @property
    def data(self):
        return self._data['root']

    @property
    def sql_data_column(self):
        return self.dbSaveKw.get('data_column') or 'shared_data'

    @property
    def sql_backup_column(self):
        return self.dbSaveKw.get('backup_column') or 'shared_backup'


    @lockedThreadpool
    def save(self):
        if self.changes :
            if self.dbSaveKw:
                kw = dict(self.dbSaveKw)
                tblobj = self.server.db.table(kw.pop('table'))
                handler = getattr(tblobj, 'saveSharedObject', None)
                if handler:
                    handler(self.shared_id, self.data, **kw)
                else:
                    self.sql_save(tblobj)
                self.server.db.commit()
            else:
                self.data.toXml(self.savepath,unresolved=True,autocreate=True)
        self.changes=False

    @lockedThreadpool
    def load(self):
        if self.dbSaveKw:
            tblobj = self.server.db.table(self.dbSaveKw['table'])
            handler = getattr(tblobj, 'loadSharedObject', None)
            if handler:
                data = handler(self.shared_id)
            else:
                data = self.sql_load(tblobj)
        elif os.path.exists(self.savepath):
            data =  Bag(self.savepath)
        else:
            data = Bag()
        self._data['root'] = data
        self.changes=False

    def sql_save(self, tblobj):
        backup = self.dbSaveKw.get('backup')
        data_column = self.sql_data_column
        with tblobj.recordToUpdate(self.shared_id) as record:
            if not self.data:
                print 'NO DATA IN SAVING', self.shared_id
            record[data_column] = deepcopy(self.data)
            onSavingHandler=getattr(tblobj, 'shared_onSaving',None)
            if onSavingHandler:
                onSavingHandler(record)

            if backup:
                backup_column = self.sql_backup_column
                if not record[backup_column]:
                    record[backup_column] =  Bag()
                    n = 0
                else:
                    n = int(record[backup_column].keys()[-1].split('_')[1])+1
                record[backup_column].setItem('v_%s' % n, record[data_column], ts=datetime.now())
                if len (record[backup_column]) > backup:
                    record[backup_column].popNode('#0')
            

    def sql_load(self, tblobj, version=None):
        record = tblobj.record(self.shared_id).output('bag')
        onLoadingHandler=getattr(tblobj, 'shared_onLoading',None)
        if onLoadingHandler:
            onLoadingHandler(record)

        if not version:
            return record[self.sql_data_column]
        else:
            return record[self.sql_backup_column].getItem('v_%i'% version)



    def onInit(self,**kwargs):
        if self.autoLoad:
            self.load()
        
    def onSubscribePage(self,page_id):
        pass
        #print 'onSubscribePage',self.shared_id,page_id
        
    def onUnsubscribePage(self,page_id):
        pass
        #print 'onUnsubscribePage',self.shared_id,page_id
    
    def onDestroy(self):
        print 'onDestroy',self.shared_id
        if self.autoSave:
            self.save()
        
        
    def onShutdown(self):
        if self.autoSave:
            self.save()
            
    def subscribe(self,page_id=None,**kwargs):
        page = self.server.pages[page_id]
        privilege= self.checkPermission(page)
        if privilege:
            page.sharedObjects.add(self.shared_id)
            subkwargs=dict(kwargs)
            subkwargs['page_id']=page_id
            subkwargs['user']=page.user
            self.subscribed_pages[page_id] = subkwargs
            self.server.sharedStatus.sharedObjectSubscriptionAddPage(self.shared_id,page_id,subkwargs)
            self.onSubscribePage(page)
            result=dict(privilege=privilege,data=self.data)
            return result

    def unsubscribe(self,page_id=None):
        self.subscribed_pages.pop(page_id,None)
        self.server.sharedStatus.sharedObjectSubscriptionRemovePage(self.shared_id,page_id)
        self.onUnsubscribePage(page_id)
        if not self.subscribed_pages:
            self.timeout=self.server.delayedCall(self.expire,self.manager.removeSharedObject,self)
            
    def checkPermission(self,page):
        privilege = 'readwrite' 
        if self.read_tags and not self.server.gnrapp.checkResourcePermission(self.read_tags,page.userTags):
            privilege = None
        elif self.write_tags and not self.server.gnrapp.checkResourcePermission(self.write_tags,page.userTags):
            privilege = 'readonly'
        return privilege
    
    @lockedCoroutine
    def datachange(self,page_id=None,path=None,value=None,attr=None,evt=None,fired=None,**kwargs):
        if fired:
            data = Bag(dict(value=value,attr=attr,path=path,shared_id=self.shared_id,evt=evt,fired=fired))
            self.broadcast(command='som.sharedObjectChange',data=data,from_page_id=page_id)
        else:
            path = 'root' if not path else 'root.%s' %path
            if evt=='del':
                self._data.popNode(path,_reason=page_id)
            else:
                self._data.setItem(path,value,_attributes=attr,_reason=page_id)

    def _on_data_trigger(self, node=None, ind=None, evt=None, pathlist=None,reason=None, **kwargs):
        self.changes=True
        if reason=='autocreate':
            return
        plist = pathlist[1:]
        if evt=='ins' or evt=='del':
            plist = plist+[node.label]
        path = '.'.join(plist)
        data = Bag(dict(value=node.value,attr=node.attr,path=path,shared_id=self.shared_id,evt=evt))
        from_page_id = reason
        self.broadcast(command='som.sharedObjectChange',data=data,from_page_id=from_page_id)

                
    def onPathFocus(self, page_id=None,curr_path=None,focused=None):
        if focused:
            self.focusedPaths[curr_path]=page_id
        else:
            self.focusedPaths.pop(curr_path,None)
        self.broadcast(command='som.onPathLock',from_page_id=page_id,data=Bag(dict(locked=focused,lock_path=curr_path)))

    
    def broadcast(self,command=None, data=None, from_page_id=None,):
        envelope = Bag(dict(command=command,data=data)).toXml()
        channels = self.server.channels
        for p in self.subscribed_pages.keys():
            if p != from_page_id:
                channels.get(p).write_message(envelope)