sqlalchemy-dlock


Namesqlalchemy-dlock JSON
Version 0.6.1.post1 PyPI version JSON
download
home_pageNone
SummaryA distributed lock implementation based on SQLAlchemy
upload_time2024-04-09 11:23:07
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseBSD-3-Clause
keywords sqlalchemy lock distributed distributed lock sql database dbms
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # sqlalchemy-dlock

[![Python package](https://github.com/tanbro/sqlalchemy-dlock/actions/workflows/python-package.yml/badge.svg)](https://github.com/tanbro/sqlalchemy-dlock/actions/workflows/python-package.yml)
[![PyPI](https://img.shields.io/pypi/v/sqlalchemy-dlock)](https://pypi.org/project/sqlalchemy-dlock/)
[![Documentation Status](https://readthedocs.org/projects/sqlalchemy-dlock/badge/?version=latest)](https://sqlalchemy-dlock.readthedocs.io/en/latest/)
[![codecov](https://codecov.io/gh/tanbro/sqlalchemy-dlock/branch/main/graph/badge.svg)](https://codecov.io/gh/tanbro/sqlalchemy-dlock)

`sqlalchemy-dlock` is a distributed-lock library based on Database and [SQLAlchemy][].

It currently supports below locks:

 Database  |                                             Lock
---------- | ---------------------------------------------------------------------------------------------
MySQL      | [named lock](https://dev.mysql.com/doc/refman/en/locking-functions.html)
PostgreSQL | [advisory lock](https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS)

## Install

```bash
pip install sqlalchemy-dlock
```

## Usage

- Work with [SQLAlchemy][] [`Connection`](https://docs.sqlalchemy.org/20/core/connections.html):

  ```python
  from sqlalchemy import create_engine
  from sqlalchemy_dlock import create_sadlock

  key = 'user/001'

  engine = create_engine('postgresql://scott:tiger@127.0.0.1/')
  conn = engine.connect()

  # Create the D-Lock on the connection
  lock = create_sadlock(conn, key)

  # it's not lock when constructed
  assert not lock.locked

  # lock
  lock.acquire()
  assert lock.locked

  # un-lock
  lock.release()
  assert not lock.locked
  ```

- `with` statement

  ```python
  from contextlib import closing

  from sqlalchemy import create_engine
  from sqlalchemy_dlock import create_sadlock

  key = 'user/001'

  engine = create_engine('postgresql://scott:tiger@127.0.0.1/')
  with engine.connect() as conn:

      # Create the D-Lock on the connection
      with create_sadlock(conn, key) as lock:
          # It's locked
          assert lock.locked

      # Auto un-locked
      assert not lock.locked

      # If do not want to be locked in `with`, a `closing` wrapper may help
      with closing(create_sadlock(conn, key)) as lock2:
          # It's NOT locked here !!!
          assert not lock2.locked
          # lock it now:
          lock2.acquire()
          assert lock2.locked

      # Auto un-locked
      assert not lock2.locked
  ```

- Work with [SQLAlchemy][] [`ORM` `Session`](https://docs.sqlalchemy.org/en/20/orm/session.html):

  ```python
  from sqlalchemy import create_engine
  from sqlalchemy.orm import sessionmaker
  from sqlalchemy_dlock import create_sadlock

  key = 'user/001'

  engine = create_engine('postgresql://scott:tiger@127.0.0.1/')
  Session = sessionmaker(bind=engine)

  with Session() as session:
    with create_sadlock(session, key) as lock:
        assert lock.locked
    assert not lock.locked
  ```

- Asynchronous I/O Support

  > đź’ˇ **TIP**
  >
  > - [SQLAlchemy][] `1.x`'s asynchronous I/O: <https://docs.sqlalchemy.org/14/orm/extensions/asyncio.html>
  > - [SQLAlchemy][] `2.x`'s asynchronous I/O: <https://docs.sqlalchemy.org/20/orm/extensions/asyncio.html>

  ```python
  from sqlalchemy.ext.asyncio import create_async_engine
  from sqlalchemy_dlock.asyncio import create_async_sadlock

  key = 'user/001'

  engine = create_async_engine('postgresql+asyncpg://scott:tiger@127.0.0.1/')

  async with engine.connect() as conn:
      async with create_async_sadlock(conn, key) as lock:
          assert lock.locked
          await lock.release()
          assert not lock.locked
          await lock.acquire()
      assert not lock.locked
  ```

  > ℹ️ **NOTE** \
  > [aiomysql][], [asyncpg][] and [psycopg][] are tested asynchronous drivers.
  >
  > We can install it with asynchronous DB libraries:
  >
  > ```bash
  > pip install SQLAlchemy[asyncio] aiomysql sqlalchemy-dlock
  > ```
  >
  > or
  >
  > ```bash
  > pip install SQLAlchemy[asyncio] asyncpg sqlalchemy-dlock
  > ```

## Test

Following drivers are tested:

- MySQL:
  - [mysqlclient][] (synchronous)
  - [pymysql][] (synchronous)
  - [aiomysql][] (asynchronous)
- Postgres:
  - [psycopg2][] (synchronous)
  - [asyncpg][] (asynchronous)
  - [psycopg][] (synchronous and asynchronous)

You can run unit-tests

- on local environment:

  1. Install the project in editable mode with `asyncio` optional dependencies, and libraries/drivers needed in test. A virtual environment ([venv][]) is strongly advised:

     ```bash
     pip install -e .[asyncio] -r tests/requirements.txt
     ```

  1. start up mysql and postgresql service

     There is a docker [compose][] file `db.docker-compose.yml` in project's top directory,
     which can be used to run mysql and postgresql develop environment conveniently:

     ```bash
     docker compose -f db.docker-compose.yml up
     ```

  1. set environment variables `TEST_URLS` and `TEST_ASYNC_URLS` for sync and async database connection url.
     Multiple connections separated by space.

     eg: (following values are also the defaults, and can be omitted)

     ```ini
     TEST_URLS=mysql://test:test@127.0.0.1/test postgresql://postgres:test@127.0.0.1/
     TEST_ASYNC_URLS=mysql+aiomysql://test:test@127.0.0.1/test postgresql+asyncpg://postgres:test@127.0.0.1/
     ```

     > ℹ️ **NOTE** \
     > The test cases would load environment variables from dot-env file `tests/.env`.

  1. run unit-test

     ```bash
     python -m unittest
     ```

- or on docker [compose][]:

  `tests/docker-compose.yml` defines a Python and [SQLAlchemy][] version matrix -- it combines Python `3.8` to `3.12` and [SQLAlchemy][] `v1`/`v2` for test cases. We can run it by:

  ```bash
  cd tests
  docker compose up --abort-on-container-exit
  ```

[SQLAlchemy]: https://www.sqlalchemy.org/ "The Python SQL Toolkit and Object Relational Mapper"
[venv]: https://docs.python.org/library/venv.html "The venv module supports creating lightweight “virtual environments”, each with their own independent set of Python packages installed in their site directories. "
[mysqlclient]: https://pypi.org/project/mysqlclient/ "Python interface to MySQL"
[psycopg2]: https://pypi.org/project/psycopg2/ "PostgreSQL database adapter for Python"
[psycopg]: https://pypi.org/project/psycopg/ "Psycopg 3 is a modern implementation of a PostgreSQL adapter for Python."
[aiomysql]: https://pypi.org/project/aiomysql/ "aiomysql is a “driver” for accessing a MySQL database from the asyncio (PEP-3156/tulip) framework."
[asyncpg]: https://pypi.org/project/asyncpg/ "asyncpg is a database interface library designed specifically for PostgreSQL and Python/asyncio. "
[pymysql]: https://pypi.org/project/pymysql/ "Pure Python MySQL Driver"
[compose]: https://docs.docker.com/compose/ "Compose is a tool for defining and running multi-container Docker applications."

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "sqlalchemy-dlock",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "SQLAlchemy, lock, distributed, distributed lock, SQL, database, DBMS",
    "author": null,
    "author_email": "liu xue yan <liu_xue_yan@foxmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/21/e0/89e0662aafe1c270079209eed572d23461b44033b78794eb0e2e94975af3/sqlalchemy-dlock-0.6.1.post1.tar.gz",
    "platform": null,
    "description": "# sqlalchemy-dlock\n\n[![Python package](https://github.com/tanbro/sqlalchemy-dlock/actions/workflows/python-package.yml/badge.svg)](https://github.com/tanbro/sqlalchemy-dlock/actions/workflows/python-package.yml)\n[![PyPI](https://img.shields.io/pypi/v/sqlalchemy-dlock)](https://pypi.org/project/sqlalchemy-dlock/)\n[![Documentation Status](https://readthedocs.org/projects/sqlalchemy-dlock/badge/?version=latest)](https://sqlalchemy-dlock.readthedocs.io/en/latest/)\n[![codecov](https://codecov.io/gh/tanbro/sqlalchemy-dlock/branch/main/graph/badge.svg)](https://codecov.io/gh/tanbro/sqlalchemy-dlock)\n\n`sqlalchemy-dlock` is a distributed-lock library based on Database and [SQLAlchemy][].\n\nIt currently supports below locks:\n\n Database  |                                             Lock\n---------- | ---------------------------------------------------------------------------------------------\nMySQL      | [named lock](https://dev.mysql.com/doc/refman/en/locking-functions.html)\nPostgreSQL | [advisory lock](https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS)\n\n## Install\n\n```bash\npip install sqlalchemy-dlock\n```\n\n## Usage\n\n- Work with [SQLAlchemy][] [`Connection`](https://docs.sqlalchemy.org/20/core/connections.html):\n\n  ```python\n  from sqlalchemy import create_engine\n  from sqlalchemy_dlock import create_sadlock\n\n  key = 'user/001'\n\n  engine = create_engine('postgresql://scott:tiger@127.0.0.1/')\n  conn = engine.connect()\n\n  # Create the D-Lock on the connection\n  lock = create_sadlock(conn, key)\n\n  # it's not lock when constructed\n  assert not lock.locked\n\n  # lock\n  lock.acquire()\n  assert lock.locked\n\n  # un-lock\n  lock.release()\n  assert not lock.locked\n  ```\n\n- `with` statement\n\n  ```python\n  from contextlib import closing\n\n  from sqlalchemy import create_engine\n  from sqlalchemy_dlock import create_sadlock\n\n  key = 'user/001'\n\n  engine = create_engine('postgresql://scott:tiger@127.0.0.1/')\n  with engine.connect() as conn:\n\n      # Create the D-Lock on the connection\n      with create_sadlock(conn, key) as lock:\n          # It's locked\n          assert lock.locked\n\n      # Auto un-locked\n      assert not lock.locked\n\n      # If do not want to be locked in `with`, a `closing` wrapper may help\n      with closing(create_sadlock(conn, key)) as lock2:\n          # It's NOT locked here !!!\n          assert not lock2.locked\n          # lock it now:\n          lock2.acquire()\n          assert lock2.locked\n\n      # Auto un-locked\n      assert not lock2.locked\n  ```\n\n- Work with [SQLAlchemy][] [`ORM` `Session`](https://docs.sqlalchemy.org/en/20/orm/session.html):\n\n  ```python\n  from sqlalchemy import create_engine\n  from sqlalchemy.orm import sessionmaker\n  from sqlalchemy_dlock import create_sadlock\n\n  key = 'user/001'\n\n  engine = create_engine('postgresql://scott:tiger@127.0.0.1/')\n  Session = sessionmaker(bind=engine)\n\n  with Session() as session:\n    with create_sadlock(session, key) as lock:\n        assert lock.locked\n    assert not lock.locked\n  ```\n\n- Asynchronous I/O Support\n\n  > \ud83d\udca1 **TIP**\n  >\n  > - [SQLAlchemy][] `1.x`'s asynchronous I/O: <https://docs.sqlalchemy.org/14/orm/extensions/asyncio.html>\n  > - [SQLAlchemy][] `2.x`'s asynchronous I/O: <https://docs.sqlalchemy.org/20/orm/extensions/asyncio.html>\n\n  ```python\n  from sqlalchemy.ext.asyncio import create_async_engine\n  from sqlalchemy_dlock.asyncio import create_async_sadlock\n\n  key = 'user/001'\n\n  engine = create_async_engine('postgresql+asyncpg://scott:tiger@127.0.0.1/')\n\n  async with engine.connect() as conn:\n      async with create_async_sadlock(conn, key) as lock:\n          assert lock.locked\n          await lock.release()\n          assert not lock.locked\n          await lock.acquire()\n      assert not lock.locked\n  ```\n\n  > \u2139\ufe0f **NOTE** \\\n  > [aiomysql][], [asyncpg][] and [psycopg][] are tested asynchronous drivers.\n  >\n  > We can install it with asynchronous DB libraries:\n  >\n  > ```bash\n  > pip install SQLAlchemy[asyncio] aiomysql sqlalchemy-dlock\n  > ```\n  >\n  > or\n  >\n  > ```bash\n  > pip install SQLAlchemy[asyncio] asyncpg sqlalchemy-dlock\n  > ```\n\n## Test\n\nFollowing drivers are tested:\n\n- MySQL:\n  - [mysqlclient][] (synchronous)\n  - [pymysql][] (synchronous)\n  - [aiomysql][] (asynchronous)\n- Postgres:\n  - [psycopg2][] (synchronous)\n  - [asyncpg][] (asynchronous)\n  - [psycopg][] (synchronous and asynchronous)\n\nYou can run unit-tests\n\n- on local environment:\n\n  1. Install the project in editable mode with `asyncio` optional dependencies, and libraries/drivers needed in test. A virtual environment ([venv][]) is strongly advised:\n\n     ```bash\n     pip install -e .[asyncio] -r tests/requirements.txt\n     ```\n\n  1. start up mysql and postgresql service\n\n     There is a docker [compose][] file `db.docker-compose.yml` in project's top directory,\n     which can be used to run mysql and postgresql develop environment conveniently:\n\n     ```bash\n     docker compose -f db.docker-compose.yml up\n     ```\n\n  1. set environment variables `TEST_URLS` and `TEST_ASYNC_URLS` for sync and async database connection url.\n     Multiple connections separated by space.\n\n     eg: (following values are also the defaults, and can be omitted)\n\n     ```ini\n     TEST_URLS=mysql://test:test@127.0.0.1/test postgresql://postgres:test@127.0.0.1/\n     TEST_ASYNC_URLS=mysql+aiomysql://test:test@127.0.0.1/test postgresql+asyncpg://postgres:test@127.0.0.1/\n     ```\n\n     > \u2139\ufe0f **NOTE** \\\n     > The test cases would load environment variables from dot-env file `tests/.env`.\n\n  1. run unit-test\n\n     ```bash\n     python -m unittest\n     ```\n\n- or on docker [compose][]:\n\n  `tests/docker-compose.yml` defines a Python and [SQLAlchemy][] version matrix -- it combines Python `3.8` to `3.12` and [SQLAlchemy][] `v1`/`v2` for test cases. We can run it by:\n\n  ```bash\n  cd tests\n  docker compose up --abort-on-container-exit\n  ```\n\n[SQLAlchemy]: https://www.sqlalchemy.org/ \"The Python SQL Toolkit and Object Relational Mapper\"\n[venv]: https://docs.python.org/library/venv.html \"The venv module supports creating lightweight \u201cvirtual environments\u201d, each with their own independent set of Python packages installed in their site directories. \"\n[mysqlclient]: https://pypi.org/project/mysqlclient/ \"Python interface to MySQL\"\n[psycopg2]: https://pypi.org/project/psycopg2/ \"PostgreSQL database adapter for Python\"\n[psycopg]: https://pypi.org/project/psycopg/ \"Psycopg 3 is a modern implementation of a PostgreSQL adapter for Python.\"\n[aiomysql]: https://pypi.org/project/aiomysql/ \"aiomysql is a \u201cdriver\u201d for accessing a MySQL database from the asyncio (PEP-3156/tulip) framework.\"\n[asyncpg]: https://pypi.org/project/asyncpg/ \"asyncpg is a database interface library designed specifically for PostgreSQL and Python/asyncio. \"\n[pymysql]: https://pypi.org/project/pymysql/ \"Pure Python MySQL Driver\"\n[compose]: https://docs.docker.com/compose/ \"Compose is a tool for defining and running multi-container Docker applications.\"\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "A distributed lock implementation based on SQLAlchemy",
    "version": "0.6.1.post1",
    "project_urls": {
        "documentation": "https://sqlalchemy-dlock.readthedocs.io/",
        "homepage": "https://github.com/tanbro/sqlalchemy-dlock",
        "repository": "https://github.com/tanbro/sqlalchemy-dlock.git"
    },
    "split_keywords": [
        "sqlalchemy",
        " lock",
        " distributed",
        " distributed lock",
        " sql",
        " database",
        " dbms"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "07fc9ac5a3481d58dea483e11df095a6c744f4e53755d933f2071cf977446d68",
                "md5": "cde5818ab39dfd00a65bf19adb4bb4f5",
                "sha256": "da8f186e2b882cc3278f238048827bb5b2700f1a71a0d0a31a1ebcb4de0be447"
            },
            "downloads": -1,
            "filename": "sqlalchemy_dlock-0.6.1.post1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cde5818ab39dfd00a65bf19adb4bb4f5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 22457,
            "upload_time": "2024-04-09T11:23:05",
            "upload_time_iso_8601": "2024-04-09T11:23:05.502121Z",
            "url": "https://files.pythonhosted.org/packages/07/fc/9ac5a3481d58dea483e11df095a6c744f4e53755d933f2071cf977446d68/sqlalchemy_dlock-0.6.1.post1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "21e089e0662aafe1c270079209eed572d23461b44033b78794eb0e2e94975af3",
                "md5": "8583a69bfd9e2a81210d298ccf0b03f7",
                "sha256": "f26d38436b8b5b1c7fcf966fcfedf308494c252c4a0561f854f0d13896d93628"
            },
            "downloads": -1,
            "filename": "sqlalchemy-dlock-0.6.1.post1.tar.gz",
            "has_sig": false,
            "md5_digest": "8583a69bfd9e2a81210d298ccf0b03f7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 18578,
            "upload_time": "2024-04-09T11:23:07",
            "upload_time_iso_8601": "2024-04-09T11:23:07.277916Z",
            "url": "https://files.pythonhosted.org/packages/21/e0/89e0662aafe1c270079209eed572d23461b44033b78794eb0e2e94975af3/sqlalchemy-dlock-0.6.1.post1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-09 11:23:07",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tanbro",
    "github_project": "sqlalchemy-dlock",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "requirements": [],
    "lcname": "sqlalchemy-dlock"
}
        
Elapsed time: 0.23027s