Add a simple query system

- Extend clint.textui.prompt with a query function.
- Add clint.textui.validators to validate the user input.
- Add a prompt example showing different usages.
- Update the README to demo the query function.
This commit is contained in:
Reto Aebersold
2014-05-08 17:18:10 -06:00
parent df7b9594a4
commit b99f79c98e
4 changed files with 166 additions and 1 deletions
+5 -1
View File
@@ -45,7 +45,6 @@ Future Features:
----------------
- Documentation!
- Simple choice system ``Are you sure? [Yn]``
- Default query system ``Installation Path [/usr/local/bin/]``
- Suggestions welcome.
@@ -113,6 +112,11 @@ I want to force color output even if stdout is not a TTY:
$ export CLINT_FORCE_COLOR=1
I want to ask for input. ::
>>> from clint.textui import prompt, validators
>>> path = prompt.query('Installation Path', default='/usr/local/bin/', validators=[validators.PathValidator()])
Installation
------------
+36
View File
@@ -11,6 +11,11 @@ Module for simple interactive prompts handling
from __future__ import absolute_import, print_function
from re import match, I
from .core import puts
from .colored import yellow
from .validators import RegexValidator
try:
raw_input
except NameError:
@@ -52,3 +57,34 @@ def yn(prompt, default='y', batch=False):
# then return True, False otherwise
elif match('n(?:o)?', input, I):
return True if default == 'n' else False
def query(prompt, default='', validators=None, batch=False):
# Set the nonempty validator as default
if validators is None:
validators = [RegexValidator(r'.+')]
# Let's build the prompt
if prompt[-1] is not ' ':
prompt += ' '
if default:
prompt += '[' + default + '] '
# If input is not valid keep asking
while True:
# If batch option is True then auto reply
# with default input
if not batch:
user_input = raw_input(prompt).strip() or default
else:
print(prompt)
user_input = ''
# Validate the user input
try:
for validator in validators:
user_input = validator(user_input)
return user_input
except Exception, e:
puts(yellow(e.message))
+104
View File
@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
"""
clint.textui.validators
~~~~~~~~~~~~~~~~~~~~~~~
Core TextUI functionality for input validation.
"""
from __future__ import absolute_import
import os
import sys
import re
# Useful for very coarse version differentiation.
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str,
else:
string_types = basestring,
class ValidationError(Exception):
"""An error while validating data."""
def __init__(self, message):
self.message = message
self.error_list = [self]
class RegexValidator(object):
regex = ''
message = 'Enter a valid value.'
def __init__(self, regex=None, message=None):
if regex is not None:
self.regex = regex
if message is not None:
self.message = message
# Compile the regex if it was not passed pre-compiled.
if isinstance(self.regex, string_types):
self.regex = re.compile(self.regex)
def __call__(self, value):
"""
Validates that the input matches the regular expression.
"""
if not self.regex.search(value):
raise ValidationError(self.message)
return value
class PathValidator(object):
message = 'Enter a valid path.'
def __init__(self, message=None):
if message is not None:
self.message = message
def __call__(self, value):
"""
Validates that the input is a valid directory.
"""
if not os.path.isdir(value):
raise ValidationError(self.message)
return value
class FileValidator(object):
message = 'Enter a valid file.'
def __init__(self, message=None):
if message is not None:
self.message = message
def __call__(self, value):
"""
Validates that the input is a valid file.
"""
if not os.path.isfile(value):
raise ValidationError(self.message)
return value
class IntegerValidator(object):
message = 'Enter a valid number.'
def __init__(self, message=None):
if message is not None:
self.message = message
def __call__(self, value):
"""
Validates that the input is a integer.
"""
try:
return int(value)
except (TypeError, ValueError):
raise ValidationError(self.message)
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
sys.path.insert(0, os.path.abspath('..'))
from clint.textui import prompt, puts, colored, validators
if __name__ == '__main__':
# Standard non-empty input
name = prompt.query("What's your name?")
# Set validators to an empty list for an optional input
language = prompt.query("Your favorite tool (optional)?", validators=[])
# Use a default value and a validator
path = prompt.query('Installation Path', default='/usr/local/bin/', validators=[validators.PathValidator()])
puts(colored.blue('Hi {0}. Install {1} to {2}'.format(name, language or 'nothing', path)))