python-qt-tools / PyQt5-stubs

Stubs for PyQt5
GNU General Public License v3.0
66 stars 31 forks source link

Set properties using keyword arguments in constructor #147

Open ThePhilgrim opened 3 years ago

ThePhilgrim commented 3 years ago

"self.scroll_area = QtWidgets.QScrollArea(widgetResizable=True)"

generates following error message:

error: Unexpected keyword argument "widgetResizable" for "QScrollArea"

altendky commented 3 years ago

Well this is fun. So, I agree that it works at run time and therefor should work when type checking.

https://replit.com/@altendky/OldfashionedRemoteComputergames-2

from PyQt5 import QtCore
from PyQt5 import QtWidgets

print(QtCore.PYQT_VERSION_STR)

application = QtWidgets.QApplication([])
scroll_area_1 = QtWidgets.QScrollArea(widgetResizable=False)
scroll_area_2 = QtWidgets.QScrollArea(widgetResizable=True)
print(scroll_area_1.widgetResizable())
print(scroll_area_2.widgetResizable())
5.15.4
False
True

But... it isn't documented for Qt itself.

https://doc.qt.io/qt-5/qscrollarea.html

Anyways, we're for accuracy so I'll plan on putting together a PR.

BryceBeagle commented 3 years ago

This is a feature of PyQt that's gonna be a pain to support:

PyQt5 does not support the setting and getting of Qt properties as if they were normal instance attributes. This is because the name of a property often conflicts with the name of the property’s getter method.

However, PyQt5 does support the initial setting of properties using keyword arguments passed when an instance is created. For example:

act = QAction("&Save", self, shortcut=QKeySequence.Save,
              statusTip="Save the document to disk", triggered=self.save)

So every single widget's constructor supports kwargs for every single one of their Qt Properties

altendky commented 3 years ago

yay...

ThePhilgrim commented 3 years ago

"self.dialog_groupbox = QtWidgets.QGroupBox(objectName="job_post_box")"

gives me:

"error: No overload variant of "QGroupBox" matches argument type "str" note: Possible overload variants: note: def QGroupBox(self, parent: Optional[QWidget] = ...) -> QGroupBox note: def QGroupBox(self, title: str, parent: Optional[QWidget] = ...) -> QGroupBox"

Should this be considered the same issue, or do you want me to create a separate issue?

altendky commented 3 years ago

Since @BryceBeagle identified this as a systemic issue, I'm not going to be tackling them all. If you want to add them, just direct PRs would suffice. No need for tickets first.

BryceBeagle commented 3 years ago

Well here's a way to get all the Qt Properties of an object:

from PyQt5.QtWidgets import QScrollArea, QApplication

app = QApplication([])

meta = QScrollArea().metaObject()

for prop_idx in range(meta.propertyCount()):
    prop = meta.property(prop_idx)
    print(prop.name(), prop.typeName())
objectName QString
modal bool
windowModality Qt::WindowModality
enabled bool
geometry QRect
frameGeometry QRect
normalGeometry QRect
x int
y int
pos QPoint
frameSize QSize
size QSize
width int
height int
rect QRect
childrenRect QRect
childrenRegion QRegion
sizePolicy QSizePolicy
minimumSize QSize
maximumSize QSize
minimumWidth int
minimumHeight int
maximumWidth int
maximumHeight int
sizeIncrement QSize
baseSize QSize
palette QPalette
font QFont
cursor QCursor
mouseTracking bool
tabletTracking bool
isActiveWindow bool
focusPolicy Qt::FocusPolicy
focus bool
contextMenuPolicy Qt::ContextMenuPolicy
updatesEnabled bool
visible bool
minimized bool
maximized bool
fullScreen bool
sizeHint QSize
minimumSizeHint QSize
acceptDrops bool
windowTitle QString
windowIcon QIcon
windowIconText QString
windowOpacity double
windowModified bool
toolTip QString
toolTipDuration int
statusTip QString
whatsThis QString
accessibleName QString
accessibleDescription QString
layoutDirection Qt::LayoutDirection
autoFillBackground bool
styleSheet QString
locale QLocale
windowFilePath QString
inputMethodHints Qt::InputMethodHints
frameShape Shape
frameShadow Shadow
lineWidth int
midLineWidth int
frameWidth int
frameRect QRect
verticalScrollBarPolicy Qt::ScrollBarPolicy
horizontalScrollBarPolicy Qt::ScrollBarPolicy
sizeAdjustPolicy SizeAdjustPolicy
widgetResizable bool
alignment Qt::Alignment

An absolute massive amount of properties. Not sure if we want to support all this, but if we do I'm thinking we could script this operation somehow.

Unfortunately, this snippet here requires knowing how to properly instantiate the QObject so that we can get the QMetaObject

BryceBeagle commented 3 years ago

Something interesting I noticed is that some properties (e.g x and y) are read-only (prop.isReadable() == True and prop.isWritable() == False), but PyQt still lets me use them as arguments in the constructor. Doing so does not seem to change their actual values post-construction.

altendky commented 3 years ago

*uuughHGHGHGHGHH*

I tend to think our focus should be on Qt6 and maybe trying to get Phil fixing whatever issues we find rather than developing our own modifier or generator. But who knows what will really work out...

BryceBeagle commented 3 years ago

I agree, this should probably be something to get Phil to implement upstream. Unfortunately, I haven't had the best experience using the mailing list in the past... I have been unable to properly reply to a thread without also turning off the email digests... :neutral_face:

altendky commented 3 years ago

It's not like it's a high traffic maillist. Aren't half the digests a single message anyways? But, I can try again when we get to working with PyQt6. I didn't get far with 'there are lots of changes, take a look at the diff and the PRs and the changelog'. So I guess the next pass will be one by one sequential reports.

What do you think @BryceBeagle and @The-Compiler, should we leave this as 'will accept PRs but presently no plan to fully implement'?

The-Compiler commented 3 years ago

What do you think @BryceBeagle and @The-Compiler, should we leave this as 'will accept PRs but presently no plan to fully implement'?

My stance is still that we should strive to automate those fixes rather than doing them manually - but then again I haven't been contributing much, so it's not like I have much of a say :slightly_smiling_face:

altendky commented 3 years ago

Is there a reason to not be fixing SIP/PyQt? Is it a bad system? Too much hassle to go through the half-open-source development path? Or, maybe you include fixing upstream generation in 'automate those fixes'.

Also, my statement was 'we are not prioritizing automating them and also will not be manually doing them en-masse'. Which I think is somewhat just a different perspective on what you wrote. :]

bluebird75 commented 2 years ago

An alternative approach to find all the properties of an object is to parse Qt documentation. This can be automated.

bluebird75 commented 2 years ago

This issue was incorrectly closed.

We should strive to support setting all properties using the object constructor .

senyai commented 2 years ago

Can we have __init__(self, **kwargs:any)? Yes, it's incorrect because it defeats the purpose of type checking, but it's less incorrect (IMO) than blaming valid arguments.

bluebird75 commented 1 year ago

@senyai interesting suggestion but we would be validating incorrect code in this case. I prefer a long term correct solution, or patching as people report the problems.