pvl/syslog/file.py
author Tero Marttila <terom@paivola.fi>
Sun, 15 Jun 2014 19:43:13 +0300
changeset 29 8fcb140f1ee0
parent 2 5a8a32cbc944
permissions -rw-r--r--
pvl.args: load default config from /etc/pvl/package/module.conf, if specified to parse(...)
"""
    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.

        TODO:   it would be nice if this raised EOFError (to avoid bugs with polling this infinitely), but at least
                the first readlines() must complete normally
    """

    @classmethod
    def open (cls, path, mode='r', **opts) :
        log.debug("%s", path)

        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 :
                log.debug("%s: eof", self)
                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()

    def close (self) :
        """
            Close our file. Further operations raise ValueError.
        """
        
        log.debug("%s", self)
        self.file.close()

    def __str__ (self) :
        # XXX: optional attr?
        return self.file.name