Can i get console input without echo in python? - python

Can I get console input without echo in python?

Use getpass:
>>> from getpass import getpass
>>> getpass()
Password:
'secret'

There is also another solution (at least on unix systems, I don't know if this is working on Windows). Simply switch off the console output and use raw_input:
os.system("stty -echo")
password = raw_input('Enter Password:')
os.system("stty echo")
print "\n"

Maybe the 'console' module is your only bet (it's kinda 'fork' of the curses module for Unix), however I haven't seen anything related to terminal echo disabling in its homepage, you might try to dig into it by yourself.

Related

Is there a way of deleting specific text for the user in Python?

I am making a program in python and want to clear what the user has enterd, this is because I am using the keyboard function to register input as is is given, but there is still text left over after a keypress is registerd and I don't want this to happen.
I was woundering if there is a module that exists to remove text that is being entered
Any help would be greatly apreciated, and just the name of a module is fine; I can figure out how to use it, just cant find an appropriate module.
EDIT:
Sorry if i did not make my self clear, I dont really want to clear the whole screen, just what the user has typed. So that they don't have to manually back space after their input has been taken.
One way to accomplish this is to use the operating system's clear function.
In windows this is cls and on unix systems this is clear. To call these you would use the os module.
For example:
os.system("clear")
You can use a lambda to make it easier, e.g.:
import os
clear = lambda: os.system('clear') # or 'cls', in case you are on windows.
clear()
You can use os.system('clear') on Mac/Linux or os.system('cls') on Windows
However on some systems you may still be able to scroll up in the terminal. In some cases you can use the up arrow key to see previously entered text.
If it is a password or other sensitive information you can use the getpass module
import getpass
password = getpass.getpass("Enter your password: ")
This will both mask the input and prevent you from up-arrowing into it
'sys.stdout.write' is the moduel I was looking for.

Trouble with masking password input in Python

I am using Python. I am making a script where the user has to enter the password in the terminal.
I have already found a solution on this website by using the getpass module.
new_password=getpass.getpass(prompt="Type new password: ")
The problem is I get a warning and the password input gets displayed as well.
Warning (from warnings module):
File "C:\Python34\lib\getpass.py", line 101
return fallback_getpass(prompt, stream)
GetPassWarning: Can not control echo on the terminal.
Warning: Password input may be echoed.
Use command prompt as admin to run this program.
Reason is because system environment where stdin, stdout and stderr are connected to /dev/tty, or another PTY-compliant device.
The IDLE REPL does not meet this requirement.
And change new_password=getpass.getpass(prompt="Type new password: ") to new_password=getpass.getpass("Type new password: ") if you are using Windows OS or new_password=getpass.getpass("Type new password: ", None) for Linux distributions.
This would help you for sure:
import getpass
pw = getpass.getpass("Enter Your Password Here: ")
if pw == "password":
print("You are Welcome...")
else:
print("Sorry! You're are not allowed.")
As per Python documentation:
getpass.getpass([prompt[, stream]])
Prompt the user for a password without echoing. The user is prompted using the string prompt, which defaults to 'Password: '. On Unix, the prompt is written to the file-like object stream. stream defaults to the controlling terminal (/dev/tty) or if that is unavailable to sys.stderr (this argument is ignored on Windows)
Changed in version 2.5: The stream parameter was added.
Note: If you call getpass from within IDLE, the input may be done in the terminal you launched IDLE from rather than the idle window itself.
Using a normal terminal with this code:
import getpass
new_password=getpass.getpass(prompt="Type new password: ")
print(new_password)
Will work alright, but if we try the same with IDLE we'll get the error you've exposed in your question.
Now, if we look at the docs here you'll see this is intended, it says:
Note If you call getpass from within IDLE, the input may be done in
the terminal you launched IDLE from rather than the idle window
itself.

Python inside bash Input Error

I have inserted python code inside bash script like this:
#!/bin/bash
echo "You are in Bash"
python <<END
# -*- coding: utf-8 -*-
import os
import sys
import getpass
print "You are in python"
username=raw_input('Bitbucket Username : ')
END
echo "Python ended"
But the problem is I am not able to take input using raw_input or input when I insert python in bash. Python alone works fine. What is the problem here in my code?
Instead of a heredoc, just user the -c parameter to pass a command:
$ python -c "username = raw_input('Enter name: ')
print 'Hello', username
"
Enter name: Chris
Hello Chris
Once you say END, you are telling bash that your program is over. Bash gives your lines as input to Python. If you are in python, type each line that you wrote there, regardless of what prompt, and when you are done, signify EOF by Ctrl-D on linux, Ctrl-Z on windows. You will see that raw_input() will have a EOFError. That is what bash is doing. It gives Python each line, and then says "We're done. Send EOF". It pays no attention to what prompt is given. It doesn't know that you are asking for input. This is a useful feature, however, because if it didn't have that, there would be nothing telling Python to exit...ever. You would have to send KeyboardInterrupt to get that program to exit.

Starting raw_input() with pre determined text

I'd like to be able to get input from the user (through raw_input() or a module) and be able to have text automatically be already entered that they can add to, delete, or modify. I know in javascript when you're using a prompt, you can do it like
var = prompt("Enter your name: ","put name here")
and it will appear as:
Enter your name:
put name here
where 'put name here' is in the text box and can be modified. I'm hoping to implement this in a shell environment (I use unix) as opposed to a window.
Any ways to do this?
Oh and tell me if I need to clarify what I am hoping for more.
I don't think you guys understand what I'm trying to do.
I basically want to include the prompt in the input, but have the user be able to backspace out the prompt/edit it if they want.
The script would possibly be used for a simple shell based one line text editor, and a tab completion type thing.
On UNIX and UNIX-alikes, such as Mac OS X and Linux, you can use the readline module. On Windows you can use pyreadline.
If you do it the way minitech suggests in his comment, write a little function to make it easier:
def input_default(prompt, default):
return raw_input("%s [%s] " % (prompt, default)) or default
name = input_default("What is your name?", "Not Sure")
Mmm, kinda hack, but try this one.
Windows:
import win32com.client as win
shell = win.Dispatch("WScript.Shell").SendKeys("Put name here")
raw_input("Enter your name: ")
In Linux/Unix environment, you can use the pyreadline, readline or curses libraries. You can find one possible solution here:
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return raw_input(prompt)
finally:
readline.set_startup_hook()

Detect where Python code is running (e.g., in Spyder interpreter vs. IDLE vs. cmd)

Is there a way in Python to detect, within a process, where that process is being executed? I have some code that includes the getpass.getpass() function, which is broken in Spyder, and it's annoying to go back and forth between the command line and the IDE all the time. It would be useful if I could add code like:
if not being run from Spyder:
use getpass
else:
use alternative
Here is the solution I ended up using. After reading Markus's answer, I noticed that Spyder adds half a dozen or so environment variables to os.environ with names like SPYDER_ENCODING, SPYDER_SHELL_ID, etc. Detecting the presence of any of these seems relatively unambiguous, compared to detecting the absence of a variable with as generic a name as 'PYTHONSTARTUP'. The code is simple, and works independently of Spyder's startup script (as far as I can tell):
if any('SPYDER' in name for name in os.environ)
# use alternative
else:
# use getpass
Since the string is at the beginning of each environment variable name, you could also use str.startswith, but it's less flexible, and a little bit slower (I was curious):
>>> import timeit
>>> s = timeit.Timer("[name.startswith('SPYDER') for name in os.environ]", "import os")
>>> i = timeit.Timer("['SPYDER' in name for name in os.environ]", "import os")
>>> s.timeit()
16.18333065883474
>>> i.timeit()
6.156869294143846
The sys.executable method may or may not be useful depending on your installation. I have a couple WinPython installations and a separate Python 2.7 installation, so I was able to check the condition sys.executable.find('WinPy') == -1 to detect a folder name in the path of the executable Spyder uses. Since the warning that shows in IDLE when you try to use getpass is less "loud" than it could be, in my opinion, I ended up also checking the condition sys.executable.find('pythonw.exe') == -1 to make it slightly louder. Using sys.executable only, that method looks like:
if sys.executable.find('pythonw.exe') == sys.executable.find('WinPy') == -1:
# use getpass
else:
# use alternative
But since I want this to work on other machines, and it's much more likely that another user would modify their WinPython installation folder name than that they would rename their IDLE executable, my final code uses sys.executable to detect IDLE and os.environ to detect Spyder, providing a "louder" warning in either case and keeping the code from breaking in the latter.
if any('SPYDER' in name for name in os.environ) \
or 'pythonw.exe' in sys.executable:
password = raw_input('WARNING: PASSWORD WILL BE SHOWN ON SCREEN\n\n' * 3
+ 'Please enter your password: ')
else:
password = getpass.getpass("Please enter your password: ")
By default, Spyder uses a startup scrip, see Preferences -> Console -> Adanced setting. This option is usually set to the scientific_startup.py file that loads pylab et al.
The easiest solution is to just add a global variable to the file and then use that in your if statement, e.g. add this line at the end of scientific_startup.py:
SPYDER_IDE_ACTIVE = True
In your script:
if not 'SPYDER_IDE_ACTIVE' in globals():
use getpass
else:
use alternative
This will work without throwing an error. You can also use exceptions if you like that more.
A second solution would be (if you cannot modify that file for some reason) to just check if the environment variable PYTHONSTARTUP is set. On my machine (using the Anaconda Python stack), it is not set for a regular Python shell. You could do
import os
if not 'PYTHONSTARTUP' in os.environ:
use getpass
else:
use alternative
Spyder provides the option of executing the current editor script in a native system terminal. This would produce identical behavior as if you were running from the command line. To set this up, open the Run Settings dialog by hitting F6. Then select the radio button "Execute in an external System terminal". Now run the script as usual by hitting F5. You should be able to use getpass in the normal fashion with this approach.
You could add env variable when running in Spyder and check it in code.

Categories

Resources