Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tutorius/TProbe.py
diff options
context:
space:
mode:
Diffstat (limited to 'tutorius/TProbe.py')
-rw-r--r--tutorius/TProbe.py175
1 files changed, 93 insertions, 82 deletions
diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py
index 6c0883a..9d19f1b 100644
--- a/tutorius/TProbe.py
+++ b/tutorius/TProbe.py
@@ -1,4 +1,5 @@
import logging
+LOGGER = logging.getLogger("sugar.tutorius.TProbe")
import os
import gobject
@@ -26,25 +27,15 @@ import copy
-------------------- ----------
"""
+#TODO Add stub error handling for remote calls in the classes so that it will
+# be clearer how errors can be handled in the future.
+
class TProbe(dbus.service.Object):
""" Tutorius Probe
Defines an entry point for Tutorius into activities that allows
performing actions and registering events onto an activity via
a DBUS Interface.
-
- Exposes the following dbus methods:
- void registered(string service)
- string ping() -> status
- string install(string action) -> address
- void update(string address, string action_props)
- void uninstall(string address)
- string subscribe(string pickled_event) -> address
- void unsubscribe(string address)
-
- Exposes the following dbus Events:
- eventOccured(event):
-
"""
def __init__(self, activity_name, activity):
@@ -54,9 +45,9 @@ class TProbe(dbus.service.Object):
@param activity_name unique activity_id
@param activity activity reference, must be a gtk container
"""
- logging.debug("TProbe :: Creating TProbe for %s (%d)", activity_name, os.getpid())
- logging.debug("TProbe :: Current gobject context: %s", str(gobject.main_context_default()))
- logging.debug("TProbe :: Current gobject depth: %s", str(gobject.main_depth()))
+ LOGGER.debug("TProbe :: Creating TProbe for %s (%d)", activity_name, os.getpid())
+ LOGGER.debug("TProbe :: Current gobject context: %s", str(gobject.main_context_default()))
+ LOGGER.debug("TProbe :: Current gobject depth: %s", str(gobject.main_depth()))
# Moving the ObjectStore assignment here, in the meantime
# the reference to the activity shouldn't be share as a
# global variable but passed by the Probe to the objects
@@ -163,6 +154,9 @@ class TProbe(dbus.service.Object):
@param pickled_event string pickled EventFilter
@return string unique name of registered event
"""
+ #TODO Perform event unmapping once Tutorials use abstract events
+ # instead of concrete EventFilters that are tied to their
+ # implementation.
eventfilter = pickle.loads(str(pickled_event))
# The callback uses the event defined previously and each
@@ -200,14 +194,8 @@ class TProbe(dbus.service.Object):
# The actual method we will call on the probe to send events
def notify(self, event):
- logging.debug("TProbe :: notify event %s", str(event))
- #HACK: reinstanciate the event with it's properties, to clear
- # any internal state from getting pickled
- if isinstance(event, TPropContainer):
- newevent = type(event)(**event._props)
- else:
- newevent = event
- self.eventOccured(pickle.dumps(newevent))
+ LOGGER.debug("TProbe :: notify event %s", str(event))
+ self.eventOccured(pickle.dumps(event))
# Return a unique name for this action
def _generate_action_reference(self, action):
@@ -225,10 +213,13 @@ class TProbe(dbus.service.Object):
def _generate_event_reference(self, event):
# TODO elavoie 2009-07-25 Should return a universal address
name = event.__class__.__name__
- suffix = 1
+ #Keep the counter to avoid looping all the time
+ suffix = getattr(self, '_event_ref_suffix', 0 ) + 1
while self._subscribedEvents.has_key(name+str(suffix)):
suffix += 1
+
+ #setattr(self, '_event_ref_suffix', suffix)
return name + str(suffix)
@@ -238,25 +229,15 @@ class ProbeProxy:
It provides an object interface to the TProbe, which requires pickled
strings, across a DBus communication.
-
- Public Methods:
- ProbeProxy(string activityName) :: Constructor
- string install(Action action)
- void update(Action action)
- void uninstall(Action action)
- void uninstall_all()
- string subscribe(Event event, callable callback)
- void unsubscribe(Event event, callable callback)
- void unsubscribe_all()
"""
def __init__(self, activityName):
"""
Constructor
- @param activityName unique activity id
+ @param activityName unique activity id. Must be a valid dbus bus name.
"""
- logging.debug("ProbeProxy :: Creating ProbeProxy for %s (%d)", activityName, os.getpid())
- logging.debug("ProbeProxy :: Current gobject context: %s", str(gobject.main_context_default()))
- logging.debug("ProbeProxy :: Current gobject depth: %s", str(gobject.main_depth()))
+ LOGGER.debug("ProbeProxy :: Creating ProbeProxy for %s (%d)", activityName, os.getpid())
+ LOGGER.debug("ProbeProxy :: Current gobject context: %s", str(gobject.main_context_default()))
+ LOGGER.debug("ProbeProxy :: Current gobject depth: %s", str(gobject.main_depth()))
bus = dbus.SessionBus()
self._object = bus.get_object(activityName, "/tutorius/Probe")
self._probe = dbus.Interface(self._object, "org.tutorius.ProbeInterface")
@@ -269,20 +250,21 @@ class ProbeProxy:
self._subscribedEvents = {}
self._registeredCallbacks = {}
+
self._object.connect_to_signal("eventOccured", self._handle_signal, dbus_interface="org.tutorius.ProbeInterface")
def _handle_signal(self, pickled_event):
event = pickle.loads(str(pickled_event))
- logging.debug("ProbeProxy :: Received Event : %s %s", str(event), str(event._props.items()))
+ LOGGER.debug("ProbeProxy :: Received Event : %s %s", str(event), str(event._props.items()))
- logging.debug("ProbeProxy :: Currently %d events registered", len(self._registeredCallbacks))
+ LOGGER.debug("ProbeProxy :: Currently %d events registered", len(self._registeredCallbacks))
if self._registeredCallbacks.has_key(event):
for callback in self._registeredCallbacks[event].itervalues():
callback(event)
else:
for event in self._registeredCallbacks.keys():
- logging.debug("==== %s", str(event._props.items()))
- logging.debug("ProbeProxy :: Event does not appear to be registered")
+ LOGGER.debug("==== %s", str(event._props.items()))
+ LOGGER.debug("ProbeProxy :: Event does not appear to be registered")
def isAlive(self):
try:
@@ -300,41 +282,38 @@ class ProbeProxy:
"""
Install an action on the TProbe's activity
@param action Action to install
+ @param block Force a synchroneous dbus call if True
@return None
"""
- remote_call(self._probe.install, (pickle.dumps(action),),
+ return remote_call(self._probe.install, (pickle.dumps(action),),
save_args(self.__update_action, action),
block=block)
- def update(self, action, block=False):
+ def update(self, action, newaction, block=False):
"""
Update an already installed action's properties and run it again
@param action Action to update
+ @param newaction Action to update it with
+ @param block Force a synchroneous dbus call if True
@return None
"""
+ #TODO review how to make this work well
if not action in self._actions:
raise RuntimeWarning("Action not installed")
- return
- remote_call(self._probe.update, (self._actions[action], pickle.dumps(action._props)), block=block)
+ #TODO Check error handling
+ return remote_call(self._probe.update, (self._actions[action], pickle.dumps(newaction._props)), block=block)
def uninstall(self, action, block=False):
"""
Uninstall an installed action
@param action Action to uninstall
+ @param block Force a synchroneous dbus call if True
"""
if action in self._actions:
remote_call(self._probe.uninstall,(self._actions.pop(action),), block=block)
- def uninstall_all(self, block=False):
- """
- Uninstall all installed actions
- @return None
- """
- for action in self._actions.keys():
- self.uninstall(action, block)
-
def __update_event(self, event, callback, address):
- logging.debug("ProbeProxy :: Registered event %s with address %s", str(event), str(address))
+ LOGGER.debug("ProbeProxy :: Registered event %s with address %s", str(hash(event)), str(address))
# Since multiple callbacks could be associated to the same
# event signature, we will store multiple callbacks
# in a dictionary indexed by the unique address
@@ -365,26 +344,33 @@ class ProbeProxy:
return address
def __clear_event(self, address):
+ LOGGER.debug("ProbeProxy :: Unregistering adress %s", str(address))
# Cleanup everything
if self._subscribedEvents.has_key(address):
event = self._subscribedEvents[address]
if self._registeredCallbacks.has_key(event)\
and self._registeredCallbacks[event].has_key(address):
+ LOGGER.debug("ProbeProxy :: POP ")
self._registeredCallbacks[event].pop(address)
if self._registeredCallbacks[event] == {}:
+ LOGGER.debug("ProbeProxy :: POP2 ")
self._registeredCallbacks.pop(event)
self._subscribedEvents.pop(address)
+ else:
+ LOGGER.debug("ProbeProxy :: unsubsribe address %s inconsistency : not registered", address)
def subscribe(self, event, callback, block=True):
"""
Register an event listener
@param event Event to listen for
@param callback callable that will be called when the event occurs
+ @param block Force a synchroneous dbus call if True (Not allowed yet)
@return address identifier used for unsubscribing
"""
+ LOGGER.debug("ProbeProxy :: Registering event %s", str(hash(event)))
if not block:
raise RuntimeError("This function does not allow non-blocking mode yet")
@@ -395,32 +381,41 @@ class ProbeProxy:
save_args(self.__update_event, event, callback),
block=block)
- def unsubscribe(self, address, block=False):
+ def unsubscribe(self, address, block=True):
"""
Unregister an event listener
@param address identifier given by subscribe()
+ @param block Force a synchroneous dbus call if True
@return None
"""
+ LOGGER.debug("ProbeProxy :: Unregister adress %s issued", str(address))
+ if not block:
+ raise RuntimeError("This function does not allow non-blocking mode yet")
if address in self._subscribedEvents.keys():
remote_call(self._probe.unsubscribe, (address,),
return_cb=save_args(self.__clear_event, address),
block=block)
else:
- logging.debug("ProbeProxy :: unsubsribe address %s failed : not registered", address)
+ LOGGER.debug("ProbeProxy :: unsubsribe address %s failed : not registered", address)
- def unsubscribe_all(self, block=False):
+ def detach(self, block=False):
"""
- Unregister all event listeners
- @return None
+ Detach the ProbeProxy from it's TProbe. All installed actions and
+ subscribed events should be removed.
"""
+ for action in self._actions.keys():
+ self.uninstall(action, block)
+
for address in self._subscribedEvents.keys():
self.unsubscribe(address, block)
+
class ProbeManager(object):
"""
The ProbeManager provides multiplexing across multiple activity ProbeProxies
For now, it only handles one at a time, though.
+ Actually it doesn't do much at all. But it keeps your encapsulation happy
"""
def __init__(self):
self._probes = {}
@@ -438,9 +433,9 @@ class ProbeManager(object):
def attach(self, activity_id):
if activity_id in self._probes:
raise RuntimeWarning("Activity already attached")
- return
self._probes[activity_id] = ProbeProxy(activity_id)
+ #TODO what do we do with this? Raise something?
if self._probes[activity_id].isAlive():
print "Alive!"
else:
@@ -449,48 +444,64 @@ class ProbeManager(object):
def detach(self, activity_id):
if activity_id in self._probes:
probe = self._probes.pop(activity_id)
- probe.unsubscribe_all()
- probe.uninstall_all()
+ probe.detach()
- def install(self, action):
- if self.currentActivity:
- return self._probes[self.currentActivity].install(action)
- else:
- raise RuntimeWarning("No activity attached")
-
- def update(self, action):
+ def install(self, action, block=False):
+ """
+ Install an action on the current activity
+ @param action Action to install
+ @param block Force a synchroneous dbus call if True
+ @return None
+ """
if self.currentActivity:
- return self._probes[self.currentActivity].update(action)
+ return self._probes[self.currentActivity].install(action, block)
else:
raise RuntimeWarning("No activity attached")
- def uninstall(self, action):
+ def update(self, action, newaction, block=False):
+ """
+ Update an already installed action's properties and run it again
+ @param action Action to update
+ @param newaction Action to update it with
+ @param block Force a synchroneous dbus call if True
+ @return None
+ """
if self.currentActivity:
- return self._probes[self.currentActivity].uninstall(action)
+ return self._probes[self.currentActivity].update(action, newaction, block)
else:
raise RuntimeWarning("No activity attached")
- def uninstall_all(self):
+ def uninstall(self, action, block=False):
+ """
+ Uninstall an installed action
+ @param action Action to uninstall
+ @param block Force a synchroneous dbus call if True
+ """
if self.currentActivity:
- return self._probes[self.currentActivity].uninstall_all()
+ return self._probes[self.currentActivity].uninstall(action, block)
else:
raise RuntimeWarning("No activity attached")
def subscribe(self, event, callback):
+ """
+ Register an event listener
+ @param event Event to listen for
+ @param callback callable that will be called when the event occurs
+ @return address identifier used for unsubscribing
+ """
if self.currentActivity:
return self._probes[self.currentActivity].subscribe(event, callback)
else:
raise RuntimeWarning("No activity attached")
def unsubscribe(self, address):
+ """
+ Unregister an event listener
+ @param address identifier given by subscribe()
+ @return None
+ """
if self.currentActivity:
return self._probes[self.currentActivity].unsubscribe(address)
else:
raise RuntimeWarning("No activity attached")
- def unsubscribe_all(self):
- if self.currentActivity:
- return self._probes[self.currentActivity].unsubscribe_all()
- else:
- raise RuntimeWarning("No activity attached")
-