I've got a Python 2.7 script that uses PyWinAuto to automate an application. At one point in the application, it goes off and does something for a long time...sometimes 15 seconds, sometimes up to 2 minutes...You never know...each time is different.
Once the process is finished, a popup appears, and I want PyWinAuto to continue on. So, I'm trying to make the program wait and check if that popup dialog has appeared. When it does, I try to break out of the loop. Here's a look at the code that does what I'm describing:
all_done = 1
while all_done != 1:
try:
app.Phazer.Static2.Texts() == [u'Would you like to Store Results?']
all_done = 1
break
except:
print("Testing...")
time.sleep(2)
..rest of the code..
However, 80% of the time, it works every time....Otherwise, PyWinAuto sometimes jumps out of the loop and tries to work on the popup dialog that hasn't appeared yet.
I'm new to Python, but I know there has to be a smarter, more reliable way to pull this off....Any ideas?
The only case I can imagine is that app.Phazer.Static2 is matched with another control sometimes.
app.Phazer.Static2 is equivalent to app.Phazer.ChildWindow(best_match='Static2'). Best match algorithm used in pywinauto can capture another static text with similar name.
Comparison operator == does't raise any exception, so you may get incorrect static text, it will return False to nothing, all_done = 1, break. That's it.
You can make the following code to make sure you connected with appropriate control:
app.Phazer.ChildWindow(class_name='Static', ctrl_index=1)
or
app.Window_(title='Phazer', class_name='#32770').ChildWindow(class_name='Static', ctrl_index=1)
if you're in doubt with capturing dialog.
And so the final check should be
if app.Phazer.ChildWindow(class_name='Static', ctrl_index=1).Texts() != [u'Would you like to Store Results?']:
raise Exception()
Related
I want to automate the process of clicking a few buttons in a game, so I wrote a script that looks for the first button and clicks it, then clicks the other two.
import pyautogui as pag
import time
while True:
if Click("Replay") == True:
time.sleep(1)
Click("Continue")
time.sleep(1)
Click("Repeat")
time.sleep(1)
else:
time.sleep(5)
The Click() function basically takes a string input and turns it into input.png, matches it to a png i have of the buttons, and clicks it. If it doesn't find it, it just says it couldnt find it.
Heres that in case you need it:
def Click(image):
image = str(image)
location = pag.locateOnScreen(image + ".png")
if location != None:
point = pag.center (location)
coordsX, coordsY = point
pag.click(coordsX, coordsY)
print("Clicked %s" % (image))
return True
else:
print("Did not find %s Button" % (image))
My end goal was to make it into an executable so I could send it to people and they could use it, but I don't want it to waste a lot of memory on the computers it runs on. I also don't want to increase the wait time on it, and I believe I saw somewhere it clears itself after 2GB or something, but I'm not that good at coding and I dont want it using that much ram in the first place. Is there anything I can do to either A. clear it at a lower threshold, or B. make it not use that much ram in the first place?
A few optimizations/cleanups to your code:
You don't need the else for time.sleep(5).
Consider adding a return False to your Click() function's else clause?
Pyautogui's website says that the locateOnScreen function will raise an error now, not return None, so consider using a try-except block. (If it doesn't return an exception for you, refer to the accepted answer to this question.)
Pyautogui allows clicking a Point object, so use this instead:
def Click(image):
image = str(image)
try:
pag.click(pag.locateCenterOnScreen(image + ".png"))
print("Clicked %s" % (image))
return True
except pag.ImageNotFoundException:
print("Did not find %s Button" % (image))
return False
I've run this code,and it uses almost no RAM for me.
Using PyGubu (tool to create Tkinter interfaces) I obtained the following GUI:
Current situation:
When I click the Button "Create", a function is called. This function takes quite some time, and the graphical interfaces is just frozen. As I would like to keep the graphical interface and the functional part as much separated as possible, I don't want to update the Progress Bar or the interface in general from the function I call
Desired situation
The best case for me would be a solution without Threading: I would like, upon clicking "Create", that my function runs, while the Progress Bar updates itself (just to show a feedback to the user, and to tell him "look, I am doing something") and the interface remains responsive, so the user can actually interact with it while the function finish.
Current attempts
I tried to solve this using Threading:
#I have this code in my main.py:
from threading import Thread
from queue import Queue, Empty
my_queue=Queue()
#And this is a simplified version of the Command of the "Create" Button:
def create_command(self):
#Show the progress bar and start it
self.show_item(self.progress)
self.progress.start()
#Run the big function
thrd = Thread(target = my_big_function, args=(some_arguments, my_queue))
thrd.start()
do_retry = True
while do_retry: #Repeat until you have a result
try:
result = my_queue.get(False) #If you have a result, exit loop. Else, throw Empty
do_retry = False
except Empty: #Queue is still empty
self.progress_var.set(self.progress_var.get()+1)
sleep(0.05)
self.mainwindow.update() #Update the progress bar
q.task_done()
self.progress.stop()
Problem of the current attempt
As I am not used to work with threads, I am facing two problems:
In some runs (not all of them, just some) I have a RuntimeError stating
RuntimeError: main thread is not in main loop
I tried to overcome this looking at other question in StackOverflow, but now it just happens randomly, and I don't know how to avoid it. The module mtTinker is no more maintained for python 3.x (there is a vague attempt full of ToDoes and blood)
If there is some kind of exception in the big function, I don't know how to handle it. The program would just run forever waiting for a result that will never come back
So
How can I obtain my desired outcome? Thanks in advance
You can try adding root.update() inside the function you call, inside the main loop. Hope that's helpful!
Is there an easy way to execute time delay (like time.sleep(3)) between every statement of Python code without having to explicitly write between every statement?
Like in the below Python Script which performs certain action on SAP GUI window. Sometimes, the script continues to the next statement before the previous statement is complete. So, I had to add a time delay between every statement so that it executes correctly. It is working with time delay, but I end up adding time.sleep(3) between every line. Just wondering if there is a better way?
import win32com.client
import time
sapgui = win32com.client.GetObject("SAPGUI").GetScriptingEngine
session = sapgui.FindById("ses[0]")
def add_record(employee_num, start_date, comp_code):
try:
time.sleep(3)
session.findById("wnd[0]/tbar[0]/okcd").text = "/npa40"
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-PERNR").text = employee_num
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-EINDA").text = start_date
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-WERKS[1,0]").text = comp_code
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSG[2,0]").text = "1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSK[3,0]").text = "U1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT").getAbsoluteRow(0).selected = True
time.sleep(3)
return "Pass"
except:
return "failed"
The right way to do what you asked for is almost certainly to use the debugger, pdb.
The right way to do what you want is probably something completely different: find some signal that tells you that the step is done, and wait for that signal. With problems like this, almost any time you pick will be way, way too long 99% of the time, but still too short 1% of the time. That signal may be joining a thread, or waiting on a (threading or multiprocessing) Condition, or getting from a queue, or awaiting a coroutine or future, or setting the sync flag on an AppleEvent, or… It really depends on what you're doing.
But if you really want to do this, you can use settrace:
def sleeper(frame, event, arg):
if event == 'line':
time.sleep(2)
return sleeper
sys.settrace(sleeper)
One small problem is that the notion of line used by the interpreter may well not be what you want. Briefly, a 'line' trace event is triggered whenever the ceval loop jumps to a different lnotab entry (see lnotab_notes.txt in the source to understand what that means—and you'll probably need at least a passing understanding of how bytecode is interpreted, at least from reading over the dis docs, to understand that). So, for example, a multiline expression is a single line; the line of a with statement may appear twice, etc.1
And there's probably an even bigger problem.
Sometimes, the script continues to next step before the previous step is fully complete.
I don't know what those steps are, but if you put the whole thread to sleep for 2 seconds, there's a good chance the step you're waiting for won't make any progress, because the thread is asleep. (For example, you're not looping through any async or GUI event loops, because you're doing nothing at all.) If so, then after 2 seconds, it'll still be just as incomplete as it was before, and you'll have wasted 2 seconds for nothing.
1. If your notion of "line" is closer to what's described in the reference docs on lexing and parsing Python, you could create an import hook that walks the AST and adds an expression statement with a Call to time.sleep(2) after each list element in each body with a module, definition, or compound statement (and then compiles and execs the result as usual).
Anything you want to happen in a program has to be explicitly stated - this is the nature of programming. This is like asking if you can print hello world without calling print("hello world").
I think the best advice to give you here is: don't think in terms of "lines", but think in term of functions.
use debugging mode and watch each and every line executing line by line.
Firstly, very much Py Newby!
I have written a program to import data from a file and display it as an image using tkinter. The loop that is misbehaving runs thus:
Get data and plot
for x in xrange(WIDE):
for y in xrange(HIGH):
dataPointLo = inFile.read(1)
dataPointHi = inFile.read(1)
pixelValue = ((ord(dataPointLo) + 256*(ord(dataPointHi)))-31500)
colour = rgb[pixelValue]
#print below makes prog run!
print pixelValue
img.put(colour, to=(x,y))
As suggested by the comment, leaving out the print stops it working, but it locks one core of the processor at 100% for as long as you leave it (well at least 20 mins!). This effect occurs both in IDLE and from the command line (Ubuntu 12.04). Of course, the print to the IDLE window slows the program down, so I would like to remove it! Any thoughts?
it sounds like the process you are running takes a long time to complete, i would suggest that the reason you think it stops is because the window doesn't update while the process is busy unless you tell it to. i suggest you add a function like the following to your code and call it once before you enter your loop:
def keep_alive(self):
self.update()
self.after(100, self.keep_alive)
this way you are adding an event to update the window every 100ms(ish) to the event loop, which will keep the program responsive. you can adjust the timing to suit you, too often will slow your loop down, too far apart and the program will feel sluggish.
So I'm trying to do this (access a file on a website, read its contents and perform actions until the content says to exit. The precondition being it has to wait x seconds before accessing the website again; to recheck the contents):
perform = True
while(perform):
data = urllib.urlopen('someurl')
data = data.read()
if(data == '0'):
dosomething()
elif(data == '1'):
#1 signifies to exit the loop
perform = False
else:
time.sleep(10)
However this never seems to work. 'Someurl' always has a value. Some Google says that it's something to do with the sleep function. Please help!
this:
import time
while True:
print "fetching"
time.sleep(10)
is the minimal test case and as this always works it can't be a problem with the time.sleep function
1) Have you tried actually checking what data you get back from reading the URL? Like, printing it out or something?
2) If the data does actually match '0' or '1', then you don't get to the else case, so the sleep() doesn't happen. This is bad because it means you try to read the data again immediately. It probably won't have changed, and web servers usually don't like you very much when you ask them for the same URL over and over without pausing (they think you are trying to hack them). Solution: don't put the sleep() call in an else case; just leave it at the same level as the original if. You don't need an else to have valid code.