pvl/syslog/file.py
changeset 114 2e88e1d8e604
child 117 58aebcd35e1a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pvl/syslog/file.py	Sun Jan 13 01:50:25 2013 +0200
@@ -0,0 +1,73 @@
+"""
+    Iterate over lines in file-like objects (without buffering lines!), write (flushing output).
+"""
+
+import logging; log = logging.getLogger('pvl.syslog.file')
+
+class File (object) :
+    """
+        Follow a file-like object, reading lines until no more are available. Never raises EOFError.
+
+        Works with python file objects that buffer readlines() when using e.g. `tail -f ... | python -u ...`.
+
+        readline() may block once there is no more input available, or may return None for evermore.
+
+        There is no fileno(), this is not pollable. At all. Don't even iterate on this with a timeout.
+        XXX: should this really return None? Might really be better to raise EOFError.. except that readlines() should return normally at EOF...
+    """
+
+    @classmethod
+    def open (cls, path, mode='r', **opts) :
+        return cls(open(path, mode), **opts)
+
+    EOL = '\n'
+
+    def __init__ (self, file) :
+        log.debug("%s", file)
+
+        self.file = file
+        
+    def readline (self) :
+        """
+            Reads a line from the file, without trailing \n.
+
+            Returns None on EOF.
+        """
+
+        line = self.file.readline()
+
+        if not line :
+            line = None
+        else : 
+            line = line.rstrip('\r\n')
+
+        log.debug("%s", line)
+
+        return line
+
+    def readlines (self) :
+        """
+            Reads any available lines from the file.
+        """
+
+        while True :
+            line = self.readline()
+            
+            if line is None :
+                return
+            else :
+                yield line
+
+    __iter__ = readlines
+
+    def writeline (self, line, eol=EOL) :
+        """
+            Write out line, flushing.
+        """
+
+        self.file.write(line)
+        self.file.write(eol)
+        self.file.flush()
+
+    __call__ = writeline
+