General way to interrupt scrolling text in console interface - python

i am trying to make a game in the console and want to have scrolling text. i want to be able to hit a key/type enter and skip the scrolling and print the rest.
so far i tried using pygame (out of the picture due to having to have a display surface active), asyncio with sys.stdin.read(1)(blocked the run on cmd and didnt query user in async based ide's).
this was my latest attempts at this.
import asyncio,time,sys
global skip
immutablesleep = 0.04
mutablesleep = [immutablesleep]
async def aprintl(string,sep="",end="\n",sleep=mutablesleep):
global skip
for letter in string+end:
print(letter+sep,end="",flush=True)
await asyncio.sleep(sleep[0])
skip = True
async def break_print():
global skip
while not skip:
ch = sys.stdin.read(1)
if len(ch)>0:
mutablesleep[0]=0
skip = True
await asyncio.sleep(0.1)
def printl(*args):
global skip
skip = False
mutablesleep[0] = immutablesleep
asyncio.gather(aprintl(*args),break_print())
keep in mind when suggesting modules that i want both os system independant code, and something that can be easly hooked into when freezing modules into exe.
Update:
currently this functions fairly well in terms of interrupting the slow print, but two issues persist:
1:
the interruption by pressing enter is cutting through the printed line, making it unreadable
2:
thread is still waiting for enter even after the print finished.
async def break_print():
global skip, ch
thread = Thread(target=t)
thread.start()
thread.join(timeout=0.1)
while not skip:
if len(ch) > 0:
mutablesleep[0]=0
skip = True
ch = ''
await asyncio.sleep(0.1)
def t():
"""Needed to read from stdin async"""
global ch
ch = sys.stdin.readline()

I believe your problem has to do with the last line
asyncio.gather(aprintl(*args),break_print())
Looking at the docs, the function signature looks like this: awaitable asyncio.gather(*aws, loop=None, return_exceptions=False). The .gather call is likely not working as expected because you are not passing a list of callables, you're instead passing aprintl(*args) to *aws and break_print() is being passed to the loop argument
Change the line to the below, and see if it works as you're expecting.
asyncio.gather([aprintl(*args),break_print()])
Update
I got your code to work, with some caveats
import asyncio
import sys
from threading import Thread
global skip
ch = ''
immutablesleep = 0.04
mutablesleep = [immutablesleep]
async def aprintl(string,sep="",end="\n",sleep=mutablesleep):
global skip
for letter in string+[end]:
if not skip:
print(letter+sep,end="",flush=True)
await asyncio.sleep(sleep[0])
skip = True
async def break_print():
global skip, ch
while not skip:
thread = Thread(target=t)
thread.start()
thread.join(timeout=.1)
if len(ch) > 0:
mutablesleep[0]=0
skip = True
ch = ''
await asyncio.sleep(0.1)
def t():
"""Needed to read from stdin async"""
global ch
ch = sys.stdin.readline()
async def printl(*args):
global skip
skip = False
mutablesleep[0] = immutablesleep
await asyncio.gather(aprintl(*args), break_print())
if __name__ == '__main__':
x = ['asdf ', 'asdf']*5000
asyncio.run(printl(x))
What was changed
Added t() which runs in a Thread for .1 seconds every time break_print runs -- this was required as I believe the reason your initial code isn't running is because it's hanging at the sys.stdin.read(1) line
Run printl() via asyncio.run()
Added an if not skip: check in aprintl(), otherwise it will print the entire input once skipped
Caveats
You must hit enter to stop the printout -- even with .read() you must hit enter. I use readline() because it will return any characters input before the enter key is hit (meaning, you could check to make sure the user input some character before hitting enter: len(ch.strip() > 0): do ...
The script doesn't exit even after skip == True -- this is likely because break_print() doesn't exit when skip == True, it will simply continue to loop.
I realize this may not work in your use case, but I hope it at least gives you some ideas.

Related

Python: Terminate Loop Using Timer

I'm quite new on python and working on a school project with this logic: Users have to answer a series of questions as fast as they can, within the given time.
For instance, the time allotted is 30 seconds, I wood loop through a dictionary of questions and get the answer. On timeout, the loop will start, even if the script is still waiting for an input.
def start_test():
for item on questions:
print(item)
answers.append(input(' : '))
I've tried using multiprocessing and multithreading, but I found out that stdin doesn't work subprocesses.
I'm looking for something like:
while duration > 0:
start_test()
def countdown():
global duration
while duration > 0:
duration -= 1
time.sleep(1)
# something lime start_test().stop()
But I can't figure out how to run the countdown function in parallel with the start_test function.
Any ideas?
So as far as I know the input is accessible via main thread only. I might be wrong.
However if that is the case, you need a non-blocking input.
Check this blog. The answer below is based on that.
Note: This is a really quick and dirty solution.
I have checked this on Linux.
If it doesn't work on Windows try this
link for further reference.
import _thread
import sys
import select
import time
def start_test():
questions = ['1','2','3']
answers = []
for item in questions:
print(item)
# Input in a non-blocking way
loop_flag = True
while loop_flag:
# Read documenation and examples on select
ready = select.select([sys.stdin], [], [], 0)[0]
if not ready:
# Check if timer has expired
if timeout:
return answers
else:
for file in ready:
line = file.readline()
if not line: # EOF, input is closed
loop_flag = False
break
elif line.rstrip():
# We have some input
answers.append(line)
# So as to get out of while
loop_flag = False
# Breaking out of for
break
return answers
def countdown():
global timeout
time.sleep(30)
timeout = True
# Global Timeout Flag
timeout = False
timer = _thread.start_new_thread(countdown, ())
answers = start_test()
print(answers)

How to structure code to be able to launch tasks that can kill/replace each other

I have a Python program that does the following:
1) endlessly wait on com port a command character
2) on character reception, launch a new thread to execute a particular piece of code
What I would need to do if a new command is received is:
1) kill the previous thread
2) launch a new one
I read here and there that doing so is not the right way to proceed.
What would be the best way to do this knowing that I need to do this in the same process so I guess I need to use threads ...
I would suggest you two differente approaches:
if your processes are both called internally from a function, you could set a timeout on the first function.
if you are running external script, you might want to kill the process.
Let me try to be more precise in my question by adding an example of my code structure.
Suppose synchronous functionA is still running because waiting internally for a particular event, if command "c" is received, I need to stop functionA and launch functionC.
def functionA():
....
....
call a synchronous serviceA that can take several seconds even more to execute
....
....
def functionB():
....
....
call a synchronous serviceB that nearly returns immediately
....
....
def functionC():
....
....
call a synchronous serviceC
....
....
#-------------------
def launch_async_task(function):
t = threading.Thread(target=function, name="async")
t.setDaemon(True)
t.start()
#------main----------
while True:
try:
car = COM_port.read(1)
if car == "a":
launch_async_task(functionA)
elif car == "b":
launch_async_task(functionB)
elif car == "c":
launch_async_task(functionC)
May want to run the serial port in a separate thread. When it receives a byte put that byte in a queue. Have the main program loop and check the queue to decide what to do with it. From the main program you can kill the thread with join and start a new thread. You may also want to look into a thread pool to see if it is what you want.
ser = serial.Serial("COM1", 9600)
que = queue.Queue()
def read_serial(com, q):
val = com.read(1)
q.put(val)
ser_th = threading.Thread(target=read_serial, args=(ser, que))
ser_th.start()
th = None
while True:
if not que.empty():
val = que.get()
if val == b"e":
break # quit
elif val == b"a":
if th is not None:
th.join(0) # Kill the previous function
th = threading.Thread(target=functionA)
th.start()
elif val == b"b":
if th is not None:
th.join(0) # Kill the previous function
th = threading.Thread(target=functionB)
th.start()
elif val == b"c":
if th is not None:
th.join(0) # Kill the previous thread (functionA)
th = threading.Thread(target=functionC)
th.start()
try:
ser.close()
th.join(0)
except:
pass
If you are creating and joining a lot of threads you may want to just have a function that checks what command to run.
running = True
def run_options(option):
if option == 0:
print("Running Option 0")
elif option == 1:
print("Running Option 1")
else:
running = False
while running:
if not que.empty():
val = que.get()
run_options(val)
Ok, I finally used a piece of code that uses ctypes lib to provide some kind of killing thread function.
I know this is not a clean way to proceed but in my case, there are no resources shared by the threads so it shouldn't have any impact ...
If it can help, here is the piece of code that can easily be found on the net:
def terminate_thread(thread):
"""Terminates a python thread from another thread.
:param thread: a threading.Thread instance
"""
if not thread.isAlive():
return
exc = ctypes.py_object(SystemExit)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(thread.ident), exc)
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
raise SystemError("PyThreadState_SetAsyncExc failed")

Problems with asyncio in 3.4.2 - it just terminates for some reason

A newbie at python and spending many hours reading docs and other code I cannot seem to get the new asyncio module in Python 3.
It keeps on terminating without a stack trace to give me a clue and should run forever but does not.
The fundamental process concept I am trying to emulate is the following:
read from port:
open port -> read data (variable length) -> place on queue1
then process data:
get data from queue1 -> condition applies -> outcome put on queue2
then write to port:
get data from queue2 and write to port
loop around from top forever
Note: The data on the in port is sporadic, variable length and several blocks may arrive out of 'sequence' thus I use asyncio. I understand asyncio will allow the case of a block arrives, then another prior to my app responding - i.e. the call get_io_from_port() facilitates multiple executions of the co-routine. This is why I have use the queues to ensure non-blocking of the process_queue()
My toy example code so far:
import queue
import asyncio
#asyncio.coroutine
def process_queue(q1, q2):
tmp = q1.Get()
if tmp == 'ABCDEF':
q2.put('12345')
elif tmp == 'GHIJKL':
q2.put =('67890')
else:
print('There is a data error')
#asyncio.coroutine
def put_io_to_port(writer, q2):
if not q2.empty():
try:
writer.write(q2.get())
except IOError as e:
print('OUT Port issue: ', e)
#asyncio.coroutine
def get_io_from_port(reader, q1):
try:
data_i = yield from reader.read(1200)
q1.put(data_i)
except IOError as e:
print('IN Port issue: ', e)
def main():
q1 = queue()
q2 = queue()
loop = asyncio.get_event_loop() # main loop declaration
reader, writer = yield from asyncio.open_connection('192.168.1.103', 5555)
# high-level call open streams - read and write
print('Start')
tasks = [
asyncio.async(get_io_from_port(reader,q1)),
asyncio.async(process_queue(q1, q2)),
asyncio.async(put_io_to_port(writer, q2)),] # do these tasks - in this order
loop.run_forever(tasks) # loop through on main loop forever
loop.close()
if __name__ == '__main__':
main()
Also, as an aside - how does one debug this code - ie tracing? What techniques could be suggested? I am using Eclipse and PyDev but to no avail.
You've made several mistakes here. First, you're treating main like its a normal function, but you've placed a yield from call in there, which will automatically convert it into a generator. That means when you do
if __name__ == "__main__":
main()
main is not actually executed; the call to main() just creates a generator object that's immediately thrown away (because you're not assigning it to a variable). This is why you're having a hard time debugging - none of the code inside main is even executing. You should convert main to be a coroutine and call it using loop.run_until_complete instead.
Next, you're trying to use the queue module, which is not designed for use in a single-threaded asynchronous program. As soon as you call queue.get(), it's going to block your main thread, which means your asyncio event loop will be blocked, which means your whole program will be deadlocked. You should use the coroutine-safe asyncio.Queue instead.
You also have a race condition in put_io_to_port. You're only trying to consume from q2 if it isn't empty, but its possible that put_io_to_port could execute before process_queue has a chance to run and populate the queue. It looks like you would be fine if you just removed the if not q2.empty() check from put_io_to_port altogether.
Finally, you're adding your coroutines to the event loop using asyncio.async, which is fine. But you have a comment that says # do these tasks, in this order, but that's not how the program will behave with asyncio.async. It just adds all the coroutines to the event loop, and they'll all run in parallel. If you really want them to run sequentially, you should just do:
yield from get_io_from_port(reader,q1)
yield from process_queue(q1, q2)
yield from put_io_to_port(writer, q2)
But that's really not necessary here. You can run all of them at the same time and get the correct behavior; if one coroutine executes ahead of the other, it will just wait until the coroutine it depends on passes it the data it needs, and then resume execution.
You also have a few typos in there (q1.Get(), q2.put =(...), etc).
So, put all those fixes together and you get this:
import queue
import asyncio
#asyncio.coroutine
def process_queue(q1, q2):
while True:
tmp = yield from q1.get()
if tmp == 'ABCDEF':
yield from q2.put('12345')
elif tmp == 'GHIJKL':
yield from q2.put('67890')
else:
print('There is a data error')
#asyncio.coroutine
def put_io_to_port(writer, q2):
while True:
try:
data = yield from q2.get()
writer.write(data)
except IOError as e:
print('OUT Port issue: ', e)
#asyncio.coroutine
def get_io_from_port(reader, q1):
while True:
try:
data_i = yield from reader.read(1200)
yield from q1.put(data_i)
except IOError as e:
print('IN Port issue: ', e)
#asyncio.coroutine
def main():
q1 = asyncio.Queue()
q2 = asyncio.Queue()
reader, writer = yield from asyncio.open_connection('192.168.1.103', 5555)
# high-level call open streams - read and write
print('Start')
tasks = [
asyncio.async(get_io_from_port(reader,q1)),
asyncio.async(process_queue(q1, q2)),
asyncio.async(put_io_to_port(writer, q2)),]
if __name__ == '__main__':
loop = asyncio.get_event_loop() # main loop declaration
loop.run_until_complete(main())
import queue
import asyncio
#asyncio.coroutine
def process_queue(q1, q2):
while True:
tmp = yield from q1.get()
if tmp == 'ABCDEF':
yield from q2.put('12345')
elif tmp == 'GHIJKL':
yield from q2.put('67890')
else:
print('There is a data error')
#asyncio.coroutine
def put_io_to_port(writer, q2):
while True:
try:
data = yield from q2.get()
writer.write(data)
except IOError as e:
print('OUT Port issue: ', e)
#asyncio.coroutine
def get_io_from_port(reader, q1):
while True:
try:
data_i = yield from reader.read(1200)
yield from q1.put(data_i)
except IOError as e:
print('IN Port issue: ', e)
#asyncio.coroutine
def main():
q1 = asyncio.Queue()
q2 = asyncio.Queue()
reader, writer = yield from asyncio.open_connection('192.168.1.103', 5555)
# high-level call open streams - read and write
print('Start')
asyncio.async(get_io_from_port(reader,q1)) # changed items so not
asyncio.async(process_queue(q1, q2)) # in task list otherwise
asyncio.async(put_io_to_port(writer, q2)) # they are not visible
if __name__ == '__main__':
loop = asyncio.get_event_loop() # main loop declaration
loop.run_until_complete(main())
Find comments inline with code to understand the problem.

wxPython: Stop threading with wxButton

How I can stop threading by clicking a wxButton?
Here is my code:
def startMonitor(self,event):
selectedInterface = self.interfaces_cblist.GetValue()
Publisher().sendMessage(("test"),selectedInterface)
self.Close()
selectInterfaceStr = str(selectedInterface)
if len(selectedInterface) == 0:
noSelect_error = wx.MessageDialog(None,"Please select an interface","",wx.OK|wx.ICON_ERROR)
noSelect_error.ShowModal()
else:
monitorStarted = wx.MessageDialog(None,"Monitor on %s started"%selectInterfaceStr,"",wx.OK|wx.ICON_ERROR)
monitorStarted.ShowModal()
self.monitorInterface_button.Disable()
threading.Thread(target=self.camtableDetection,args=(selectInterfaceStr,)).start()
threading.Thread(target=self.dhcpexhaustion,args=(selectInterfaceStr,)).start()
def camtableDetection(self,getInterface):
global interface
interface = str(getInterface)
THRESH=(254/4)
START = 5
def monitorPackets(p):
if p.haslayer(IP):
hwSrc = p.getlayer(Ether).src
if hwSrc not in hwList:
hwList.append(hwSrc)
delta = datetime.datetime.now() - start
if((delta.seconds > START) and ((len(hwList)/delta.seconds) > THRESH)):
print "[*]- Detected CAM Table Attack."
#camAttackDetected = wx.MessageDialog(None,"Cam Attack Detected","",wx.ICON_ERROR)
#camAttackDetected.ShowModal()
hwList = []
start = datetime.datetime.now()
sniff(iface=interface,prn=monitorPackets)
def dhcpexhaustion(self,getInterface):
interface = str(getInterface)
global reqCnt
global ofrCnt
reqCnt = 0
ofrCnt = 0
def monitorPackets(p):
if p.haslayer(BOOTP):
global reqCnt
global ofrCnt
opCode = p.getlayer(BOOTP).op
if opCode == 1:
reqCnt=reqCnt+1
elif opCode == 2:
ofrCnt=ofrCnt+1
print "[*] - "+str(reqCnt)+" Requests, "+str(ofrCnt)+" Offers."
sniff(iface=interface,prn=monitorPackets)
I am thinking to stop the threading when I click on a button, but have no idea how can it can be done.
There are self.abort techniques, but I'm not sure how to apply it in my code.
As I said in a comment:
If [sniff is] a function that you have no control over (e.g., from a C extension module) and it loops forever, then it must have some way to cancel it. Maybe it's having your callback return a special value, maybe it's calling a control function, maybe it's closing the object it's working on… whatever it is, you have to do that.
So, why not read the documentation for scapy.sniff to see how to cancel it?
Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets
count: number of packets to capture. 0 means infinity
store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
offline: pcap file to read packets from, instead of sniffing them
timeout: stop sniffing after a given time (default: None)
L2socket: use the provided L2socket
opened_socket: provide an object ready to use .recv() on
stop_filter: python function applied to each packet to determine
if we have to stop the capture after this packet
ex: stop_filter = lambda x: x.haslayer(TCP)
So, the way to stop it sniffing forever is to pass it a stop_filter function, which will return True when you want to stop it. So that function is where you're going to check your stop flag. For example:
def __init__(self, whatever):
self.stopflag = False
self.stoplock = threading.Lock()
# rest of your init
def stop(self):
with self.stoplock:
self.stopflag = True
def stop_filter(self):
with self.stoplock:
return self.stopflag
def dhcpexhaustion(self, getInterface):
# etc.
sniff(iface=interface,prn=monitorPackets, stop_filter=self.stop_filter)
You're probably going to want to store the two Thread objects at start time, so you can join them at stop time, rather than just leaking them until your program exits. But otherwise, this should do it.

Python wait x secs for a key and continue execution if not pressed

I'm a n00b to python, and I'm looking a code snippet/sample which performs the following:
Display a message like "Press any key to configure or wait X seconds to continue"
Wait, for example, 5 seconds and continue execution, or enter a configure() subroutine if a key is pressed.
Thank you for your help!
Yvan Janssens
If you're on Unix/Linux then the select module will help you.
import sys
from select import select
print "Press any key to configure or wait 5 seconds..."
timeout = 5
rlist, wlist, xlist = select([sys.stdin], [], [], timeout)
if rlist:
print "Config selected..."
else:
print "Timed out..."
If you're on Windows, then look into the msvcrt module. (Note this doesn't work in IDLE, but will in cmd prompt)
import sys, time, msvcrt
timeout = 5
startTime = time.time()
inp = None
print "Press any key to configure or wait 5 seconds... "
while True:
if msvcrt.kbhit():
inp = msvcrt.getch()
break
elif time.time() - startTime > timeout:
break
if inp:
print "Config selected..."
else:
print "Timed out..."
Edit Changed the code samples so you could tell whether there was a timeout or a keypress...
Python doesn't have any standard way to catch this, it gets keyboard input only through input() and raw_input().
If you really want this you could use Tkinter or pygame to catch the keystrokes as "events". There are also some platform-specific solutions like pyHook. But if it's not absolutely vital to your program, I suggest you make it work another way.
If you combine time.sleep, threading.Thread, and sys.stdin.read you can easily wait for a specified amount of time for input and then continue.
t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()
Here's how I did it:
import threading
import time
import sys
class MyThread(threading.Thread):
def __init__(self, threadID, name, counter, f):
super().__init__()
self.threadID = threadID
self.name = name
self.counter = counter
self.func = f
def run(self):
self.func()
class KeyboardMonitor:
def __init__(self):
# Setting a boolean flag is atomic in Python.
# It's hard to imagine a boolean being
# anything else, with or without the GIL.
# If inter-thread communication is anything more complicated than
# a couple of flags, you should replace low level variables with
# a thread safe buffer.
self.keepGoing = True
def wait4KeyEntry(self):
while self.keepGoing:
s = input("Type q to quit: ")
if s == "q":
self.keepGoing = False
def mainThread(self, f, *args, **kwargs):
"""Pass in some main function you want to run, and this will run it
until keepGoing = False. The first argument of function f must be
this class, so that that function can check the keepGoing flag and
quit when keepGoing is false."""
keyboardThread = MyThread(1, "keyboard_thread", 0, self.wait4KeyEntry)
keyboardThread.start()
while self.keepGoing:
f(self, *args, **kwargs)
def main(keyMonitorInst, *args, **kwargs):
while keyMonitorInst.keepGoing:
print("Running again...")
time.sleep(1)
if __name__ == "__main__":
uut = KeyboardMonitor()
uut.mainThread(main)
Rather than make a blocking call time out, my approach is to start a thread that waits for the user to enter input, while another thread does something else. The two processes communicate through a small number of atomic operations: in this case, setting a boolean flag. For anything more complicated than atomic operations, obviously you should replace the atomic variable with a threadsafe buffer of some kind.

Categories