Qt6 でハマった件

# はじめに
　PyQt6 を使っていて、少しハマったことがあったのでメモを残しておく。

　概要は以下。

 - ResizeToContents を設定している QHeaderView を使った QTableView で、アイテム数の少ないモデルに切り替えた際、_Out of range_ を起こす。

　もしかしたら私の使い方がおかしいのかもしれない……。

# 確認環境
OS: Windows 11 Home (22H2)
Shell: Git Bash (git version 2.41.0.windows.3)
Python: 3.10.6
PyQt: 6.5.2

# 確認用コード
　少し長いかもしれない。(約120行）

```python:test.py
# -*- coding: utf-8 -*-
import sys
from PyQt6 import QtCore, QtGui, QtWidgets


class _Model(QtCore.QAbstractTableModel):
    def __init__(self, items, headers, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._items = items
        self._headers = headers

    def rowCount(self, *a, **k):
        return len(self._items)

    def columnCount(self, *a, **k):
        return len(self._headers)

    def flags(self, index):
        return super().flags(index)

    def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole):
        if False:
            print('data', index.row(), index.column(),
                  role, self.roleNames().get(role, '<>'))

        if index.isValid():
            if role in (QtCore.Qt.ItemDataRole.DisplayRole,
                        QtCore.Qt.ItemDataRole.EditRole):
                return self._items[index.row()][index.column()]
        return None

    def headerData(self, section, orientation,
                   role=QtCore.Qt.ItemDataRole.DisplayRole):
        if orientation == QtCore.Qt.Orientation.Horizontal and \
           role == QtCore.Qt.ItemDataRole.DisplayRole:
            print('In headerData: ', section, 'of', len(self._headers))
            try:
                assert section < len(self._headers), \
                    'Not section(%d) < len(%d)' % (section, len(self._headers))
                return self._headers[section]
            except Exception as e:
                print(str(e))
                return '------'
        return super().headerData(section, orientation, role)


class _HHeader(QtWidgets.QHeaderView):
    def __init__(self, parent):
        super().__init__(QtCore.Qt.Orientation.Horizontal, parent)
        if True:
            self.setSectionResizeMode(
                QtWidgets.QHeaderView.ResizeMode.ResizeToContents)


class _Table(QtWidgets.QTableView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setHorizontalHeader(_HHeader(self))


class Main(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._setupUI()

        self.m1 = _Model(items=[['a', 'b', 'c'], ['a', 'b', 'c']],
                         headers=['#1', '#2', '#3'])
        self.m2 = _Model(items=[],
                         headers=[])

    def _setupUI(self):
        self.setWindowTitle("test")
        self.resize(600, 400)

        menubar = self.menuBar()
        filemenu = menubar.addMenu("テスト(&T)")

        act = QtGui.QAction("Model #1", self)
        act.triggered.connect(self.setModel1)
        filemenu.addAction(act)

        act = QtGui.QAction("Model #2a", self)
        act.triggered.connect(self.setModel2a)
        filemenu.addAction(act)

        act = QtGui.QAction("Model #2b", self)
        act.triggered.connect(self.setModel2b)
        filemenu.addAction(act)

        act = QtGui.QAction("閉じる(&X) ", self)
        act.setShortcut("Ctrl+Q")
        act.setStatusTip("ウィンドウを閉じる")
        act.triggered.connect(self.close)
        filemenu.addAction(act)

        self.tv = _Table(self)
        self.setCentralWidget(self.tv)

    def setModel1(self):
        print('setModel1')
        self.tv.setModel(self.m1)

    def setModel2a(self):
        print('setModel2a')
        self.tv.setModel(self.m2)

    def setModel2b(self):
        print('setModel2b')
        self.tv.setModel(None)
        self.tv.setModel(self.m2)


if __name__ == '__main__':
    q = QtWidgets.QApplication(sys.argv)
    m = Main()
    m.show()
    q.exec()
```

# 動作確認

__1.__ 上記 `test.py` を実行する。
```shell-session:test.pyの実行
$ python test.py
```

__2.__ ウィンドウが立ち上がったら、メニューの [テスト] から [Model #1] を選ぶ。
　　⇒縦２，横３のテーブルが表示される。

__3.__ メニューの [テスト] から [Model #2a]を選ぶ。
　　⇒エラーが発生。以下のようなメッセージが表示されるハズ。
```shell-session:実行ログ
setModel2a
In headerData:  0 of 0
Not section(0) < len(0)
In headerData:  1 of 0
Not section(1) < len(0)
In headerData:  2 of 0
Not section(2) < len(0)
```

　アイテムがあるモデルから、アイテムの無いモデルへ切り替えると、エラーが発生する様子。

　これを回避するには、いったんモデルを __None__ にする必要があるみたい。

__4.__ もう一度メニューの [テスト] から [Model #1] を選ぶ。
　　⇒縦２，横３のテーブルが表示される。

__5.__ メニューの [テスト] から [Model #2b]を選ぶ。
　　⇒内部的には、いったん None を設定してから空のモデルに設定しているので、今度はエラーは発生しない……ハズ。

# 終わりに

　ちなみに、別の環境（PyQt6 6.2.3 on Ubuntu 22.04）でも同様の動作をする。なので、私の使い方が間違っているのかもしれない。なにか勘違いをしているのかも？　もしくは、いったん None を入れるのが正しいお作法……なのかもしれない？