APT command line interface-like yes/no input?

Python

Python Problem Overview


Is there any short way to achieve what the APT (Advanced Package Tool) command line interface does in Python?

I mean, when the package manager prompts a yes/no question followed by [Yes/no], the script accepts YES/Y/yes/y or Enter (defaults to Yes as hinted by the capital letter).

The only thing I find in the official docs is input and raw_input...

I know it's not that hard to emulate, but it's annoying to rewrite :|

Python Solutions


Solution 1 - Python

As you mentioned, the easiest way is to use raw_input() (or simply input() for Python 3). There is no built-in way to do this. From Recipe 577058:

import sys


def query_yes_no(question, default="yes"):
    """Ask a yes/no question via raw_input() and return their answer.

    "question" is a string that is presented to the user.
    "default" is the presumed answer if the user just hits <Enter>.
            It must be "yes" (the default), "no" or None (meaning
            an answer is required of the user).

    The "answer" return value is True for "yes" or False for "no".
    """
    valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
    if default is None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [Y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '%s'" % default)

    while True:
        sys.stdout.write(question + prompt)
        choice = input().lower()
        if default is not None and choice == "":
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            sys.stdout.write("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n")

(For Python 2, use raw_input instead of input.) Usage example:

>>> query_yes_no("Is cabbage yummier than cauliflower?")
Is cabbage yummier than cauliflower? [Y/n] oops
Please respond with 'yes' or 'no' (or 'y' or 'n').
Is cabbage yummier than cauliflower? [Y/n] [ENTER]
>>> True

>>> query_yes_no("Is cabbage yummier than cauliflower?", None)
Is cabbage yummier than cauliflower? [y/n] [ENTER]
Please respond with 'yes' or 'no' (or 'y' or 'n').
Is cabbage yummier than cauliflower? [y/n] y
>>> True

Solution 2 - Python

I'd do it this way:

# raw_input returns the empty string for "enter"
yes = {'yes','y', 'ye', ''}
no = {'no','n'}

choice = raw_input().lower()
if choice in yes:
   return True
elif choice in no:
   return False
else:
   sys.stdout.write("Please respond with 'yes' or 'no'")

Solution 3 - Python

You can use click's confirm method.

import click

if click.confirm('Do you want to continue?', default=True):
    print('Do something')

This will print:

$ Do you want to continue? [Y/n]:

Should work for Python 2/3 on Linux, Mac or Windows.

Docs: http://click.pocoo.org/5/prompts/#confirmation-prompts

Solution 4 - Python

There is a function strtobool in Python's standard library: http://docs.python.org/2/distutils/apiref.html?highlight=distutils.util#distutils.util.strtobool

You can use it to check user's input and transform it to True or False value.

Solution 5 - Python

A very simple (but not very sophisticated) way of doing this for a single choice would be:

msg = 'Shall I?'
shall = input("%s (y/N) " % msg).lower() == 'y'

You could also write a simple (slightly improved) function around this:

def yn_choice(message, default='y'):
    choices = 'Y/n' if default.lower() in ('y', 'yes') else 'y/N'
    choice = input("%s (%s) " % (message, choices))
    values = ('y', 'yes', '') if choices == 'Y/n' else ('y', 'yes')
    return choice.strip().lower() in values

Note: On Python 2, use raw_input instead of input.

Solution 6 - Python

as mentioned by @Alexander Artemenko, here's a simple solution using strtobool

from distutils.util import strtobool

def user_yes_no_query(question):
    sys.stdout.write('%s [y/n]\n' % question)
    while True:
        try:
            return strtobool(raw_input().lower())
        except ValueError:
            sys.stdout.write('Please respond with \'y\' or \'n\'.\n')

#usage

>>> user_yes_no_query('Do you like cheese?')
Do you like cheese? [y/n]
Only on tuesdays
Please respond with 'y' or 'n'.
ok
Please respond with 'y' or 'n'.
y
>>> True

Solution 7 - Python

I know this has been answered a bunch of ways and this may not answer OP's specific question (with the list of criteria) but this is what I did for the most common use case and it's far simpler than the other responses:

answer = input('Please indicate approval: [y/n]')
if not answer or answer[0].lower() != 'y':
    print('You did not indicate approval')
    exit(1)

Solution 8 - Python

You can also use prompter.

Shamelessly taken from the README:

#pip install prompter

from prompter import yesno

>>> yesno('Really?')
Really? [Y/n]
True

>>> yesno('Really?')
Really? [Y/n] no
False

>>> yesno('Really?', default='no')
Really? [y/N]
True

Solution 9 - Python

I modified fmark's answer to by python 2/3 compatible more pythonic.

See ipython's utility module if you are interested in something with more error handling

# PY2/3 compatibility
from __future__ import print_function
# You could use the six package for this
try:
    input_ = raw_input
except NameError:
    input_ = input

def query_yes_no(question, default=True):
    """Ask a yes/no question via standard input and return the answer.

    If invalid input is given, the user will be asked until
    they acutally give valid input.

    Args:
        question(str):
            A question that is presented to the user.
        default(bool|None):
            The default value when enter is pressed with no value.
            When None, there is no default value and the query
            will loop.
    Returns:
        A bool indicating whether user has entered yes or no.

    Side Effects:
        Blocks program execution until valid input(y/n) is given.
    """
    yes_list = ["yes", "y"]
    no_list = ["no", "n"]

    default_dict = {  # default => prompt default string
        None: "[y/n]",
        True: "[Y/n]",
        False: "[y/N]",
    }

    default_str = default_dict[default]
    prompt_str = "%s %s " % (question, default_str)

    while True:
        choice = input_(prompt_str).lower()

        if not choice and default is not None:
            return default
        if choice in yes_list:
            return True
        if choice in no_list:
            return False

        notification_str = "Please respond with 'y' or 'n'"
        print(notification_str)

Solution 10 - Python

For Python 3, I'm using this function:

def user_prompt(question: str) -> bool:
    """ Prompt the yes/no-*question* to the user. """
    from distutils.util import strtobool

    while True:
        user_input = input(question + " [y/n]: ")
        try:
            return bool(strtobool(user_input))
        except ValueError:
            print("Please use y/n or yes/no.\n")

The [strtobool()][1] function converts a string into a bool. If the string cant be parsed it will raise a ValueError.

In Python 3 raw_input() has been renamed to [input()][2].

As Geoff said, strtobool actually returns 0 or 1, therefore the result has to be cast to bool.


This is the implementation of strtobool, if you want special words to be recognized as true, you can copy the code and add your own cases.

def strtobool (val):
    """Convert a string representation of truth to true (1) or false (0).
    True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
    are 'n', 'no', 'f', 'false', 'off', and '0'.  Raises ValueError if
    'val' is anything else.
    """
    val = val.lower()
    if val in ('y', 'yes', 't', 'true', 'on', '1'):
        return 1
    elif val in ('n', 'no', 'f', 'false', 'off', '0'):
        return 0
    else:
        raise ValueError("invalid truth value %r" % (val,))

[1]: https://docs.python.org/3.6/distutils/apiref.html?highlight=distutils.util#distutils.util.strtobool "strtobool" [2]: https://docs.python.org/3/library/functions.html#input "input"

Solution 11 - Python

on 2.7, is this too non-pythonic?

if raw_input('your prompt').lower()[0]=='y':
   your code here
else:
   alternate code here

it captures any variation of Yes at least.

Solution 12 - Python

Doing the same with python 3.x, where raw_input() doesn't exist:

def ask(question, default = None):
    hasDefault = default is not None
    prompt = (question 
               + " [" + ["y", "Y"][hasDefault and default] + "/" 
               + ["n", "N"][hasDefault and not default] + "] ")
  
    while True:
        sys.stdout.write(prompt)
        choice = input().strip().lower()
        if choice == '':
            if default is not None:
                return default
        else:
            if "yes".startswith(choice):
                return True
            if "no".startswith(choice):
                return False
        
        sys.stdout.write("Please respond with 'yes' or 'no' "
                             "(or 'y' or 'n').\n")

Solution 13 - Python

You could try something like the code below to be able to work with choices from the variable 'accepted' show here:

print( 'accepted: {}'.format(accepted) )
# accepted: {'yes': ['', 'Yes', 'yes', 'YES', 'y', 'Y'], 'no': ['No', 'no', 'NO', 'n', 'N']}

Here is the code ..

#!/usr/bin/python3

def makeChoi(yeh, neh):
	accept = {}
	# for w in words:
	accept['yes'] = [ '', yeh, yeh.lower(), yeh.upper(), yeh.lower()[0], yeh.upper()[0] ]
	accept['no'] = [ neh, neh.lower(), neh.upper(), neh.lower()[0], neh.upper()[0] ]
	return accept

accepted = makeChoi('Yes', 'No')

def doYeh():
	print('Yeh! Let\'s do it.')

def doNeh():
	print('Neh! Let\'s not do it.')

choi = None
while not choi:
	choi = input( 'Please choose: Y/n? ' )
	if choi in accepted['yes']:
		choi = True
		doYeh()
	elif choi in accepted['no']:
		choi = True
		doNeh()
	else:
		print('Your choice was "{}". Please use an accepted input value ..'.format(choi))
		print( accepted )
		choi = None

Solution 14 - Python

As a programming noob, I found a bunch of the above answers overly complex, especially if the goal is to have a simple function that you can pass various yes/no questions to, forcing the user to select yes or no. After scouring this page and several others, and borrowing all of the various good ideas, I ended up with the following:

def yes_no(question_to_be_answered):
    while True:
        choice = input(question_to_be_answered).lower()
        if choice[:1] == 'y': 
            return True
        elif choice[:1] == 'n':
            return False
        else:
            print("Please respond with 'Yes' or 'No'\n")

#See it in Practice below 

musical_taste = yes_no('Do you like Pine Coladas?')
if musical_taste == True:
    print('and getting caught in the rain')
elif musical_taste == False:
    print('You clearly have no taste in music')

Solution 15 - Python

How about this:

def yes(prompt = 'Please enter Yes/No: '):
while True:
	try:
		i = raw_input(prompt)
	except KeyboardInterrupt:
		return False
	if i.lower() in ('yes','y'): return True
	elif i.lower() in ('no','n'): return False

Solution 16 - Python

This is what I use:

import sys

# cs = case sensitive
# ys = whatever you want to be "yes" - string or tuple of strings

#  prompt('promptString') == 1:               # only y
#  prompt('promptString',cs = 0) == 1:        # y or Y
#  prompt('promptString','Yes') == 1:         # only Yes
#  prompt('promptString',('y','yes')) == 1:   # only y or yes
#  prompt('promptString',('Y','Yes')) == 1:   # only Y or Yes
#  prompt('promptString',('y','yes'),0) == 1: # Yes, YES, yes, y, Y etc.

def prompt(ps,ys='y',cs=1):
    sys.stdout.write(ps)
    ii = raw_input()
    if cs == 0:
        ii = ii.lower()
    if type(ys) == tuple:
        for accept in ys:
            if cs == 0:
                accept = accept.lower()
            if ii == accept:
                return True
    else:
        if ii == ys:
            return True
    return False

Solution 17 - Python

def question(question, answers):
	acceptable = False
	while not acceptable:
		print(question + "specify '%s' or '%s'") % answers
		answer = raw_input()
		if answer.lower() == answers[0].lower() or answers[0].lower():
			print('Answer == %s') % answer
			acceptable = True
	return answer

raining = question("Is it raining today?", ("Y", "N"))

This is how I'd do it.

Output

Is it raining today? Specify 'Y' or 'N'
> Y
answer = 'Y'

Solution 18 - Python

Here's my take on it, I simply wanted to abort if the user did not affirm the action.

import distutils

if unsafe_case:
    print('Proceed with potentially unsafe thing? [y/n]')
    while True:
        try:
            verify = distutils.util.strtobool(raw_input())
            if not verify:
                raise SystemExit  # Abort on user reject
            break
        except ValueError as err:
            print('Please enter \'yes\' or \'no\'')
            # Try again
    print('Continuing ...')
do_unsafe_thing()

Solution 19 - Python

One-liner with Python 3.8 and above:

while res:= input("When correct, press enter to continue...").lower() not in {'y','yes','Y','YES',''}: pass

Solution 20 - Python

Python x.x

res = True
while res:
    res = input("Please confirm with y/yes...").lower(); res = res not in {'y','yes','Y','YES',''}

Solution 21 - Python

Since the answer is expected yes or no, in the examples below, the first solution is to repeat the question using the function while, and the second solution is to use recursion - is the process of defining something in terms of itself.

def yes_or_no(question):
    while "the answer is invalid":
        reply = str(input(question+' (y/n): ')).lower().strip()
        if reply[:1] == 'y':
            return True
        if reply[:1] == 'n':
            return False

yes_or_no("Do you know who Novak Djokovic is?")

second solution:

def yes_or_no(question):
    """Simple Yes/No Function."""
    prompt = f'{question} ? (y/n): '
    answer = input(prompt).strip().lower()
    if answer not in ['y', 'n']:
        print(f'{answer} is invalid, please try again...')
        return yes_or_no(question)
    if answer == 'y':
        return True
    return False

def main():
    """Run main function."""
    answer = yes_or_no("Do you know who Novak Djokovic is?")
    print(f'you answer was: {answer}')


if __name__ == '__main__':
    main()

Solution 22 - Python

What I used to do is...

question = 'Will the apple fall?'
print(question)
answer = int(input("Pls enter the answer: "
if answer == "y",
print('Well done')
print(answer)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionh3.View Question on Stackoverflow
Solution 1 - PythonfmarkView Answer on Stackoverflow
Solution 2 - PythonVicki LaidlerView Answer on Stackoverflow
Solution 3 - PythonEyal LevinView Answer on Stackoverflow
Solution 4 - PythonAlexander ArtemenkoView Answer on Stackoverflow
Solution 5 - PythonDanilo BargenView Answer on Stackoverflow
Solution 6 - PythonjamesView Answer on Stackoverflow
Solution 7 - PythonDouglas AdamsView Answer on Stackoverflow
Solution 8 - PythonibizamanView Answer on Stackoverflow
Solution 9 - PythonBryce GuintaView Answer on Stackoverflow
Solution 10 - PythonJosefView Answer on Stackoverflow
Solution 11 - PythonSpeqtreView Answer on Stackoverflow
Solution 12 - PythonpjmView Answer on Stackoverflow
Solution 13 - PythonRandy SkretkaView Answer on Stackoverflow
Solution 14 - PythonMikeView Answer on Stackoverflow
Solution 15 - PythonVisgean SkeloruView Answer on Stackoverflow
Solution 16 - PythonfyngyrzView Answer on Stackoverflow
Solution 17 - PythonCallam DelaneyView Answer on Stackoverflow
Solution 18 - PythonThorSummonerView Answer on Stackoverflow
Solution 19 - PythonscenoxView Answer on Stackoverflow
Solution 20 - PythonAK_View Answer on Stackoverflow
Solution 21 - PythonMilovan TomaševićView Answer on Stackoverflow
Solution 22 - PythonKashyapView Answer on Stackoverflow