Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yes/No prompt in Python3 using strtobool

I've been trying to write an elegant [y/n] prompt for scripts that I'll be running over command line. I came across this:

http://mattoc.com/python-yes-no-prompt-cli.html

This is the program I wrote up to test it (it really just involved changing raw_input to input as I'm using Python3):

import sys
from distutils import strtobool

def prompt(query):
    sys.stdout.write("%s [y/n]: " % query)
    val = input()
    try:
        ret = strtobool(val)
    except ValueError:
        sys.stdout.write("Please answer with y/n")
        return prompt(query)
    return ret

while True:
    if prompt("Would you like to close the program?") == True:
        break
    else:
        continue

However, whenever I try to run the code I get the following error:

ImportError: cannot import name strtobool

Changing "from distutils import strtobool" to "import distutils" doesn't help, as a NameError is raised:

Would you like to close the program? [y/n]: y
Traceback (most recent call last):
  File "yes_no.py", line 15, in <module>
    if prompt("Would you like to close the program?") == True:
  File "yes_no.py", line 6, in prompt
    val = input()
  File "<string>", line 1, in <module>
NameError: name 'y' is not defined

How do I go about solving this problem?

like image 839
Lukasz Avatar asked Feb 15 '17 11:02

Lukasz


2 Answers

The first error message:

ImportError: cannot import name strtobool

is telling you that there's no publically visible strtobool function in the distutils module you've imported.

This is because it's moved in python3: use from distutils.util import strtobool instead.

https://docs.python.org/3/distutils/apiref.html#distutils.util.strtobool


The second error message deeply confuses me -- it seems to imply that the y you input is trying to be interpreted as code (and therefore complains that it doesn't know about any y variable. I can't quite see how that'd happen!

... two years pass ...

Ahh, I get it now... input in Python 3 is "get a string from the keyboard", but input in Python 2 is "get a string from the keyboard, and eval it". Assuming you don't want to eval the input, use raw_input on Python 2 instead.

like image 124
Dragon Avatar answered Sep 27 '22 19:09

Dragon


The distutils package has been deprecated in Python 3.10 and will be removed from Python 3.12. Fortunately, the strtobool function is pretty small, so you can just copy its code to your module:

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,))
like image 26
Eugene Yarmash Avatar answered Sep 27 '22 21:09

Eugene Yarmash