while working on a library for raising exceptions in the context of another thread, i've come across a bug in PyThreadState_SetAsyncExc. if i raise an instance, sys.exc_info() confuses the exception value for the exception type, and the exception value is set None. if i raise the type itself, the interpreter creates an instance internally, but then i can't pass arguments to the exception.
code: ===================================== import threading import ctypes def _async_raise(tid, excobj): res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj)) if res == 0: raise ValueError("nonexistent thread id") elif res > 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") class Thread(threading.Thread): def raise_exc(self, excobj): assert self.isAlive(), "thread must be started" for tid, tobj in threading._active.items(): if tobj is self: _async_raise(tid, excobj) break # the thread was alive when we entered the loop, but was not found # in the dict, hence it must have been already terminated. should we raise # an exception here? silently ignore? def terminate(self): self.raise_exc(SystemExit()) if __name__ == "__main__": import time import sys i_am_active = False def f(): global i_am_active i_am_active = True try: try: while True: time.sleep(0.01) except IOError, ex: print "IOError handler" except TypeError, ex: print "TypeError handler" print "ex=", repr(ex) typ, val, tb = sys.exc_info() print "typ=", repr(typ) print "val=", repr(val) print "tb=", tb finally: i_am_active = False t1 = Thread(target = f) t1.start() time.sleep(1) t1.raise_exc(TypeError("blah blah")) while i_am_active: time.sleep(0.01) print "!! thread terminated" output: ===================================== TypeError handler ex= None typ= <exceptions.TypeError instance at 0x00C15D28> # should be the type val= None # should be the instance tb= <traceback object at 0x00C159E0> !! thread terminated if i change: t1.raise_exc(TypeError("blah blah")) to: t1.raise_exc(TypeError) i get: ===================================== TypeError handler ex= <exceptions.TypeError instance at 0x00C159B8> typ= <class exceptions.TypeError at 0x00B945A0> val= <exceptions.TypeError instance at 0x00C159B8> tb= <traceback object at 0x00C15D00> !! thread terminated but then of course i can't pass arguments to the exception -tomer _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com