How can I take input from the user above a printed line? - python

How can I print directly after my input without waiting until the user answered the input statement?
def InputSaveName():
try:
import os, sys, time, pickle, colorama
except Exception as e:
print("Some modules are mssing! Install them and try again! {}".format(e))
colorama.init()
print("+----------------------+")
print("What is your name adventurer?")
name = input("> ")
print("+----------------------+")
I want the bottom line to print without waiting for the user to put something in the input statement. In short: I want the code to run simultaneously.

This seems to be an XY problem. You do not really want to use threading to run multiple lines of code at once. To build a complex full-screen terminal application, you should have a look at curses:
import curses
def getname(stdscr):
stdscr.clear()
stdscr.addstr(0, 0, "+---------------------------+")
stdscr.addstr(1, 0, "What is your name adventurer?")
stdscr.addstr(2, 0, "> ")
stdscr.addstr(3, 0, "+---------------------------+")
curses.echo()
return stdscr.getstr(2, 3, 20)
s = curses.wrapper(getname)
print("Name is", s)
This only asks for the name and then returns, but you can also add lines, or replace existing lines on the existing screen and refresh the screen.

Without being 100% sure if it works in the specific examples you have typed in your question because of access to the standard output.
If you want to run things in parallel you can read about threads / subprocess https://docs.python.org/3/library/subprocess.html
or fork / multiprocessing
https://docs.python.org/3/library/multiprocessing.html
EDIT after op's EDIT ;-)
What you want to do seems very similar to what's described in this question Python nonblocking console input

This might be what you are looking for.
There is a "background process" running while waiting for your input using two separate threads.
import time
import threading
def myInput():
print("Type your name when ready!")
name = input()
print("Your name is: ", name)
def backgroundProcess():
while (True):
print("Some code is running...")
time.sleep(1)
inputThread = threading.Thread(target=myInput)
processThread = threading.Thread(target=backgroundProcess)
inputThread.start()
processThread.start()

You can use threading or multiprocessing modules:
import threading
def makeAsomethingOne():
print('I am One!')
def makeAsomethingTwo(printedData=None):
print('I am Two!',printedData)
name = input("> ")
firstThread = threading.Thread(target=makeAsomethingOne)
twiceThread = threading.Thread(target=makeAsomethingTwo,args=[name])
firstThread.start()
twiceThread.start()
This code runs almost simultaneously.

Related

Starting a python script from another before it crashes

I'm trying to make some project code I have written, more resilient to crashes, except the circumstances of my previous crashes have all been different.
So that I do not have to try and account for every single one, I thought I'd try to get my code to either restart, or execute a copy of itself in place of it and then close itself down gracefully, meaning its replacement, because it's coded identically, would in essence be the same as restarting from the beginning again. The desired result for me would be that while the error resulting circumstances are present, my code would be in a program swap out, or restart loop until such time as it can execute its code normally again....until the next time it faces a similar situation.
To experiment with, I've written two programs. I'm hoping from these examples someone will understand what I am trying to achieve. I want the first script to execute, then start the execute process for the second (in a new terminal) before closing itself down gracefully.
Is this even possible?
Thanks in advance.
first.py
#!/usr/bin/env python
#!/bin/bash
#first.py
import time
import os
import sys
from subprocess import run
import subprocess
thisfile = "first"
#thisfile = "second"
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
#os.system("first.py")
#exec(open("first.py").read())
#run("python "+"first.py", check=False)
#import first
#os.system('python first.py')
#subprocess.call(" python first.py 1", shell=True)
os.execv("first.py", sys.argv)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
#os.system("second.py")
#exec(open("second.py").read())
#run("python "+"second.py", check=False)
#import second
#os.system('python second.py')
#subprocess.call(" python second.py 1", shell=True)
os.execv("second.py", sys.argv)
print("I'm leaving first now")
break
time.sleep(1)
sys.exit("Quitting")
second.py (basically a copy of first.py)
#!/usr/bin/env python
#!/bin/bash
#second.py
import time
import os
import sys
from subprocess import run
import subprocess
#thisfile = "first"
thisfile = "second"
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
#os.system("first.py")
#exec(open("first.py").read())
#run("python "+"first.py", check=False)
#import first
#os.system('python first.py')
#subprocess.call(" python first.py 1", shell=True)
os.execv("first.py", sys.argv)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
#os.system("second.py")
#exec(open("second.py").read())
#run("python "+"second.py", check=False)
#import second
#os.system('python second.py')
#subprocess.call(" python second.py 1", shell=True)
os.execv("second.py", sys.argv)
print("I'm leaving first now")
break
time.sleep(1)
sys.exit("Quitting")
I have tried quite a few solutions as can be seen with my hashed out lines of code. Nothing so far though has given me the result I am after unfortunately.
EDIT: This is the part of the actual code i think i am having problems with. This is the part where I am attempting to publish to my MQTT broker.
try:
client.connect(broker, port, 10) #connect to broker
time.sleep(1)
except:
print("Cannot connect")
sys.exit("Quitting")
Instead of exiting with the "quitting" part, will it keep my code alive if i route it to stay within a repeat loop until such time as it successfully connects to the broker again and then continue back with the rest of the script? Or is this wishful thinking?
You can do this in many ways. Your subprocess.call() option would work - but it depends on the details of implementation. Perhaps the easiest is to use multiprocessing to run the program in a subprocess while the parent simply restarts it as necessary.
import multiprocessing as mp
import time
def do_the_things(arg1, arg2):
print("doing the things")
time.sleep(2) # for test
raise RuntimeError("Virgin Media dun me wrong")
def launch_and_monitor():
while True:
print("start the things")
proc = mp.Process(target=do_the_things, args=(0, 1))
proc.start()
proc.wait()
print("things went awry")
time.sleep(2) # a moment before restart hoping badness resolves
if __name__ == "__main__":
launch_and_monitor()
Note: The child process uses the same terminal as the parent. Running separate terminals is quite a bit more difficult. It would depend, for instance, on how you've setup to have a terminal attach to the pi.
If you want to catch and process errors in the parent process, you could write some extra code to catch the error, pickle it, and have a queue to pass it back to the parent. Multiprocessing pools already do that, so you could just have a pool with 1 process and and a single iterable to consume.
with multiprocessing.Pool(1) as pool:
while True:
try:
result = pool.map(do_the_things, [(0,1)])
except Exception as e:
print("caught", e)
Ok, I got it!
For anyone else interested in trying to do what my original question was:
To close down a script on the occurrence of an error and then open either a new script, or a copy of the original one (for the purpose of having the same functionality as the first) in a new terminal window, this is the answer using my original code samples as an example (first.py and second.py where both scripts run the exact same code - other than defining them as different names and this name allocation defined within for which alternate file to open in its place)
first.py
import time
import subprocess
thisfile = "first"
#thisfile = "second"
if thisfile == "second":
restartcommand = 'python3 /home/mypi/myprograms/first.py'
else:
restartcommand = 'python3 /home/mypi/myprograms/second.py'
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving first now")
break
time.sleep(1)
quit()
second.py
import time
import subprocess
#thisfile = "first"
thisfile = "second"
if thisfile == "second":
restartcommand = 'python3 /home/mypi/myprograms/first.py'
else:
restartcommand = 'python3 /home/mypi/myprograms/second.py'
time.sleep(3)
while thisfile == "second":
print("this is the second file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving second now")
break
while thisfile == "first":
print("this is the first file")
time.sleep(1)
subprocess.run('lxterminal -e ' + restartcommand, shell=True)
print("I'm leaving first now")
break
time.sleep(1)
quit()
The result of running either one of these will be that the program runs, then opens the other file and starts running that before closing down itself and this operation will continue back and forth, back and forth until you close down the running file before it gets a chance to open the other file.
Try it! it's fun!

Using a function to print an input one letter at a time

I am making a game/quiz in Python, but ran into a small issue. I made a function to print one letter at a time, but when I use that function for an input, it does not work and prints all at once. I've tried making a string for the input and multiple other things. To fix this temporarily, I have just been printing my question, and then using an input function to make an input, but I'm wondering if there is a better way. Here is my code:
import time
import sys
def input1():
input("")
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
q1 = "\nLet's get started. What is my favorite color?"
oneprint(q1)
input1()
I think you may want to add the same for loop that requires c inside of your script in your input1 function, here is an example of how you could do such a thing:
import time
import sys
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
def input1():
inp = input("")
oneprint(inp)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
q1 = "\nLet's get started. What is my favorite color?"
oneprint(q1)
input1()
if you try this it will print the desired color that was answered by the player by getting the input and getting each letter and writing it and flushing it through the oneprint function.
This will display the input and oneprint it:
import time
import sys
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
oneprint("\nLet's get started. What is my favorite color?")
oneprint(input("\n"))
This will hide the input, and oneprint it:
import time
import sys
from getpass import getpass
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
oneprint("\nLet's get started. What is my favorite color?")
oneprint(getpass("\n>"))
Where getpass is a password formatted input
I figured out the answer. If anyone else is having this issue you should just do:
input(oneprint(Blah Blah Blah Your Question Here))

How do I add limited input time to my code?

I've been trying to find a good limited-input-time code for Python scripts and I finally got a code to work:
from threading import Timer
timeout = 5
t = Timer(timeout, print, ["Time's up!"])
t.start()
entry = input('> ')
t.cancel()
but, I need to be able to run a function when the timer ends.
Also - I want the function called inside of the timer code - otherwise if you type your entry before the timer runs out, the function will still be called no matter what.
Could anyone kindly edit this code I have to be able to run a function when the timer ends?
If it is fine that you block the main thread when the user has not provided any answer, the above code that you have shared might work.
Otherwise you could use msvcrt in the following sense:
import msvcrt
import time
class TimeoutExpired(Exception):
pass
def input_with_timeout(prompt, timeout, timer=time.monotonic):
sys.stdout.write(prompt)
sys.stdout.flush()
endtime = timer() + timeout
result = []
while timer() < endtime:
if msvcrt.kbhit():
result.append(msvcrt.getwche()) #XXX can it block on multibyte characters?
if result[-1] == '\n': #XXX check what Windows returns here
return ''.join(result[:-1])
time.sleep(0.04) # just to yield to other processes/threads
raise TimeoutExpired
The above code is compliant with Python3 and you will need to test it.
Reading from the Python Documentation https://docs.python.org/3/library/threading.html#timer-objects
I have come up with the following snippet which might work(Try running in your command line prompt)
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 has something
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds

Multiprocessing beside a main loop

I'm struggling with a issue for some time now.
I'm building a little script which uses a main loop. This is a process that needs some attention from the users. The user responds on the steps and than some magic happens with use of some functions
Beside this I want to spawn another process which monitors the computer system for some specific events like pressing specif keys. If these events occur then it will launch the same functions as when the user gives in the right values.
So I need to make two processes:
-The main loop (which allows user interaction)
-The background "event scanner", which searches for specific events and then reacts on it.
I try this by launching a main loop and a daemon multiprocessing process. The problem is that when I launch the background process it starts, but after that I does not launch the main loop.
I simplified everything a little to make it more clear:
import multiprocessing, sys, time
def main_loop():
while 1:
input = input('What kind of food do you like?')
print(input)
def test():
while 1:
time.sleep(1)
print('this should run in the background')
if __name__ == '__main__':
try:
print('hello!')
mProcess = multiprocessing.Process(target=test())
mProcess.daemon = True
mProcess.start()
#after starting main loop does not start while it prints out the test loop fine.
main_loop()
except:
sys.exit(0)
You should do
mProcess = multiprocessing.Process(target=test)
instead of
mProcess = multiprocessing.Process(target=test())
Your code actually calls test in the parent process, and that call never returns.
You can use the locking synchronization to have a better control over your program's flow. Curiously, the input function raise an EOF error, but I'm sure you can find a workaround.
import multiprocessing, sys, time
def main_loop(l):
time.sleep(4)
l.acquire()
# raise an EOFError, I don't know why .
#_input = input('What kind of food do you like?')
print(" raw input at 4 sec ")
l.release()
return
def test(l):
i=0
while i<8:
time.sleep(1)
l.acquire()
print('this should run in the background : ', i+1, 'sec')
l.release()
i+=1
return
if __name__ == '__main__':
lock = multiprocessing.Lock()
#try:
print('hello!')
mProcess = multiprocessing.Process(target=test, args = (lock, ) ).start()
inputProcess = multiprocessing.Process(target=main_loop, args = (lock,)).start()
#except:
#sys.exit(0)

Python in Linux: Put user input asynchronously into queue

I am trying to run a program that takes in input as a job is getting done. I have looked through several forms, and looked into the documentation. I'm running this in Debian, and I understand that I can use this getch function to receive characters without hitting the return key. To break it down, this is what I am trying to implement in my infinite while loop
Take in input (threading didn't work here for me
Put input into Queue
If there are no running jobs, start the job with the item in front of the queue as a variable
I am also running the threading module to execute another instruction. Is there any way I can do this?
Update: This is what I have tried so far:
First, I tried using a timer from the threading module to stop it from waiting, which went something like this.
def getchnow():
def time_up():
answer= None
print 'time up...'
wait = Timer(5,time_up) # x is amount of time in seconds
wait.start()
try:
print "enter answer below"
answer = getch()
except Exception:
print 'pass\n'
answer = None
if answer != True: # it means if variable have somthing
wait.cancel() # time_up will not execute(so, no skip)
return answer
line = getchnow()
#Add line variable to queue
#Do stuff with queue
The problem here is that it still waited for user input.
I then tried to put the getch function into another thread.
q = Queue.Queue
q.put(getch())
if q.get() != True: # it means if variable have somthing
line = q.get()
#Add line variable to queue
#Do stuff with queue
This attempt doesn't let me do anything.
I read more of this link, and there was an implementation of what I wanted at the bottom.
I used the select module for a Non-Blocking implementation on Linux.
This times out in (5 seconds here) if no input is received.
Particularly useful when used in a thread, so that the getch call is
non-blocking and will allow the thread to exit cleanly
# This class gets a single character input from the keyboard
class _GetchUnix:
def __init__(self):
import tty, sys
from select import select
def __call__(self):
import sys, tty, termios
from select import select
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
[i, o, e] = select([sys.stdin.fileno()], [], [], 2)
if i:
ch=sys.stdin.read(1)
else:
ch=''
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
getch = _GetchUnix()
# End Class
I've also used [i, o, e] = select([sys.stdin.fileno()], [], [], 2), but I've heard it might not work on windows. If anyone still needs a multi-threaded, non-blocking input example:
import threading
import sys
import time
bufferLock=threading.Lock()
inputBuffer=[]
class InputThread(threading.Thread):
def run(self):
global inputBuffer
print("starting input")
while True:
line=sys.stdin.readline()
bufferLock.acquire()
inputBuffer.insert(0,line)
bufferLock.release()
input_thread=InputThread()
input_thread.start()
while True:
time.sleep(4)
bufferLock.acquire()
if len(inputBuffer)>0:
print("Popping: "+inputBuffer.pop())
bufferLock.release()

Categories

Resources