pvl/syslog/file.py
author Tero Marttila <terom@paivola.fi>
Sun, 13 Jan 2013 02:11:12 +0200
changeset 117 58aebcd35e1a
parent 114 2e88e1d8e604
child 136 de243aafe33b
permissions -rw-r--r--
pvl.syslog.file: flush in __call__
"""
    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.
        """

        log.debug("%s", line)

        self.file.write(str(line))
        self.file.write(eol)

    def __call__ (self, *lines) :
        """
            Write out lines, and flush.
        """

        for line in lines :
            self.writeline(line)

        self.file.flush()