Package: promptly
# Promptly[![Build Status](https://travis-ci.org/aventurella/promptly.png?branch=master)](https://travis-ci.org/aventurella/promptly)A little python utility to help you build command line prompts that canbe styled using CSS.# Changes## v0.6.1Switched to six for compatAdded travis test for python 3.4## v0.6.0Inputs can now specify duplicate keys and a list will be returned, for example:```pythonfrom promptly import consolefrom promptly import Formform = Form()form.add.string('name','What is your name?',default='Ollie')form.add.string('name','What is your other name?',default='Potato')form.add.int('number','Pick a number')console.run(form)print(dict(form))## {#   'name': ['value1', 'value2'],#   'number': 9# }#```## v0.5.4Altered the console runners.console.ConsoleRunner.render()  to fix inconsistentrendering in some teminals.There was an issue on some terminals where passing the full prompt toto input/raw_input (py3 and py2 respectively) would do some interestingthings with line wrapping and color codes. Part of the color code issuewas probably related to `readline` and this reported documentation issuere ansi escapes for readline (http://bugs.python.org/issue17337#msg183328)http://bugs.python.org/issue17337The fix applied however, skips sending the majority of the prompt throughinput/raw_input and instead writes it to stdout. Only the single linefor the actual prompting is now sent to input/raw_input. This appearsto address the issue.## v0.5.3Notifications can now be added into forms. The effect for the console runnerwill be to simply print the notification and then continue to the nextquestion in the form. When converting the form to a dict, like branches,notifications will not be included in the data that is returned.```pythonfrom promptly import consolefrom promptly import Formform = Form()form.add.notification('Welcome to a promptly form')form.add.string('favorite_dog', 'Who is your favorite dog?', default='Lucy')form.add.notification('Thanks for filling out the form!')console.run(form)print(dict(form))```In the case of the above you would get a prompt sequence like this:```···Welcome to a promptly form···Who is your favorite dog?> Lucy···Thanks for filling out the form!···{'favorite_dog': 'Lucy'}```## v0.5.2Pyreadline does not supprt `set_startup_hook(lambda: readline.insert_text(default))`as such the defaults on windows based machines would not show up.The solution for this release was to alter the console renderer for stringand integer input on those machines who have pyreadline installed.In that case the prompt will appear as follows:```Who is your favorite dog? [Lucy]>```Note that the default is tacked on to the end of the question.Compare this to the style we get when we have a system thatsupports readline:```Who is your favorite dog?> Lucy```Integers and String based prompts are rendered like this.## v0.5.1Added some love for our Windows friends. We now check weather or not readline is availableand if not install pyreadline in that case.## v0.5## WARNING 0.5 is backwards incompatibleThis should be the last backwards incompatible update for a while. v0.5saw a redesign of how forms are run. This was done in the hope that one dayI have time to do a curses or urwid implementation. We will see. On the wholethough it does make it more confirguable for individuals that do not likethe default form rendering as Promptly now supports form runners.What are form runners? Well put simply, in prior versions you would call:```python# < v0.5from promptly import Fromform = Form()form.add.string('favorite_food', 'What is your favorite food?')form.run()```This worked well, but it bound the prompts to a single implementation of the`Form` object. `v0.5` treats the `Form` object as more of a collection and therunners figure out how to deal with it. Lets take a look at the example fromabove in in `v0.5`:```python# v0.5+from promptly import Fromform promptly import consoleform = Form()form.add.string('favorite_food', 'What is your favorite food?')console.run(form)```Pretty much exactly the same, but we just hand the form off to therun to deal with, instead of the form.Some additional changes, the `promptly.inputs.*` have all been renamedand simplified. Now they basically act as marker classes for input types.They help the runner identify the kind of prompts to generate.The logic, such as `StringInput.build_prompt`, basically got moved into`promptly.renderers.console.StringPrompt`. If you were always using theshortcut syntax for cerating your forms:```pythonform.add.string(...)form.add.bool(...)form.add.int(...)form.add.select(...)form.add.multiselect(...)```Then you don't have to worry about anything, everything should stillwork fine for you. If you were using the more verbose style:```pythonform.add('age',IntegerInput('What is your age?',default=1))```Things will break for you. It's probably better to always be using theshortcuts.All of the input types now take "notifications" This is a convenient wayto annotate your questions. Lets take a look at a prompt with notificationsand the same prompt without notifications.First, no notifications:```pythonfrom promptly import Fromform promptly import consoleform = Form()form.add.string('name', 'What is your name?', default='Lucy')console.run(form, prefix='[promptly] ')```That will generate a prompt that looks like this:```[promptly] What is your name?> Lucy```Now lets look at the same prompt with notifications:```pythonfrom promptly import Fromform promptly import consoleform = Form()form.add.string('name','What is your name?',notifications=('This will help to identify you later', 'Identification is fun!')default='Lucy')console.run(form, prefix='[promptly] ')```That will generate a prompt that looks like this:```[promptly] What is your name?This will help to identify you laterIdentification is fun!···> Lucy```The notifications appear after the question, but before the user input.The available CSS styles have also been updated to account for these.See the list below for the default styles available.There is also convenience function for just dropping notificationsto the console without running though a form. They will be styled accordingto the notification and prefix styles:```pythonfrom promptly import consoleconsole.notification('Hello World', prefix='[notice] ', stylesheet=None)```This will immediately write a message to sys.stdout.## v0.4**Migration Guide**## WARNING 0.4 is backwards incompatible**Migration Guide**-   `my_form.add.choice` should be become `my_form.add.select`-   `ChoiceInput` should become `SelectInput`-   SelectInput (formerly ChoiceInput) and MultiSelectInput now takean option_format callable. By default this callable is`promptly.utils.numeric_options`. This will take a list ['foo', 'bar']and return a list: [(1, 'foo'), (2, 'bar')]. So if you only neednumbers for your choices or multi-select input's you don'tneed to worry about, you get them for free. If you were passingyour own in something like: `zip(range(1,3), ['foo', 'bar'])` youno longer need to do that. In fact that will break things for youso you should replace it with just your list of choices### New Features#### BranchesForms can now branch. The branch input item takes a callable that willbe executed and is expected to return another `Form` object. This `Form`object will be merged into the currently running form at the locationwhere the branch was added. The callable signature is as follows:`my_branch_building_action(form, *args, **kwargs):`Example branch usage:```pythondef handler(form, name):branch = Form()if form.age.value < 30:branch.add.string('name', 'What is your name?')else:branch.add.string('name', 'What is your pet's name?', default=name)return branchform = Form()form.add.int('age', 'What is your age?', default=age)form.add.branch(handler, name='Lucy')# The branch fields will be added here in terms of# position in the form once the user reaches the branchform.add.int('number', 'What is your favorite number?')form.run()```#### MultiSelectInputA new input type has been added, `MultiSelectInput`, a shortcut for creatingone is also available in the form of:`my_form.add.multiselect(key, label, choices, done_label='Done')`Note that done_label is optional.MultiSelectInput lets the user choose multiple options from a SelectInputstyle display. It marks the currently selected items. If the user chooses thesame option that has already been selected it will be deselected.A final option is added to the list of choices provided to representthe sentinel choice. The `done_label` kwarg sets the value used hereBy default it is set to *Done*. The user must select the sentinel choicein order to continue on in the form.## Lets Make a Promptly Form```pythonfrom promptly import Formform promptly import console# Build our formform = Form()# add questions in the sequence you would like them to appearform.add.string('name','What is your name?',default='Aubrey')form.add.int('age','What is your age?',default=1)# no options_format kwarg is provided for ChoiceInput# so it will use the default numeric_optionsform.add.select('color','What is your favorite color',('red', 'green', 'blue'),default=1)form.add.bool('yaks', 'Do you like yaks?', default=True)# Our form is created, lets prompt the user for the answers:# promptly comes with a default set of styles or you can# provide your own.with open('/path/to/my/styles.css') as css:console.run(form, prefix='[promptly] ', stylesheet=css.read())# control has returned back to our script, lets see what the user said:print(form.name.value)print(form.age.value)print(form.color.value)  # this will be a (key, value) tupleprint(form.yaks.value)if form.age.value < 12:print(form.food.value)# Or we can just convert the whole form into a dictionary:d = dict(form)print(d)```## CSS StylingPromptly prompts are styles with a very limited subset of CSS.Only the following properties apply:- color- background-color- font-weightThe avialable colors are limited to the color names provided by colorama:```Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.Style: DIM, NORMAL, BRIGHT, RESET_ALL```In other words:```css.prefix {color: white;background-color: blue;}```The font-weight property maps to colorama Style values in the following way:```font-weight: normal;   -> Style.NORMALfont-weight: bold;     -> Style.BRIGHTfont-weight: lighter;  -> Style.DIM```### Heads UpThe CSS parser in promptly is **VERY VERY** primitive. It's just enough to parsewhat is below and that's all. It is by no means a full implementation of theCSS spec.## Default Prompty StylesheetBelow is the default stylesheet included with promptly. This stylesheetpresents the exhaustive set of selectors that can be used to styleyour prompts. If it's not below, promptly doesn't support it.Remember each selector can support:```csscolor: <value>background-color: <value>font-weight: </value>```The default stylesheet below does not use every available optionfor obvious reasons. But you should feel free too if you so desire.```body``` will set the default color and font-weight and background color.The additional styles effectively cascade on top of body.New selectors in `v0.5``.action` represents the Cheveron before the user input is displayed.`.input` are the style for the user input.`.notification .footer` are the styles for the 3 dots that appear belowselection choices and after notifications.```cssbody{color:white;font-weight:normal;}.action{color:magenta;font-weight:bold;}.input{color:white;font-weight:bold;}.prefix{color:blue;font-weight:bold;}.notification .label{color:white;font-weight:bold;}.notification .footer{color:white;font-weight:normal;}.string .label{color:white;}.string .default-wrapper{color:white;font-weight:bold;}.string .default-value{color:yellow;}.integer .label{color:white;}.integer .default-wrapper{color:white;font-weight:bold;}.integer .default-value{color:yellow;}.boolean .label{color:white;}.boolean .default-wrapper{color:white;font-weight:bold;}.boolean .default-value{color:yellow;}.boolean .other-value{color:yellow;}.boolean .seperator{color:white;font-weight:bold;}.choices .label{color:white;}.choices .default-wrapper{color:white;font-weight:bold;}.choices .default-value{color:yellow;}.choices .option-key{color:yellow;}.choices .seperator{color:yellow;font-weight:lighter;}.choices .option-value{color:white;font-weight:bold;}.choices .action{color:magenta;font-weight:bold;}.choices .selection{color:white;}```