X-Git-Url: http://git.tremily.us/?p=hooke.git;a=blobdiff_plain;f=hooke%2Fengine.py;h=f2ab92c0b14723a92e621b9a4e0be6d61871738d;hp=b4381298178f59723b540cfc901a7968ac93e1c1;hb=60b12a779acf92ec32ef2d0ed9e5766b11705150;hpb=608c372b4c9beb3f8c0cfc5a2889012827592d12 diff --git a/hooke/engine.py b/hooke/engine.py index b438129..f2ab92c 100644 --- a/hooke/engine.py +++ b/hooke/engine.py @@ -1,26 +1,26 @@ -# Copyright (C) 2010 W. Trevor King +# Copyright (C) 2010-2012 W. Trevor King # # This file is part of Hooke. # -# Hooke is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. +# Hooke is free software: you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. # -# Hooke 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 Lesser General -# Public License for more details. +# Hooke 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 Lesser General Public License for more +# details. # -# You should have received a copy of the GNU Lesser General Public -# License along with Hooke. If not, see -# . +# You should have received a copy of the GNU Lesser General Public License +# along with Hooke. If not, see . """The `engine` module provides :class:`CommandEngine` for executing :class:`hooke.command.Command`\s. """ import logging +from Queue import Queue, Empty from .command import NullQueue @@ -35,16 +35,55 @@ class CloseEngine (QueueMessage): class CommandMessage (QueueMessage): - """A message storing a command to run, `command` should be a - :class:`hooke.command.Command` instance, and `arguments` should be - a :class:`dict` with `argname` keys and `value` values to be - passed to the command. + """A message storing a command to run, `command` should be the + name of a :class:`hooke.command.Command` instance, and `arguments` + should be a :class:`dict` with `argname` keys and `value` values + to be passed to the command. """ def __init__(self, command, arguments=None): self.command = command if arguments == None: arguments = {} self.arguments = arguments + self.explicit_user_call = True + """Message is explicitly user-executed. This is useful for + distinguishing auto-generated calls (for which + `explicit_user_call` should be `False` such as the GUIs + current status requests. + """ + + def __str__(self): + return str(self.__unicode__()) + + def __unicode__(self): + """Return a unicode representation of the `CommandMessage`. + + Examples + -------- + >>> from .compat.odict import odict + >>> cm = CommandMessage('command A') + >>> print(unicode(cm)) + + >>> cm.arguments = odict([('param a','value a'), ('param b', 'value b')]) + >>> print(unicode(cm)) + + + The parameters are sorted by name, so you won't be surprised + in any doctests, etc. + + >>> cm.arguments = odict([('param b','value b'), ('param a', 'value a')]) + >>> print(unicode(cm)) + + """ + if len(self.arguments) > 0: + return u'<%s %s {%s}>' % ( + self.__class__.__name__, self.command, + ', '.join(['%s: %s' % (key, value) + for key,value in sorted(self.arguments.items())])) + return u'<%s %s>' % (self.__class__.__name__, self.command) + + def __repr__(self): + return self.__str__() class CommandEngine (object): @@ -63,6 +102,10 @@ class CommandEngine (object): be ready to receive the next :class:`QueueMessage`. """ log = logging.getLogger('hooke') + log.debug('engine starting') + for playlist in hooke.playlists: # Curve._hooke is not pickled. + for curve in playlist: + curve.set_hooke(hooke) while True: log.debug('engine waiting for command') msg = ui_to_command_queue.get() @@ -72,12 +115,14 @@ class CommandEngine (object): 'engine closing, placed hooke instance in return queue') break assert isinstance(msg, CommandMessage), type(msg) - log.debug('engine running %s' % msg.command.name) - msg.command.run(hooke, ui_to_command_queue, command_to_ui_queue, - **msg.arguments) + log.debug('engine running %s' % msg) + cmd = hooke.command_by_name[msg.command] + cmd.run(hooke, ui_to_command_queue, command_to_ui_queue, + **msg.arguments) def run_command(self, hooke, command, arguments): - """Internal command execution. + """Run the command named `command` with `arguments` using + :meth:`~hooke.engine.CommandEngine.run_command`. This allows commands to execute sub commands and enables :class:`~hooke.command_stack.CommandStack` execution. @@ -86,4 +131,15 @@ class CommandEngine (object): communication queues, so make sure they will not need user interaction. """ - command.run(hooke, NullQueue(), NullQueue(), arguments) + log = logging.getLogger('hooke') + log.debug('engine running internal %s' + % CommandMessage(command, arguments)) + outqueue = Queue() + cmd = hooke.command_by_name[command] + cmd.run(hooke, NullQueue(), outqueue, **arguments) + while True: + try: + msg = outqueue.get(block=False) + except Empty: + break + log.debug('engine message from %s (%s): %s' % (command, type(msg), msg))