Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. PySide6 Unsupported keyword on Grid Layout
QtWS25 Last Chance

PySide6 Unsupported keyword on Grid Layout

Scheduled Pinned Locked Moved Unsolved Qt for Python
pysideqt for pythonpython
9 Posts 3 Posters 456 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    edreis
    wrote on 14 Jan 2025, 20:48 last edited by
    #1

    Somehow this code gives AttributeError when using rowSpan and columnSpan keywords.

    import sys
    
    from PySide6.QtWidgets import QApplication, QGridLayout, QLabel, QWidget
    
    app = QApplication(sys.argv)
    window = QWidget()
    grid_layout = QGridLayout(window)
    
    
    widget = QLabel("Hello")
    grid_layout.addWidget(widget, 0, 0, rowSpan=1, columnSpan=1)
    
    window.show()
    
    app.exec()
    

    I have PySide6

    $ pip freeze | grep PySide                                                                               
    PySide6==6.8.1.1
    PySide6_Addons==6.8.1.1
    PySide6_Essentials==6.8.1.1
    

    This is the error message.

    $ /bin/python grid_layout_problem.py
    Traceback (most recent call last):
      File "<................>/grid_layout_problem.py", line 19, in <module>
        grid_layout.addWidget(widget, 0, 0, rowSpan=1, columnSpan=1)
    AttributeError: PySide6.QtWidgets.QGridLayout.addWidget(): unsupported keyword 'rowSpan'
    
    1 Reply Last reply
    0
    • F Offline
      F Offline
      friedemannkleint
      wrote on 15 Jan 2025, 08:08 last edited by
      #2

      There are 2 overloads; the function does not have default parameters (and thus no named parameters):

      QGridLayout::addWidget(QWidget*,int,int,QFlags<Qt::AlignmentFlag>=)
      QGridLayout::addWidget(QWidget*,int,int,int,int,QFlags<Qt::AlignmentFlag>=)
      
      J 1 Reply Last reply 15 Jan 2025, 10:21
      1
      • F friedemannkleint
        15 Jan 2025, 08:08

        There are 2 overloads; the function does not have default parameters (and thus no named parameters):

        QGridLayout::addWidget(QWidget*,int,int,QFlags<Qt::AlignmentFlag>=)
        QGridLayout::addWidget(QWidget*,int,int,int,int,QFlags<Qt::AlignmentFlag>=)
        
        J Offline
        J Offline
        JonB
        wrote on 15 Jan 2025, 10:21 last edited by JonB
        #3

        @friedemannkleint said in PySide6 Unsupported keyword on Grid Layout:

        the function does not have default parameters (and thus no named parameters)

        Hi @friedemannkleint. I always respect your replies as you have shown you know what you are talking about. However, although you are correct that the solution here is for the OP to use positional parameters like addWidget(0, 0, 1, 1), I believe your explanation is not correct here.

        Python allows named parameters not only for optional ones but also for mandatory ones if the coder desires. The only requirements being that any named parameters come after any positional ones and that the name be correct. Within this coder can mix in named parameters and/or positional parameters as they please, regardless of default parameters or not.

        When I look (in PyCharm) at the declaration of QGridLayout.addWidget() method it gives me

            @overload
            def addWidget(self, arg__1: PySide6.QtWidgets.QWidget, row: int, column: int, rowSpan: int, columnSpan: int, alignment: PySide6.QtCore.Qt.AlignmentFlag = ...) -> None: ...
        

        Therefore in principle the OP should be able to use ..., rowSpan=1, columnSpan=1).

        To test this I introduce into the OP's code the following:

        def addWidget(arg__1: QtWidgets.QWidget, row: int, column: int, rowSpan: int, columnSpan: int,
                      alignment: QtCore.Qt.AlignmentFlag = ...) -> None:
            pass
        
        addWidget(widget, 0, 0, rowSpan=1, columnSpan=1, alignment=QtCore.Qt.AlignmentFlag.AlignLeft)
        

        That is a "global" addWidget() function just to test. And this works without error. (You may remove the final truly optional alignment=..., it makes no difference.) So why not in the OP's case?

        If I try the OP's code under PyQt6 I get the same 'rowSpan' is not a valid keyword argument error but a bit more information about what is going on:

        Traceback (most recent call last):
          File "/home/jon/QtTests/PyQt/namedparams/namedparams.py", line 14, in <module>
            grid_layout.addWidget(widget, 0, 0, rowSpan=1, colSpan=1, alignment=QtCore.Qt.AlignmentFlag.AlignLeft)
        TypeError: arguments did not match any overloaded call:
          addWidget(self, w: Optional[QWidget]): too many arguments
          addWidget(self, a0: Optional[QWidget], row: int, column: int, alignment: Qt.AlignmentFlag = Qt.Alignment()): 'rowSpan' is not a valid keyword argument
          addWidget(self, a0: Optional[QWidget], row: int, column: int, rowSpan: int, columnSpan: int, alignment: Qt.AlignmentFlag = Qt.Alignment()): 'rowSpan' is not a valid keyword argument
        

        Python is having trouble matching the call to any overloaded definition.

        I don't know exactly what or why, but I think the problem with using the keywords here --- which would normally work --- is because of QGridLayout.addWidget() being an @overload, and the implementation of that (which involves something about rewriting the function declaration/definition each time it meets @overload) causing it to be unable to find a correct match when a named (perhaps non-default?) parameter is used, confusing/changing its look up rules in this case?

        I am unable to track down the exact rules when mixing overloads and named parameters in Python. However I note that, say, Mixing function overloading and named parameters opens with:

        What are the problems that occur when a language allows both function overloading and named parameters? Most languages seem to only support one or the other.

        Overload resolution definitely becomes harder

        It's not always problematic in Python. For example, the OP uses widget = QLabel("Hello") which matches

            @overload
            def __init__(self, text: str, parent: Optional[PySide6.QtWidgets.QWidget] = ..., f: PySide6.QtCore.Qt.WindowType = ...) -> None: ...
        

        But here I am also able to write QLabel(text="Hello") if I wish and this does work. So sometimes a named parameter does work with @overload and sometimes not. I don't know why this is the case but not for QGridLayout.addWidget(), I can only guess it's to do with the various different overloads?

        I wonder if it's to do with the following: I believe Python implements @overload by type of the parameters being different to pick which one to call. I wonder/think it might do this by changing the names of the parameters to include a "type-specifier", at least in the case where there are alternative overloads? I wonder whether the rowSpan/columnSpan parameter names might have been altered in this way and so no longer match the plain word? I do not have time to investigate this at the moment, but may return to it later.....

        I am always interested in learning if you know better/more specifically than this?

        1 Reply Last reply
        0
        • F Offline
          F Offline
          friedemannkleint
          wrote on 15 Jan 2025, 14:11 last edited by
          #4

          It is simply a restriction of shiboken that it does not generate code for named parameters unless the argument has default values (see PYSIDE-1964 ).

          J 1 Reply Last reply 15 Jan 2025, 14:15
          1
          • F friedemannkleint
            15 Jan 2025, 14:11

            It is simply a restriction of shiboken that it does not generate code for named parameters unless the argument has default values (see PYSIDE-1964 ).

            J Offline
            J Offline
            JonB
            wrote on 15 Jan 2025, 14:15 last edited by JonB
            #5

            @friedemannkleint
            That is a very brief answer. Could you explain in that case why I find QLabel(text="Hello") does work if Shiboken "does not generate code for named parameters unless the argument has default values"? init(text[, parent=None[, f=Qt.WindowFlags()]]) does not have text taking any default value. Thanks.

            Also, glancing at the bug stuff, why does

            from PySide6.QtCore import QRect
            print(QRect(left=1,top=2,width=3,height=4))
            

            print a QRect with 0 size instead of erroring with OP's unsupported keyword 'left'?

            'Coz it looks like I spent a long time playing with this when I didn't need to... :( ;-)

            1 Reply Last reply
            0
            • F Offline
              F Offline
              friedemannkleint
              wrote on 15 Jan 2025, 15:29 last edited by
              #6

              What probably kicks in here is the ability to pass property=value pairs to the QObject-constructors. About the QRect, I don't know.

              J 1 Reply Last reply 15 Jan 2025, 15:39
              1
              • F friedemannkleint
                15 Jan 2025, 15:29

                What probably kicks in here is the ability to pass property=value pairs to the QObject-constructors. About the QRect, I don't know.

                J Offline
                J Offline
                JonB
                wrote on 15 Jan 2025, 15:39 last edited by JonB
                #7

                @friedemannkleint
                Hi, yes, I was just coming to the same conclusion on this one! See e.g. https://stackoverflow.com/a/73285686/489865

                Qtw.QMessageBox(text="Foo")
                text() is a valid Qt property of QMessageBox;

                QObject properties

                Almost all QObjects accept named arguments that correspond to the object's properties, even if they're not declared in the constructor's definition.

                For instance, all QWidgets support the enabled property, meaning that you can do the following:

                button = QPushButton(enabled=False)

                So if a QObject has a property you can use its name as propname=value and that is not to do with the parameters to the constructor here.

                In effect QLabel(text="Hello") is not calling the constructor overload which accepts text as its first argument, it's calling the constructor which takes no parameter explicitly and than "augmenting" it by an assignment to property named text instead.

                It also says there

                The OP isn't really confused here, because, in Python terms, calling QMessageBox(text="Foo", title="Bar") would normally be entirely correct. The real problem is that the bindings cannot fully resolve all the differences between the Python and C++ call syntaxes, so various work-arounds must be used (such as keyword support for object properties)

                My goodness it's complicated! I now have to accept your "restriction of shiboken that it does not generate code for named parameters unless the argument has default values" :) May I ask, I see you contributing on the bug forum, are you a Qt [Company] developer/contributor or just a punter like myself? If I had realised you were TQtC I probably would not have queried your reply further! Thanks.

                1 Reply Last reply
                0
                • F Offline
                  F Offline
                  friedemannkleint
                  wrote on 15 Jan 2025, 20:14 last edited by
                  #8

                  I am actually working on Qt for Python for the Qt Company ;-)

                  1 Reply Last reply
                  1
                  • J Offline
                    J Offline
                    JonB
                    wrote on 15 Jan 2025, 22:42 last edited by
                    #9

                    Well it's nice to know it's in good hands :)

                    1 Reply Last reply
                    0

                    5/9

                    15 Jan 2025, 14:15

                    • Login

                    • Login or register to search.
                    5 out of 9
                    • First post
                      5/9
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved