Move on after passing command in windows python - python

Below is a function I am using. When I call the command the spawn a putty session, it completely freezes up my gui program until I close the putty session. Is there any way to get around this, so that it calls the to the command, and then just moves along? (there is more I am passing to the command, but I have removed it to clean it up.
def SpawnSessionrmt(self,event):
if "SSH" in self.protormt:
subprocess.call('C:/bin/putty.exe ',shell=True)
elif "RDP" in self.protormt:
subprocess.call('C:/bin/rdp.exe)
else:
print "Not that you will see this...but that isn't a valid protocol"

The problem is that, as the docs say, call will:
Run the command described by args. Wait for command to complete, then return the returncode attribute.
If you don't want to wait for the command to complete, don't use call. Just create a Popen instance (and, ideally, wait for it later on, maybe at exit time, or in a background thread).
For example:
def SpawnSessionrmt(self,event):
if "SSH" in self.protormt:
self.children.append(subprocess.Popen('C:/bin/putty.exe ',shell=True))
elif "RDP" in self.protormt:
self.children.append(subprocess.Popen('C:/bin/rdp.exe'))
else:
print "Not that you will see this...but that isn't a valid protocol"
def WaitForChildren(self):
for child in self.children:
child.wait()
For a GUI app, I think the simplest thing to do might be to just put the subprocess.call into a background thread. That way, you can update the GUI when the actual work is done.
Unfortunately, each GUI framework has a different way of doing that—some let you do GUI stuff from any thread, some have a run_on_main_thread function, some let you post events to the main thread to be picked up by its event loop, some require you to build your own inter-thread communication system, etc. And you didn't tell us which GUI framework you're using.
So, here's an example with one framework I picked at random, wx:
def SpawnSessionrmt(self,event):
if "SSH" in self.protormt:
cmd = 'C:/bin/putty.exe'
elif "RDP" in self.protormt:
cmd = 'C:/bin/rdp.exe'
else:
print "Not that you will see this...but that isn't a valid protocol"
return
def background_function():
result = subprocess.call(cmd)
event = wx.CommandEvent(MY_UPDATE_ID)
event.SetInt(result)
self.GetEventHandler().AddPendingEvent(event)
t = threading.Thread(target=background_function)
t.daemon = True
t.start()
(PS, I hate my random number generator, because I hate wx… but at least it didn't pick Tkinter, which would have forced me to write my own cross-thread communication around a Queue or Condition…)

Related

Maya GUI freezes during subprocess call

I need to conform some maya scenes we receive from a client to make them compatible to our pipeline. I'd like to batch that action, obviously, and I'm asked to launch the process from within Maya.
I've tried two methods already (quite similar to each other), which both work, but the problem is that the Maya GUI freezes until the process is complete. I'd like for the process to be completely transparent for the user so that they can keep workind, and only a message when it's done.
Here's what I tried and found until now:
This tutorial here : http://www.toadstorm.com/blog/?p=136 led me to write this and save it:
filename = sys.argv[1]
def createSphere(filename):
std.initialize(name='python')
try:
mc.file(filename, open=True, pmt=False, force=True)
sphere = mc.polySphere() [0]
mc.file(save=True, force=True)
sys.stdout.write(sphere)
except Exception, e:
sys.stderr.write(str(e))
sys.exit(-1)
if float(mc.about(v=True)) >= 2016.0:
std.uninitialize()
createSphere(filename)
Then to call it from within maya that way:
mayapyPath = 'C:/Program Files/Autodesk/Maya2016/bin/mayapy.exe'
scriptPath = 'P:/WG_MAYA_Users/lbouet/scripts/createSphere.py'
filenames = ['file1', 'file2', 'file3', 'file4']
def massCreateSphere(filenames):
for filename in filenames:
maya = subprocess.Popen(mayapyPath+' '+scriptPath+' '+filename,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
out,err = maya.communicate()
exitcode = maya.returncode
if str(exitcode) != '0':
print(err)
print 'error opening file: %s' % (filename)
else:
print 'added sphere %s to %s' % (out,filename)
massCreateSphere(filenames)
It works fine, but like I said, freezes Maya GUI until the process is over. And it's just for creating a sphere, so not nearly close to all the actions I'll actually have to perform on the scenes.
I've also tried to run the first script via a .bat file calling mayabatch and running the script, same issue.
I found this post (Running list of cmd.exe commands from maya in Python) who seems to be exactly what I'm looking for, but I can't see how to adapt it to my situation ?
From what I understand the issue might come from calling Popen in a loop (i.e. multiple times), but I really can't see how to do otherwise... I'm thinking maybe saving the second script somewhere on disk too and calling that one from Maya ?
In this case subprocess.communicate() will block until the child process is done, so it is not going to fix your problem on its own.
If you just want to kick off the processes and not wait for them to complete -- 'fire and forget' style -- you can just use threads, starting off a new thread for each process. However you'll have to be very careful about reporting back to the user -- if you try to touch the Maya scene or GUI from an outside thread you'll get mysterious, undebuggable errors. print() is usually ok but maya.cmds() is not. If you're only printing messages you can probably get away with maya.utils.executeDeferred() which is discussed in this question and in the docs.

Python Curses while Multithreading

I have a multithreaded program written in Python where I have a number of things happening at the same time:
reading raw data from an external source
organizing such data into different lists (parsing)
saving the post-parsed data into mass storage
some threads being used to flush some buffers from time to time and other optimizations
displaying parts of such data for real-time monitoring, using Curses.
The program is latency-sensitive, so I really need this to be multithreaded.
I got the curses thread to display correctly what I want to.
The problem is that while I had everything working without the curses thread, I had a "killswitch" in the main() function that terminated all activity at the press of a key.
I have this global variable called "killThreads" that goes into all functions who are called as threads, and all these functions only work as:
def oneThread():
while (not killThreads):
doStuff()
...
And then the main function defines the killThread as False, initializes all threads and turns the killThread as True after a raw_input():
killThreads=False
thisThread=threading.Thread(target=oneThread)
otherThread=threading.Thread(target=twoThread)
thisThread.setDaemon(True)
otherThread.setDaemon(True)
thisThread.start()
otherThread.start()
raw_input('Press to end the program')
killThreads=True
Everything ran fine until I ran a thread with the Curses module to display data.
It seems that while the Curses thread is on, it takes over all input commands. I tried to use getch() with no success. All I could do to keep everything running was to establish a timer within the Curses function:
def displayData():
screen=curses.initscr()
screen.nodelay(1)
timeKill=0
while (timeKill<80):
#stuff is drawn#
time.sleep(0.25)
timeKill+=1
Could anyone tell me how to go over Curses and get my keyboard input to "reach" the main function and kill all threads? Or do I always have to input to Curses and then make the Curses function alter the killThreads variable? If so, how do I do it (or where do I find the documentation for that)?
Thank you so much for your help.
Nice to meet you.
I'm trying to accomplish the same today. Look at this solution:
killThreads=False
thisThread=threading.Thread(target=oneThread)
otherThread=threading.Thread(target=twoThread)
thisThread.setDaemon(True)
otherThread.setDaemon(True)
thisThread.start()
otherThread.start()
raw_input('Press "q" to end the program')
key = ''
while key != ord('q'):
key = screen.getch()
killThreads=True
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
See, while will looping very fastly and waiting for q button be pressed, before switch your var killThreads to True.
It is pretty common practice. However, this while loop making thousands of idle loops in second, may be there can be more elegant way or better to embed into this while loop time.sleep(0.1) at least.

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.

How can a Python function be called on script exit reliably?

How do you register a function with all the correct handlers etc to be called when the Python script is exitted (successfully or not)?
I have tried:
#atexit.register
def finalise():
'''
Function handles program close
'''
print("Tidying up...")
...
print("Closing")
...but this does not get called when the user closes the command prompt window for example (because #atexit.register decorated functions do not get called when the exitcode is non zero)
I am looking for a way of guaranteeing finalise() is called on program exit, regardless of errors.
For context, my Python program is a continually looping service program that aims to run all the time.
Thanks in advance
I don't think it can be done in pure Python. From documentation:
Note: the functions registered via this module are not called when the
program is killed by a signal not handled by Python, when a Python
fatal internal error is detected, or when os._exit() is called.
I think you may find this useful: How to capture a command prompt window close event in python
Have you tried to just catch all kinds of exceptions in your main function or code block?
For context, my Python program is a continually looping service program that aims to run all the time.
This is very hard to get right (see How do you create a daemon in Python?). You should use a library like http://pypi.python.org/pypi/python-daemon/ instead.
This one should work
works both on Ctrl-C and when the assertion fails. Maybe you can use a similar construct and pack it as a decorator, or whatever.
def main():
print raw_input('> ')
# do all your stuff here
if __name__ == '__main__':
try:
main()
finally:
print 'Bye!'
atexit.register(func)
func = lambda x: x
Use http://docs.python.org/2/library/atexit.html

Python: How to quit CLI when stuck in blocking raw_input?

I have a GUI program which should also be controllable via CLI (for monitoring). The CLI is implemented in a while loop using raw_input.
If I quit the program via a GUI close button, it hangs in raw_input and does not quit until it gets an input.
How can I immediately abort raw_input without entering an input?
I run it on WinXP but I want it to be platform independent, it should also work within Eclipse since it is a developer tool. Python version is 2.6.
I searched stackoverflow for hours and I know there are many answers to that topic, but is there really no platform independent solution to have a non-blocking CLI reader?
If not, what would be the best way to overcome this problem?
Thanks
That's not maybe the best solution but you could use the thread module which has a function thread.interrupt_main(). So can run two thread : one with your raw_input method and one which can give the interruption signal. The upper level thread raise a KeyboardInterrupt exception.
import thread
import time
def main():
try:
m = thread.start_new_thread(killable_input, tuple())
while 1:
time.sleep(0.1)
except KeyboardInterrupt:
print "exception"
def killable_input():
w = thread.start_new_thread(normal_input, tuple())
i = thread.start_new_thread(wait_sometime, tuple())
def normal_input():
s = raw_input("input:")
def wait_sometime():
time.sleep(4) # or any other condition to kill the thread
print "too slow, killing imput"
thread.interrupt_main()
if __name__ == '__main__':
main()
Depending on what GUI toolkit you're using, find a way to hook up an event listener to the close window action and make it call win32api.TerminateProcess(-1, 0).
For reference, on Linux calling sys.exit() works.

Categories