A platform independent file lock for Python

Overview

py-filelock

travis-ci

This package contains a single module, which implements a platform independent file lock in Python, which provides a simple way of inter-process communication:

from filelock import Timeout, FileLock

lock = FileLock("high_ground.txt.lock")
with lock:
    open("high_ground.txt", "a").write("You were the chosen one.")        

Don't use a FileLock to lock the file you want to write to, instead create a separate .lock file as shown above.

animated example

Similar libraries

Perhaps you are looking for something like

Installation

py-filelock is available via PyPi:

$ pip3 install filelock

Documentation

The documentation for the API is available on readthedocs.org.

Examples

A FileLock is used to indicate another process of your application that a resource or working directory is currently used. To do so, create a FileLock first:

from filelock import Timeout, FileLock

file_path = "high_ground.txt"
lock_path = "high_ground.txt.lock"

lock = FileLock(lock_path, timeout=1)

The lock object supports multiple ways for acquiring the lock, including the ones used to acquire standard Python thread locks:

with lock:
    open(file_path, "a").write("Hello there!")

lock.acquire()
try:
    open(file_path, "a").write("General Kenobi!")
finally:
    lock.release()

The acquire() method accepts also a timeout parameter. If the lock cannot be acquired within timeout seconds, a Timeout exception is raised:

try:
    with lock.acquire(timeout=10):
        open(file_path, "a").write("I have a bad feeling about this.")
except Timeout:
    print("Another instance of this application currently holds the lock.")

The lock objects are recursive locks, which means that once acquired, they will not block on successive lock requests:

def cite1():
    with lock:
        open(file_path, "a").write("I hate it when he does that.")

def cite2():
    with lock:
        open(file_path, "a").write("You don't want to sell me death sticks.")

# The lock is acquired here.
with lock:
    cite1()
    cite2()

# And released here.

FileLock vs SoftFileLock

The FileLock is platform dependent while the SoftFileLock is not. Use the FileLock if all instances of your application are running on the same host and a SoftFileLock otherwise.

The SoftFileLock only watches the existence of the lock file. This makes it ultra portable, but also more prone to dead locks if the application crashes. You can simply delete the lock file in such cases.

Contributions

Contributions are always welcome, please make sure they pass all tests before creating a pull request. Never hesitate to open a new issue, although it may take some time for me to respond.

License

This package is public domain.

Comments
  • Create lockfile on Linux with safe permissions

    Create lockfile on Linux with safe permissions

    According to the documentation of os.open the former mode was in fact the flags for the open operation. I renamed this from open_mode to open_flags and added the permission as 0o660 so that the created lockfile now has -rw-rw---- and not -rwxr-xr-x as before.

    opened by ghost 19
  • 3.3.0 breaks pylint

    3.3.0 breaks pylint

    Since the last update, I am getting the following warnings. I suspect this has to do with the fact that pylint cannot deduce that the correct instance will not be superclassed by ABC (if-else definition of classes).

    import filelock
    
    with filelock.FileLock("abc.lock"):
        print("hi")
    
    
    pylint bla.py 
    ************* Module bla
    bla.py:1:0: C0114: Missing module docstring (missing-module-docstring)
    bla.py:3:5: E0110: Abstract class 'WindowsFileLock' with abstract methods instantiated (abstract-class-instantiated)
    bla.py:3:5: E0110: Abstract class 'UnixFileLock' with abstract methods instantiated (abstract-class-instantiated)
    
    
    opened by Zahlii 11
  • Handle Unwritable Path

    Handle Unwritable Path

    Description

    If the OS cannot open a file because the path is bad, it does not make sense to repeatedly attempt to open the file as it will continue to fail, indefinitely if the -1 default timeout is used, without any feedback to the user.

    This modifies the behavior to raise the OSError/IOError exception received on Windows or Unix so FileLock exits rather than a futile infinite loop that will never succeed.

    Tests are written to demonstrate the behavior.

    opened by ooglek 10
  • Dropped support for 3.6 in 3.4.2?

    Dropped support for 3.6 in 3.4.2?

    I thought the convention was that dropping support for a Python version was a breaking change, so this should have been 4.0.0? Maybe there are other philosophies.

    opened by nedbat 8
  • Unexpected and different behaviors on Windows and Linux

    Unexpected and different behaviors on Windows and Linux

    Hi there, When I run the following script, it runs successfully on Linux but fails on Windows 10:

    import filelock
    
    lock = filelock.FileLock('test.txt')
    with lock:
        f = open('test.txt', 'w')
        f.write('hello')
        f.close()
    

    The error on Windows is:

    PermissionError: [Errno 13] Permission denied
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "lock.py", line 9, in <module>
        f.close()
    PermissionError: [Errno 13] Permission denied
    

    However, if I move f.close() outside of the context manager, the script successfully runs on Windows and Linux:

    lock = filelock.FileLock('test.txt')
    with lock:
        f = open('test.txt', 'w')
        f.write('hello')
    f.close()
    

    Why exactly must the f.close() be placed outside the context manager on Windows, but not on Linux? Is it related to msvcrt.locking()?

    I'm using filelock 2.0.7, Windows 10 (x64) and Debian Jessie (x64).

    opened by kmdouglass 8
  • Please add simple use case on README.md

    Please add simple use case on README.md

    Hi, found this from a search. Please add the 4 line usage. I expect something like this:

    LOCK_FILE = ...
    LOCK = InterprocessLock(LOCK_FILE)
    
    def foo():
        with LOCK:
            do_something()
    

    Thanks

    opened by zackees 7
  • Fix misspelled keyword argument `poll_interval` for method `acquire`

    Fix misspelled keyword argument `poll_interval` for method `acquire`

    Fix misspelled keyword argument poll_interval for method acquire. Fixes #62.

    I tried my best to add the backward compatibility layer in this PR to not break existing codebases.

    opened by XuehaiPan 7
  • Multiprocessing with FileLock fails in python 3.9

    Multiprocessing with FileLock fails in python 3.9

    On python 3.9 with filelock 3.8.0, this code hangs:

    from multiprocessing import Pool
    from filelock import FileLock
    
    
    def run(i):
        print(f"got the lock in multi process [{i}]")
    
    
    with FileLock("tmp.lock"):
        with Pool(2) as pool:
            pool.map(run, range(2))
    
    

    This is because the subprocesses tries to acquire the lock from the main process for some reason. This is not the case in older versions of python.

    This can cause many issues in python 3.9.

    For example, we use multiprocessing to run a pool of jobs and we use filelock to prevent running the same pool of job several times and avoid writing collisions.

    First reported in https://github.com/huggingface/datasets/issues/4113

    opened by lhoestq 6
  • [Request] Add option to disable logger

    [Request] Add option to disable logger

    By default this package will always print to a logger, but for my use case it only ends up cluttering the logs with "released, acquired, released, acquired, etc". I'd appreciate it if you could add the option to disable the logger :)

    help-wanted documentation 
    opened by Winning117 6
  • Update `FileLock` constructor to accept `pathlib.Path`

    Update `FileLock` constructor to accept `pathlib.Path`

    This is a small fix for people who employ pathlib.Path for their path handling. It allows a Path object to be passed to the constructor of FileLock. It is then converted to a normal str when storing it inside the object leaving the rest of the library unaffected.

    opened by f-koehler 5
  • Locking is not exclusive when two threads request for a lock at a very close interval

    Locking is not exclusive when two threads request for a lock at a very close interval

    We are using py-filelock 3.0.12 and have experienced a problem when multiple threads are trying to acquire the lock on the same file at almost the same time. This happens quite often in our AWS EC2 instance and causes data corruption. We are just following the examples in the documentation to use the module. Is there any way to avoid this?

    bug help-wanted 
    opened by fhcat 5
  • FileNotFoundError: [Errno 2] No such file or directory: '/tmp/locks/my_lock.lock'

    FileNotFoundError: [Errno 2] No such file or directory: '/tmp/locks/my_lock.lock'

    I have been intermittently seeing this error (was thinking possibly due to a race condition), but one of my coworkers started running into this issue repeatedly. Any idea why this could be happening? Reproducing solely on macOS

    Code I'm running:

    lock_path = '/tmp/locks/my_lock.lock'
    with FileLock(lock_path, timeout=0):
       ... 
    

    I see that in _acquire() the os.O_CREAT flag is being provided to os.open(), so shouldn't the file be created if it does not exist?

    Sanitized traceback:

    Traceback (most recent call last):
      File "/Users/my_user/.virtualenvs/my_proj/my_proj/cache.py", line 311, in update_cache
        with FileLock(lock_path, timeout=0):
      File "/Users/my_user/.virtualenvs/my_env/lib/python3.10/site-packages/filelock/_api.py", line 220, in __enter__
        self.acquire()
      File "/Users/my_user/.virtualenvs/my_env/lib/python3.10/site-packages/filelock/_api.py", line 173, in acquire
        self._acquire()
      File "/Users/my_user/.virtualenvs/my_env/lib/python3.10/site-packages/filelock/_unix.py", line 35, in _acquire
        fd = os.open(self._lock_file, open_mode)
    FileNotFoundError: [Errno 2] No such file or directory: '/tmp/locks/my_lock.lock'
    
    needs-more-info 
    opened by connormason 6
  • What happens if another type of OSError is raised when attempting to create a soft lock?

    What happens if another type of OSError is raised when attempting to create a soft lock?

    I ran into a strange bug when trying to lock a file on a network file-system mounted inside a container, where the lock file was created but for some reason it seems as though the file-handle wasn't properly returned. My process then got stuck waiting for the lock to be released (when it had in fact created the lock). Looking at the following code, it seems that if the OSError errno isn't EEXIST, ENOENT or EACCES, then it is assumed the file is locked

    https://github.com/tox-dev/py-filelock/blob/4730a40b87cc4b094330b2af7723658428323d60/src/filelock/_soft.py#L23-L32

    wouldn't it be more robust to do something like

     try: 
         fd = os.open(self._lock_file, mode) 
     except OSError as exception: 
         if (exception.errno == EEXIST # expected if cannot lock 
                 or (if exception.errno == EACCES and sys.platform == "win32"):  # note windows does not allow you to make a folder r/o only files 
             pass 
         else:
             raise
    

    Or do you actually want the code to keep attempting to try creating the lock on other OSErrors?

    opened by tclose 0
  • API documentation of `filelock.FileLock` is inaccurate

    API documentation of `filelock.FileLock` is inaccurate

    The API documentation of filelock.FileLock simply reads:

    alias of filelock._unix.UnixFileLock

    Naturally, this is only true on platforms supporting fcntl.flock, else it might be a WindowsFileLock or SoftFileLock. I assume that ReadTheDocs runs and produces the HTML pages on a Linux system.

    I would expect the docs to instead indicate that this is an alias for the lock implementation specific to the platform the code is being run on, which may be any of the three classes. Ideally, this would be true also for filelock.FileLock.__doc__ at runtime (e.g. for help() in the REPL).

    I'm not very familiar with Sphinx, so I don't know what the best approach for this is. My intuitive attempt would be to make FileLock a subclass of the relevant implementation (i.e. class FileLock(_FileLock) in src/filelock/__init__.py) and give it its own docstring. However, the 'Bases' line in the Sphinx-generated docs would still have to be fixed or suppressed for this particular class.

    help-wanted documentation 
    opened by JustAnotherArchivist 1
  • File permission of lock file

    File permission of lock file

    The creation of a lockfile with …

    lock = FileLock("/var/lock/foo.lock")

    … leads to these file permissions: -rwxr-xr-x

    Is there any way to prevent that the lock file becomes an executable with root ownership?

    (Version: 3.0.12-2 in Ubuntu 20.04)

    help-wanted 
    opened by ghost 6
  • Does not successfully lock on Windows

    Does not successfully lock on Windows

    Hi,

    On Windows 10.0.19041.687 Pro x64. Python 3.7.0: x64.

    Here is a test script:

    import tempfile
    import pathlib
    import threading
    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    from filelock import FileLock
    import time
    
    TEST_FILE = pathlib.Path(tempfile.gettempdir()) / 'test_file.txt'
    TEST_LOCK_FILE =  pathlib.Path(tempfile.gettempdir()) / 'test_file.txt.lock'
    LOCK = FileLock(TEST_LOCK_FILE)
    
    def test():
        with LOCK:
            assert TEST_FILE.read_text() == 'hi'
            TEST_FILE.write_text('')
            assert TEST_FILE.read_text() == ''
            TEST_FILE.write_text('hi')
            assert TEST_FILE.read_text() == 'hi'
            return True
    
    if __name__ == '__main__':
        print(f"Test file: {TEST_FILE}")
        print(f"Test lock file: {TEST_LOCK_FILE}")
        TEST_FILE.write_text('hi')
    
        results = []
    
        # works with ProcessPoolExecutor but not with ThreadPoolExecutor
        # It also is more likely to work if we sleep after calling submit()
        with ThreadPoolExecutor(max_workers=16) as pool:
            for i in range(100):
                if i % 10 == 0:
                    print (f"Loop: {i+1}")
                results.append(pool.submit(test))
    
            for idx, result in enumerate(results):
                print (f"Checking result: {idx + 1}")
                assert result.result() == True
    

    Example run:

    PS C:\Users\csm10495\Desktop> python .\file_lock_test.py
    Test file: C:\Users\csm10495\AppData\Local\Temp\test_file.txt
    Test lock file: C:\Users\csm10495\AppData\Local\Temp\test_file.txt.lock
    Loop: 1
    Loop: 11
    Loop: 21
    Loop: 31
    Loop: 41
    Loop: 51
    Loop: 61
    Loop: 71
    Loop: 81
    Loop: 91
    Checking result: 1
    Traceback (most recent call last):
      File ".\file_lock_test.py", line 38, in <module>
        assert result.result() == True
      File "C:\Python37\lib\concurrent\futures\_base.py", line 425, in result
        return self.__get_result()
      File "C:\Python37\lib\concurrent\futures\_base.py", line 384, in __get_result
        raise self._exception
      File "C:\Python37\lib\concurrent\futures\thread.py", line 57, in run
        result = self.fn(*self.args, **self.kwargs)
      File ".\file_lock_test.py", line 18, in test
        assert TEST_FILE.read_text() == 'hi'
    AssertionError
    

    Using a ThreadPoolExecutor seems to lead to assertion errors making me think the lock file wasn't atomically created. If I sleep a bit (like .01), after doing submit() it seems to work, but sort of defeats the purpose of the test.

    help-wanted documentation 
    opened by csm10495 5
Releases(3.9.0)
  • 3.9.0(Dec 28, 2022)

    What's Changed

    • Move to hatchling build backend by @gaborbernat in https://github.com/tox-dev/py-filelock/pull/185

    Full Changelog: https://github.com/tox-dev/py-filelock/compare/3.8.2...3.9.0

    Source code(tar.gz)
    Source code(zip)
  • 3.8.2(Dec 5, 2022)

    What's Changed

    • Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.6.1 by @dependabot in https://github.com/tox-dev/py-filelock/pull/178
    • Update the license classifier to "Unlicense" by @jond01 in https://github.com/tox-dev/py-filelock/pull/180

    New Contributors

    • @jond01 made their first contribution in https://github.com/tox-dev/py-filelock/pull/180

    Full Changelog: https://github.com/tox-dev/py-filelock/compare/3.8.1...3.8.2

    Source code(tar.gz)
    Source code(zip)
  • 3.8.1(Dec 5, 2022)

    What's Changed

    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/166
    • link to flufl.lock by @dholth in https://github.com/tox-dev/py-filelock/pull/167
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/168
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/169
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/170
    • fix BaseFileLock.timeout's getter/setter being obscured by itself by @dearfl in https://github.com/tox-dev/py-filelock/pull/172
    • Fix mypy fails understanding FileLock by @gaborbernat in https://github.com/tox-dev/py-filelock/pull/177

    New Contributors

    • @dholth made their first contribution in https://github.com/tox-dev/py-filelock/pull/167
    • @dearfl made their first contribution in https://github.com/tox-dev/py-filelock/pull/172

    Full Changelog: https://github.com/tox-dev/py-filelock/compare/3.8.0...3.8.1

    Source code(tar.gz)
    Source code(zip)
  • 3.8.0(Aug 10, 2022)

    What's Changed

    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/149
    • Bump actions/upload-artifact from 2 to 3 by @dependabot in https://github.com/tox-dev/py-filelock/pull/154
    • Bump actions/download-artifact from 2 to 3 by @dependabot in https://github.com/tox-dev/py-filelock/pull/152
    • Bump pre-commit/action from 2.0.3 to 3.0.0 by @dependabot in https://github.com/tox-dev/py-filelock/pull/151
    • Bump actions/checkout from 2 to 3 by @dependabot in https://github.com/tox-dev/py-filelock/pull/153
    • Bump actions/setup-python from 2 to 4 by @dependabot in https://github.com/tox-dev/py-filelock/pull/150
    • Add timeout unit to docstrings by @jnordberg in https://github.com/tox-dev/py-filelock/pull/148
    • Unify badges style by @DeadNews in https://github.com/tox-dev/py-filelock/pull/155
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/156
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/157
    • Check 3.11 support by @gaborbernat in https://github.com/tox-dev/py-filelock/pull/158
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/159
    • Bump dependencies by @gaborbernat in https://github.com/tox-dev/py-filelock/pull/160
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/tox-dev/py-filelock/pull/162

    New Contributors

    • @dependabot made their first contribution in https://github.com/tox-dev/py-filelock/pull/154
    • @jnordberg made their first contribution in https://github.com/tox-dev/py-filelock/pull/148
    • @DeadNews made their first contribution in https://github.com/tox-dev/py-filelock/pull/155

    Full Changelog: https://github.com/tox-dev/py-filelock/compare/3.7.1...3.8.0

    Source code(tar.gz)
    Source code(zip)
  • 3.2.0(Sep 30, 2021)

A python script to convert an ucompressed Gnucash XML file to a text file for Ledger and hledger.

README 1 gnucash2ledger gnucash2ledger is a Python script based on the Github Gist by nonducor (nonducor/gcash2ledger.py). This Python script will tak

Thomas Freeman 0 Jan 28, 2022
Publicly Open Amazon AWS S3 Bucket Viewer

S3Viewer Publicly open storage viewer (Amazon S3 Bucket, Azure Blob, FTP server, HTTP Index Of/) s3viewer is a free tool for security researchers that

Sharon Brizinov 377 Dec 02, 2022
Python library for reading and writing tabular data via streams.

tabulator-py A library for reading and writing tabular data (csv/xls/json/etc). [Important Notice] We have released Frictionless Framework. This frame

Frictionless Data 231 Dec 09, 2022
Python's Filesystem abstraction layer

PyFilesystem2 Python's Filesystem abstraction layer. Documentation Wiki API Documentation GitHub Repository Blog Introduction Think of PyFilesystem's

pyFilesystem 1.8k Jan 02, 2023
ValveVMF - A python library to parse Valve's VMF files

ValveVMF ValveVMF is a Python library for parsing .vmf files for the Source Engi

pySourceSDK 2 Jan 02, 2022
Kartothek - a Python library to manage large amounts of tabular data in a blob store

Kartothek - a Python library to manage (create, read, update, delete) large amounts of tabular data in a blob store

15 Dec 25, 2022
A platform independent file lock for Python

py-filelock This package contains a single module, which implements a platform independent file lock in Python, which provides a simple way of inter-p

Benedikt Schmitt 497 Jan 05, 2023
Fast Python reader and editor for ASAM MDF / MF4 (Measurement Data Format) files

asammdf is a fast parser and editor for ASAM (Association for Standardization of Automation and Measuring Systems) MDF (Measurement Data Format) files

Daniel Hrisca 440 Dec 31, 2022
An object-oriented approach to Python file/directory operations.

Unipath An object-oriented approach to file/directory operations Version: 1.1 Home page: https://github.com/mikeorr/Unipath Docs: https://github.com/m

Mike Orr 506 Dec 29, 2022
Various technical documentation, in electronically parseable format

a-pile-of-documentation Various technical documentation, in electronically parseable format. You will need Python 3 to run the scripts and programs in

Jonathan Campbell 2 Nov 20, 2022
OneDriveExplorer - A command line and GUI based application for reconstructing the folder strucure of OneDrive from the UserCid.dat file

OneDriveExplorer - A command line and GUI based application for reconstructing the folder strucure of OneDrive from the UserCid.dat file

Brian Maloney 100 Dec 13, 2022
Annotate your Python requirements.txt file with summaries of each package.

Summarize Requirements 🐍 📜 Annotate your Python requirements.txt file with a short summary of each package. This tool: takes a Python requirements.t

Zeke Sikelianos 8 Apr 22, 2022
A tool written in python to generate basic repo files from github

A tool written in python to generate basic repo files from github

Riley 7 Dec 02, 2021
A python script generate password files in plain text

KeePass (or any desktop pw manager?) Helper WARNING: This script will generate password files in plain text. ITS NOT SECURE. I needed help remembering

Eric Thomas 1 Nov 21, 2021
Transforme rapidamente seu arquivo CSV (de qualquer tamanho) para SQL de forma rápida.

Transformador de CSV para SQL Transforme rapidamente seu arquivo CSV (de qualquer tamanho) para SQL de forma rápida, e com isso insira seus dados usan

William Rodrigues 4 Oct 17, 2022
Python interface for reading and appending tar files

Python interface for reading and appending tar files, while keeping a fast index for finding and reading files in the archive. This interface has been

Lawrence Livermore National Laboratory 1 Nov 12, 2021
Python Sreamlit Duplicate Records Finder Remover

Python-Sreamlit-Duplicate-Records-Finder-Remover Streamlit is an open-source Python library that makes it easy to create and share beautiful, custom w

RONALD KANYEPI 1 Jan 21, 2022
Pti-file-format - Reverse engineering the Polyend Tracker instrument file format

pti-file-format Reverse engineering the Polyend Tracker instrument file format.

Jaap Roes 14 Dec 30, 2022
Singer is an open source standard for moving data between databases, web APIs, files, queues, and just about anything else you can think of.

Singer is an open source standard for moving data between databases, web APIs, files, queues, and just about anything else you can think of. Th

Singer 1.1k Jan 05, 2023
An universal file format tool kit. At present will handle the ico format problem.

An universal file format tool kit. At present will handle the ico format problem.

Sadam·Sadik 1 Dec 26, 2021