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

Kyle Altendorf sda at fstab.net
Wed Aug 7 18:06:58 BST 2019



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.

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

Cheers,
-kyle


More information about the PyQt mailing list