Metadata-Version: 2.1
Name: aiologic
Version: 0.5.0
Summary: GIL-powered* locking library for Python
Author-email: Ilya Egorov <0x42005e1f@gmail.com>
License: Copyright 2024 Ilya Egorov <0x42005e1f@gmail.com>.
        
        Permission to use, copy, modify, and/or distribute this software for any
        purpose with or without fee is hereby granted, provided that the above
        copyright notice and this permission notice appear in all copies.
        
        THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
        REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
        AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
        INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
        LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
        OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        PERFORMANCE OF THIS SOFTWARE.
        
Project-URL: Source, https://github.com/x42005e1f/aiologic
Classifier: Development Status :: 3 - Alpha
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: ISC License (ISCL)
Classifier: Intended Audience :: Developers
Classifier: Framework :: AsyncIO
Classifier: Framework :: Trio
Classifier: Framework :: AnyIO
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/x-rst
License-File: LICENSE
Provides-Extra: trio
Requires-Dist: trio>=0.23.0; extra == "trio"
Provides-Extra: anyio
Requires-Dist: anyio>=3.0.0; extra == "anyio"
Provides-Extra: gevent
Requires-Dist: gevent>=21.1.0; extra == "gevent"
Provides-Extra: sniffio
Requires-Dist: sniffio>=1.3.0; extra == "sniffio"
Provides-Extra: eventlet
Requires-Dist: eventlet>=0.15.1; extra == "eventlet"

========
aiologic
========

**aiologic** is an async-aware library for tasks synchronization and their
communication in different threads and different event loops. Let's take a look
at the example:

.. code:: python

    import time

    from threading import Thread, get_ident

    import anyio

    from aiologic import Lock

    lock = Lock()
    start = time.monotonic()


    async def func():
        print(
            f"{time.monotonic() - start:.0f}:",
            f"thread={get_ident()}",
            f"task={anyio.get_current_task().id}",
            'start',
        )

        async with lock:
            await anyio.sleep(1)

        print(
            f"{time.monotonic() - start:.0f}:",
            f"thread={get_ident()}",
            f"task={anyio.get_current_task().id}",
            'stop',
        )


    async def main():
        async with anyio.create_task_group() as tasks:
            for _ in range(2):
                tasks.start_soon(func)


    for _ in range(2):
        Thread(target=anyio.run, args=[main]).start()

It prints something like this:

.. code-block::

    0: thread=140011620005632 task=140011624407888 start
    0: thread=140011611612928 task=140011602572720 start
    0: thread=140011620005632 task=140011624408560 start
    0: thread=140011611612928 task=140011602574512 start
    1: thread=140011620005632 task=140011624407888 stop
    2: thread=140011611612928 task=140011602572720 stop
    3: thread=140011620005632 task=140011624408560 stop
    4: thread=140011611612928 task=140011602574512 stop

As you can see, when using `aiologic.Lock`, tasks from different event loops
are all able to acquire a lock. In the same case if you use `anyio.Lock`, it
will raise a `RuntimeError`. And `threading.Lock` will cause a deadlock.

Features
========

* Python 3.8+ support
* `CPython <https://www.python.org/>`_ and `PyPy <https://pypy.org/>`_ support
* Cancellation and timeouts support
* Optional `Trio-style checkpoints
  <https://trio.readthedocs.io/en/stable/reference-core.html#checkpoints>`_:

  * enabled by default for Trio itself
  * disabled by default for all others

* Only one checkpoint per asynchronous call:

  * exactly one context switch if checkpoints are enabled
  * zero or one context switch if checkpoints are disabled

* Fairness wherever possible (with some caveats)
* Thread safety wherever possible

Synchronization primitives:

* Semaphores: counting and bounded
* Locks: primitive, ownable and reentrant
* Capacity limiters
* Conditions
* Barriers: single-use only
* Events: one-time and reusable
* Resource guards

Communication primitives:

* Queues: FIFO and LIFO

Supported concurrency libraries:

* `asyncio <https://docs.python.org/3/library/asyncio.html>`_
  and `trio <https://trio.readthedocs.io>`_ (coroutine-based)
* `eventlet <https://eventlet.readthedocs.io>`_
  and `gevent <https://www.gevent.org/>`_ (greenlet-based)

All synchronization primitives are implemented entirely on effectively atomic
operations, which gives `an incredible speedup on PyPy
<https://gist.github.com/x42005e1f/149d3994d5f7bd878def71d5404e6ea4>`_ compared
to alternatives from the threading module. All this works because of GIL, but
per-object locks also ensure that `the same operations are still atomic
<https://peps.python.org/pep-0703/#container-thread-safety>`_, so aiologic also
works when running in a `free-threaded mode
<https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython>`_.
