5

I am trying to create a program that take the user input but rather than displaying the actual input I would like to replace the input with an *

I have tried using this code but I keep getting the error below, I would appreciate any guidance or help.

import msvcrt
import sys


def userinput(prompt='>'):
    write = sys.stdout.write
    for x in prompt:
        msvcrt.putch(x)

    entry = ""

    while 1:
        x = msvcrt.getch()
        print(repr(x))

        if x == '\r' or x == '\n':
            break
        if x == '\b':
            entry = entry[:-1]
        else:
            write('*')
            entry = entry + x
    return entry

userEntry = userinput()

Error:

Traceback (most recent call last):
  File "C:\Users\Mehdi\Documents\Teaching\KS5\AS CS\getPass.py", line 24, in <module>
    userEntry = userinput()
  File "C:\Users\Mehdi\Documents\Teaching\KS5\AS CS\getPass.py", line 9, in userinput
    msvcrt.putch(x)
TypeError: putch() argument must be a byte string of length 1, not str
pzp
  • 6,249
  • 1
  • 26
  • 38
Sarah
  • 133
  • 1
  • 9
  • 1
    I'm not super familiar with this but it sounds like you need to convert x from a string to a byte string, this link might help you there. [link](http://stackoverflow.com/questions/7585435/best-way-to-convert-string-to-bytes-in-python-3) – Eric Nov 17 '16 at 20:24
  • I just fixed your indentation. I believe I interpreted your intent correctly, but if I did not (there was some ambiguity), please edit your question and correct it. – pzp Nov 17 '16 at 20:33
  • 2
    Check out the [`getpass`](https://docs.python.org/3.5/library/getpass.html#module-getpass) module. It seems to do exactly what you are asking for. – pzp Nov 17 '16 at 20:48
  • `putch()` expect one byte but Python uses unicode so one char may use more then one byte. – furas Nov 17 '16 at 20:54
  • @pzp I tired the getpass and got the following error Warning (from warnings module): File "C:\Users\Mehdi\AppData\Local\Programs\Python\Python35-32\lib\getpass.py", line 101 return fallback_getpass(prompt, stream) GetPassWarning: Can not control echo on the terminal. Warning: Password input may be echoed. Enter the Password: – Sarah Nov 17 '16 at 20:57
  • @furas I understand the cause of the error but i do not know how to fix it – Sarah Nov 17 '16 at 20:58
  • @Sarah Where are you running the code? In IDLE, perchance? Read this other [SO question about someone who was experiencing the same error](https://stackoverflow.com/questions/38878741/getpasswarning-can-not-control-echo-on-the-terminal-when-running-from-idle). – pzp Nov 17 '16 at 21:01

2 Answers2

0

You could use the Tkinter module to get the user input. here's the code

    from tkinter import *
    root = Tk()
    entry = Entry(root)
    entry.pack()
    entry.config(show='*')
    userinput = entry.get()

You can replace the '*' in the config function with any symbol you'd like. That symbol will replace the answer. The value that the user inputs is stored in the entry.get() function which you should save as a variable. Put a print statement before this so that they know what you want them to put in the entry. Or you can just do this before the entry

   label = Label(root, text='Input the text here')
   label.pack()
Anonymous
  • 25
  • 6
-1

As per the error you get, putch gets a byte, not a string, so use

for x in prompt:
    msvcrt.putch(x.encode()[:1])

(the [:1] is usually not necessary, just to make sure the bytes array is of length 1 as required)


More common practice than using streams would be to use msvcrt.getch and loop until you get a newline, while printing a string of the user input length full of * every time and printing to the same line by carriage return at the end of the printing function:

import msvcrt

def getch():
    return chr(msvcrt.getch()[0])

def hidden_input (input_message = 'enter input:'):

    user_input = ''
    new_ch = ''

    while new_ch != '\r':
        print(input_message, '*' * len(user_input), ' ' * 20, end = '\r')
        user_input = user_input[:-1] if new_ch == '\b' else user_input + new_ch 
        new_ch = getch()

    return user_input

hidden_input()
Uriel
  • 15,579
  • 6
  • 25
  • 46