Functionality superseded by hooke.command.Request/.Response.
setattr(self, key, value)
self.args = (self.traceback + str(self.exception),)
+class InList (list):
+ """:class:`Request` validator class.
+
+ Examples
+ --------
+
+ >>> i = InList(['abc', 'def', 5, True])
+ >>> i('abc')
+ >>> i(5)
+ >>> i(False)
+ Traceback (most recent call last):
+ ...
+ ValueError: False
+ """
+ def __init__(self, *args, **kwargs):
+ list.__init__(self, *args, **kwargs)
+
+ def __call__(self, value):
+ """Raises ValueError if a given `value` is not in our internal
+ list.
+ """
+ if value not in self:
+ raise ValueError(value)
+
class Interaction (object):
"""Mid-command inter-process interaction.
+
+ Stores :attr:`type`, a string representing the interaction type
+ ('boolean', 'string', ...).
"""
- pass
+ def __init__(self, type):
+ self.type = type
class Request (Interaction):
"""Command engine requests for information from the UI.
"""
- def __init__(self, msg, default=None):
- super(Request, self).__init__()
+ def __init__(self, type, response_class,
+ msg, default=None, validator=None):
+ super(Request, self).__init__(type)
+ self.response_class = response_class
self.msg = msg
self.default = default
+ self.validator = validator
+
+ def response(self, value):
+ if self.validator != None:
+ self.validator(value)
+ return self.response_class(value)
class Response (Interaction):
"""UI response to a :class:`Request`.
"""
- def __init__(self, value):
- super(Response, self).__init__()
+ def __init__(self, type, value):
+ super(Response, self).__init__(type)
self.value = value
class BooleanRequest (Request):
- pass
+ def __init__(self, msg, default=None):
+ super(BooleanRequest, self).__init__(
+ 'boolean', BooleanResponse, msg, default,
+ validator = InList([True, False, default]))
class BooleanResponse (Response):
- pass
+ def __init__(self, value):
+ super(BooleanResponse, self).__init__('boolean', value)
+
+class StringRequest (Request):
+ def __init__(self, msg, default=None):
+ super(StringRequest, self).__init__(
+ 'string', StringResponse, msg, default)
+
+class StringResponse (Response):
+ def __init__(self, value):
+ super(StringResponse, self).__init__('string', value)
+
+class FloatRequest (Request):
+ def __init__(self, msg, default=None):
+ super(FloatRequest, self).__init__(
+ 'float', FloatResponse, msg, default)
+
+class FloatResponse (Response):
+ def __init__(self, value):
+ super(FloatResponse, self).__init__('float', value)
+
+class SelectionRequest (Request):
+ def __init__(self, msg, default=None, options=[]):
+ super(SelectionRequest, self).__init__(
+ 'selection', SelectionResponse, msg, default)
+ self.options = options
+
+class SelectionResponse (Response):
+ def __init__(self, value):
+ super(SelectionResponse, self).__init__('selection', value)
+
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
<BLANKLINE>
<BLANKLINE>
An example Command.
ITEM:
- Success
+ <BLANKLINE>
"""
def __init__(self, name, aliases=None, arguments=[], help=''):
self.name = name
+++ /dev/null
-'''
-Input check routines.
-
-Copyright (C) 2008 Alberto Gomez-Casado (University of Twente).
-
-This program is released under the GNU General Public License version 2.
-
-This is just a collection of wrappers for raw_input(), I noticed using
-hooke that unexpected answers from the user often triggered a nasty
-crash, so what they do is provide some basic check of inputs to avoid
-'voids', letters where numbers are expected, etc
-
-The basic call there is safeinput(message,[list])
-Message is a string that is shown to the user ('Enter filename:')
-[list] can be present or not.
- - If not present safeinput is just a raw_input shielded against void
-inputs (it will keep asking until it gets some answer)
- - If a list of only one element is provided, it is interpreted as a
-default value (in case a void input that value will be returned)
- - If a list of two or more 'string' elements is provided, user input
-must match one of them to be valid
- - If a list of two integer elements [a, b] is provided, user input
-is required to be in the interval [a,b]
-
-More info about the underlying calls can be found in the code. However
-I am still not very satisfied with them, That's why I made safeinput()
-to wrap all so I can improve them without further fiddling with other
-module's code.
-'''
-
-from types import *
-
-
-def safeinput (message, valid=[]):
- '''
- friendlier frontend for alphainput and numinput
- valid should be a list of 0...n values
- '''
-
- #if possible values are not listed we just ask for any non-null input
- if len(valid)==0:
- return alphainput(message, '',1,[])
-
-
- if len(valid)>0:
- #if valid values are string we use alphainput, if it is only one we take as default
- if type(valid[0]) is StringType:
- if len(valid)==1:
- return alphainput(message, valid[0], 0,[])
- else:
- return alphainput(message,'', 1,valid)
-
- #if valid values are numbers we use numinput
- if type(valid[0]) is IntType:
- if len(valid)==1:
- return numinput(message,valid[0],1,[])
- else:
- return numinput(message,'',1,valid)
-
-
-def alphainput (message, default, repeat, valid):
- '''
- message: prompt for the user
- default: return value if user input was not correct (and repeat=0)
- repeat: keeps asking user till it gets a valid input
- valid: list of allowed answers, empty list for "anything"
- '''
- if default and not repeat:
- print 'Press [enter] for default: ('+str(default)+')'
- reply=raw_input(message)
- if len(valid)>0:
- if reply in valid:
- return reply
- else:
- if repeat==1:
- while reply not in valid:
- reply=raw_input('You should enter any of these: '+ str(valid) +'\n'+ message)
- return reply
- else:
- return default
- else:
- if len(reply)>0:
- return reply
- else:
- if not repeat:
- return default
- else:
- while len(reply)==0:
- print 'Try again'
- reply=raw_input(message)
- return reply
-
-
-def checkalphainput (test, default, valid):
- #useful when input was taken form command args
- if len(valid)>0:
- if test in valid:
- return test
- else:
- return default
- else:
- #TODO: raise exception?
- if len(test)>0:
- return test
- else:
- return default
-
-
-def numinput(message, default, repeat, limits):
- '''
- message: prompt for the user
- default: return value if user input was not correct (and repeat=0)
- repeat: keeps asking user till it gets a valid input
- limits: pair of values, input is checked to be between them, empty list for "any number"
- '''
- if default and not repeat:
- print 'Press [enter] for default: '+str(default)
-
- reply=raw_input(message)
-
- try:
- intreply=int(reply)
- except:
- intreply=None
-
- if len(limits)==2:
- high=int(limits.pop())
- low=int(limits.pop())
- if intreply>=low and intreply <= high:
- return intreply
- else:
- if repeat==1:
- while intreply<low or intreply>high :
- reply=raw_input('You should enter values between: '+ str(low)+' and '+str(high) +'\n'+ message)
- try:
- intreply=int(reply)
- except:
- intreply=None
- return intreply
- else:
- return default
- else:
- if intreply!=None:
- return intreply
- else:
- if not repeat:
- return default
- else:
- while intreply==None:
- print 'Try again'
- reply=raw_input(message)
- try:
- intreply=int(reply)
- except:
- intreply=None
- return intreply
-
-
-def checknuminput(test,default,limits):
- #useful when input was taken from command args
- if len(limits)==2:
- high=int(limits.pop())
- low=int(limits.pop())
- if test>=low and test <= high:
- return int(test)
- else:
- return default
- else:
- if len(test)>0:
- return int(test)
- else:
- return default
import readline # including readline makes cmd.Cmd.cmdloop() smarter
import shlex
-from ..command import CommandExit, Exit, BooleanRequest, BooleanResponse, \
+from ..command import CommandExit, Exit, Request, BooleanRequest, \
Command, Argument, StoreValue
from ..ui import UserInterface, CommandMessage
self.cmd.stdout.write(msg.__class__.__name__+'\n')
self.cmd.stdout.write(str(msg).rstrip()+'\n')
break
- elif isinstance(msg, BooleanRequest):
- self._boolean_request(msg)
+ elif isinstance(msg, Request):
+ self._handle_request(msg)
continue
self.cmd.stdout.write(str(msg).rstrip()+'\n')
% (len(arguments), self.name_fn(self.command.name),
target_string))
- def _boolean_request(self, msg):
+ def _handle_request(self, msg):
+ """Repeatedly try to get a response to `msg`.
+ """
+ prompt = getattr(self, '_%s_request_prompt' % msg.type, None)
+ if prompt == None:
+ raise NotImplementedError('_%s_request_prompt' % msg.type)
+ prompt_string = prompt(msg)
+ parser = getattr(self, '_%s_request_parser' % msg.type, None)
+ if parser == None:
+ raise NotImplementedError('_%s_request_parser' % msg.type)
+ error = None
+ while True:
+ if error != None:
+ self.cmd.stdout.write(''.join([
+ error.__class__.__name__, ': ', str(error), '\n']))
+ self.cmd.stdout.write(prompt_string)
+ value = parser(msg, self.cmd.stdin.readline())
+ try:
+ response = msg.response(value)
+ break
+ except ValueError, error:
+ continue
+ self.cmd.inqueue.put(response)
+
+ def _boolean_request_prompt(self, msg):
if msg.default == True:
yn = ' [Y/n] '
else:
yn = ' [y/N] '
- self.cmd.stdout.write(msg.msg+yn)
- response = self.cmd.stdin.readline().strip().lower()
- if response.startswith('y'):
- self.cmd.inqueue.put(BooleanResponse(True))
- elif response.startswith('n'):
- self.cmd.inqueue.put(BooleanResponse(False))
+ return msg.msg + yn
+
+ def _boolean_request_parser(self, msg, response):
+ value = response.strip().lower()
+ if value.startswith('y'):
+ value = True
+ elif value.startswith('n'):
+ value = False
+ elif len(value) == 0:
+ value = msg.default
+ return value
+
+ def _string_request_prompt(self, msg):
+ if msg.default == None:
+ d = ' '
else:
- self.cmd.inqueue.put(BooleanResponse(msg.default))
+ d = ' [%s] ' % msg.default
+ return msg.msg + d
+
+ def _string_request_parser(self, msg, response):
+ return response.strip()
+
+ def _float_request_prompt(self, msg):
+ return self._string_request_prompt(msg)
+
+ def _float_request_parser(self, msg, resposne):
+ return float(response)
+
+ def _selection_request_prompt(self, msg):
+ options = []
+ for i,option in enumerate(msg.options):
+ options.append(' %d) %s' % (i,option))
+ options = ''.join(options)
+ if msg.default == None:
+ prompt = '? '
+ else:
+ prompt = '? [%d] ' % msg.default
+ return '\n'.join([msg,options,prompt])
+
+ def _selection_request_parser(self, msg, response):
+ return int(response)
+
class HelpCommand (CommandMethod):
def __init__(self, *args, **kwargs):
default = False
outqueue.put(BooleanRequest(msg, default))
result = inqueue.get()
- assert isinstance(result, BooleanResponse)
+ assert result.type == 'boolean'
_exit = result.value
if _exit == True:
raise Exit()