import os  
import time  
import errno  

class FileLockException(Exception):  
    pass  

class FileLock(object):  
    """ A file locking mechanism that has context-manager support so  
        you can use it in a with statement. This should be relatively cross 
        compatible as it doesn't rely on msvcrt or fcntl for the locking. 
    """  

    def __init__(self, file_name, timeout=10, delay=1):  
        """ Prepare the file locker. Specify the file to lock and optionally 
            the maximum timeout and the delay between each attempt to lock. 
        """  
        self.is_locked = False  
        self.lockfile = os.path.join('/var/lock/', "LCK..%s" % file_name)  
        self.file_name = file_name  
        self.timeout = timeout  
        self.delay = delay  


    def acquire(self):  
        """ Acquire the lock, if possible. If the lock is in use, it check again 
            every `wait` seconds. It does this until it either gets the lock or 
            exceeds `timeout` number of seconds, in which case it throws  
            an exception. 
        """  
        start_time = time.time()  
        while True:  
            try:  
                #Open file exclusively  
                self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR, mode=0o644)
                os.write(self.fd, ("%9d\n" % os.getpid()).encode('utf-8') )
                break;  
            except OSError as e:  
                if e.errno == errno.EEXIST:
                    pid = self._check()
                    if not pid:
                        os.remove(self.lockfile)
                if (time.time() - start_time) >= self.timeout:  
                    raise FileLockException("Timeout occured.")  
                time.sleep(self.delay)  
        self.is_locked = True  


    def release(self):  
        """ Get rid of the lock by deleting the lockfile.  
            When working in a `with` statement, this gets automatically  
            called at the end. 
        """  
        #Close files, delete files  
        if self.is_locked:  
            os.close(self.fd)  
            os.unlink(self.lockfile)  
            self.is_locked = False  


    def __enter__(self):  
        """ Activated when used in the with statement.  
            Should automatically acquire a lock to be used in the with block. 
        """  
        if not self.is_locked:  
            self.acquire()  
        return self  


    def __exit__(self, type, value, traceback):  
        """ Activated at the end of the with statement. 
            It automatically releases the lock if it isn't locked. 
        """  
        if self.is_locked:  
            self.release()  


    def __del__(self):  
        """ Make sure that the FileLock instance doesn't leave a lockfile 
            lying around. 
        """  
        self.release()  

    def _check(self):
        """check if a process is still running

the process id is expected to be in pidfile, which should exist.

if it is still running, returns the pid, if not, return False."""
        with open(self.lockfile, 'r') as f:
            try:
                pidstr = f.read()
                pid = int(pidstr)
            except ValueError:
                # not an integer
                return False
            try:
                os.kill(pid, 0)
            except OSError:
                return False
            else:
                return pid
""" 
#use as: 
from filelock import FileLock 
with FileLock("myfile.txt"): 
    # work with the file as it is now locked 
    print("Lock acquired.") 
"""  