When while loop placed in wxPython events - python

I'm trying to write a GUI program grabbing specific contents from a webpage. The idea is when I hit the start button, the program should start extracting information from that page. And I want to add some code to check if connected to the Internet. If not, continue trying until connected.
So I just added the following code in the event, but found it didn't work. Also the whole program has to be closed in a forced way. Here's my code:
import urllib2
import time
InternetNotOn = True
while InternetNotOn:
try:
urllib2.urlopen("http://google.com")
InternetNotOn = False
print "Everyting is fine!"
except urllib2.URLError, e:
print "Error!"
time.sleep(10)
What could the problem be?

When you have an event based program, the overall flow of the program is this:
while the-program-is-running:
wait-for-an-event
service-the-event
exit
Now, lets see what happens when service-the-event calls something with a (potentially) infinite loop:
while the-program-is-running:
wait-for-an-event
while the-internet-is-on:
do-something
exit
Do you see the problem? In the worse case your program may never call wait-for-an-event again because your loop is running.
Remember: the event loop is already an infinite loop, you don't need to add another infinite loop inside of it. Instead, take advantage of the existing loop. You can use wx.CallAfter or wx.CallLater to call a method which will cause your function to be called at the next iteration of the event loop.
Then, within your function you call wx.CallAfter or wx.CallLater again to cause it to again be called on the next iteration of the event loop.

Instead of time.sleep(10) you can call wxApp::Yield and time.sleep(1) ten times.
Beware of reentrancy problems (e.g. pressing the start button again.). The start button could be dimmed while in the event handler.
But Bryan Oakley's solution is probably the better way.

Related

I created a python bind for CS:GO with pyautogui but it doesnt work

I created a simple bind script. It works on IDLE Python but it doesn't work in CS:GO. Do you know why?
Mayby it must be on background to work?
import keyboard
import pyautogui
import time
def EventListen():
while True:
try:
if keyboard.is_pressed('n'):
pyautogui.press('`')
pyautogui.typewrite('say EZ')
pyautogui.press('enter')
pyautogui.press('`')
EventListen()
except:
EventListen()
EventListen()
I don't see the need to use pyautogui since you are already using keyboard which is sufficient to perform the tasks you need. I have made some changes to your code
import time
import keyboard
def EventListen():
while True:
try:
if keyboard.is_pressed('n'):
keyboard.press('`')
keyboard.write('say EZ')
keyboard.press('enter')
keyboard.press('`')
elif keyboard.is_pressed('/'): #add something to end the process
break
except:
EventListen()
time.sleep(0.001)
EventListen()
There is no need to call the function in the while loop, as it will anyway be executed infinitely unless you kill the process. I don't see why the script wouldn't run in the background, in fact I am typing this
n`say EZ
`
using the script. What might be possible is that your previous program ran continuously, causing high CPU usage which might have competed with the game's demand. I recomend you to add a small delay before every iteration of the while loop, in this case I have added 1 ms delay, which will cause significant reduction in CPU usage. I am not sure if that solved your problem as I am unable to reproduce your exact case, let me know if it helped.
EDIT : I forgot to mention, I have added another binding of keyboard.is_pressed('/') which will make the program break out of the loop and hence terminate it when / key is pressed. You can change this as you like. If you don't want any other binding as such (which I don't recommend) then you can rely on manually killing the task.
you should make an exe with pyinstaller and you run it background

Python: how to envisage the interruption of a loop before its normal end

I have a loop running for quite a long time (several hours). It may be that the user, looking at the current results, considers the run iterations as sufficient and then wants to stop the loop before its natural end, but without interrupting the whole program (no "Ctrl+C") since some final results processing is necessary.
To do that, I added the possibility of creating a specific 'stop' file in the working directory. At each loop, the code verify if that file exists and, if that is the case, it end the loop. I do not know if this solution is efficient and whether better solutions exist.
Example
i = 0
while i < 1000 and not(path.isfile(path.join(self.wrkdir,'stop'))) :
DoSomeStuff
i += 1
FinalizingStuff
If the only reason for not using Ctrl+C is that you think it will stop all your program, then the best solution is to use it instead of watching the files.
Simply because you can catch this exception (it is called KeyboardInterrupt) in your code as any other and do whatever you want.
import time
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print('Ok, user is pissed with our loop, go further')
finally:
# if some resources need to be cleaned
pass
print('Here we are, nothing is lost')

How to stop a for loop while in execution

I am currently running a program, which i expect to go on for an hour or two. I need to break out of the loop right now, so that rest of the program continues.
This is a part of the code:
from nltk.corpus import brown
from nltk import word_tokenize, sent_tokenize
from operator import itemgetter
sentences = []
try:
for i in range(0,55000):
try:
sentences.append(brown.sents()[i])
print i
except:
break
except:
pass
the loop is currently around 30,000. I want to exit and continue with the code (not shown here). Please suggest me how to such that, the program doesn't break exit completely. (Not like keyboard interrupt)
Since it is already running, you can't modify the code. Unless you invoked it under pdb, you can't break into the Python debugger to alter the condition to leave the loop and continue with the rest of the program. So none of the normal avenues are open to you.
There is one outside solution, which requires intimate knowledge of the Python interpreter and runtime. You can attach the gdb debugger to the Python process (or VisualStudio if you are on Windows). Then when you break in, examine the stack trace of the main thread. You will see a whole series of nested PyEval_* calls and so on. If you can figure out where the loop is in the stack trace, then identify the loop. Then you will need to find the counter variable (an integer wrapped in a PyObject) and set it to a large enough value to trigger the end of the loop, then let the process continue. Not for the faint of heart! Some more info is here:
Tracing the Python stack in GDB
Realistically, you just need to decide if you either leave it alone to finish, or kill it and restart.
It's probably easiest to simply kill the process, modify your code so that the loop is interruptible (as #fedorSmirnov suggests) with the KeyboardInterrupt exception, then start again. You will lose the processing time you have invested already, but consider it a sunken cost.
There's lots of useful information here on how to add support to your program for debugging the running process:
Showing the stack trace from a running Python application
I think you could also put the for loop in a try block and catch the keyBoardInterrupt exception by proceeding with the rest of the program. With this approach, you should be able to break out of the loop by hitting ctrl + C while staying inside your program. The code would look similar to this:
try:
# your for loop
except KeyboardInterrupt:
print "interrupted"
# rest of your program
You can save the data with pickle before the break command. Next time load the data and continue the loop.

Performing an action upon unexpected exit python

I was wandering if there was a way to perform an action before the program closes. I am running a program over a long time and I do want to be able to close it and have the data be saved in a text file or something but there is no way of me interfering with the while True loop I have running, and simply saving the data each loop would be highly ineffective.
So is there a way that I can save data, say a list, when I hit the x or destroy the program? I have been looking at the atexit module but have had no luck, except when I set the program to finish at a certain point.
def saveFile(list):
print "Saving List"
with open("file.txt", "a") as test_file:
test_file.write(str(list[-1]))
atexit.register(saveFile(list))
That is my whole atexit part of the code and like I said, it runs fine when I set it to close through the while loop.
Is this possible, to save something when the application is terminated?
Your atexit usage is wrong. It expects a function and its arguments, but you're just calling your function right away and passing the result to atexit.register(). Try:
atexit.register(saveFile, list)
Be aware that this uses the list reference as it exists at the time you call atexit.register(), so if you assign to list afterwards, those changes will not be picked up. Modifying the list itself without reassigning should be fine, though.
You could use the handle_exit context manager from this ActiveState recipe:
http://code.activestate.com/recipes/577997-handle-exit-context-manager/
It handles SystemExit, KeyboardInterrupt, SIGINT, and SIGTERM, with a simple interface:
def cleanup():
print 'do some cleanup here'
def main():
print 'do something'
if __name__ == '__main__':
with handle_exit(cleanup):
main()
There's nothing you can in reaction to a SIGKILL. It kills your process immediately, without any allowed cleanup.
Catch the SystemExit exception at the top of your application, then rethrow it.
There are a a couple of approaches to this. As some have commented you could used signal handling ... your [Ctrl]+[C] from the terminal where this is running in the foreground is dispatching a SIGHUP signal to your process (from the terminal's drivers).
Another approach would be to use a non-blocking os.read() on sys.stdin.fileno such that you're polling your keyboard one during every loop to see if an "exit" keystroke or sequence has been entered.
A similarly non-blocking polling approach can be implemented using the select module's functionality. I've see that used with the termios and tty modules. (Seems inelegant that it needs all those to save, set changes to, and restore the terminal settings, and I've also seen some examples using os and fcntl; and I'm not sure when or why one would prefer one over the other if os.isatty(sys.stdin.fileno())).
Yet another approach would be to use the curses module with window.nodelay() or window.timeout() to set your desired input behavior and then either window.getch() or window.getkey() to poll for any input.

python: adding a reset function to a threaded application

My python code runs a function that takes a long time:
Navigation()
During this execution I'd like to have a reset button. For reset button to work, I used threading and I managed to get my code into threaded callback function with the button press. How do I terminate the Navigation() that is currently running and call another fresh Navigation() function? thanks.
Thanks in advance.
If your navigation function has a loop that it executes, you could have a check to see if an "interrupt" variable is set to True. If so, you could have the Navigation function terminate during that check:
def navigation(self):
# reset self.interrupt as appropriate
while not self.interrupt:
pass # Do something here
# You will want some other exit condition as well, of course.
def button_pressed_response(self):
self.interrupt = True
self.navigation()
If you have access to a multithreaded library as you indicated, you could use a more elegant callback function and simplify the reset logic as well.
This answer pretty much sums up issues and pitfalls of terminating threads:
https://stackoverflow.com/a/325528

Categories