pvl/syslog/file.py
author Tero Marttila <terom@paivola.fi>
Sun, 13 Jan 2013 01:50:25 +0200
changeset 114 2e88e1d8e604
child 117 58aebcd35e1a
permissions -rw-r--r--
pvl.syslog.tail: split into pvl.syslog.file/tail, clarify line/None/EOFError behaviour
"""
    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