[PyQt] graphical file tail
Eric Frederich
eric.frederich at gmail.com
Mon Jun 24 20:24:25 BST 2013
I'm trying to tail several files graphically.
I have been trying to find a way to tail several files in a GUI
without much luck at all.
I get errors from tail saying broken pipe.
I get PyQt errors saying underlying C++ objects have been destroyed.
I get other Qt errors saying that threads are still running when the
application exits
etc....
The implementation posted below seems to suffer from the following errors.
Not all the time. It depends.
QThread: Destroyed while thread is still running
QWaitCondition::wakeAll(): mutex lock failure:
Please tell me what I'm doing wrong.
Feel free to tell me if I'm doing something bone-headed.
Basically, I want to graphically tail files and when the GUI closes
the tail subprocesses are killed.
Seems like a simple request, but I can't get it right.
#!/usr/bin/env python
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os
from subprocess import Popen, PIPE
class Tailer(QThread):
def __init__(self, fname, parent=None):
super(Tailer, self).__init__(parent)
self.fname = fname
self.connect(self, SIGNAL('finished()'), self.cleanup)
def cleanup(self):
print 'CLEANING UP'
self.p.kill()
print 'killed'
def run(self):
command = ["tail", "-f", self.fname]
print command
self.p = Popen(command, stdout=PIPE, stderr=PIPE)
while True:
line = self.p.stdout.readline()
self.emit(SIGNAL('newline'), line.rstrip())
if not line:
print 'BREAKING'
break
def foo(self):
self.p.kill()
class TailWidget(QWidget):
def __init__(self, fnames, parent=None):
super(TailWidget, self).__init__(parent)
layout = QGridLayout()
self.threads = {}
self.browsers = {}
for i, fname in enumerate(fnames):
if not os.path.exists(fname):
print fname, "doesn't exist; creating"
p = Popen(['touch', fname], stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
ret = p.wait()
assert ret == 0
t = Tailer(fname, self)
self.threads[fname] = t
b = QTextBrowser()
self.browsers[fname] = b
layout.addWidget(QLabel('Tail on %s' % fname), 0, i)
layout.addWidget(b, 1, i)
self.connect(t, SIGNAL("newline"), b.append)
t.start()
self.setLayout(layout)
def closeEvent(self, event):
for fname, t in self.threads.items():
t.foo()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
tw = TailWidget(sys.argv[1:])
tw.show()
sys.exit(app.exec_())
More information about the PyQt
mailing list