X-Git-Url: http://git.tremily.us/?p=hooke.git;a=blobdiff_plain;f=hooke%2Fcommand.py;h=974e3b5e7f121b65d153c517de027f164c74ac11;hp=73f01fe3d443a20b0fb9483ed462896e4a2f3884;hb=565f9d7b69d2e4a9ea447d7a50f8f835c3e08642;hpb=f201a3efe4cf7e1a20292dbd9858163358596081 diff --git a/hooke/command.py b/hooke/command.py index 73f01fe..974e3b5 100644 --- a/hooke/command.py +++ b/hooke/command.py @@ -1,5 +1,28 @@ +# Copyright (C) 2010 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 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 +# . + """The `command` module provides :class:`Command`\s and :class:`Argument`\s for defining commands. + +It also provides :class:`CommandExit` and subclasses for communicating +command completion information between +:class:`hooke.engine.CommandEngine`\s and +:class:`hooke.ui.UserInterface`\s. """ import Queue as queue @@ -23,43 +46,48 @@ class Failure (CommandExit): pass class UncaughtException (Failure): - def __init__(self, exception): + def __init__(self, exception, traceback_string=None): + super(UncaughtException, self).__init__() + if traceback_string == None: + traceback_string = traceback.format_exc() + sys.exc_clear() self.exception = exception - self.exc_string = traceback.format_exc() - sys.exc_clear() - super(UncaughtException, self).__init__(self.exc_string) + self.traceback = traceback_string + self.__setstate__(self.__getstate__()) -class Interaction (object): - """Mid-command inter-process interaction. - """ - pass + def __getstate__(self): + """Return a picklable representation of the objects state. -class Request (Interaction): - """Command engine requests for information from the UI. - """ - def __init__(self, msg, default=None): - super(Request, self).__init__() - self.msg = msg - self.default = default + :mod:`pickle`'s doesn't call a :meth:`__init__` when + rebuilding a class instance. To preserve :attr:`args` through + a pickle cycle, we use :meth:`__getstate__` and + :meth:`__setstate__`. -class Response (Interaction): - """UI response to a :class:`Request`. - """ - def __init__(self, value): - super(Response, self).__init__() - self.value = value + See `pickling class instances`_ and `pickling examples`_. -class BooleanRequest (Request): - pass + .. _pickling class instances: + http://docs.python.org/library/pickle.html#pickling-and-unpickling-normal-class-instances + .. _pickling examples: + http://docs.python.org/library/pickle.html#example + """ + return {'exception':self.exception, 'traceback':self.traceback} + + def __setstate__(self, state): + """Apply the picklable state from :meth:`__getstate__` to + reconstruct the instance. + """ + for key,value in state.items(): + setattr(self, key, value) + self.args = (self.traceback + str(self.exception),) -class BooleanResponse (Response): - pass class Command (object): """One-line command description here. >>> c = Command(name='test', help='An example Command.') - >>> status = c.run(NullQueue(), PrintQueue(), help=True) # doctest: +REPORT_UDIFF + >>> hooke = None + >>> status = c.run(hooke, NullQueue(), PrintQueue(), + ... help=True) # doctest: +REPORT_UDIFF ITEM: Command: test @@ -69,18 +97,21 @@ class Command (object): An example Command. ITEM: - Success + """ - def __init__(self, name, aliases=None, arguments=[], help=''): + def __init__(self, name, aliases=None, arguments=[], help='', + plugin=None): + # TODO: see_also=[other,command,instances,...] self.name = name if aliases == None: aliases = [] self.aliases = aliases self.arguments = [ Argument(name='help', type='bool', default=False, count=1, - callback=StoreValue(True), help='Print a help message.'), + help='Print a help message.'), ] + arguments self._help = help + self.plugin = plugin def run(self, hooke, inqueue=None, outqueue=None, **kwargs): """`Normalize inputs and handle before punting @@ -110,7 +141,7 @@ class Command (object): outqueue.put(e) return 0 - def _run(self, inqueue, outqueue, params): + def _run(self, hooke, inqueue, outqueue, params): """This is where the command-specific magic will happen. """ pass @@ -134,12 +165,14 @@ class Command (object): '\n '.join(['%s: %s' % (name,value) for name,value in sorted(settings)]))) name,value = settings[0] - if name != argument.name: - params.remove(name) + if num_provided == 0: params[argument.name] = value + else: + if name != argument.name: + params.remove(name) + params[argument.name] = value if argument.callback != None: - if num_provided > 0: - value = argument.callback(hooke, self, argument, value) + value = argument.callback(hooke, self, argument, value) params[argument.name] = value argument.validate(value) return params