Removed hooke.libinput
authorW. Trevor King <wking@drexel.edu>
Wed, 12 May 2010 16:54:35 +0000 (12:54 -0400)
committerW. Trevor King <wking@drexel.edu>
Wed, 12 May 2010 16:54:35 +0000 (12:54 -0400)
Functionality superseded by hooke.command.Request/.Response.

hooke/command.py
hooke/libinput.py [deleted file]
hooke/ui/commandline.py

index 5c0f1b2eacf007d7486ab9e1293459cd2357fe08..0a6abc3a1df0aca56239436b5096d1f2d87af22c 100644 (file)
@@ -57,37 +57,108 @@ class UncaughtException (Failure):
             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>
@@ -97,7 +168,7 @@ class Command (object):
     <BLANKLINE>
     An example Command.
     ITEM:
-    Success
+    <BLANKLINE>
     """
     def __init__(self, name, aliases=None, arguments=[], help=''):
         self.name = name
diff --git a/hooke/libinput.py b/hooke/libinput.py
deleted file mode 100644 (file)
index 21ca05f..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-'''
-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
index f42d014145d9a545026a912fb0985cd0af6d971f..c6520bd244ba15d237fcab7697c15128264d8410 100644 (file)
@@ -7,7 +7,7 @@ import optparse
 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
 
@@ -91,8 +91,8 @@ class DoCommand (CommandMethod):
                 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')
 
@@ -146,19 +146,77 @@ class DoCommand (CommandMethod):
                 % (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):
@@ -243,7 +301,7 @@ typing mistakes ;).
                 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()