fifolock


Namefifolock JSON
Version 0.0.20 PyPI version JSON
download
home_pagehttps://github.com/michalc/fifolock
SummaryA flexible low-level tool to make synchronisation primitives in asyncio Python
upload_time2019-05-02 19:34:41
maintainer
docs_urlNone
authorMichal Charemza
requires_python>=3.5
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # fifolock [![CircleCI](https://circleci.com/gh/michalc/fifolock.svg?style=svg)](https://circleci.com/gh/michalc/fifolock) [![Maintainability](https://api.codeclimate.com/v1/badges/9f7c8caf9b66ad2175e4/maintainability)](https://codeclimate.com/github/michalc/fifolock/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/9f7c8caf9b66ad2175e4/test_coverage)](https://codeclimate.com/github/michalc/fifolock/test_coverage)

A flexible low-level tool to make synchronisation primitives in asyncio Python. As the name suggests, locks are granted strictly in the order requested: first-in-first-out; and are not reentrant.


## Installation

```bash
pip install fifolock
```


## Recipes

### Mutex (exclusive) lock

```python
import asyncio
from fifolock import FifoLock


class Mutex(asyncio.Future):
    @staticmethod
    def is_compatible(holds):
        return not holds[Mutex]


lock = FifoLock()

async def access():
    async with lock(Mutex):
        # access resource
```

### Read/write (shared/exclusive) lock

```python
import asyncio
from fifolock import FifoLock


class Read(asyncio.Future):
    @staticmethod
    def is_compatible(holds):
        return not holds[Write]

class Write(asyncio.Future):
    @staticmethod
    def is_compatible(holds):
        return not holds[Read] and not holds[Write]


lock = FifoLock()

async def read():
    async with lock(Read):
        # shared access

async def write():
    async with lock(Write):
        # exclusive access
```

### Semaphore

```python
import asyncio
from fifolock import FifoLock


class SemaphoreBase(asyncio.Future):
    @classmethod
    def is_compatible(cls, holds):
        return holds[cls] < cls.size


lock = FifoLock()
Semaphore = type('Semaphore', (SemaphoreBase, ), {'size': 3})

async def access():
    async with lock(Semaphore):
        # at most 3 concurrent accesses
```


## Running tests

```bash
python setup.py test
```


## Design choices

Each mode of the lock is a subclass of `asyncio.Future`. This could be seen as a leak some of the internals of `FifoLock`, but it allows for clear client and internal code.

- Classes are hashable, so each can be a key in the `holds` dictionary passed to the `is_compatible` method. This allows the compatibility conditions to be read clearly in the client code, and the `holds` dictionary to be mutated clearly internally.

- An instance of it, created inside `FifoLock`, is _both_ the object awaited upon, and stored in a deque with a way of accessing its `is_compatible` method.

- The fact it's a class and not an instance of a class also makes clear it is to store no state, merely configuration.

A downside is that for configurable modes, such as for a semaphore, the client must dynamically create a class: this is not a frequently-used pattern.

The fact that the lock is _not_ reentrant is deliberate: the class of algorithms this is designed for does not require this. This would add unnecessary complexity, and presumably be slower.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/michalc/fifolock",
    "name": "fifolock",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": "",
    "keywords": "",
    "author": "Michal Charemza",
    "author_email": "michal@charemza.name",
    "download_url": "https://files.pythonhosted.org/packages/a5/d1/e7272af6b1b956460ce2ecde67522cf8715832d1c3f63f97d3bba318329f/fifolock-0.0.20.tar.gz",
    "platform": "",
    "description": "# fifolock [![CircleCI](https://circleci.com/gh/michalc/fifolock.svg?style=svg)](https://circleci.com/gh/michalc/fifolock) [![Maintainability](https://api.codeclimate.com/v1/badges/9f7c8caf9b66ad2175e4/maintainability)](https://codeclimate.com/github/michalc/fifolock/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/9f7c8caf9b66ad2175e4/test_coverage)](https://codeclimate.com/github/michalc/fifolock/test_coverage)\n\nA flexible low-level tool to make synchronisation primitives in asyncio Python. As the name suggests, locks are granted strictly in the order requested: first-in-first-out; and are not reentrant.\n\n\n## Installation\n\n```bash\npip install fifolock\n```\n\n\n## Recipes\n\n### Mutex (exclusive) lock\n\n```python\nimport asyncio\nfrom fifolock import FifoLock\n\n\nclass Mutex(asyncio.Future):\n    @staticmethod\n    def is_compatible(holds):\n        return not holds[Mutex]\n\n\nlock = FifoLock()\n\nasync def access():\n    async with lock(Mutex):\n        # access resource\n```\n\n### Read/write (shared/exclusive) lock\n\n```python\nimport asyncio\nfrom fifolock import FifoLock\n\n\nclass Read(asyncio.Future):\n    @staticmethod\n    def is_compatible(holds):\n        return not holds[Write]\n\nclass Write(asyncio.Future):\n    @staticmethod\n    def is_compatible(holds):\n        return not holds[Read] and not holds[Write]\n\n\nlock = FifoLock()\n\nasync def read():\n    async with lock(Read):\n        # shared access\n\nasync def write():\n    async with lock(Write):\n        # exclusive access\n```\n\n### Semaphore\n\n```python\nimport asyncio\nfrom fifolock import FifoLock\n\n\nclass SemaphoreBase(asyncio.Future):\n    @classmethod\n    def is_compatible(cls, holds):\n        return holds[cls] < cls.size\n\n\nlock = FifoLock()\nSemaphore = type('Semaphore', (SemaphoreBase, ), {'size': 3})\n\nasync def access():\n    async with lock(Semaphore):\n        # at most 3 concurrent accesses\n```\n\n\n## Running tests\n\n```bash\npython setup.py test\n```\n\n\n## Design choices\n\nEach mode of the lock is a subclass of `asyncio.Future`. This could be seen as a leak some of the internals of `FifoLock`, but it allows for clear client and internal code.\n\n- Classes are hashable, so each can be a key in the `holds` dictionary passed to the `is_compatible` method. This allows the compatibility conditions to be read clearly in the client code, and the `holds` dictionary to be mutated clearly internally.\n\n- An instance of it, created inside `FifoLock`, is _both_ the object awaited upon, and stored in a deque with a way of accessing its `is_compatible` method.\n\n- The fact it's a class and not an instance of a class also makes clear it is to store no state, merely configuration.\n\nA downside is that for configurable modes, such as for a semaphore, the client must dynamically create a class: this is not a frequently-used pattern.\n\nThe fact that the lock is _not_ reentrant is deliberate: the class of algorithms this is designed for does not require this. This would add unnecessary complexity, and presumably be slower.\n\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "A flexible low-level tool to make synchronisation primitives in asyncio Python",
    "version": "0.0.20",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "ead5a28cdb3d6c608a3689cc4f493331",
                "sha256": "48ce70e50ceecd799e0346b6a92bb1d0301fd6b9ebeb3a2b3383e0ca7c3e73f5"
            },
            "downloads": -1,
            "filename": "fifolock-0.0.20-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ead5a28cdb3d6c608a3689cc4f493331",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.5",
            "size": 3753,
            "upload_time": "2019-05-02T19:34:39",
            "upload_time_iso_8601": "2019-05-02T19:34:39.938055Z",
            "url": "https://files.pythonhosted.org/packages/57/4b/9496f5c90796fb56217cf9f6fde868eb19d6788fb5c2ea5d5fa97db36579/fifolock-0.0.20-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "788f802285eeee5e1a48e8b94880909f",
                "sha256": "c38ac427605d87936a6131524aa2a1ef2964f12892e76c1749b136b9e53a88f9"
            },
            "downloads": -1,
            "filename": "fifolock-0.0.20.tar.gz",
            "has_sig": false,
            "md5_digest": "788f802285eeee5e1a48e8b94880909f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 2874,
            "upload_time": "2019-05-02T19:34:41",
            "upload_time_iso_8601": "2019-05-02T19:34:41.050779Z",
            "url": "https://files.pythonhosted.org/packages/a5/d1/e7272af6b1b956460ce2ecde67522cf8715832d1c3f63f97d3bba318329f/fifolock-0.0.20.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2019-05-02 19:34:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "michalc",
    "github_project": "fifolock",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": false,
    "lcname": "fifolock"
}
        
Elapsed time: 0.01742s