[prev in list] [next in list] [prev in thread] [next in thread]
List: pykde
Subject: Re: [PyQt] Conflict between setuptools & requirements in official PyQt5 docs
From: "Jones, Bryan" <bjones () ece ! msstate ! edu>
Date: 2016-02-12 18:00:31
Message-ID: CAHhYbD_iNsxUgitPxQ6V1iFOzJsvL0SJE6tQax8+X0SaDa6Bvg () mail ! gmail ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
Phil,
I'm always impressed with you quick turnaround. Thanks for the fix!
Bryan
On Wed, Feb 10, 2016 at 4:38 PM, Phil Thompson <phil@riverbankcomputing.com>
wrote:
>
> > On 10 Feb 2016, at 8:57 pm, Jones, Bryan <bjones@ece.msstate.edu> wrote:
> >
> > Thanks for the feedback. The first two crashes (quickCrash and
> slowCrash) were, as you say, fairly obvious programmer errors. It would be
> nice if this would emit some sort of error ("QApplication destroyed;
> terminating application") with a backtrace.
> >
> > The third case is more interesting -- the cause is more subtle and more
> likely (IMHO) to occur in "real" code. Here's a second pass at it, with a
> bit of cleanup. It looks like I've created a cycle between the QWidget
> (whose destroyed signal refers to foo) and the function foo (which retains
> a reference to the QWidget). When Python breaks the cycle during its
> garbage collection, it finalizes the QWidget, which invokes foo, which
> causes a crash. The QApplication instance, however, is still valid and has
> not been either finalized (that is, Python's __del__) or destroyed (the C++
> destructor). Any thoughts?
> >
> > import sys
> > import os
> > import platform
> > import gc
> > import sip
> > from PyQt5.QtWidgets import QApplication, QWidget
> > from PyQt5.QtCore import QT_VERSION_STR
> > from PyQt5.Qt import PYQT_VERSION_STR
> >
> > app = None
> >
> > DEBUG = False
> >
> > if DEBUG:
> > def printDestroyed(qObject):
> > qObjectStr = str(qObject)
> > def destroyed():
> > print('destroyed {}'.format(qObjectStr))
> > qObject.destroyed.connect(destroyed)
> >
> > class QApplicationF(QApplication):
> > def __del__(self):
> > print('finalized {}'.format(self))
> >
> > class QWidgetF(QWidget):
> > def __del__(self):
> > print('finalized {}'.format(self))
> >
> > def checkLeaks():
> > for o in gc.get_objects():
> > try:
> > if not sip.isdeleted(o):
> > sip.dump(o)
> > except TypeError:
> > pass
> >
> > else:
> > def printDestroyed(_): pass
> > QApplicationF = QApplication
> > QWidgetF = QWidget
> > def checkLeaks(): pass
> >
> > def foo(x):
> > return lambda: x
> >
> > def qtMain(doCrash):
> > global app
> > app = QApplicationF(sys.argv)
> > printDestroyed(app)
> >
> > w = QWidgetF()
> > printDestroyed(w)
> >
> > param = w if doCrash else 1
> > w.destroyed.connect(foo(param))
> >
> > def gcCrash(createCycle, doCollect):
> > qtMain(createCycle)
> > checkLeaks()
> > gc.collect(doCollect)
> >
> > if __name__ == '__main__':
> > # Both must be True for a crash.
> > gcCrash(True, True)
>
> Attached is a patch (also in tonight's PyQt5 snapshot but you'll need a
> SIP snapshot as well) that will stop this particular crash.
>
> Note that as soon as you start using __del__ the behaviour of the garbage
> collector changes.
>
> Phil
>
>
--
Bryan A. Jones, Ph.D.
Associate Professor
Department of Electrical and Computer Engineering
231 Simrall / PO Box 9571
Mississippi State University
Mississippi state, MS 39762
http://www.ece.msstate.edu/~bjones
bjones AT ece DOT msstate DOT edu
voice 662-325-3149
fax 662-325-2298
Our Master, Jesus Christ, is on his way. He'll show up right on
time, his arrival guaranteed by the Blessed and Undisputed Ruler,
High King, High God.
- 1 Tim. 6:14b-15 (The Message)
[Attachment #5 (text/html)]
<div dir="ltr">Phil,<div><br></div><div>I'm always impressed with you quick \
turnaround. Thanks for the fix!</div><div><br></div><div>Bryan</div></div><div \
class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 10, 2016 at 4:38 PM, \
Phil Thompson <span dir="ltr"><<a href="mailto:phil@riverbankcomputing.com" \
target="_blank">phil@riverbankcomputing.com</a>></span> wrote:<br><blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"><div class="HOEnZb"><div class="h5"><br> > On 10 Feb 2016, \
at 8:57 pm, Jones, Bryan <<a \
href="mailto:bjones@ece.msstate.edu">bjones@ece.msstate.edu</a>> wrote:<br> \
><br> > Thanks for the feedback. The first two crashes (quickCrash and \
slowCrash) were, as you say, fairly obvious programmer errors. It would be nice if \
this would emit some sort of error ("QApplication destroyed; terminating \
application") with a backtrace.<br> ><br>
> The third case is more interesting -- the cause is more subtle and more likely \
(IMHO) to occur in "real" code. Here's a second pass at it, with a bit \
of cleanup. It looks like I've created a cycle between the QWidget (whose \
destroyed signal refers to foo) and the function foo (which retains a reference to \
the QWidget). When Python breaks the cycle during its garbage collection, it \
finalizes the QWidget, which invokes foo, which causes a crash. The QApplication \
instance, however, is still valid and has not been either finalized (that is, \
Python's __del__) or destroyed (the C++ destructor). Any thoughts?<br> ><br>
> import sys<br>
> import os<br>
> import platform<br>
> import gc<br>
> import sip<br>
> from PyQt5.QtWidgets import QApplication, QWidget<br>
> from PyQt5.QtCore import QT_VERSION_STR<br>
> from PyQt5.Qt import PYQT_VERSION_STR<br>
><br>
> app = None<br>
><br>
> DEBUG = False<br>
><br>
> if DEBUG:<br>
> def printDestroyed(qObject):<br>
> qObjectStr = str(qObject)<br>
> def destroyed():<br>
> print('destroyed {}'.format(qObjectStr))<br>
> qObject.destroyed.connect(destroyed)<br>
><br>
> class QApplicationF(QApplication):<br>
> def __del__(self):<br>
> print('finalized {}'.format(self))<br>
><br>
> class QWidgetF(QWidget):<br>
> def __del__(self):<br>
> print('finalized {}'.format(self))<br>
><br>
> def checkLeaks():<br>
> for o in gc.get_objects():<br>
> try:<br>
> if not sip.isdeleted(o):<br>
> sip.dump(o)<br>
> except TypeError:<br>
> pass<br>
><br>
> else:<br>
> def printDestroyed(_): pass<br>
> QApplicationF = QApplication<br>
> QWidgetF = QWidget<br>
> def checkLeaks(): pass<br>
><br>
> def foo(x):<br>
> return lambda: x<br>
><br>
> def qtMain(doCrash):<br>
> global app<br>
> app = QApplicationF(sys.argv)<br>
> printDestroyed(app)<br>
><br>
> w = QWidgetF()<br>
> printDestroyed(w)<br>
><br>
> param = w if doCrash else 1<br>
> w.destroyed.connect(foo(param))<br>
><br>
> def gcCrash(createCycle, doCollect):<br>
> qtMain(createCycle)<br>
> checkLeaks()<br>
> gc.collect(doCollect)<br>
><br>
> if __name__ == '__main__':<br>
> # Both must be True for a crash.<br>
> gcCrash(True, True)<br>
<br>
</div></div>Attached is a patch (also in tonight's PyQt5 snapshot but you'll \
need a SIP snapshot as well) that will stop this particular crash.<br> <br>
Note that as soon as you start using __del__ the behaviour of the garbage collector \
changes.<br> <span class="HOEnZb"><font color="#888888"><br>
Phil<br>
<br>
</font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br><div \
class="gmail_signature">Bryan A. Jones, Ph.D.<br>Associate Professor<br>Department of \
Electrical and Computer Engineering<br>231 Simrall / PO Box 9571<br>Mississippi State \
University<br>Mississippi state, MS 39762<br><a \
href="http://www.ece.msstate.edu/~bjones" \
target="_blank">http://www.ece.msstate.edu/~bjones</a><br>bjones AT ece DOT msstate \
DOT edu<br>voice 662-325-3149<br>fax 662-325-2298<br><br>Our Master, Jesus Christ, is \
on his way. He'll show up right on<br>time, his arrival guaranteed by the Blessed \
and Undisputed Ruler,<br>High King, High God.<br>- 1 Tim. 6:14b-15 (The \
Message)<br></div> </div>
[Attachment #6 (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