Python function call not runing correcly from thread - python

I'm having some trouble getting this to work, i'm trying to append GUI texts to a window that allready exists, i'm using the python interpreter for autodesk maya, i attach here part of the host script where i check for multiple connections and try to add the text for each connection.
The problem comes when calling the interpHostData() function from inside the while loop inside the thread, it dosnt add anything to the window;
But whenever i call the function by itself outside of a thread it works correctly.
If anyone has a clue on how can i fix this i would apreciate it, thanks in advance.
def hostUpdate():
global socketHost
global clientL
clientL=[]
cmds.text('mt1',e=1,l='Update Process Started...')
while 1:
connectionMain,addressMain=socketHost.accept()
cmds.text('mt1',e=1,l='Connected with: %s'%str(addressMain))
#----------Different Thread for each connection
tid=thr.start_new_thread(hostRecieve,(connectionMain,addressMain))
clientL.append([connectionMain,addressMain,tid])
cmds.text('mt1',e=1,l='Thread started with: %s'%str(addressMain))
def hostRecieve(connI,addrI):
global clientL
cmds.text('mt1',e=1,l='Recieve Process Started...')
while 1: #------------------------------------Loop to keep listening for connections
try:
cmData=connI.recv(4096)
interpHostData(cmData) #--------------IF I CALL FROM HERE DOSN'T WORK
except:
for cl in clientL:
if connI==cl[0]:
clientL.remove(cl)
cmds.text('mt1',e=1,l='Disconnected from %s'%str(addrI))
break
def interpHostData(cmDataC):
global cliLayout
tplD=cmDataC.split(',')
if tplD[0]=='0':
cID=tplD[2]
cmds.setParent(cliLayout)
cmds.text(cID+'_1',l=tplD[1])
cmds.text(cID+'_2',l=tplD[3])
cmds.text(cID+'_3',l=tplD[4])
cmds.text(cID+'_4',l='_')
cmds.text(cID+'_5',l='_')
cmds.text(cID+'_6',l='_')
cmds.text(cID+'_7',l='_')
cmds.text(cID+'_8',l='_')
cmds.columnLayout(cID+'_9')
cmds.progressBar(cID+'_10',h=10)
cmds.progressBar(cID+'_11',h=10)
cmds.setParent(cliLayout)
cmds.text(cID+'_12',l='_')
cmds.text(cID+'_13',l='Online')

You can only run Maya ui commands from the main thread. You can use maya.util.ExcecuteDeferred() to get around this to some degree but it takes extra work and won't be as responsive as a true multi-threaded app. Longer explanation in this question

Related

Block python's atexit during a crash?

I have a python script I've written which uses atexit.register() to run a function to persist a list of dictionaries when the program exits. However, this code is also running when the script exits due to a crash or runtime error. Usually, this results in the data becoming corrupted.
Is there any way to block it from running when the program exits abnormally?
EDIT: To clarify, this involves a program using flask, and I'm trying to prevent the data persistence code from running on an exit that results from an error being raised.
You don't want to use atexit with Flask. You want to use Flask signals. It sounds like you are specifically looking for the request_finished signal.
from flask import request_finished
def request_finished_handler(sender, response, **extra):
sender.logger.debug('Request context is about to close down. '
'Response: %s', response)
# do some fancy storage stuff.
request_finished.connect(request_finished_handler, app)
The benefit of request_finished is that it only fires after a successful response. That means that so long as there isn't an error in another signal, you should be good.
One way: at global level in main program:
abormal_termination = False
def your_cleanup_function():
# Add next two lines at the top
if abnormal_termination:
return
# ...
# At end of main program:
try:
# your original code goes here
except Exception: # replace according to what *you* consider "abnormal"
abnormal_termination = True # stop atexit handler
Not pretty, but straightforward ;-)

client not receiving data via TCP socket

I have started network programming using Python and am working on a basic peer-to-peer chat client-server application. I got it working for console, but am facing problem while developing a GUI.
This is the code for my client script. It is sending data to the server but is unable to receive /display the data sent from server, I am at a loss. Please show the error in my code and the solution.
from socket import *
from tkinter import *
host="127.0.0.1"
port=1420
buffer=1024
server=(host,port)
clientsock=socket(AF_INET,SOCK_STREAM)
clientsock.connect(server)
class ipbcc(Frame):
def __init__(self,master):
Frame.__init__(self,master)
self.grid()
self.create()
self.connect()
def write(self,event):
msg=self.e.get()
clientsock.send(msg.encode())
def create(self):
self.pic=PhotoImage(file="logo.gif")
self.label=Label(self,image=self.pic)
self.label.grid(column=0)
self.wall=Text(self,width=70,height=20,wrap=WORD)
self.wall.grid(row = 0, column = 1, columnspan = 2, sticky = W)
self.e=Entry(self,width=50)
self.e.grid(row = 1, column = 1, sticky = W)
self.e.bind('<Return>',self.write)
def add(self,data):
self.wall.insert(END,data)
def connect(self):
def xloop():
while 1:
data=clientsock.recv(buffer).decode()
print(data)
self.add(data)
root=Tk()
root.title("IPBCC v0.1")
app=ipbcc(root)
root.mainloop()
PS: Python Version 3.3 and there is no problem in the server script.
Your connect function defines a function called xloop, but it doesn't call that function, or return it, or store it somewhere for anyone else to call it. You need to call that function for it to do anything.
Of course if you just call it directly inline, it will run forever, meaning you never get back to the event loop, and the UI freezes up and stops responding to the user.
There are two options for this: threading, or polling.
The obvious way to do this is with a background thread. The basic idea is very simple:
def connect(self):
def xloop():
while 1:
data=clientsock.recv(buffer).decode()
print(data)
self.add(data)
self.t = threading.Thread(target=xloop)
self.t.start()
However, there are two problems with this.
First, there's no way to stop the background thread. When you try to exit the program, it will wait for the background thread to stop—which means it will wait forever.
There's an easy solution to that one: if you make it a "daemon thread", it will be summarily killed when the main program exits. This is obviously no good for threads that are doing work that could be corrupted if interrupted in the middle, but in your case that doesn't seem to be a problem. So, just change one line:
self.t = threading.Thread(target=xloop, daemon=True)
Second, that self.add method needs to modify a Tkinter widget. You can't do that from a background thread. Depending on your platform, it may fail silently, raise an exception, or even crash—or, worse, it may work 99% of the time and fail 1%.
So, you need some way to send a message to the main thread, asking it to do the widget modification for you. This is a bit complicated, but Tkinter and Threads explains how to do it.
Alternatively, you could use mtTkinter, which intercepts Tkinter calls in background threads and passes them to the main thread automatically, so you don't have to worry about it.
The other option is to change the blocking xloop function into a nonblocking function that polls for data. The problem is that you want to wait on Tkinter GUI events, but you also want to wait on the socket.
If you could integrate the socket into the main event loop, that would be easy: a new message coming in would be handled just like any other event. Some of the more powerful GUI frameworks like Qt give you ways to do this, but Tkinter does not. A reactor framework like Twisted can tie itself into Tkinter and add it for you (or at least fake nicely). But if you want to stick with your basic design, you have to do it yourself.
So, there are two options:
Give Tkinter full control. Ask it to call your function every, say, 1/20th of a second, and in the function do a non-blocking check. Or maybe loop around non-blocking checks until there's nothing left to read.
Give the socket control. Ask Tkinter to call your function every time it gets a chance, and block for 1/20th of a second checking for data before returning to Tkinter.
Of course 1/20th of a second may not be the right length—for many applications, no answer is really correct. Anyway, here's a simple example:
def poll_socket(self):
r, w, x = select.select([clientsock], [], [], 0)
if r:
data=clientsock.recv(buffer).decode()
print(data)
self.add(data)
self.after(50, self.poll_socket)
def connect(self):
self.after(50, self.poll_socket)
You define xloop, however you never actually call it as far as I can see.
I would suggest you look into using threads - the threading module in the standard library would be one way to go. Then, in your code you will be able to create a thread running the xloop function, without stopping the rest of your code. Alternatively, you could remove the loop from xloop (or indeed just put the code in the function into the connect function) and call it periodically, using widget.after(milliseconds, a_function)
I'd also like to mention that from amodule import * is considered bad practice (although tkinter is one of the exceptions to this rule).
It might help to follow the flow. The "app=ipbcc(root)" step would call "self.connect()" and that has a "def xloop():" that has the step "data=clientsock.recv". But, then somebody needs to invoke xloop(). Who does that? Btw, why do have a function inside a method?
Also, I don't see anybody invoking the "clientsock.send(msg.encode())" via the write() method. I am not familiar with the Tinker part (and what the mainloop() does), so can you please check if there are callers to send() and the recv() call.

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

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