Following code prompts for user and password, when run in console:
import getpass
user = getpass.getpass("Username:")
passwd = getpass.getpass("Password for " + user + ":")
print "Got", user, passwd
The obvious problem with above is, user name is not echoed as it is typed.
Now getpass documentation says "On Unix it defaults to using /dev/tty before falling back to sys.stdin and sys.stderr."
Question: How to ask for both username and password, so that they are read from same source, and username is echoed normally, while password is not?
Why not just use raw_input for the username:
import getpass
user = raw_input("Username:")
passwd = getpass.getpass("Password for " + user + ":")
print("Got", user, passwd)
Demo:
Username:iCodez
Password for iCodez:
('Got', 'iCodez', 'secret')
There is another alternative, which I found documented here. Detect whether the input stream is a TTY, and change your input method based on that information.
I used something like this:
#!/usr/bin/python
import sys
import getpass
if sys.stdin.isatty():
print "Enter credentials"
username = raw_input("Username: ")
password = getpass.getpass("Password: ")
else:
username = sys.stdin.readline().rstrip()
password = sys.stdin.readline().rstrip()
print "Username: [%s], password [%s]" % (username, password)
This works fine from a terminal:
bash> ./mytest.py
Enter credentials
Username: one
Password:
Username: [one], password [two]
for piped input:
bash> echo "one
> two" | ./mytest.py
Username: [one], password [two]
for input from a file:
bash> echo "one" > input
bash> echo "two" >> input
bash> ./mytest.py < input
Username: [one], password [two]
and also for a heredoc:
bash> ./mytest.py << EOF
> one
> two
> EOF
Username: [one], password [two]
Personally, that covers all of my needs.
In Python 2.x, use raw_input (input in Python 3.x) instead of getpass.getpass for username.
user = raw_input("Username:")
It would be possible to use raw_input (input in Python 3) but as already mentioned in the question, getpass is using /dev/tty before falling back to sys.stdin and sys.stderr. This means that in some situations getpass and raw_input is using different sources.
On linux, you might see the difference by executing the application with the following command:
my_app.py < /path/to/some/file
The function raw_input would read from the file while getpass would still use the terminal. Even if it is not documented explicitly, the same is happening on Windows.
I have not found a function that is doing something like getpass without hiding the input. I think you have to implement it yourself or search for a library which is doing it. You can look at the current implementation of getpass in Python 3 and in Python 2.7 to get some inspiration.
I wrote an exmaple below. Basically, I used the implementation of Python 3 and removed everything that is related to hiding the input. Then, I made some changes to support Python 2.
def _raw_input(prompt, fin, fout):
if prompt:
try:
fout.write(prompt)
except UnicodeEncodeError:
# Replace characters that are not supported by the terminal
prompt = prompt.encode(fout.encoding, 'replace')
prompt = prompt.decode(fout.encoding)
fout.write(prompt)
fout.flush()
line = fin.readline()
return line[:-1] if line[-1] == '\n' else line
def _ttyinput_unix(prompt):
try:
fd = os.open("/dev/tty", os.O_RDWR, os.O_NOCTTY)
if sys.version_info < (3, 0):
with os.fdopen(fd, 'w+', 1) as tty:
return _raw_input(prompt, tty, tty)
with io.FileIO(fd, 'w+') as tty:
with io.TextIOWrapper(tty) as wrapper:
return _raw_input(prompt, wrapper, wrapper)
except (OSError, AttributeError) as e:
return _raw_input(prompt, sys.stdin, sys.stderr)
def _ttyinput_win(prompt):
if sys.stdin is not sys.__stdin__:
# I don't know why getpass is doing this.
return _raw_input(prompt, sys.stdin, sys.stderr)
if sys.version_info >= (3, 0):
getch = msvcrt.getwch
putch = msvcrt.putwch
else:
getch = msvcrt.getch
putch = msvcrt.putch
for c in prompt:
putch(c)
password = ""
while True:
c = getch()
if c == '\r' or c == '\n':
break
if c == '\003':
raise KeyboardInterrupt
if c == '\b':
if len(password) > 0:
password = password[:-1]
for x in "\b \b":
putch(x)
else:
password += c
putch(c)
putch('\r')
putch('\n')
return password
try:
import msvcrt
ttyinput = _ttyinput_win
except ImportError:
ttyinput = _ttyinput_unix
I tested my implementation with Python 2.7 on Windows and with Python 2.7 and 3.5 on Arch Linux.
try this:
user = raw_input("Username:")
Related
I'm using Python 2.7's raw_input to read from stdin.
I want to let the user change a given default string.
Code:
i = raw_input("Please enter name:")
Console:
Please enter name: Jack
The user should be presented with Jack but can change (backspace) it to something else.
The Please enter name: argument would be the prompt for raw_input and that part shouldn't be changeable by the user.
You could do:
i = raw_input("Please enter name[Jack]:") or "Jack"
This way, if user just presses return without entering anything, "i" will be assigned "Jack".
Python2.7 get raw_input and set a default value:
Put this in a file called a.py:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return raw_input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
Run the program, it stops and presents the user with this:
el#defiant ~ $ python2.7 a.py
Caffeine is: an insecticide
The cursor is at the end, user presses backspace until 'an insecticide' is gone, types something else, then presses enter:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
Program finishes like this, final answer gets what the user typed:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
final answer: water soluable
Equivalent to above, but works in Python3:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
More info on what's going on here:
https://stackoverflow.com/a/2533142/445131
In dheerosaur's answer If user press Enter to select default value in reality it wont be saved as python considers it as '' string so Extending a bit on what dheerosaur.
default = "Jack"
user_input = raw_input("Please enter name: %s"%default + chr(8)*4)
if not user_input:
user_input = default
Fyi .. The ASCII value of backspace is 08
I only add this because you should write a simple function for reuse. Here is the one I wrote:
def default_input( message, defaultVal ):
if defaultVal:
return raw_input( "%s [%s]:" % (message,defaultVal) ) or defaultVal
else:
return raw_input( "%s " % (message) )
On platforms with readline, you can use the method described here: https://stackoverflow.com/a/2533142/1090657
On Windows, you can use the msvcrt module:
from msvcrt import getch, putch
def putstr(str):
for c in str:
putch(c)
def input(prompt, default=None):
putstr(prompt)
if default is None:
data = []
else:
data = list(default)
putstr(data)
while True:
c = getch()
if c in '\r\n':
break
elif c == '\003': # Ctrl-C
putstr('\r\n')
raise KeyboardInterrupt
elif c == '\b': # Backspace
if data:
putstr('\b \b') # Backspace and wipe the character cell
data.pop()
elif c in '\0\xe0': # Special keys
getch()
else:
putch(c)
data.append(c)
putstr('\r\n')
return ''.join(data)
Note that arrows keys don't work for the windows version, when it's used, nothing will happen.
For windows users with gitbash/msys2 or cygwin you can use it's built in readline through python subprocess. It is a sort of hack but works quite well and doesn't require any third party code. For personal tools this works really well.
Msys2 specific: If you want ctrl+c to immediately exit, you will need to run your program with
winpty python program.py
import subprocess
import shlex
def inputMsysOrCygwin(prompt = "", prefilled = ""):
"""Run your program with winpty python program.py if you want ctrl+c to behave properly while in subprocess"""
try:
bashCmd = "read -e -p {} -i {} bash_input; printf '%s' \"$bash_input\"".format(shlex.quote(prompt), shlex.quote(prefilled))
userInput = subprocess.check_output(["sh", "-c", bashCmd], encoding='utf-8')
return userInput
except FileNotFoundError:
raise FileNotFoundError("Invalid environment: inputMsysOrCygwin can only be run from bash where 'read' is available.")
userInput = ""
try:
#cygwin or msys2 shell
userInput = inputMsysOrCygwin("Prompt: ", "This is default text")
except FileNotFoundError:
#cmd or powershell context where bash and read are not available
userInput = input("Prompt [This is default text]: ") or "This is default text"
print("userInput={}".format(userInput))
Try this: raw_input("Please enter name: Jack" + chr(8)*4)
The ASCII value of backspace is 08.
You know how in Linux when you try some Sudo stuff it tells you to enter the password and, as you type, nothing is shown in the terminal window (the password is not shown)?
Is there a way to do that in Python? I'm working on a script that requires so sensitive info and would like for it to be hidden when I'm typing it.
In other words, I want to get the password from the user without showing the password.
Use getpass.getpass():
from getpass import getpass
password = getpass()
An optional prompt can be passed as parameter; the default is "Password: ".
Note that this function requires a proper terminal, so it can turn off echoing of typed characters – see “GetPassWarning: Can not control echo on the terminal” when running from IDLE for further details.
import getpass
pswd = getpass.getpass('Password:')
getpass works on Linux, Windows, and Mac.
This code will print an asterisk instead of every letter.
import sys
import msvcrt
passwor = ''
while True:
x = msvcrt.getch()
if x == '\r':
break
sys.stdout.write('*')
passwor +=x
print '\n'+passwor
Updating on the answer of #Ahmed ALaa
# import msvcrt
import getch
def getPass():
passwor = ''
while True:
x = getch.getch()
# x = msvcrt.getch().decode("utf-8")
if x == '\r' or x == '\n':
break
print('*', end='', flush=True)
passwor +=x
return passwor
print("\nout=", getPass())
msvcrt us only for windows, but getch from PyPI should work for both (I only tested with linux).
You can also comment/uncomment the two lines to make it work for windows.
You can also use the pwinput module which works on both Windows and Linux.
It replaces the char with '*' (by default) and backspace works.
import pwinput
password = pwinput.pwinput(prompt='Password: ')
You can, optionally, pass a different mask character as well.
import pwinput
password = pwinput.pwinput(prompt='Password: ', mask='')
See the pwinput documentation for more information.
Here is my code based off the code offered by #Ahmed ALaa
Features:
Works for passwords up to 64 characters
Accepts backspace input
Outputs * character (DEC: 42 ; HEX: 0x2A) instead of the input character
Demerits:
Works on Windows only
The function secure_password_input() returns the password as a string when called. It accepts a Password Prompt string, which will be displayed to the user to type the password
def secure_password_input(prompt=''):
p_s = ''
proxy_string = [' '] * 64
while True:
sys.stdout.write('\x0D' + prompt + ''.join(proxy_string))
c = msvcrt.getch()
if c == b'\r':
break
elif c == b'\x08':
p_s = p_s[:-1]
proxy_string[len(p_s)] = " "
else:
proxy_string[len(p_s)] = "*"
p_s += c.decode()
sys.stdout.write('\n')
return p_s
how do I change the text to * while it is being inputted, like:
#Think that the code below is running in the console and I am
#inputting in it
Password: Example # How do make it turn it to '*******' while it is still being written?
Yup, i am not forced to only input, I can type in any command, please just tell me how to.
And you can tell tk code too
use the getpass module -
import getpass
getpass.getpass("Enter your password: ")
For tkinter entry, use the option show. Here is a code:
import tkinter as tk
root = tk.Tk()
passw = tk.Entry(root,show="*")
passw.grid(row=0,column=0)
passb = tk.Button(root,text="Print Password",command=lambda :print(passw.get()))
passb.grid(row=1,column=0)
root.mainloop()
To get password in console, you will have to modify the module getpass (Try at your own risk). Go to your python folder and open folder Lib. Open the file getpass.py and go to line 98 (there will be a function naming win_getpass)
Replace the whole function (win_getpass) with (lines:98-119) (Updated):
def win_getpass(prompt='Password: ', stream=None,show=""):
"""Prompt for password with echo off, using Windows getch()."""
if sys.stdin is not sys.__stdin__:
return fallback_getpass(prompt, stream)
for c in prompt:
msvcrt.putwch(c)
pw = ""
while True:
c = msvcrt.getwch()
if c == '\r' or c == '\n':
break
if c == '\003':
raise KeyboardInterrupt
if c == '\b':
pw = pw[:-1]
if pw != "":msvcrt.putwch("\b");msvcrt.putwch(" ");msvcrt.putwch("\b")
else:
pw = pw + c
msvcrt.putwch(show)
msvcrt.putwch('\r')
msvcrt.putwch('\n')
return pw
Now you can use the getpass function as:
import getpass
getpass.getpass("Enter your password: ",show="*")
You can change the value of show to whatever you want to show. Default is empty (means hide).
Note:
getpass will only work in console. It will raise error in IDLE.
Screenshot:
everytime it shows my PASS in this way cmd 'PASS XXXXXX'.How can I stop it showing my PASS? Here is my code.Everyone knows how to do it?
import os, sys, string
import poplib
import getpass
host = "pop3.163.com"
username = raw_input('Username:')
pp = poplib.POP3(host)
pp.set_debuglevel(1)
pp.user(username)
pp.pass_(getpass.getpass())
action =""
if len(sys.argv) > 1:
action = sys.argv[1]
if action == 'stat':
ret = pp.stat()
print ret
# sys.exit()
else:
print "I dont know this command"
Quite simply, it's because you've asked the POP3 lib to give you debugging output. Some of what it's included appears to be the password that's being sent to the server. To avoid this, you should simply omit your log level set (the documentation says the default level is 0 -> no output), or explicitly set it to 0.
When you use getpass you need to save it in a variable or else, in the command line at least, it will print out the password:
>>> import getpass
>>> getpass.getpass()
Password:
'password'
>>> pword = getpass.getpass()
Password:
>>> pword
'password'
I'm using Python 2.7's raw_input to read from stdin.
I want to let the user change a given default string.
Code:
i = raw_input("Please enter name:")
Console:
Please enter name: Jack
The user should be presented with Jack but can change (backspace) it to something else.
The Please enter name: argument would be the prompt for raw_input and that part shouldn't be changeable by the user.
You could do:
i = raw_input("Please enter name[Jack]:") or "Jack"
This way, if user just presses return without entering anything, "i" will be assigned "Jack".
Python2.7 get raw_input and set a default value:
Put this in a file called a.py:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return raw_input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
Run the program, it stops and presents the user with this:
el#defiant ~ $ python2.7 a.py
Caffeine is: an insecticide
The cursor is at the end, user presses backspace until 'an insecticide' is gone, types something else, then presses enter:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
Program finishes like this, final answer gets what the user typed:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
final answer: water soluable
Equivalent to above, but works in Python3:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
More info on what's going on here:
https://stackoverflow.com/a/2533142/445131
In dheerosaur's answer If user press Enter to select default value in reality it wont be saved as python considers it as '' string so Extending a bit on what dheerosaur.
default = "Jack"
user_input = raw_input("Please enter name: %s"%default + chr(8)*4)
if not user_input:
user_input = default
Fyi .. The ASCII value of backspace is 08
I only add this because you should write a simple function for reuse. Here is the one I wrote:
def default_input( message, defaultVal ):
if defaultVal:
return raw_input( "%s [%s]:" % (message,defaultVal) ) or defaultVal
else:
return raw_input( "%s " % (message) )
On platforms with readline, you can use the method described here: https://stackoverflow.com/a/2533142/1090657
On Windows, you can use the msvcrt module:
from msvcrt import getch, putch
def putstr(str):
for c in str:
putch(c)
def input(prompt, default=None):
putstr(prompt)
if default is None:
data = []
else:
data = list(default)
putstr(data)
while True:
c = getch()
if c in '\r\n':
break
elif c == '\003': # Ctrl-C
putstr('\r\n')
raise KeyboardInterrupt
elif c == '\b': # Backspace
if data:
putstr('\b \b') # Backspace and wipe the character cell
data.pop()
elif c in '\0\xe0': # Special keys
getch()
else:
putch(c)
data.append(c)
putstr('\r\n')
return ''.join(data)
Note that arrows keys don't work for the windows version, when it's used, nothing will happen.
For windows users with gitbash/msys2 or cygwin you can use it's built in readline through python subprocess. It is a sort of hack but works quite well and doesn't require any third party code. For personal tools this works really well.
Msys2 specific: If you want ctrl+c to immediately exit, you will need to run your program with
winpty python program.py
import subprocess
import shlex
def inputMsysOrCygwin(prompt = "", prefilled = ""):
"""Run your program with winpty python program.py if you want ctrl+c to behave properly while in subprocess"""
try:
bashCmd = "read -e -p {} -i {} bash_input; printf '%s' \"$bash_input\"".format(shlex.quote(prompt), shlex.quote(prefilled))
userInput = subprocess.check_output(["sh", "-c", bashCmd], encoding='utf-8')
return userInput
except FileNotFoundError:
raise FileNotFoundError("Invalid environment: inputMsysOrCygwin can only be run from bash where 'read' is available.")
userInput = ""
try:
#cygwin or msys2 shell
userInput = inputMsysOrCygwin("Prompt: ", "This is default text")
except FileNotFoundError:
#cmd or powershell context where bash and read are not available
userInput = input("Prompt [This is default text]: ") or "This is default text"
print("userInput={}".format(userInput))
Try this: raw_input("Please enter name: Jack" + chr(8)*4)
The ASCII value of backspace is 08.