tailhead/__init__.py
def follow_path(file_path, buffering=-1, encoding=None, errors='strict'):
    """
    Similar to follow, but also looks up if inode of file is changed
    e.g. if it was re-created.

    Returned generator yields strings encoded by using encoding.
    If encoding is not specified, it defaults to locale.getpreferredencoding()

    >>> import io
    >>> import os
    >>> f = io.open('test_follow_path.txt', 'w+')
    >>> generator = follow_path('test_follow_path.txt')
    >>> _ = f.write('Line 1\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 1
    >>> _ = f.write('Line 2\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 2
    >>> _ = f.truncate(0)
    >>> _ = f.seek(0)
    >>> _ = f.write('Line 3\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 3
    >>> f.close()
    >>> os.remove('test_follow_path.txt')
    >>> f = io.open('test_follow_path.txt', 'w+')
    >>> _ = f.write('Line 4\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 4
    >>> print(next(generator))
    None
    >>> f.close()
    >>> os.remove('test_follow_path.txt')
    """
    if encoding is None:
        encoding = locale.getpreferredencoding()

    class FollowPathGenerator(object):
        def __init__(self):
            if os.path.isfile(file_path):
                self.following_file = io.open(file_path, 'rb', buffering)
                self.follow_generator = Tailer(self.following_file, end=True).follow()
                self.follow_from_end_on_open = False
            else:
                self.following_file = None
                self.follow_generator = None
                self.follow_from_end_on_open = True

        def next(self):
            while True:
                if self.follow_generator:
                    line = next(self.follow_generator)
                else:
                    line = None

                if line is None:
                    if self.follow_generator:
                        try:
                            is_file_changed = not os.path.isfile(file_path) or os.stat(file_path).st_ino != os.fstat(self.following_file.fileno()).st_ino
                        except OSError:
                            # File could be deleted between isfile and stat invocations, which will make the latter to fail.
                            is_file_changed = True

                        if is_file_changed:
                            # File was deleted or re-created.
                            self.following_file.close()
                            self.following_file = None
                            self.follow_generator = None

                    if not self.follow_generator and os.path.isfile(file_path):
                        # New file is available. Open it.
                        try:
                            self.following_file = io.open(file_path, 'rb', buffering)
                            self.follow_generator = Tailer(self.following_file, end=self.follow_from_end_on_open).follow()
                            self.follow_from_end_on_open = False  # something could be written before we noticed change of file
                        except (IOError, OSError) as e:
                            LOG.info("Unable to tail file: %s", e)
                            if self.following_file:
                                self.following_file.close()

                            self.following_file= None
                            self.follow_generator = None
                            line = None
                        else:
                            line = next(self.follow_generator)

                return line.decode(encoding, errors) if line is not None else line

        def __iter__(self):
            return self

        def __next__(self):
            return self.next()

    return FollowPathGenerator()
def follow_path(file_path, buffering=-1, encoding=None, errors='strict'):
    """
    Similar to follow, but also looks up if inode of file is changed
    e.g. if it was re-created.

    Returned generator yields strings encoded by using encoding.
    If encoding is not specified, it defaults to locale.getpreferredencoding()

    >>> import io
    >>> import os
    >>> f = io.open('test_follow_path.txt', 'w+')
    >>> generator = follow_path('test_follow_path.txt')
    >>> _ = f.write('Line 1\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 1
    >>> _ = f.write('Line 2\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 2
    >>> _ = f.truncate(0)
    >>> _ = f.seek(0)
    >>> _ = f.write('Line 3\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 3
    >>> f.close()
    >>> os.remove('test_follow_path.txt')
    >>> f = io.open('test_follow_path.txt', 'w+')
    >>> _ = f.write('Line 4\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 4
    >>> print(next(generator))
    None
    >>> f.close()
    >>> os.remove('test_follow_path.txt')
    """
    if encoding is None:
        encoding = locale.getpreferredencoding()

    class FollowPathGenerator(object):
        def __init__(self):
            if os.path.isfile(file_path):
                self.following_file = io.open(file_path, 'rb', buffering)
                self.follow_generator = Tailer(self.following_file, end=True).follow()
                self.follow_from_end_on_open = False
            else:
                self.following_file = None
                self.follow_generator = None
                self.follow_from_end_on_open = True

        def next(self):
            while True:
                if self.follow_generator:
                    line = next(self.follow_generator)
                else:
                    line = None

                if line is None:
                    if self.follow_generator:
                        try:
                            is_file_changed = not os.path.isfile(file_path) or os.stat(file_path).st_ino != os.fstat(self.following_file.fileno()).st_ino
                        except OSError:
                            # File could be deleted between isfile and stat invocations, which will make the latter to fail.
                            is_file_changed = True

                        if is_file_changed:
                            # File was deleted or re-created.
                            self.following_file.close()
                            self.following_file = None
                            self.follow_generator = None

                    if not self.follow_generator and os.path.isfile(file_path):
                        # New file is available. Open it.
                        try:
                            self.following_file = io.open(file_path, 'rb', buffering)
                            self.follow_generator = Tailer(self.following_file, end=self.follow_from_end_on_open).follow()
                            self.follow_from_end_on_open = False  # something could be written before we noticed change of file
                        except (IOError, OSError) as e:
                            LOG.info("Unable to tail file: %s", e)
                            if self.following_file:
                                self.following_file.close()

                            self.following_file= None
                            self.follow_generator = None
                            line = None
                        else:
                            line = next(self.follow_generator)

                return line.decode(encoding, errors) if line is not None else line

        def __iter__(self):
            return self

        def __next__(self):
            return self.next()

    return FollowPathGenerator()
def follow_path ( file_path , buffering = - 1 , encoding = None , errors = 'strict' ) : if encoding is None : encoding = locale . getpreferredencoding ( ) class FollowPathGenerator ( object ) : def __init__ ( self ) : if os . path . isfile ( file_path ) : self . following_file = io . open ( file_path , 'rb' , buffering ) self . follow_generator = Tailer ( self . following_file , end = True ) . follow ( ) self . follow_from_end_on_open = False else : self . following_file = None self . follow_generator = None self . follow_from_end_on_open = True def next ( self ) : while True : if self . follow_generator : line = next ( self . follow_generator ) else : line = None if line is None : if self . follow_generator : try : is_file_changed = not os . path . isfile ( file_path ) or os . stat ( file_path ) . st_ino != os . fstat ( self . following_file . fileno ( ) ) . st_ino except OSError : # File could be deleted between isfile and stat invocations, which will make the latter to fail. is_file_changed = True if is_file_changed : # File was deleted or re-created. self . following_file . close ( ) self . following_file = None self . follow_generator = None if not self . follow_generator and os . path . isfile ( file_path ) : # New file is available. Open it. try : self . following_file = io . open ( file_path , 'rb' , buffering ) self . follow_generator = Tailer ( self . following_file , end = self . follow_from_end_on_open ) . follow ( ) self . follow_from_end_on_open = False # something could be written before we noticed change of file except ( IOError , OSError ) as e : LOG . info ( "Unable to tail file: %s" , e ) if self . following_file : self . following_file . close ( ) self . following_file = None self . follow_generator = None line = None else : line = next ( self . follow_generator ) return line . decode ( encoding , errors ) if line is not None else line def __iter__ ( self ) : return self def __next__ ( self ) : return self . next ( ) return FollowPathGenerator ( )
Similar to follow, but also looks up if inode of file is changed
    e.g. if it was re-created.

    Returned generator yields strings encoded by using encoding.
    If encoding is not specified, it defaults to locale.getpreferredencoding()

    >>> import io
    >>> import os
    >>> f = io.open('test_follow_path.txt', 'w+')
    >>> generator = follow_path('test_follow_path.txt')
    >>> _ = f.write('Line 1\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 1
    >>> _ = f.write('Line 2\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 2
    >>> _ = f.truncate(0)
    >>> _ = f.seek(0)
    >>> _ = f.write('Line 3\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 3
    >>> f.close()
    >>> os.remove('test_follow_path.txt')
    >>> f = io.open('test_follow_path.txt', 'w+')
    >>> _ = f.write('Line 4\\n')
    >>> f.flush()
    >>> print(next(generator))
    Line 4
    >>> print(next(generator))
    None
    >>> f.close()
    >>> os.remove('test_follow_path.txt')
Similar to follow but also looks up if inode of file is changed e . g . if it was re - created .