From 7f82e474b4eaaef2795fb39539330f5ff6221922 Mon Sep 17 00:00:00 2001 From: mike Date: Tue, 17 Nov 2009 00:04:23 +0000 Subject: WIP for Engine with Resources --- diff --git a/tests/probetests.py b/tests/probetests.py index 8321e19..67132ff 100644 --- a/tests/probetests.py +++ b/tests/probetests.py @@ -223,11 +223,13 @@ class ProbeTest(unittest.TestCase): del self.activity def test_ping(self): + print "test_ping" #Test ping() res = self.probe.ping() assert res == "alive", "Probe should be alive" def test_action(self): + print "test_action" global message_box action = MockAddon() action.i, action.s = (5,"woot") @@ -271,6 +273,7 @@ class ProbeTest(unittest.TestCase): assert message_box == "Test", "undo should not have happened again" def test_events(self): + print "test_events" global message_box global event_box @@ -319,6 +322,7 @@ class ProbeManagerTest(unittest.TestCase): self._registered_actions = {} def test_register_probe(self): + print "test_register_probe" assert len(self.probeManager.get_registered_probes_list()) == 0 self.probeManager.register_probe("act1", "unique_id_1") @@ -334,6 +338,7 @@ class ProbeManagerTest(unittest.TestCase): assert self.probeManager.get_registered_probes_list("act2")[0][0] == "unique_id_2" def test_register_multiple_probes(self): + print "test_register_multiple_probes" assert len(self.probeManager.get_registered_probes_list()) == 0 self.probeManager.register_probe("act1", "unique_id_1") @@ -344,6 +349,7 @@ class ProbeManagerTest(unittest.TestCase): assert self.probeManager.get_registered_probes_list("act1")[1][0] == "unique_id_2" def test_unregister_probe(self): + print "test_unregister_probe" assert len(self.probeManager.get_registered_probes_list()) == 0 self.probeManager.register_probe("act1", "unique_id_1") self.probeManager.register_probe("act1","unique_id_2") @@ -360,6 +366,7 @@ class ProbeManagerTest(unittest.TestCase): self._registered_actions[action_name] = action_address def test_actions(self): + print "test_actions" self.probeManager.register_probe("act1", "unique_id_1") self.probeManager.register_probe("act2", "unique_id_2") act1 = self.probeManager.get_registered_probes_list("act1")[0][1] @@ -393,6 +400,7 @@ class ProbeManagerTest(unittest.TestCase): assert act1.MockAction is None, "Action should be uninstalled" def test_events(self): + print "test_events" self.probeManager.register_probe("act1", "unique_id_1") self.probeManager.register_probe("act2", "unique_id_2") act1 = self.probeManager.get_registered_probes_list("act1")[0][1] @@ -425,6 +433,10 @@ class ProbeManagerTest(unittest.TestCase): class ProbeProxyTest(unittest.TestCase): def setUp(self): + #Set a default dbus mainloop + m = DBusGMainLoop(set_as_default=True) + dbus.set_default_main_loop(m) + dbus.SessionBus = MockSessionBus self.mockObj = MockProxyObject("unittest.TestCase", "/tutorius/Probe/unique_id_1") @@ -437,6 +449,7 @@ class ProbeProxyTest(unittest.TestCase): MockProxyObject._MockProxyObjects = {} def test_Alive(self): + print "test_Alive" self.mockObj.MockRet["ping"] = "alive" assert self.probeProxy.isAlive() == True, "Alive should return True" @@ -447,6 +460,7 @@ class ProbeProxyTest(unittest.TestCase): self._registered_actions[action_name] = action_address def test_actions(self): + print "test_Actions" action = MockAddon() action.i, action.s = 5, "action" action2 = MockAddon() @@ -478,6 +492,7 @@ class ProbeProxyTest(unittest.TestCase): assert self.mockObj.MockCall["uninstall"]["args"][0] == address, "1 argument, the action address" def test_events(self): + print "test_events" event = MockAddon() event.i, event.s = 5, "event" event2 = MockAddon() diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py index cfa734b..1bfa5e8 100644 --- a/tutorius/TProbe.py +++ b/tutorius/TProbe.py @@ -1,3 +1,18 @@ +# Copyright (C) 2009, Tutorius.org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging LOGGER = logging.getLogger("sugar.tutorius.TProbe") import os @@ -8,12 +23,11 @@ import dbus import dbus.service import cPickle as pickle - from . import addon from .services import ObjectStore from .properties import TPropContainer -from .dbustools import remote_call, save_args +from .dbustools import remote_call, save_args, Future, logError import copy """ @@ -125,6 +139,8 @@ class TProbe(dbus.service.Object): address = self._generate_action_reference(action) + LOGGER.debug("Installing action with name : %s"%address) + self._installedActions[address] = action if action._props: @@ -143,6 +159,7 @@ class TProbe(dbus.service.Object): @param action_props pickled action properties @return None """ + LOGGER.debug("Updating action at address : %s"%address) action = self._installedActions[address] if action._props: @@ -160,6 +177,7 @@ class TProbe(dbus.service.Object): @return None """ if self._installedActions.has_key(address): + LOGGER.debug("Uninstalling action : %s"%address) action = self._installedActions[address] action.undo() self._installedActions.pop(address) @@ -190,6 +208,7 @@ class TProbe(dbus.service.Object): name = self._generate_event_reference(eventfilter) self._subscribedEvents[name] = eventfilter + LOGGER.debug("Subscribed to event %s"%name) return name @dbus.service.method("org.tutorius.ProbeInterface", @@ -202,6 +221,7 @@ class TProbe(dbus.service.Object): """ if self._subscribedEvents.has_key(address): + LOGGER.debug("Unsubscribing event at address : %s"%address) eventfilter = self._subscribedEvents[address] eventfilter.remove_handlers() self._subscribedEvents.pop(address) @@ -312,9 +332,15 @@ class ProbeProxy: @param block Force a synchroneous dbus call if True @return None """ - return remote_call(self._probe.install, (pickle.dumps(action),), - save_args(self.__update_action, action, callback), - block=block) + LOGGER.debug("ProbeProxy :: installing a new action %s"%str(action)) + action_address = Future("action_install") + #remote_call(self._probe.install, (pickle.dumps(action),), + # action_address._set, block) + self._probe.install(pickle.dumps(action), reply_handler=action_address._set, error_handler=logError) + # Get the value from the future! + address_name = action_address.get() + callback(address_name) + return address_name def update(self, action_address, newaction, block=False): """ @@ -328,7 +354,14 @@ class ProbeProxy: if not action_address in self._actions.keys(): raise RuntimeWarning("Action not installed") #TODO Check error handling - return remote_call(self._probe.update, (self._actions[action_address], pickle.dumps(newaction._props)), block=block) + LOGGER.debug("ProbeProxy :: Updating action at address %s"%action_address) + future_address = Future("action_update") + # Call the update method + remote_call(self._probe.update, (self._actions[action_address], pickle.dumps(newaction._props)), + save_args(future_address._set, action_address), block=block) + # Wait for the callback to be completed + future_address.get() + return None def uninstall(self, action_address, block=False): """ @@ -337,7 +370,12 @@ class ProbeProxy: @param block Force a synchroneous dbus call if True """ if action_name in self._actions.keys(): - remote_call(self._probe.uninstall,(self._actions.pop(action_name),), block=block) + LOGGER.debug("ProbeProxy :: Uninstalling action at %s"%action_address) + future_uninstall = Future("action_uninstall") + remote_call(self._probe.uninstall, (self._actions.pop(action_name),), + save_args(future_uninstall._set, action_address), block=block) + future_uninstall.get() + LOGGER.debug("ProbeProxy :: Uninstall complete for action at %s"%action_address) def __update_event(self, event, callback, address): LOGGER.debug("ProbeProxy :: Registered event %s with address %s", str(hash(event)), str(address)) @@ -402,9 +440,13 @@ class ProbeProxy: # TODO elavoie 2009-07-25 When we will allow for patterns both # for event types and sources, we will need to revise the lookup # mechanism for which callback function to call - return remote_call(self._probe.subscribe, (pickle.dumps(event),), - save_args(self.__update_event, event, callback), - block=block) + + # TODO : Remove all the block(s) from the dbus stack + future_subscribe = Future("event_subscribe") + self._probe.subscribe(pickle.dumps(event), reply_handler=future_subscribe._set, error_handler=logError) + event_address = future_subscribe.get() + LOGGER.debug("ProbeProxy :: Registering of event %s complete"%str(hash(event))) + return self.__update_event(event, callback, event_address) def unsubscribe(self, address, block=True): """ @@ -415,9 +457,13 @@ class ProbeProxy: """ LOGGER.debug("ProbeProxy :: Unregister adress %s issued", str(address)) if address in self._subscribedEvents.keys(): + future_unsubscribe = Future("event_subscribe") remote_call(self._probe.unsubscribe, (address,), - return_cb=save_args(self.__clear_event, address), + return_cb=save_args(future_unsubscribe._set, address), block=block) + future_unsubscribe.get() + self.__clear_event(address) + LOGGER.debug("ProbeProxy :: Unsubscribing from address %s complete"%str(address)) else: LOGGER.debug("ProbeProxy :: unsubscribe address %s failed : not registered", address) @@ -426,11 +472,13 @@ class ProbeProxy: Detach the ProbeProxy from it's TProbe. All installed actions and subscribed events should be removed. """ + LOGGER.debug("ProbeProxy :: detaching...") for action_addr in self._actions.keys(): self.uninstall(action_addr, block) for address in self._subscribedEvents.keys(): self.unsubscribe(address, block) + LOGGER.debug("ProbeProxy :: detaching complete") class ProbeManager(object): diff --git a/tutorius/dbustools.py b/tutorius/dbustools.py index 02acd3d..d96594e 100644 --- a/tutorius/dbustools.py +++ b/tutorius/dbustools.py @@ -1,3 +1,18 @@ +# Copyright (C) 2009, Tutorius.org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging import gobject @@ -43,13 +58,15 @@ def remote_call(callable, args, return_cb=None, error_cb=None, block=False): callable(*args, reply_handler=reply_cb, error_handler=errhandler_cb) class Future(object): - def __init__(self): + def __init__(self, log_name="default_Future"): self._value = None + self._log_name = log_name def get(self): context = gobject.MainLoop().get_context() while self._value == None and context.iteration(True): - pass + LOGGER.debug("Future variable %s executed event loop while waiting for its value"%str(self._log_name)) + LOGGER.debug("Future variable %s has received its value"%self._log_name) return self._value def _set(self, value): diff --git a/tutorius/engine.py b/tutorius/engine.py index ec281b3..e102406 100644 --- a/tutorius/engine.py +++ b/tutorius/engine.py @@ -1,3 +1,18 @@ +# Copyright (C) 2009, Tutorius.org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging import dbus.mainloop.glib from jarabe.model import shell @@ -10,6 +25,8 @@ from .tutorial import Tutorial, AutomaticTransitionEvent from .translator import ResourceTranslator +LOGGER = logging.getLogger("TutorialRunner") + class TutorialRunner(object): """ Driver for the execution of one tutorial @@ -37,13 +54,16 @@ class TutorialRunner(object): def start(self): self.setCurrentActivity() #Temp Hack until activity in events/actions + LOGGER.debug("Starting tutorial : %s"%self._tutorial.name) self.enterState(self._tutorial.INIT) def stop(self): self.setCurrentActivity() #Temp Hack until activity in events/actions + LOGGER.debug("Stopping tutorial execution for tutorial : %s"%self._tutorial.name) self.enterState(self._tutorial.END) self._teardownState() self._state = None + LOGGER.debug("Teardown complete for tutorial : %s"%self._tutorial.name) def _handleEvent(self, next_state, event): #FIXME sanity check, log event that was not installed and ignore @@ -87,7 +107,7 @@ class TutorialRunner(object): # Install all the actions first for (action_name, action) in actions.items(): - self._pM.install(action, save_args(self.__save_address, action_name), block=True) + self._pM.install(action, save_args(self.__save_address, action_name)) # Install the event filters for (event, next_state) in transitions.values(): @@ -107,11 +127,13 @@ class TutorialRunner(object): @param state_name The name of the state to enter in """ + LOGGER.debug("Tutorial %s moving into state : %s"%(self._tutorial.name, state_name)) self.setCurrentActivity() #Temp Hack until activity in events/actions # Recursive base case if state_name == self._state: #Nothing to do + LOGGER.debug("Installation of state %s completed"%state_name) return self._teardownState() @@ -142,8 +164,10 @@ class Engine: @param tutorialID unique tutorial identifier used to retrieve it from the disk """ if self._tutorial: + LOGGER.debug("Stopping old tutorial : %s"%self._tutorial.name) self.stop() + LOGGER.debug("Starting new tutorial with ID : %s"%str(tutorialID)) # Insert the resource translation layer into the translator_layer = ResourceTranslator(self._probeManager, tutorialID) self._tutorial = TutorialRunner(Vault.loadTutorial(tutorialID), translator_layer) diff --git a/tutorius/tutorial.py b/tutorius/tutorial.py index 793d6f2..c933df7 100644 --- a/tutorius/tutorial.py +++ b/tutorius/tutorial.py @@ -88,7 +88,7 @@ class Tutorial(object): self._state_name_nb = 0 - def add_state(self, action_dict={}, transition_list=()): + def add_state(self, action_list=[], transition_list=()): """ Add a new state to the state machine. The state is initialized with the action list and transition list @@ -98,19 +98,19 @@ class Tutorial(object): The transitions are added using add_transition. - @param action_dict The dictionary of valid action_name:actions for this state + @param action_list The list of actions for this state @param transition_list The list of valid transitions @return unique name for this state """ name = self._generate_unique_state_name() - for (action_name, action) in action_dict.items(): + for action in action_list: self._validate_action(action) for transition in transition_list: self._validate_transition(transition) - state = State(name, action_dict, transition_list) + state = State(name, action_list, transition_list) self._state_dict[name] = state -- cgit v0.9.1