2017-06-27 3 views
0

私は、Ubuntuでpyqt5を使ってディレクトリ構造をナビゲートするときにクラッシュが断続的に発生することがありました。フォルダに移動するだけでクラッシュすることもあり、表示されているディレクトリの外部変更によってトリガされることもあります。次のコードは後者の例です。PyQt5 QFileSystemModelとQSortFilterProxyModel..doingでクラッシュしました。何か間違っていますか?

私がビルドしているアプリケーションは、プログラムの起動時に表示されているディレクトリをチェックします。有効なディレクトリではなくなった場合は、ツリーを次の有効なディレクトリに移動します。以下のコードは、ディレクトリ構造を作成し、ファイルにナビゲートしてファイルを選択し、ツリーの名前を変更した後、無効なディレクトリから無効なディレクトリに移動することをシミュレートしています。このコードを数回実行すると、クラッシュすることがあります。時には最初の実行時に、時には少々実行後にクラッシュすることがあります。

gdbスタックトレースのプロキシモデル機能を見て、モードを更新しようとしました。これは私の問題を解決するように見えましたが、これは私には間違っています。

私は解決策に満足していませんでしたが、修正して書いていましたが、今日はモデルの更新でもこのコードで再びクラッシュしました。

これらのクラスを一緒に使用する方法を示すサンプルコードはありません。誰かが私が何か間違っているのを見ますか?

import os, sys, tempfile 
from PyQt5 import QtCore, QtWidgets 


class Widget(QtWidgets.QWidget): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init__(self, parent) 

     layout = QtWidgets.QVBoxLayout() 
     self.setLayout(layout) 
     self._view = QtWidgets.QTableView() 
     layout.addWidget(self._view) 

     self._model = QtWidgets.QFileSystemModel() 
     self._model.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.AllEntries) 

     self._proxy = QtCore.QSortFilterProxyModel(self) 
     self._proxy.setSourceModel(self._model) 
     self._view.setModel(self._proxy) 

     header = self._view.horizontalHeader() 
     header.setSortIndicator(0, QtCore.Qt.AscendingOrder) 
     self._proxy.sort(header.sortIndicatorSection(), header.sortIndicatorOrder()) 

     # Create a temporary directory structure (tmpxyz/a/b/c) starting at the location of this file 
     # This is oddly very specific..less nesting or no file to select doesn't exhibit the problem!? 
     path = os.path.dirname(os.path.abspath(__file__)) 
     self.temp_dir = tempfile.TemporaryDirectory(dir=path) 
     print('created temporary directory', self.temp_dir.name) 
     foo_dir = os.path.join(self.temp_dir.name, 'foo') 
     os.mkdir(foo_dir) 
     self.a_dir = os.path.join(foo_dir, 'a') 
     os.mkdir(self.a_dir) 
     b_dir = os.path.join(self.a_dir, 'b') 
     os.mkdir(b_dir) 
     c_dir = os.path.join(b_dir, 'c') 
     os.mkdir(c_dir) 
     self.temp_file_name = os.path.join(c_dir, 'foo.txt') 
     with open(self.temp_file_name, 'w') as txtfile: 
      print('foo', file=txtfile) 

     self._model.setRootPath(c_dir) 

     # moved the following to loaded..didn't seem to help 
     # source_index = self._model.index(c_dir) 
     # index = self._proxy.mapFromSource(source_index) 
     # self._view.setRootIndex(index) 

     QtCore.QTimer.singleShot(4000, self._select_temp_file) 
     QtCore.QTimer.singleShot(5000, self._rename_test_dir) 

     self._model.directoryLoaded.connect(self._loaded) 

    def _loaded(self): 
     print('_loaded') 
     path = self._model.rootPath() 
     print('_loaded', path) 
     source_index = self._model.index(path) 
     index = self._proxy.mapFromSource(source_index) 
     self._view.setRootIndex(index) 

    def _select_temp_file(self): 
     source_index = self._model.index(self.temp_file_name) 
     if source_index.isValid(): 
      index = self._proxy.mapFromSource(source_index) 
      self._view.setCurrentIndex(index) 

    # Simulate an external application moving the current directory 
    def _rename_test_dir(self): 
     os.rename(self.a_dir, self.a_dir+'x') 
     path = self._model.rootPath() 
     print('_rename_test_dir', path) 
     if not os.path.isdir(path): 
      def _make_valid_path(path_): 
       if os.path.isdir(path_): 
        return path_ 
       while path_: 
        path_, _ = os.path.split(path_) 
        if os.path.isdir(path_): 
         return path_ 
       return '/' 

      print('Path not valid:', path) 
      path = _make_valid_path(path) 
      print('New Path:', path) 

      self._model.setRootPath(path) 
      print('_rename_test_dir 5') 
      # Using gdb showed a crash in the proxy model..so update it here...decreases crash frequency 
      # self._proxy.setSourceModel(self._model) 
      # print('_rename_test_dir 6') 
      # self._view.setModel(self._proxy) 
      print('_rename_test_dir 7') 

if __name__ == "__main__": 
    app = QtWidgets.QApplication(sys.argv) 
    widget = Widget() 
    widget.show() 
    sys.exit(app.exec_()) 

UPDATE:

それがコードから明らかではない場合、プログラムは全く相互作用および相互作用は、試験を妨害することはできないが必要です。ディレクトリ構造が作成されると、自動的に構造のリーフレベルに移動します。 4秒後にfoo.txtファイルが選択されます。別の2番目の後に、ツリーの 'a'ディレクトリの名前を変更してから、以前に使用された 'a'にツリーを戻ってナビゲートします。すべてうまくいけば、fooディレクトリが表示され、 'ax'ディレクトリが表示され、プログラムを終了して再試行できます。 GBDの下で実行

は、最後の2つの実行までtrace..edited次のスタックを取得する前に約8回を取った:私は古いライブラリの問題としてこれをオフに書いている

gdb --args python3 test_qfilesystemmodel_crash2.py 
(gdb) run 
Starting program: /usr/bin/python3 test_qfilesystemmodel_crash2.py 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 
[New Thread 0x7fffe9ea5700 (LWP 21128)] 
[New Thread 0x7fffdb5e5700 (LWP 21129)] 
[New Thread 0x7fffdade4700 (LWP 21130)] 
created temporary directory /home/myuser/Desktop/haiqu/src/tmp8dl0_uny 
_loaded 
_loaded /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo/a/b/c 
_rename_test_dir /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo/a/b/c 
Path not valid: /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo/a/b/c 
New Path: /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo 
_rename_test_dir 5 
_rename_test_dir 7 
_loaded 
_loaded /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo 
[Thread 0x7fffdb5e5700 (LWP 21129) exited] 
[Thread 0x7fffe9ea5700 (LWP 21128) exited] 
[Thread 0x7ffff7fbb700 (LWP 21127) exited] 
[Inferior 1 (process 21127) exited normally] 
(gdb) run 
Starting program: /usr/bin/python3 test_qfilesystemmodel_crash2.py 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 
[New Thread 0x7fffe9ea5700 (LWP 21132)] 
[New Thread 0x7fffdb5e5700 (LWP 21133)] 
[New Thread 0x7fffdade4700 (LWP 21134)] 
created temporary directory /home/myuser/Desktop/haiqu/src/tmpwr560n5l 
_loaded 
_loaded /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo/a/b/c 
_rename_test_dir /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo/a/b/c 
Path not valid: /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo/a/b/c 
New Path: /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo 
_rename_test_dir 5 
_rename_test_dir 7 

Thread 1 "python3" received signal SIGSEGV, Segmentation fault. 
0x00007ffff5062e89 in QSortFilterProxyModel::sibling(int, int, QModelIndex const&) const() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
(gdb) bt 
#0 0x00007ffff5062e89 in QSortFilterProxyModel::sibling(int, int, QModelIndex const&) const() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#1 0x00007ffff568d2d4 in ??() from /usr/lib/python3/dist-packages/PyQt5/QtCore.cpython-35m-x86_64-linux-gnu.so 
#2 0x00007ffff0af35ff in ??() from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#3 0x00007ffff00f9779 in QAccessible::updateAccessibility(QAccessibleEvent*)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5 
#4 0x00007ffff0b028cc in ??() from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#5 0x00007ffff0b07486 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#6 0x00007ffff50cb4a9 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#7 0x00007ffff51426e4 in QAbstractItemModel::rowsInserted(QModelIndex const&, int, int, QAbstractItemModel::QPrivateSignal)() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#8 0x00007ffff5046f7b in QAbstractItemModel::endInsertRows()() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#9 0x00007ffff5068246 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#10 0x00007ffff506a685 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#11 0x00007ffff506e089 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#12 0x00007ffff50cb4a9 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#13 0x00007ffff51426e4 in QAbstractItemModel::rowsInserted(QModelIndex const&, int, int, QAbstractItemModel::QPrivateSignal)() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#14 0x00007ffff5046f7b in QAbstractItemModel::endInsertRows()() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#15 0x00007ffff0acf6e6 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#16 0x00007ffff0ad51f9 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#17 0x00007ffff50cc359 in QObject::event(QEvent*)() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#18 0x00007ffff0ad58b2 in QFileSystemModel::event(QEvent*)() from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#19 0x00007ffff131ecdb in ??() from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-35m-x86_64-linux-gnu.so 
#20 0x00007ffff08b635c in QApplicationPrivate::notify_helper(QObject*, QEvent*)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#21 0x00007ffff08bdb11 in QApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5 
#22 0x00007ffff124cdee in ??() from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-35m-x86_64-linux-gnu.so 
#23 0x00007ffff509f8a0 in QCoreApplication::notifyInternal2(QObject*, QEvent*)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#24 0x00007ffff50a202d in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#25 0x00007ffff50f3b03 in ??() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#26 0x00007ffff3b35377 in g_main_context_dispatch() from /lib/x86_64-linux-gnu/libglib-2.0.so.0 
#27 0x00007ffff3b355e0 in ??() from /lib/x86_64-linux-gnu/libglib-2.0.so.0 
#28 0x00007ffff3b3568c in g_main_context_iteration() from /lib/x86_64-linux-gnu/libglib-2.0.so.0 
#29 0x00007ffff50f3f0f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#30 0x00007ffff509d88a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)() 
    from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#31 0x00007ffff50a5ffc in QCoreApplication::exec()() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 
#32 0x00007ffff1210ddb in ??() from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-35m-x86_64-linux-gnu.so 
#33 0x000055555571b28f in PyCFunction_Call() 
#34 0x00005555556d21e9 in PyEval_EvalFrameEx() 
#35 0x00005555556d6d16 in ??() 
#36 0x00005555556d7a1f in PyEval_EvalCode() 
#37 0x00005555557a4b02 in ??() 
#38 0x00005555557a6f8d in PyRun_FileExFlags() 
#39 0x00005555557a772e in PyRun_SimpleFileExFlags() 
#40 0x00005555557d72e7 in Py_Main() 
#41 0x0000555555667b31 in main() 
(gdb) 
+0

私はコードをテストしても問題は発生しません。 – eyllanesc

+0

私はあなたのテストを20回実行しましたが、問題はありませんでした。使用しているPythonとpyqtのバージョンと使用しているOSのバージョンは何ですか? – eyllanesc

+0

@eyllanesc python3 --version Python 3.5.3 ... qt 5.7.1 uname -a Linux ibp 4.10.0-24-generic#28-Ubuntu SMP Wed Jun 14 08:14:34 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux lsb_release -a LSBモジュールは使用できません。 Ubuntuの 説明:Ubuntuの17.04 リリース:17.04 コードネーム:ID ディストリビュータピリッ –

答えて

0

。 pyqt5.8とpython3.6にアップデートした後、クラッシュを再現することができなくなりました。助けてくれてありがとう。

関連する問題