I have a function to display a GUI window where the user can type the password. I use IDLE shell a lot during development, so using getpass
is not an option.
This function is part of a utility script that has other functions I want to be able to use (after submitting the password using this function).
import tkinter
def password_from_user():
password = None
def get_password(*__):
nonlocal password
password = entry.get()
window.destroy()
window = tkinter.Tk()
entry = tkinter.Entry(window, width=40, show='*')
entry.bind('<Return>', get_password)
entry.pack()
entry.focus_set()
window.mainloop()
return password
The password gets stored and returned from the function. However, the Tkinter window stays open. I can press ⌘+Tab to switch back to IDLE shell, but it's slightly inconvenient. I'd like this window to be completely closed.
If I run this as a script, of course, everything gets closed at the end:
if __name__ == '__main__':
print(password_from_user())
But, I need this function only for IDLE session. If I were only using command line, I would use getpass
which would be more than sufficient.
Edit 1: I have tried using both destroy
and quit
. Neither of them works for me.
Edit 2: Just tested on a Windows machine with Python 3.8.5. It works. So, I'm pretty sure it's something to do with macOS.
Figured out a solution that satisfies me.
Save the Tkinter code in a separate module (say, _password_box_ui.py
):
import tkinter
password = None
def get_password(*__):
global password
password = entry.get()
window.quit()
window = tkinter.Tk()
window.title('Password')
entry = tkinter.Entry(window, width=40, show='*')
entry.bind('<Return>', get_password)
entry.pack()
entry.focus_set()
window.mainloop()
print(password)
Then, in another module (which I'll import in the IDLE shell), use a function like this:
import pathlib
import subprocess
import sys
def password_from_user():
process = subprocess.run(
[
f'{sys.base_exec_prefix}/bin/python',
pathlib.Path(__file__).parent / '_password_box_ui.py',
],
capture_output=True,
)
return process.stdout.rstrip(b'\n').decode()
May not be very elegant, but serves my purpose, which is to use IDLE to get password from the user using a GUI (so that, ultimately, no password needs to be stored in plaintext anywhere).