1

Using PyQt and Python I came across the following issue:

  1. Set up a QFileSystemModel, call setRootPath() and hook up to the dataChanged signal.
  2. Open a new file from Python and write some text into it. Then close it.
  3. Reopen the file in append mode and write some more text into it. Then close it.
  4. Open a file in an external editor. Write some stuff. Save. Write more stuff. Save.

If you do (3), the dataChanged signal is NOT emitted. However, if you do (4), the dataChanged signal IS emitted.

Any clues? A code snippet that reproduces the issue is included below.

Best regards,

Mads

import sys
import os

from PyQt4 import QtGui, QtCore

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

        layout = QtGui.QVBoxLayout()
        self.setLayout(layout)
        self._view = QtGui.QListView()
        layout.addWidget(self._view)

        # Add the model
        self._model = QtGui.QFileSystemModel()
        self._model.setRootPath(QtCore.QDir().rootPath())
        self._model.setReadOnly(False)
        self._model.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.AllEntries)        
        self._view.setModel(self._model)

        # Root path
        path = os.path.dirname(os.path.abspath(__file__))
        self._model.setRootPath(path)

        # Set a root index
        index = self._model.index(path)
        self._view.setRootIndex(index)

        # Generate a file with some text
        print 'Making file'
        f = open('foo.dat', 'w')
        f.write('Some stuff\n')
        f.close()

        self.connect(self._model, QtCore.SIGNAL('dataChanged(const QModelIndex &, const QModelIndex &)'), self.dataChanged)

        # Append more text - this should trigger a signal call
        print 'Modifying file'
        f = open('foo.dat', 'w+')
        f.write('Some more stuff\n')
        f.close()

    def dataChanged(self, index_0, index_1):
        print 'dataChanged', self._model.filePath(index_0), self._model.filePath(index_1)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    widget = Widget()
    widget.show()

    sys.exit(app.exec_())

Here are some more general observations:

The basic problem is that QFileSystemModel apparently does not monitor file changes in a proper way:

Case 1 (Ubuntu):

1) Run the script in the background as 'python fsm.py &' 2) Launch a Python prompt in the same directory where the script was started in 3) Type:

f = open('foo.txt', 'w')
f.write('eyeyehydhdhdhdhdhdhhdhdshshs')
f.close()

The new file IS detected by the QFileSystemModel when open() is called. However, the file modifications caused by f.write() and f.close() are NOT detected.

Case 2 (Ubuntu):

1) While the script 'fsm.py' is still running, open a new file using some external editor (gedit, emacs, etc.) 2) Write some stuff and save

In this case, both the new file and the modification are detected. This is the first thing I don't understand. How come Python IO is not detected but IO from an editor is?

Case 3 (Ubuntu):

Using Ubuntu: I launch the Nautilus file browser and repeat step 1-3 from Case 1-2. Then both the new file and the modification are detected by nautilus. So there Python generated IO is monitored, but apparently using GNOME file monitoring system.

Case 1 (Windows 7):

Same behavior.

Case 2 (Windows 7):

If Notepad or Wordpad is used, file modifications are NOT detected. If GVim 7.3 is used, file modifications ARE detected.

Case 3 (Windows 7):

Launching the native Windows 7 file browser, all mods from Case 1-2 are detected.

Can you make any sense out of this?

repoman
  • 3,485
  • 2
  • 16
  • 15
  • Quick guess: the editor doesn't append to, but replaces the file? – Martijn Pieters May 22 '12 at 10:03
  • 1
    Running that code, I do get `dataChanged`. Perhaps it depends on Python version and/or OS. I tried with Python 2.7, PyQt 4.9.1, Qt 4.8.1 on Ubuntu. – Avaris May 22 '12 at 10:32
  • Are you sure that for 3rd case `dataChanged` signal is not emitted because when i ran your code this was the output for my [first run](http://pastie.org/3949212) and I got `dataCHanged` signal and when i tried to make other changed to the file that is by editing in notepad no `dataChanged` signal was emitted. – RanRag May 22 '12 at 10:34
  • The dataChanged signal is issued initially, but not for the file opened by the Python code. Notice, that dataChanged also prints the filePath, which should be 'foo.dat' – repoman May 22 '12 at 10:41
  • 1
    Ok if I understand you correctly the `dataChanged` that is issued initially is not for the file `foo.dat`. Ok fine but as you mentioned that `dataChanged` is issued for the case 4 but it is not atleast for me. So for me the `dataChanged` is issued only once initially and after that whatever I do it is not being issued. – RanRag May 22 '12 at 10:49
  • @RanRag: What OS and editor are you using? – repoman May 22 '12 at 10:52
  • @Avaris: What file name or path is printed by dataChanged? Is should be 'foo.dat'. – repoman May 22 '12 at 10:54
  • Windows7 , python 2.6.5, notepad and vim. – RanRag May 22 '12 at 10:56
  • @repoman: It was not the file. Curiously, It was not the directory the file was in either. It was `/home` and the file is located several level of directories below that. – Avaris May 22 '12 at 11:07
  • @Avaris: /home is also printed on my machine. If you starting editing anything from within an editor, is the signal then emitted? – repoman May 22 '12 at 11:15
  • 1
    @repoman: `Modified Date` is not monitored. Change your view to `QTreeView` and modify the file after showing the window (better if you put a little delay) if you want to observe. Python modifies the file and modified date actually changes but the view doesn't update. In fact, I don't think individual files are monitored (perhaps it is too expensive). Renaming a file triggers `rowsRemoved` and then `rowsInserted`. – Avaris May 22 '12 at 12:16
  • Hey. Thanks for your comments. I added some more details to the above post. It seems that QFileSystemModel (or my misuse of it) does not meet my requirements for a full-blown file monitoring tool (monitoring everything from a root dir and downwards). Any suggestions for a Python tool that can do this? – repoman May 23 '12 at 09:41
  • @repoman: Take a look at [qfilesystemwatcher](http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qfilesystemwatcher.html) and also [this](http://stackoverflow.com/questions/9681870/qt-or-pyqt-check-when-file-is-used-by-another-process-wait-until-finish-copy) and [this](http://stackoverflow.com/questions/182197/how-do-i-watch-a-file-for-changes-using-python) question. – RanRag May 23 '12 at 11:55

0 Answers0