mirror of
https://github.com/kennethreitz/clint.git
synced 2026-06-05 23:00:18 +00:00
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:
+5
-1
@@ -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
|
||||
------------
|
||||
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
@@ -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)))
|
||||
Reference in New Issue
Block a user