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
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()
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()
Related
I'm trying to make sure the input the user uses is all letters.I tried the .alpha method but since this is a file, a "." will be included returning it false. I also tried using "quit" sentinel value to exit the program but that isn't working. It keeps saying break is outside the loop. I also want the user to keep inputting if the file is not found error is raised.
The Assignment1
def main():
fileName = inputTxt()
FiletoReadFrom = openingFile(fileName)
counter = 0
for line in FiletoReadFrom:
outputFile = open("output.txt", "a+")
counter = counter + 1
outputFile.write("/* {} */ {}\n".format(counter, line.strip()))
if counter == 0:
print("This is an empty file")
else:
print("The file has been made")
FiletoReadFrom.close()
outputFile.close()
def inputTxt():
flag = True
while flag == True:
FileName= input("Please Enter the Name of the File, or type quit to exit ")
if FileName == quit:
flag == False
break
print("goodbye")
else:
return FileName
def openingFile(filetoReadFrom):
try:
a = open(filetoReadFrom, 'r')
return a
except FileNotFoundError:
print("This File was not Found", "Enter again or type quit to exit")
main()
There are different questions here, which is frowned upon on this site. Please never do that again.
the quit and break problem:
It is just a typo. As you forgot quoting 'quit', Python sees it at an undeclared variable which gives a syntax error. Fix:
...
while flag == True:
FileName= input("Please Enter the Name of the File, or type quit to exit ")
if FileName == 'quit':
flag == False
break
...
But it is still wrong, because break will only exit from the loop and inputTxt will return None which is not what you expect. Calling sys.exit() could be better here.
Test for letters and not numbers:
You must choose a white list (only alphas and dot) or black list (no numbers) way. In idiomatic Python it could be:
if all((x.isalpha() or x == '.') for x in FileName): # white list
# process error condition
if any(x.isdigit() for x in FileName): # black list
# process error condition
You could also use the re module which is great at controlling that a string respect a given pattern...
keep asking until a valid file is given:
You should use a loop:
def main():
while True:
fileName = inputTxt()
FiletoReadFrom = openingFile(fileName)
if FileToReadFrom is not None: # openingFile returns None when file does not exist
break
But IMHO, you should remove the openingFile function and directly use (and test) open in main
I got a question which says "Write a function user prints even number from list). We have to ask the user to input a list. I am getting a "Type Error: not all arguments converted during string formatting". Please help were am I wrong.
def even_no(x):
a = x.split()
new_list = []
for i in a:
if i % 2 == 0:
new_list.append(i)
input_no = input("Enter number sequence: ")
print(even_no(input_no))
% is also use for string formatting, and since the split method belongs to string, it also returns a string, hence, the interpreter tries to format it.
change the line:
if i % 2 == 0:
to
if int(i) % 2 == 0:
that your code should work.
As a side note, your function won't print anything because there's no return for the even_no function
You forgot to convert the numbers from str to int. map can be used for this. Also you did not return your list.
def even_no(x):
a = map(int, x.split())
new_list = []
for i in a:
if i % 2 == 0:
new_list.append(i)
return new_list
input_no = input("Enter number sequence: ")
print(even_no(input_no))
Execution example:
Enter number sequence: 10 20 30
[10, 20, 30]
A couple of issues to be noted.
The first one has already been mentioned, which is the need to convert strings to integers.
The second is with the following line:
input_no = input("Enter number sequence: ") .
When I tested, the function "even_no" would not execute with the above line present as a global variable.
To overcome this problem I used tkinter and a class in the following code.
Please note: This allows the user to enter a number or numbers into an entry field. Each number should be separated by a space. Only numbers should be used.
If any even numbers are entered, they will be printed into a list in the python shell. If No even numbers are entered, an empty list will be printed. If non-numeric characters are entered, the Value Error is handled to guide the user on the correct method of input.
import tkinter as tk
from tkinter import Tk, messagebox
import tkinter.filedialog
from tkinter import Tk, Label, Button
from tkinter import *
class Control(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.controller = self
self.shared_data = {
"input_no": tk.StringVar(),
}
self.title('Even')
self.entry = Entry(self, textvariable=self.shared_data["input_no"])
self.entry.pack()
self.enterbutton = tk.Button(self, text='Enter',
command=(self.even_no)
)
self.enterbutton.pack()
def even_no(self):
try:
user_input = self.shared_data["input_no"].get()
a = user_input.split()
new_list = []
for i in a:
if int(i) % 2 == 0:
new_list.append(int(i))
print(new_list)
except ValueError:
print('Invalid Entry. Please enter numbers only. \n'
'Please make sure that each number is separated by a space.')
Control1 = Control()
Control1.mainloop()
Your indentation was a bit so I fixed that and you also forgot to use return. I fixed all of that including your TypeError. Here is the code:
def even_no(x):
a = x.split()
new_list = []
for i in a:
if int(i) % 2 == 0:
new_list.append(i)
return new_list
input_no = input("Enter number sequence: ")
print(even_no(input_no))
I was programming a project of secret messages which uses a few lists and appends. To my understanding, I don't think that any of my lists are out of range so I am very confused on why I am getting this error. Here is my code.
from tkinter import Tk, messagebox, simpledialog
def is_even(number):
return number % 2 == 0
def get_even_letters(message):
even_letters = []
for counter in range(0, len(message)):
if is_even(counter):
even_letters.append(message[counter])
return even_letters
def get_odd_letters(message):
odd_letters = []
for counter in range(0, len(message)):
if not is_even(counter):
odd_letters.append(message[counter])
return odd_letters
def swap_letters(message):
letter_list = []
if not is_even(len(message)):
message = message + 'x'
even_letters = get_even_letters(message)
odd_letters = get_odd_letters(message)
for counter in range(0, int(len(message)/2)):
letter_list.append(odd_letters[counter])
letter_list.append(even_letters[counter])
new_message = ''.join(letter_list)
return new_message
def get_task():
task = simpledialog.askstring('Task', 'Do you want to encrypt or decrypt?')
return task
def get_message():
message = simpledialog.askstring('Message', 'Enter the secret message: ')
return message
root = Tk()
root.withdraw()
while True:
task = get_task()
if task == 'encrypt':
message = get_message()
encrypted = swap_letters(message)
messagebox.showinfo('Ciphertext of the secret message: ', encrypted)
elif task == 'decrypt':
message = get_message()
decrypted = swap_letters(message)
messagebox.showinfo('Plaintext of the secret message: ', decrypted)
else:
break
root.mainloop()
Here is my error code:
Traceback (most recent call last):
File "C:/Users/Osprey/AppData/Local/Programs/Python/Python36-32/secret_messages.py", line 52, in
encrypted = swap_letters(message)
File "C:/Users/Osprey/AppData/Local/Programs/Python/Python36-32/secret_messages.py", line 31, in swap_letters
letter_list.append(odd_letters[counter])
IndexError: list index out of range
It seems you indented return of your functions earlier than you should.
In:
for counter in range(0, len(message)):
if not is_even(counter):
odd_letters.append(message[counter])
return odd_letters
The return odd_letters will activate after the append, when your if condition is met.
What that means is that, as soon as your function finds a number that isn't even, it will append to the odd_letters and will return a list with only that number, since you returned it too early. That's why you get an IndexError, your list only has one item, so it will only accept it in case you only query it for index 0.
To fix it, just remove 4 spaces. The other function has the same problem.
Alright so I was messing around with the code and when I did this:
def get_message():
message = simpledialog.askstring('Message', 'Enter the secret message: ')
return str(message)
it worked!!!
I'm working on a GUI Python program using Tkinter.
I have a function that is called when a button is pressed (and when the program is loaded). The program is currently unfinished and only checks data validation at this current point. As the default entry is current invalid, it throws an error.
However, after this point, the entry box is disabled and will not let me enter any data. I cannot figure out why this is happening and I was wondering if someone could tell me the reason so I can work on a solution.
Thanks
import sys
import random
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
root = Tk()
root.title("COSC110 - Guessing Game")
hint = StringVar()
guesses = []
guess_input = ''
def loadWordList(filename): #Load the words from a file into a list given a filename.
file = open(filename, 'r')
line = file.read().lower()
wordlist = line.split()
return wordlist
word = random.choice(loadWordList('words.txt'))
def getHint(word, guesses): #Get hint function, calculates and returns the current hint.
hint = ' '
for letter in word:
if letter not in guesses:
hint += '_ '
else:
hint += letter
return hint
def guessButton(guess, word, guesses):
guess = str(guess_input)
guess = guess.lower()
if not guess.isalpha():
is_valid = False
elif len(guess) !=1:
is_valid = False
else:
is_valid = True
while is_valid == False:
messagebox.showinfo("Error:","Invalid input. Please enter a letter from a-z.")
break
hint.set(getHint(word, guesses))
return hint
label_instruct = Label(root, text="Please enter your guess: ")
label_instruct.grid(row=1,column=1,padx=5,pady=10)
guess_input = Entry(root,textvariable=guess_input)
guess_input.grid(row=1, column=2)
guess_button = Button(root, text="Guess", width=15, command=guessButton(guess_input,word,guesses))
guess_button.grid(row=1, column=3,padx=15)
current_hint = Label(root, textvariable=hint)
current_hint.grid(column=2,row=2)
label_hint = Label(root, text="Current hint:")
label_hint.grid(column=1,row=2)
label_remaining = Label(root, text="Remaining guesses: ")
label_remaining.grid(column=1,row=3)
root.mainloop() # the window is now displayed
Any tips are appreciated.
There are two apparent problems.
Firstly, you shouldn't use
guess_button = Button(root, text="Guess", width=15, command=guessButton(guess_input,word,guesses))
because you can't call a function with arguments on the command config.
My suggestion would be to take a look here and use one of the proposed methods, I particularly like the one using functools and partial:
from functools import partial
#(...)
button = Tk.Button(master=frame, text='press', command=partial(action, arg))
with action being the function you want to call and arg the parameters you want to call separated by a comma.
Secondly, you are using
guess = str(guess_input)
which doesn't return the Entry typed text, use instead
guess = guess_input.get()
PS: Albeit not directly related to your question, you should use
if var is False:
instead of
if var == False:
I made a small program in Python (.py) and converted it into a Windows executable file (.exe) using Py2exe. It asks for a string and then outputs a string -- very simple! -- and works flawlessly in Python.
However, when the exe file finishes execution in the command window, the command window closes automatically before I can get a glimpse of its output (I assume it does print the output because, like I said, it works flawlessly in Python).
How can I prevent this from happening? I assume I need to change my code, but what exactly do I need to add to it?
Here is my code, in case it helps you to see it (it's a word-wrapper):
import string
def insertNewlines(text, lineLength):
if text == '':
return ''
elif len(text) <= lineLength:
return text
elif text[lineLength] == ' ':
return text[:lineLength] + '\n' + insertNewlines(text[lineLength+1:], lineLength)
elif text[lineLength-1] == ' ':
return text[:lineLength] + '\n' + insertNewlines(text[lineLength:], lineLength)
else:
if string.find(text, ' ', lineLength) == -1:
return text
else:
return text[:string.find(text,' ',lineLength)+1] + '\n' + insertNewlines(text[string.find(text,' ',lineLength)+1:], lineLength)
print
if __name__ == '__main__':
text = str(raw_input("Enter text to word-wrap: "))
lineLength = int(raw_input("Enter number of characters per line: "))
print
print insertNewlines(text, lineLength)
Thank you.
The simplest way is probably to use raw_input() just before your program finishes. It will wait until you hit enter before closing.
if __name__ == '__main__':
text = str(raw_input("Enter text to word-wrap: "))
lineLength = int(raw_input("Enter number of characters per line: "))
print
print insertNewlines(text, lineLength)
raw_input()
Just put this at the end of your code:
junk = raw_input ("Hit ENTER to exit: ")
In other words, your main segment should be:
if __name__ == '__main__':
text = str(raw_input("Enter text to word-wrap: "))
lineLength = int(raw_input("Enter number of characters per line: "))
print
print insertNewlines(text, lineLength)
junk = raw_input ("Press ENTER to continue: ")
This is what I use in my scripts:
#### windows only ####
import msvcrt
def readch(echo=True):
"Get a single character on Windows."
while msvcrt.kbhit():
msvcrt.getch()
ch = msvcrt.getch()
while ch in b'\x00\xe0':
msvcrt.getch()
ch = msvcrt.getch()
if echo:
msvcrt.putch(ch)
return ch.decode()
def pause(prompt='Press any key to continue . . .'):
if prompt:
print prompt,
readch()
######################
Sometimes though, I just use the following to make the window stay open for a short time before closing.
import time
time.sleep(3)