Can UI interact while program loop through several task - python-3.x

I´m developing a program that handles many task in a sequence. I call this mode "AutoMode". But i need to let the user take control and start using the program manual, through menu options, and finally choose "AutoMode" again.
How can I interrupt the "AutoMode" without stopping the program executing. Guess input() will keep the program wait for ever for user to make an input and the rest of the code will stop executing?
Any suggestions?

Found a solution that solve this issue, but seems to need several keyboard interacts.
In example below this results in many keypress to get the while loop to enter the if statement and take the program back to main menu.
import keyboard
import time
my_counter = 1
while True:
my_counter += 1
if keyboard.is_pressed('h'):
print("Letter H was pushed")
time.sleep(2)
break
print("Something is going on... ", my_counter)
time.sleep(0.5)
print("Simulate user interupt and return to main menu...")

Related

How to run infinite-loop python script that includes external .py script that's non-blocking but yet needs a response

I have two .py scripts. One is a infinite-loop(infinite.py) and the other is a test order on a website(order.py).
I need to execute order.py externally for x. I need this to be non blocking so that my infinite loop can keep checking the other items to see if I need to run order.py for the next "x" that gets popped out from list. The problem is that order.py takes 2 minutes to complete and I need a return of some kind to perform some logic that states if the order was successful, to add x back to list. I do not want "x" to be back in list yet or else it will try to perform another order.py on the same item from list.
I have tried to use subprocess.Popen and call but I can't seem to get them to work. I can either get it to run externally and be non-blocking but I won't be able to get my response from order.py or I get order.py to run but the infinite.py is waiting for order.py to finish before continuing with loop. I have also tried threading as well
Here is the structure of my code.
list = ["item1", "item2", "item3", "item4"]
while True:
x = list.pop(0)
#Performs a simple check 1
if check is True:
#Performs check 2
if check2 is True:
# This is the section I need help with.
# I need to execute order.py and wait for a response while this
# infinite loop keeps going
if order.py is successful:
list.append(x)
else:
print("Problem with order.py")
list.append(x)
else:
list.append(x)
time.sleep(30)
pass
else:
list.append(x)
time.sleep(30)
pass
So after asking a few people I realized what I am trying to do will never work. An example that explained to me was imagine a hand of poker where the current hand is no finished so you do not know the results of your earning before placing a new bet with your current chips. I am closing this post.

Timer that runs in the background in Python 3.7.0

I am trying to make a timer in my text-based adventure games so that for every second that passes, 1 hp is taken away from the user, while they are in a certain scenario and can still use other functions. Here's my code:
#Imports and base variables
import time
import threading
import random
hp=100 #Health
p="snow" #Starting point
invtry=[] #Inventory of Character
#Function to drop health
def hlthdrp():
hp-1
t=threading.Timer(1.0,hlthdrp)
t.start()
while p=="snow" or p=="Snow":
if hp==0 and p=="snow" or p=="Snow":
print ("You died of frostbite")
t.cancel()
threading.wait(timeout=5.0)
As of right now, I'm not getting any errors, but instead, a completely blank shell, or terminal. If anyone could help, that'd be great!
You must call threading.Timer recursively else it only calling one time
And you can use lower() function to compare snow or some string
There is your fixed code i hope it will be usefull for you.
def hlthdrp():
global hp
print(hp)# just for testing
hp=hp-1
if hp!=0:
threading.Timer(1, hlthdrp).start()
hlthdrp()
while p.lower()=="snow":
if hp==0 :
print ("You died of frostbite")
elif hp!=0 :
pass

Gtk Window Non-Responsive During Selenium Automation

Good Afternoon :) Having a problem with my Python3 Gtk3 application and Selenium WebDriver (ChromeDriver). Also, using Linux if it matters.
Basically, the user presses a button to start the Selenium webdriver automation and then as the automation process is going, it 'SHOULD' give feedback to the user in the GUI (See Content.content_liststore.append(list(item)) and LogBox.log_text_buffer).
However, it's not adding anything into the content_liststore until after fb_driver.close() is done. In the meantime, the Gtk window just "hangs".
Now, I've been looking into multithreading in hopes of the GUI being responsive to this feedback but I've also been reading that Selenium doesn't like multithreading (but I presume thats running multiple browsers/tabs (which this is not)).
So, my question is; Is multithreading the go-to fix for getting this to work?
# ELSE IF, FACEBOOK COOKIES DO NOT EXIST, PROCEED TO LOGIN PAGE
elif os.stat('facebook_cookies').st_size == 0:
while True:
try: # look for element, if not found, refresh the webpage
assert "Facebook" in fb_driver.title
login_elem = fb_driver.find_element_by_id("m_login_email")
login_elem.send_keys(facebook_username)
login_elem = fb_driver.find_element_by_id("m_login_password")
login_elem.send_keys(facebook_password)
login_elem.send_keys(Keys.RETURN)
except ElementNotVisibleException:
fb_driver.refresh()
StatusBar.status_bar.push(StatusBar.context_id, "m_login_password element not found, trying again...")
ProblemsLog.text_buffer.set_text("Facebook has hidden the password field, refreshing page...")
else:
query_elem = fb_driver.find_element_by_name("query")
query_elem.send_keys(target)
query_elem.send_keys(Keys.RETURN)
break
m_facebook_url_remove = "query="
m_facebook_url = fb_driver.current_url.split(m_facebook_url_remove, 1)[1] # Remove string before "query="
facebook_url = "https://www.facebook.com/search/top/?q=" + m_facebook_url # Merge left-over string with the desktop url
StatusBar.status_bar.push(StatusBar.context_id, "Facebook elements found")
fb_title = fb_driver.title
fb_contents = [(target_name.title(), "Facebook", facebook_url)]
for item in fb_contents:
Content.content_liststore.append(list(item))
#progress_bar.set_fraction(0.10)
LogBox.log_text_buffer.set_text("Facebook Search Complete")
with open('facebook_cookies', 'wb') as filehandler:
pickle.dump(fb_driver.get_cookies(), filehandler)
fb_driver.close()
I've considered it not working because of the 'while' loop, but another piece of code doesn't have a loop and does the exact same thing, it waits for Selenium to finish before adding content to the GUI.
Additionally, the user can select multiple websites to do this with, so the application can first go to Facebook (do it's business then close), go to LinkedIn (do it's business then close) and so fourth. And it still waits for all the Selenium code to finish before adding anything to the Gtk GUI.
I really hope that makes sense! Thank you :)
Your`s question is the answer you are lookig for. Take a read here https://wiki.gnome.org/Projects/PyGObject/Threading

Maya threading causing crash

I've started an autosave script editor script (using Maya 2014), but it's really unstable and can crash if something happens at the same time as a save. I also just realised crashes will happen even when not saving, so I tried to find what the actual problem was, and ended up with barely any code left but still able to replicate it.
My idea for the code is to run a background thread, where it'll loop and backup the scripts at an interval, but check a value every second to make sure it's not been paused or cancelled (cancelled will stop the loop).
I presume the problem is something to do with how background threads work in Maya, as it can crash if loading/closing the script editor window, or switching tabs on the render view settings (at least with Mental Ray selected, since it seems to take longer loading tabs than the default renderer). I presume there's other ways, but those are the ones that were really easy to find.
After getting it down to just time.sleep() in a while loop, it really doesn't make sense to me as to why it should be causing a crash. I also used a different sleep function that does while time.time()>startTime+1, to make sure it wasn't the time module, but it still caused crashes.
Here is the cut down code if anyone wants to try it, once you start the thread with AutoSave.start(), if you continuously load and close the script editor window, you should eventually get a runtime error (that says R6025 pure virtual function call). It may take multiple attempts, but it always seems to eventually happen.
import threading, time
import pymel.core as pm
class AutoSaveThread(object):
def __init__( self ):
thread = threading.Thread(target=self.run, args=())
thread.daemon = True
thread.start()
def run(self):
while True:
time.sleep(1)
print "Open and close the script editor enough times and this will crash"
class AutoSave:
#classmethod
def start( self ):
AutoSaveThread()
I have a dozen or so tabs open so loading/closing takes a bit longer than if I had none, this could potentially increase the time window in which crashes can happen.
For the record, here is the bit of code built into Maya that will always run whenever the script editor window is closed. I thought it may have something to do with my modified version of it saving, then this trying to save at the same time, but it's still crashing with nothing happening in the loop.
global proc syncExecuterBackupFiles(){
global string $gCommandExecuter[];
global string $executerBackupFileName;
if(`optionVar -q saveActionsScriptEditor`) {
// clear the script editor temp dir first before writing temp files
string $scriptEditorTempDir = (`internalVar -userPrefDir` + "scriptEditorTemp/");
string $tempFiles[] = `getFileList -folder $scriptEditorTempDir`;
string $file;
for ($file in $tempFiles) {
sysFile -delete ($scriptEditorTempDir + $file);
}
// save all the executer control text to files
int $i = 0;
for($i = 0; $i < size($gCommandExecuter); $i++) {
cmdScrollFieldExecuter -e -storeContents $executerBackupFileName $gCommandExecuter[$i];
}
}
}
Try wrapping your call to print in pymel.mayautils.executeDeferred or maya.utils.executeDeferred so that it is executed on the main UI thread.
if you continuously load and close the script editor window, you should eventually get a runtime error (that says R6025 pure virtual function call). It may take multiple attempts, but it always seems to eventually happen.
I was able to confirm this behavior on Maya 2012, and I doubt it's version specific.
My bet is that your test call to print is what is actually causing Maya to crash, because even though print is normally just a python statement, Maya has some sort of hook into it to update the Script Editor's Output Window (and potentially the Command Response bar) with the string you are printing, which are both running on the main UI Thread.
From the Autodesk Knowledge article "Python and threading":
Maya API and Maya Command architectures are not thread-safe. Maya commands throw an exception if they are called outside the main thread, and use of the OpenMaya API from threads other than the main one has unforeseen side effects.
By passing your print statement to pymel.mayautils.executeDeferred I've (at least thus far, who knows with Maya ;-) ) been unable to cause a crash.
import threading, time
import pymel.core as pm
import pymel.mayautils # like maya.utils, for executeDeferred
# Set to False at any time to allow your threads to stop
keep_threads_alive = True
def wrapped_print():
print "Opening and closing the script editor shouldn't make this crash\n"
class AutoSaveThread(object):
def __init__(self):
thread = threading.Thread(target=self.run)
thread.start()
def run(self):
while keep_threads_alive:
time.sleep(1)
pymel.mayautils.executeDeferred(wrapped_print)
...
The only side-effect of wrapping specifically a print statement is that it no longer echoes to the Command Response bar. If preserving that behavior is important to you just use pymel.mel.mprint instead.
import threading
import time
import maya.utils as utils
run_timer = True
run_num = 0
def example(interval = 10):
global run_timer;global run_num;
def your_function_goes_here():
print "hello",run_num
run_num +=1
while run_timer:
time.sleep(interval)
utils.executeDeferred(your_function_goes_here)
t = threading.Thread(None, target = example, args = (1,) )
t.start()
# stop :
# run_timer = False

Refresh PyGTK window every minute?

I have a PyGTK app that is supposed to be a desktop monitor of some data source. I have it almost complete but there is just this one problem of auto-refreshing.
In my program I want it to fetch data from database and refresh the window every minute. Here's what I have for the refresh function (it refresh once per second now for testing):
def refresh(self):
cnxn = pyodbc.connect(r'Driver={SQL Server};Server=IL1WP0550DB;Database=Customer_Analytics;Trusted_Connection=yes;')
cursor = cnxn.cursor()
cursor.execute("SELECT * FROM TestGroup_test_group_result")
data = []
while 1:
row = cursor.fetchone()
if not row:
break
#data.append([row.TestGroupName, row.PWF, row.Expires, row.TestGroupID])
data.append([str(datetime.now()), row.PWF, row.Expires, row.TestGroupID])
cnxn.close()
self.fill_text(data)
threading.Timer(1, self.refresh).start()
Using this function I can update my window, but it only works when I drag my window around. When I put a series of print statements around, it looks like it is only executing the script when the window is moving.
Anyone know how to fix it?
Additional info: I realize that it only processes the refresh when there is a signal.
With GTK you need to make sure your widgets are only updated from the main thread. You can do this by using a timeout function with gtk.timeout_add() or gtk.timeout_add_seconds(). If you use python's threading functions the widgets are not updated from the main thread and so it does not work. For timeouts of greater than one second you should use gtk.timeout_add_seconds() as it avoids unnecessary wake ups where the timing isn't that critical.
Use gtk.timeout_add(1000, self.refresh) instead of threading.Timer(1, self.refresh).start() did the trick :)
Don't know why though
python3:
from gi.repository import GObject
def refresh_data(self):
[do stuff here]
if self.running:
GObject.timeout_add(1000, self.refresh_data)
Set self.running to False to stop.

Resources