[PyQt] New exception in Python 3.7.4 when bad code tries to PyQt5.uic.loadUi()

Phil Thompson phil at riverbankcomputing.com
Wed Aug 7 18:50:17 BST 2019


On 07/08/2019 18:06, Kyle Altendorf wrote:
> On 2019-08-07 12:50, Phil Thompson wrote:
>> On 07/08/2019 16:54, Kyle Altendorf wrote:
>>> On 2019-08-07 07:13, Phil Thompson wrote:
>>>> On 05/08/2019 18:25, Kyle Altendorf wrote:
>>>>> On 2019-08-03 14:38, Kyle Altendorf wrote:
>>>>>> I have many custom widgets with pyqtProperty's and GUI elements 
>>>>>> loaded
>>>>>> from .ui files.  In various ways, my existing code tries to access
>>>>>> not-yet-present attributes in pyqtProperty's while the .ui is 
>>>>>> being
>>>>>> loaded.  This is obviously bad and I plan to fix my code.  I share
>>>>>> this example because I already finished it and because this is an 
>>>>>> odd
>>>>>> change of behavior from a micro version bump of Python.  Also, it 
>>>>>> is
>>>>>> odd that each first time my code raises an exception there is not
>>>>>> necessarily a Qt failure.  For example, WidgetB must be 
>>>>>> constructed
>>>>>> twice to get the traceback.  I understand that this may well not 
>>>>>> get
>>>>>> 'fixed' since it probably never should have worked to begin with.
>>>>>> 
>>>>>> Code and output from 3.7.3/3.7.4 on Linux/Windows are attached and
>>>>>> also available at:
>>>>>>     
>>>>>> https://gist.github.com/altendky/f15f8d180269a4080c25dec83cf556a0
>>>>>> 
>>>>>> Here is the basic traceback:
>>>>>> 
>>>>>>     AttributeError: __getattribute__
>>>>>> 
>>>>>>     The above exception was the direct cause of the following 
>>>>>> exception:
>>>>>> 
>>>>>>     Traceback (most recent call last):
>>>>>>       File "bad.py", line 146, in main
>>>>>>         widgets.append(WidgetA(broken=True))
>>>>>>       File "bad.py", line 53, in __init__
>>>>>>         PyQt5.uic.loadUi(io.StringIO(ui_text), self)
>>>>>>       File
>>>>>> "C:\epc\bug\venv3.7-32\lib\site-packages\PyQt5\uic\__init__.py", 
>>>>>> line
>>>>>> 227, in loadUi
>>>>>>         return DynamicUILoader(package).loadUi(uifile, 
>>>>>> baseinstance,
>>>>>> resource_suffix)
>>>>>>       File
>>>>>> "C:\epc\bug\venv3.7-32\lib\site-packages\PyQt5\uic\Loader\loader.py",
>>>>>> line 72, in loadUi
>>>>>>         return self.parse(filename, resource_suffix, basedir)
>>>>>>       File
>>>>>> "C:\epc\bug\venv3.7-32\lib\site-packages\PyQt5\uic\uiparser.py", 
>>>>>> line
>>>>>> 1030, in parse
>>>>>>         actor(elem)
>>>>>>       File
>>>>>> "C:\epc\bug\venv3.7-32\lib\site-packages\PyQt5\uic\uiparser.py", 
>>>>>> line
>>>>>> 942, in createConnections
>>>>>>         QtCore.QMetaObject.connectSlotsByName(self.toplevelWidget)
>>>>>>     SystemError: <built-in function connectSlotsByName> returned a
>>>>>> result with an error set
>>>>> 
>>>>> I read briefly about this SystemError and it seems that while yes, 
>>>>> my
>>>>> code was raising an exception and shouldn't really have worked 
>>>>> ever...
>>>>>  this error indicates that connectSlotsByName() isn't properly
>>>>> propagating the exception and is instead returning a value as if no
>>>>> exception occurred.  As such it seems that there is an error in the
>>>>> PyQt connectSlotsByName() wrapper in addition to my code.  Though I
>>>>> admittedly don't know my way around SIP nor the C-API much.
>>>> 
>>>> It could also be that an exception is being correctly ignored, but 
>>>> not
>>>> cleared with PyErr_Clear().
>>> 
>>> Why would it be correct to ignore my code raising an exception?  It
>>> seems bad that my code has been seemingly silently raising these
>>> exceptions for a few years and I was unaware of it.  I guess it could
>>> be argued that it would be handy for PyQt to add an exception 
>>> ignoring
>>> feature and let connectSlotsByName() continue with it's work despite
>>> Python code failing.  But this isn't the direction I would personally
>>> default.  Mostly unhandled exceptions should be seen I would think.
>> 
>> I wasn't referring to your code but to the implementation of
>> connectSlotsByName().
> 
> That's what I was responding to.  It doesn't seem like
> connectSlotsByName() should be silencing exceptions raised by my code
> that it calls.  Or maybe something else is calling my code and this is
> just a delayed error.  Regardless, I would think that if my code
> raises an exception the default behavior ought to be to fail and show
> that error, not continue silently.  I know my code is bad in this
> regard and neither before nor at Python 3.7.4 is there a message about
> the exception my code raises.

As I said, I wasn’t referring to exceptions raised by your code.

> Anyways, I think we may have agreed that something somewhere, other
> than my code raising an exception, isn't quite right?

Yes (although I don’t get a traceback with v3.8).

Phil



More information about the PyQt mailing list