[prev in list] [next in list] [prev in thread] [next in thread]
List: pykde
Subject: Re: [PyQt] Any way to run code before each QThread?
From: John Ehresman <jpe () wingware ! com>
Date: 2018-07-16 15:03:51
Message-ID: 8942d158-6bf4-8840-2732-690a3095e859 () wingware ! com
[Download RAW message or body]
On 7/15/18 8:19 PM, Ned Batchelder wrote:
> How does Wing wrap the run method? How does it get a chance to do that?
Wing monkeypatches QThread to replace QThread.__init__ with it's own
callable after the QtCore module is loaded. Within the __init__
replacement, the .run method on the new instance is replaced by a
replacement run callable that calls settrace before calling the saved
run method. This is done because user code does override the run method
in subclasses of QThread and monkeypatching in __init__ captures the
overridden run method in most cases. I've attached a snippet of Wing's
code; it's an extract and won't run as is but hopefully it's helpful.
This is an ugly hack and there is code that it won't work for, but it
should work most of the time.
Cheers,
John
["qthreadhack.py" (text/x-python-script)]
import sys
import new
class CQThreadInitWrapper:
"""Used to wrap QThread.__init__ so we can debug QThreads"""
def __init__(self, orig_new_thread, settrace, err):
self.fOrigQThread = orig_new_thread
self.fSetTrace = settrace
self.fErr = err
def __call__(self, qthread, *args, **kw):
"""This is the wrapper for QThread.__init__. Calls the original
__init__ then sets up a wrapper around run()."""
self.fErr.out("CQThreadInitWrapper called")
if kw:
self.fOrigQThread(qthread, *args, **kw)
elif args:
self.fOrigQThread(qthread, *args)
else:
self.fOrigQThread(qthread)
self._fOrigRun = qthread.run
def run_wrapper(*args, **kw):
self.fSetTrace(dbgtracer.bootstrap_new_thread)
if kw:
self._fOrigRun(*args, **kw)
elif args:
self._fOrigRun(*args)
else:
self._fOrigRun()
dbgtracer.thread_exiting()
qthread.run = run_wrapper
# Since this callable class isn't a builtin function, __get__
# is needed to to allow it to be used for an instance method. See
# http://docs.python.org/3/howto/descriptor.html#functions-and-methods
# Note python3's types.MethodType only takes 2 args (the above page
# is incorrect as of Jan 21, 2014)
if sys.version_info >= (3, 0):
def __get__(self, obj, objtype=None):
"Simulate func_descr_get() in Objects/funcobject.c"
# Just return the callable if no instance; case when
# repr(QThread.__init__) is called. Calling MethodType w/ obj = None
# raises an exception
if obj is None:
return self
return types.MethodType(self, obj)
def __repr__(self):
return "<wing debugger wrapper for " + repr(self.fOrigQThread) + ">"
wrapper = CQThreadInitWrapper(QtCore.__init__, sys.settrace, err_stream)
if sys.version_info >= (3, 0):
QtCore.QThread.__init__ = wrapper
else:
QtCore.QThread.__init__ = new.instancemethod(wrapper, None, QtCore.QThread)
[Attachment #4 (text/plain)]
_______________________________________________
PyQt mailing list PyQt@riverbankcomputing.com
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic