I trigger di Bag

Le Bag sono dotate anche di un sistema di trigger, ovvero una parte di logica che gestisce l’invio e ricezione di eventi di notifica quando dei dati vengono scritti o modificati all’interno della Bag ad un dato path Questo sistema di trigger è basato sul concetto di subscription ovvero un collegamento tra un tipo di evento (update, insert, delete) ad un preciso path con una funzione di callback da invocare.

I trigger possono essere definiti sia a livello di Bag he di BagNode usando in entrambi i casi il metodo subscribe Anche se si chiamano nello stesso modo hanno due signature differenti.

  • Bag.subscribe(update=callback1, insert=callback2, delete=callback3, any=callback4)

  • BagNode.subscribe(updval=callback1, updattr=callback2)

Il metodo subscribe

La subscription di un tipo di evento significa che ogni volta che quell’evento avviene, una notifica viene propagata per tutti i livelli della bag e il gestore degli eventi provvederà ad invocare tutte le chiamate di callback interessate.

>>> family = Bag()
>>> family['Walt'] = Bag()
>>> walt = family['Walt']
>>> walt['children'] = Bag()
>>> walt['children.Mickey.weight'] = 32
>>> walt['children.Mickey.height'] = 53
>>> walt['children.Donald.height'] = 51

Ora definiamo delle funzioni di callback dette anche eventhandler.

def onUpdate(node=None, pathlist=None, oldvalue=None, evt=None, **kwargs):
     if evt=='upd_value':
         print """My node at path: %s\n has been updated. Value
         changed from %s to %s \n""" %('.'.join(pathlist), oldvalue, node.getValue())
     if evt=='upd_attrs':
         print 'My node at path: %s\n has been updated. attributes changed\n'

 def onDelete(node=None, pathlist=None, ind=None, **kwargs):
     print 'My node %s at path: %s\n has been deleted from position %i.\n' %(node.getLabel(), '.'.join(pathlist), ind)

 def onInsert(node=None, pathlist=None, **kwargs):
     print 'A new node has been inserted at path: %s \n' %('.'.join(pathlist))

Una funzione eventhandler deve ricevere i seguenti parametri

Parameter

Type

Description

node

BagNode

Il nodo inserted/deleted/updated

pathlist

list

Include the Bag subscribed’s path linked to the node where the event was catched

oldvalue

any

Negli updates il precedente valore del nodo

ind

int

La posizione (index) del valore inserito o cancellato

evt

string

Event type: insert, delete, upd_value, upd_attrs

Adesso usiamo il metodo subscribe per mettere insieme gli eventi ai metodi eventhandler

>>> family.subscribe(update=onUpdate, insert=onInsert, delete=onDelete)
>>> walt['children.Mickey.weight']=36
My node at path: Walt.children.Mickey.weight
has been updated. Value changed from 32 to 36
>>> walt['children.Donald.weight']=31
A new node has been inserted at path: Walt.children.Donald
>>> walt.delItem('children.Mickey.height')
My node height at path: walt.children.Mickey
has been deleted from position 2.

Possiamo aggiungere quante sottoscrizioni vogliamo per lo stesso evento

def onChange(node=None, evt=None, pathlist=None, **kwargs):
       print '%s on node %s at path %s'%(evt, node.getLabel(),('.'.join(pathlist) or 'nullpath'))
>>> family.subscribe(any=onBagEvent)

Il parametro»any» è equivalente ad impostare la stessa callback per tutti gli eventi. Ulteriori sottoscrizioni non vanno in override, questo significa che se per update assegno un’altra funzione ad ogni update vengono chiamate entrambe.

>>> walt['children.Mickey.weight']=37
My node at path: Walt.children.Mickey.weight
has been updated. Value changed from 32 to 37
update on node height at path Walt.children.Mickey.weight

Dal momento che un evento è propagato lungo tutti i livelli gerarchici della bag, può innescare chiamate da tutte le Bag sottoscritte.

def onNewChild(node=None, ind=None, **kwargs):
        print 'Greetings for %s, your son number %i \n' %(node.getLabel(), ind+1)

>>> walt['children'].subscribe(insert=onNewChild)
>>> walt['children.Goofy']=Bag()
Greetings for Goofy, your son number 3
A new node has been inserted at path: Walt.children
ins on node children at path Walt

All the trigger functions are executed at different levels, as the event is catched.

Unsubscribe Bag

E” possibile annullare una subscription con il metodo unsubscribe()

>>> Walt['children'].unsubscribe(insert=onNewChild)
>>> family.unsubscribe(insert=onInsert)

E così abbiamo eliminato la subscription agli eventi di inserimento.

Trigger su BagNode

I trigger sulle Bag assumono che ciascun nodo si debba comportare come gli altri e a volte questo non basta. Ecco perché è possibile fare una subscription anche a livello di BagNode ottenendo una maggiore granularità.

Dal momento che per aggiornamento di un nodo si può intendere sia di valore che di attributi è possibile specificare due diversi tipi di trigger

-upd_value: quando viene aggiornato il valore

-upd_attrs: quando vengono aggiornati gli attributi

def onValueChange(node, info=None, evt=None):
        if evt == 'upd_value':
            print 'My value is changed from %s to %s \n' %(info, node.getValue())
        if evt == 'upd_attrs':
            print 'My attributes: %s is/are changed \n' %(', '.join(info))



>>> Walt.getNode('children.Mickey.weight').subscribe(upd_value=onValueChange)
>>> Walt['children.Mickey.weight']=55
My value is changed from 36 to 55
My node at path: Walt.children.Mickey.weight
has been updated. Value changed from 36 to 55

Autore della sezione: Giovanni Porcari