Directory watcher and notifier for files added or removed I have written a piece of code that notifies if something is added or removed from a folder location:

from PyQt4 import QtGui
from PyQt4 import QtCore
import sys
import os


def xor(lst1, lst2):
    """ returns a tuple of items of item not in either of lists
    """
    x = lst2 if len(lst2) &gt; len(lst1) else lst1
    y = lst1 if len(lst1) &lt; len(lst2) else lst2
    return tuple(item for item in x if item not in y)


class MyMainWindow(QtGui.QMainWindow):
    def __init__(self, pathToWatch=None, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.setupUi()
        self._pathToWatch = pathToWatch or "/Users/ppl/Desktop/testFolder"
        self._initialContent = os.listdir(self._pathToWatch)
        self._fileSysWatcher    = QtCore.QFileSystemWatcher()
        self._fileSysWatcher.addPath(self._pathToWatch)
        self.connectSignals()

    def connectSignals(self):
        QtCore.QObject.connect(self._fileSysWatcher, QtCore.SIGNAL("directoryChanged(QString)"),
            self,      QtCore.SLOT("slotDirChanged(QString)"))

    def setupUi(self):
        self.label = QtGui.QLabel("Watching folder")
        self.setCentralWidget(self.label)
        self.setWindowTitle("Detect Dir Change")

    @QtCore.pyqtSlot("QString")   
    def slotDirChanged(self, path):
        newContent = ''.join(xor(os.listdir(path), self._initialContent))

        self._initialContent = os.listdir(path)
        msg = ""
        if newContent not in self._initialContent:
            msg = "removed: %s" % newContent
        else:
            msg = "added: %s" %  newContent
        self.label.setText("Detected Directory Change!! \n %s" % msg)


def main():  
    app         = QtGui.QApplication(sys.argv)
    window      = MyMainWindow()
    window.show()
    window.raise_()


    return sys.exit(app.exec_())
if __name__ == '__main__':
  main()


I have used QFileSystemWatcher that notifies that the change happened and then I recheck the content to compare with the difference.
This code compares the size of the lists twice:


x = lst2 if len(lst2) &gt; len(lst1) else lst1
y = lst1 if len(lst1) &lt; len(lst2) else lst2



It would be better to do that only once:

longer, shorter = (lst2, lst1) if len(lst2) &gt; len(lst1) else (lst1, lst2)


Notice that I also used better names instead of the meaningless x, y.

With this change the function becomes:

def xor(lst1, lst2):
    """ returns a tuple of items of item not in either of lists
    """
    longer, shorter = (lst2, lst1) if len(lst2) &gt; len(lst1) else (lst1, lst2)
    return tuple(item for item in longer if item not in shorter)


It might also help to turn the shorter list into a set for faster lookups:

    longer, shorter = (lst2, set(lst1)) if len(lst2) &gt; len(lst1) else (lst1, set(lst2))


However, at this point, I realize the method doesn't do what the comment says it does:
it returns the items of the longer list that are not in the shorter list,
which is not the same as items in neither lists (can be fewer than that).



It would be better to move "/Users/ppl/Desktop/testFolder" into a constant at the top of the file, rather than buried inside a class constructor.



It's recommended to follow PEP8, the Python coding style guide.

For example there are several coding style violations here:


def main():  
    app         = QtGui.QApplication(sys.argv)
    window      = MyMainWindow()
    window.show()
    window.raise_()


    return sys.exit(app.exec_())
if __name__ == '__main__':
  main()



The recommended writing style would be:

def main():  
    app = QtGui.QApplication(sys.argv)
    window = MyMainWindow()
    window.show()
    window.raise_()

    return sys.exit(app.exec_())

if __name__ == '__main__':
    main()