次の理由でメモリがリークする(GDIやユーザーハンドルなどのメモリや他のカーネルオブジェクトが繰り返し実行されるたびに、テスト終了まで戻ってこない)理由について説明している人はいませんか:pytestでのpyqtテストでのメモリリーク
import pytest
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
class TestCase:
@pytest.mark.parametrize('dummy', range(1000))
def test_empty(self, dummy):
# self.view = None # does NOT fix the leak if uncommented!
self.app = QApplication.instance()
if self.app is None:
self.app = QApplication([])
self.view = QGraphicsView()
self.view.setFixedSize(600, 400)
self.view.setScene(QGraphicsScene())
self.view.show()
QTimer.singleShot(100, self.app.exit)
self.app.exec()
# self.view = None # FIXES the leak if uncommented!
次のいずれかの条件がTrueになると何の漏れはありません。
- Iなし-IFY場合ビューがテストメソッドが戻る前に(最後の行のコメントを解除)
- 私がデコレータを削除して、 の代わりに関数の先頭に "while True"を付けると、ビューのローカル(ビュー#1の驚くべきことではありません)が 関数のローカルになります。テスト 自体は一度実行されますが、ウィンドウは
興味深いことに、私は次の変更のいずれか作ればリークが消えない)以上にわたり再作成してます:
- を私はNoneにビューを設定します終了時ではなく関数の先頭にある(コメントアウトされた行は、テストメソッドをパラメータ化するのではなく、テストモジュールを生成する小さなPythonスクリプトで簡単に行える)、または多くのテストクラス、多くのテストモジュールを作成します(これは私が気づいた問題は、それぞれが多数のテストメソッドを持ついくつかのクラスを持つ100個のテストモジュールからなる巨大なテストスイートです。テストスイートのメモリーリークは、テストの数がpytestがすべてのテストを実行する前にGDIハンドルが不足しています)。 app.closeAllWindows()によって
- 私はapp.exitする単発の呼び出しを置き換えるには、()我々のアプリで
実際のテストは、いくつかのことを必要とし(私がこのMCVEに問題があったかもしれないと思いました)オブジェクトはsetup_method()で作成されるため、テストインスタンスのデータメンバーにPyQtオブジェクトを割り当てることは避けられません。だから私たちのための唯一の現実的な解決法は、メソッドによって作成されたPyQtオブジェクトがNone-ify PyQtオブジェクトになるように各テストメソッドを編集することですが、これはエラーが発生しやすくなります。私はもっと良い方法があると思っています。
ビューはシーンの所有権を取得しないため、参照を保持する必要があります。 – ekhumoro
@ekhumoroはい、実際のコードはこれを行います。実際には、setScene()を使って行を削除することはできますが、まだ漏れがあります。 – Schollii
も参照してくださいhttps://github.com/pytest-dev/pytest/issues/1649 – dbn