Insert separator in Python input() function - python

I'm looking for a way to insert separator in the input() function.
To be clear, my script asks the user to input a timeout in H:MM:SS, and I'd like Python to insert : by himself.
So if the user types "14250", I want the terminal to display 1:42:50 (during the input, not after pressing ENTER).
Is it possible in Python?

Here's a version for Linux. It is based on and very similar to the version by anurag, but Linux's getch modules does not know getwch and putwch, so those have to be substituted.
from getch import getche as getc
def gettime():
timestr = ''
print('Enter time in 24-hr format (hh:mm:ss): ', end='', flush=True)
for i in range(6):
timestr += getc() # get and echo character
if i in (1, 3): # add ":" after 2nd and 4th digit
print(":", end="", flush=True)
timestr += ':'
print() # complete the line
return timestr
time = gettime()
print("The time is", time)
Sample output:
Enter time in 24-hr format (hh:mm:ss): 12:34:56
The time is 12:34:56
I think this would also work on Windows with from msvcrt import getwche as getc but I can not test this.

There is a way to achieve the result (to some extent), tested on Windows 10, Python 3.7:
import msvcrt as osch
def main():
timestr = ''
print('Enter time in 24-hr format (hh:mm:ss): ', end='', flush=True)
for i in range(6):
ch = osch.getwch()
if i!=0 and i%2==0:
osch.putwch(':')
timestr += ':'
osch.putwch(ch)
timestr += ch
return timestr
if __name__ == "__main__":
res = main()
print('\n')
print(res)
Please note that the variable timestr was created merely as storage for future use. Also, you can apply all kinds of validity checks. In my opinion, this method can't be used to parse a time input of type 14923 into 1:49:23 as lookahead is not available and there is no way of knowing whether user is going to input 12-hr time or 24-hr time. I am going for 24-hr time, which means, instead of 14923, user will be required to enter 014923.

Related

In python, how can I display my output in a external window instead of python terminal?

I try to make a countdown timer in python
could anyone help me? this is my code and I need something like the image
this is my code and I need something like the image
import time
import datetime
title = input("title: ")
year = input("year: ")
month = input("month: ")
day = input("day: ")
hour = input("hour: ")
minute = input("minute: ")
targetTime = datetime.datetime(int(year), int(month), int(day), int(hour), int(minute))
def countdown(targetTime):
while True:
difference = targetTime - datetime.datetime.now()
countHours, remainder = divmod(difference.seconds, 3600)
countMinutes, countSeconds = divmod(remainder, 60)
if difference.days == 0 and countHours == 0 and countMinutes == 0 and countSeconds == 0:
print("BOOOM!")
break
print( str(difference.days) + "d "
+ str(countHours) + "h "
+ str(countMinutes) + "m "
+ str(countSeconds) + "s " + "until "
+ str(title)
)
time.sleep(1)
countdown(targetTime)
[1]: https://i.stack.imgur.com/EJONp.png
do you really need to use tkinter?. i recommend you pysimplegui, it is pretty sweet
this is an example of a clock, which is (nearly) what you want:
import PySimpleGUI as sg
import datetime
sg.set_options(border_width=0)
sg.theme('dark')
layout = [[sg.Text('Time: '), sg.Text('', key='_time_')], [sg.Quit()]]
window = sg.Window('Simple Clock', no_titlebar=True).Layout(layout)
def getTime():
return datetime.datetime.now().strftime('%H:%M:%S')
def main(gui_obj):
while True:
event, values = gui_obj.Read(timeout=10)
if event in (None, 'Quit'):
break
gui_obj['_time_'].Update(getTime())
if __name__ == '__main__':
main(window)
Below are some tkinter commands
Entry : for entering users input
.get() : to get the user entered inputs and assign to your var's
label : for labelling text
button : to start the function
message box : to display text finally
If you are not confident with Tkinter Classes approach and want to remain on your IDE Input principle - even so as suggested by Siva is the correct approach - use for displaying opencv or plt:
e.g. opencv
create empty image in desired size
create loop
write text with actual counter time on image
image show
use dynamic wait Key to ensure every sec the pic gets updated
At the end, whatever suits you best is the best solution.

Trying to apply a function to a user input

I'm trying to use an external function and apply it to a basic user input. Basically the external function (Code 1) makes the text in (Code 2) print out slowly, like a video game dialog. However the first variable called "intro" is not affected by this function, only the "response" variable is. I don't know how to fix that.
Code 1:
import sys,time,os
def typewriter(self):
for char in message:
sys.stdout.write(char)
sys.stdout.flush()
if char !="\n":
time.sleep(0.1)
else:
time.sleep(1)
os.system("cls")
Code 2:
from typewriter import *
intro = input("What is your name?\n")
typewriter(intro)
response = ("Nice to meet you " + intro + ".\n\
My name is Program.")
message = intro and response
typewriter(response)
You almost got it! As it has been mentioned, your typewriter function should be receiving the text it should print. But also, "What is your name?" is now being printed by input, not by your function.
This works:
import sys
import time
def typewriter(message):
for char in message:
sys.stdout.write(char)
sys.stdout.flush()
if char !="\n":
time.sleep(0.1)
else:
time.sleep(1)
intro = "What is your name?\n"
typewriter(intro)
name = input()
response = ("Nice to meet you " + name + ".\n\
My name is Program.")
typewriter(response)
Clearly function typewriter is not taking any argument to process the data. When you have called the typewriter(intro) the first time the message variable is not defined. I think you need to change the typewriter function as follows.
def typewriter(message):
for char in message:
sys.stdout.write(char)
sys.stdout.flush()
if char !="\n":
time.sleep(0.1)
else:
time.sleep(1)
first of all I tried to rename the input in the typewrite function instead of self i wrote message:
import sys,time,os
def typewriter(message):
for char in message:
sys.stdout.write(char)
sys.stdout.flush()
if char !="\n":
time.sleep(0.1)
else:
time.sleep(1)
os.system("cls")
i would also change the second code to this:
from typewriter import *
typewriter("What is your name?\n")
intro = input()
response = ("Nice to meet you " + intro + ".\n\
My name is Program.")
message = intro and response
typewriter(response)
have fun with coding!

How to prevent printing from previous function in current function?

I'm currently writing a test function for class to test provided cases on provided solution code. However I'm running into an issue where a print statement is executing when I don't want it to.
This is the provided solution that I'm testing:
def alphapinDecode(tone):
phone_num = ''
if checkTone(tone): #or checkTone2
while len(tone) > 0:
# retrieve the first tone
next_tone = tone[0:2]
tone = tone[2:]
# find its position
cons = next_tone[0]
vow = next_tone[1]
num1 = consonants.find(cons)
num2 = vowels.find(vow)
# reconstruct this part of the number -
# multiply (was divided) and add back
# the remainder from the encryption division.
phone = (num1 * 5) + num2
# recreate the number
# by treating it as a string
phone = str(phone)
# if single digit, not leading digit, add 0
if len(phone) == 1 and phone_num != '':
phone = '0' + phone
phone_num = phone_num + phone
# but return in original format
phone_num = int(phone_num)
else:
print('Tone is not in correct format.')
phone_num = -1
return phone_num
Here's the (partially done) code for the test function I have written:
def test_decode(f):
testCases = (
('lo', 43),
('hi', 27),
('bomelela', 3464140),
('bomeluco', 3464408),
('', -1),
('abcd', -1),
('diju', 1234),
)
for i in range(len(testCases)):
if f(testCases[i][0]) == testCases[i][1] and testCases[i][1] == -1:
print('Checking '+ f.__name__ + '(' + testCases[i][0] + ')...Tone is not in correct format.')
print('Its value -1 is correct!')
return None
When executing test_decode(alphapinDecode), I get this:
Tone is not in correct format.
Checking alphapinDecode()...Tone is not in correct format.
Its value -1 is correct!
Tone is not in correct format.
Checking alphapinDecode(abcd)...Tone is not in correct format.
Its value -1 is correct!
As you can see, because of the print statement in alphapinDecode(I think), it is printing an extra "Tone is not in correct format." above the print statement I have written.
How would I prevent this print statement from executing, and why is it printing if the print statement I wrote in my test function doesn't ask for the result of alphapinDecode?
We are not allowed to alter the code of the given solution.
I'm fairly new to stackOverflow, so sorry for any formatting issues. Thank you!
Edit: Fixed the idents of the test_decode function
One easy solution would be to pass an extra parameter say, a boolean variable debug to the function. That would go something like this.
def func1(var1, debug):
if debug:
print("Printing from func1")
# Do additional stuff
Now when you call it. You now have the option of setting the debug variable.
func1("hello", debug=True) # will print the statement
func1("hello", debug=False) # will not print statement.
If you cannot modify the called function. Then you can follow this method. explained by #FakeRainBrigand here.
import sys, os
# Disable
def blockPrint():
sys.stdout = open(os.devnull, 'w')
# Restore
def enablePrint():
sys.stdout = sys.__stdout__
print 'This will print'
blockPrint()
print "This won't"
enablePrint()
print "This will too"

How to call another script in one script, and run them at the same time?

I am very new to Python, but the project I am working on confused me.
In the project, I give multiple choices for uses to choose, one of the choices has a reminder function. So in the reminder function, the user can set reminder, and the function will match the reminder to current time every 15 seconds until they match and print a statement.
This is the code for reminder.
import time
def setReminder(number):
reminderList = []
for i in range(number):
reminderL = []
mon = input('enter the month(1-12):')
day = input('enter the date(1-31):')
hour = input('enter the hour(0-23):')
minute = input('enter the minute(0-59):')
print()
if ((int(mon)<1 or int(mon)>12)
or (int(day)<1 or int(day)>31)
or (int(hour)<0 or int(hour)>23)
or (int(minute)<0 or int(minute)>59)):
print('invalid date and time, please set again!')
mon = input('enter the month(1-12):')
day = input('enter the date(1-31):')
hour = input('enter the hour(0-23):')
minute = input('enter the minute(0-59):')
reminderL.extend((mon, day, hour, minute))
reminder = ''
for element in reminderL:
if int(element)<10:
element = '0' + element
reminder = reminder + element + ' '
reminderList.append(reminder)
return reminderList
def main():
num = int(input('enter the numbers of reminder you want to set(1-9):'))
if num not in range(1,10):
print('invalid input, try again!')
num = int(input('enter the numbers of reminder you want to set(0-9):'))
List = setReminder(num)
print(List)
for i in range(num):
tim = time.strftime('%m %d %H %M ')
while tim not in List:
time.sleep(15)
tim = time.strftime('%m %d %H %M ')
print('Hello, it is time to take medicine!')
main()
However, if the user set the reminder time to very late, for example next day, then this function will run until next day. Hence I want my body script to run while this reminder function is running.
This is generally how my body script is like(it is in a different script with the reminder one):
menu()
option = int(input('Your choice?'))
while (option != 4):
if option not in (1, 2, 3, 4):
print('Invalid input! Please select again!')
option = int(input('Your choice?'))
else:
if option == 1:
print()
elif option == 2:
feedback(gender, dat)
elif option == 3:
print()
print()
print('Anything else?')
menu()
option = int(input('Your choice?'))
So option 3 is the reminder, but while reminder function is try to match the time, I want the user to be able to use the other choices. The only way I think can work is to call the function and run it on another shell page. Could you give me any advice on how to do so?
The tool you need is threading. Suppose you have two separate script files: reminder.py and program.py. Then you have to delete or comment out line main() in reminder and import reminder and threading into program. Next is to modify program:
elif option == 3:
rem_thread = threading.Thread(
target=reminder.main)
rem_thread.start()
This is very basic example of how to use threads in Python. However, this addition to the code cannot solve your problem because of two reasons: (1) interference between input() calls in different threads; (2) blocking by input(). To solve the first problem you should pause main thread while user enters time parts. To solve the second problem you should start one more thread.
Here is the code that kinda works (Win10 / command prompt). There is a whole bunch of design issues to be addressed to make the code more or less usable. I tested it with 1 remainder because every remainder needs separate thread. Interference between input() and print() still present because several threads share the same console. This issue can be solved with processes instead of threads or with GUI. Of course, GUI is preferable.
import queue
import threading
import time
def setReminder(number):
reminderList = []
for i in range(number):
reminderL = []
mon = input('enter the month(1-12):')
day = input('enter the date(1-31):')
hour = input('enter the hour(0-23):')
minute = input('enter the minute(0-59):')
print()
if ((int(mon)<1 or int(mon)>12)
or (int(day)<1 or int(day)>31)
or (int(hour)<0 or int(hour)>23)
or (int(minute)<0 or int(minute)>59)):
print('invalid date and time, please set again!')
mon = input('enter the month(1-12):')
day = input('enter the date(1-31):')
hour = input('enter the hour(0-23):')
minute = input('enter the minute(0-59):')
reminderL.extend((mon, day, hour, minute))
reminder = ''
for element in reminderL:
if int(element)<10:
element = '0' + element
reminder = reminder + element + ' '
reminderList.append(reminder)
return reminderList
def reminder_main(wait_queue):
num = int(input('enter the numbers of reminder you want to set(1-9):'))
if num not in range(1,10):
print('invalid input, try again!')
num = int(input('enter the numbers of reminder you want to set(0-9):'))
List = setReminder(num)
print(List)
wait_queue.put('go-go-go') # unpause main thread
for i in range(num):
tim = time.strftime('%m %d %H %M ')
while tim not in List:
time.sleep(1)
tim = time.strftime('%m %d %H %M ')
print('Hello, it is time to take medicine!')
def main():
while True:
try:
option = int(input('Your choice? '))
except ValueError:
print('Cannot convert your choice into integer.')
else:
if option not in (1, 2, 3, 4):
print('Allowed options are 1, 2, 3, 4.')
else:
if option == 1:
pass
if option == 2:
pass
if option == 3:
wait_queue = queue.Queue()
# remainder thread
threading.Thread(
target=reminder_main,
kwargs={'wait_queue': wait_queue},
daemon=True).start()
wait_queue.get() # this is pause - waitng for any data
elif option == 4:
print('Exiting...')
break
if __name__ == '__main__':
# main thread
threading.Thread(
target=main).start()

How to set time limit on raw_input

in python, is there a way to, while waiting for a user input, count time so that after, say 30 seconds, the raw_input() function is automatically skipped?
The signal.alarm function, on which #jer's recommended solution is based, is unfortunately Unix-only. If you need a cross-platform or Windows-specific solution, you can base it on threading.Timer instead, using thread.interrupt_main to send a KeyboardInterrupt to the main thread from the timer thread. I.e.:
import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
this will return None whether the 30 seconds time out or the user explicitly decides to hit control-C to give up on inputting anything, but it seems OK to treat the two cases in the same way (if you need to distinguish, you could use for the timer a function of your own that, before interrupting the main thread, records somewhere the fact that a timeout has happened, and in your handler for KeyboardInterrupt access that "somewhere" to discriminate which of the two cases occurred).
Edit: I could have sworn this was working but I must have been wrong -- the code above omits the obviously-needed timer.start(), and even with it I can't make it work any more. select.select would be the obvious other thing to try but it won't work on a "normal file" (including stdin) in Windows -- in Unix it works on all files, in Windows, only on sockets.
So I don't know how to do a cross-platform "raw input with timeout". A windows-specific one can be constructed with a tight loop polling msvcrt.kbhit, performing a msvcrt.getche (and checking if it's a return to indicate the output's done, in which case it breaks out of the loop, otherwise accumulates and keeps waiting) and checking the time to time out if needed. I cannot test because I have no Windows machine (they're all Macs and Linux ones), but here the untested code I would suggest:
import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
finishat = time.time() + timeout
result = []
while True:
if msvcrt.kbhit():
result.append(msvcrt.getche())
if result[-1] == '\r': # or \n, whatever Win returns;-)
return ''.join(result)
time.sleep(0.1) # just to yield to other processes/threads
else:
if time.time() > finishat:
return None
The OP in a comment says he does not want to return None upon timeout, but what's the alternative? Raising an exception? Returning a different default value? Whatever alternative he wants he can clearly put it in place of my return None;-).
If you don't want to time out just because the user is typing slowly (as opposed to, not typing at all!-), you could recompute finishat after every successful character input.
I found a solution to this problem in a blog post. Here's the code from that blog post:
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Please note: this code will only work on *nix OSs.
The input() function is designed to wait for the user to enter something (at least the [Enter] key).
If you are not dead set to use input(), below is a much lighter solution using tkinter. In tkinter, dialog boxes (and any widget) can be destroyed after a given time.
Here is an example :
import tkinter as tk
def W_Input (label='Input dialog box', timeout=5000):
w = tk.Tk()
w.title(label)
W_Input.data=''
wFrame = tk.Frame(w, background="light yellow", padx=20, pady=20)
wFrame.pack()
wEntryBox = tk.Entry(wFrame, background="white", width=100)
wEntryBox.focus_force()
wEntryBox.pack()
def fin():
W_Input.data = str(wEntryBox.get())
w.destroy()
wSubmitButton = tk.Button(w, text='OK', command=fin, default='active')
wSubmitButton.pack()
# --- optionnal extra code in order to have a stroke on "Return" equivalent to a mouse click on the OK button
def fin_R(event): fin()
w.bind("<Return>", fin_R)
# --- END extra code ---
w.after(timeout, w.destroy) # This is the KEY INSTRUCTION that destroys the dialog box after the given timeout in millisecondsd
w.mainloop()
W_Input() # can be called with 2 parameter, the window title (string), and the timeout duration in miliseconds
if W_Input.data : print('\nYou entered this : ', W_Input.data, end=2*'\n')
else : print('\nNothing was entered \n')
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print('time up...')
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print('pass\n')
answer = None
if answer != True: # it means if variable have somthing
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
As it is self defined... run it in command line prompt , I hope you will get the answer
read this python doc you will be crystal clear what just happened in this code!!
A curses example which takes for a timed math test
#!/usr/bin/env python3
import curses
import curses.ascii
import time
#stdscr = curses.initscr() - Using curses.wrapper instead
def main(stdscr):
hd = 100 #Timeout in tenths of a second
answer = ''
stdscr.addstr('5+3=') #Your prompt text
s = time.time() #Timing function to show that solution is working properly
while True:
#curses.echo(False)
curses.halfdelay(hd)
start = time.time()
c = stdscr.getch()
if c == curses.ascii.NL: #Enter Press
break
elif c == -1: #Return on timer complete
break
elif c == curses.ascii.DEL: #Backspace key for corrections. Could add additional hooks for cursor movement
answer = answer[:-1]
y, x = curses.getsyx()
stdscr.delch(y, x-1)
elif curses.ascii.isdigit(c): #Filter because I only wanted digits accepted
answer += chr(c)
stdscr.addstr(chr(c))
hd -= int((time.time() - start) * 10) #Sets the new time on getch based on the time already used
stdscr.addstr('\n')
stdscr.addstr('Elapsed Time: %i\n'%(time.time() - s))
stdscr.addstr('This is the answer: %s\n'%answer)
#stdscr.refresh() ##implied with the call to getch
stdscr.addstr('Press any key to exit...')
curses.wrapper(main)
under linux one could use curses and getch function, its non blocking.
see getch()
https://docs.python.org/2/library/curses.html
function that waits for keyboard input for x seconds (you have to initialize a curses window (win1) first!
import time
def tastaturabfrage():
inittime = int(time.time()) # time now
waitingtime = 2.00 # time to wait in seconds
while inittime+waitingtime>int(time.time()):
key = win1.getch() #check if keyboard entry or screen resize
if key == curses.KEY_RESIZE:
empty()
resize()
key=0
if key == 118:
p(4,'KEY V Pressed')
yourfunction();
if key == 107:
p(4,'KEY K Pressed')
yourfunction();
if key == 99:
p(4,'KEY c Pressed')
yourfunction();
if key == 120:
p(4,'KEY x Pressed')
yourfunction();
else:
yourfunction
key=0
This is for newer python versions, but I believe it will still answer the question. What this does is it creates a message to the user that the time is up, then ends the code. I'm sure there's a way to make it skip the input rather than completely end the code, but either way, this should at least help...
import sys
import time
from threading import Thread
import pyautogui as pag
#imports the needed modules
xyz = 1 #for a reference call
choice1 = None #sets the starting status
def check():
time.sleep(15)#the time limit set on the message
global xyz
if choice1 != None: # if choice1 has input in it, than the time will not expire
return
if xyz == 1: # if no input has been made within the time limit, then this message
# will display
pag.confirm(text = 'Time is up!', title = 'Time is up!!!!!!!!!')
sys.exit()
Thread(target = check).start()#starts the timer
choice1 = input("Please Enter your choice: ")

Categories