Skip to main content

Provide sync compatibility for your async functions

Project description

Easy Sync

codecov

Provide sync compatibility for your async functions

Motivation

I don't want to always duplicate implementations for both synchronous and asynchronous versions of the same thing, and think out two name for each of them, as it is a waste of time.

So I hope there is some magic which can turn my asynchronous function implementations into synchronous versions.

I call this magic @sync_compatible here, with this decorator, your function f can be called via both await f(x) (in a asynchronous context) or f(x).wait() (in a synchronous context).

Features

  1. Use a single name of function for both async and sync version
  2. Automatic provide a sync vertion from async version (code generation underground)
  3. Lightweight, pure python, and no dependencies
  4. Strict type annotation (validated by pylance the strict mode)
  5. Unit test, and test coverage ratio is monitored

Usage

Install via pip install easy-sync or poetry add easy-sync from (pypi)

The Magic Style

from easy_sync import sync_compatible

@sync_compatible
async def async_add(a: int, b: int) -> int:
    await asyncio.sleep(1)
    ''' Add two numbers asynchronously '''
    return a + b

def do_sync():

    print(async_add(1, 2).wait())
    print(async_add(3, 4).wait())

do_sync()

async def async_main():
    result = await async_add(1, 2)
    print(result)

asyncio.run(async_main())

NOTE: There are some requirements

This will generate a sync version code of your async function, which replaces all await f(...) into f(...).wait() and await asyncio.sleep(...) statements inside the function body into time.sleep(...).

So you need to:

  1. Make sure all await statement inside the body of the decorated function is sync compatible.

A statement is sync compatible here if it is one of the following cases:

- The called function `f` is decorated with `@sync_compatible` decorator, and called like `await f(...)`
- The called function is exactly `asyncio.sleep`, and the statement is literally `await asyncio.sleep(...)`

For other case, you might need to define a wrapper for yourself, via The Name Reusing Style of @sync_compatible

  1. Knowing that other decorators is ignored in the generated sync version code, since they are written for async functions, and very possible not support sync functions, keep them might cause unexpected error. If you really need them, please use The Name Reusing Style and add decorators manually.

  2. Knowing that if you use this decorator together with other decorators, make this the outer one can solve .wait() method not found issues.

The Name Reusing Style

Use this helper to just reuse name only, you need to provide the sync version yourself.

This is not our final goal, but at least it solves the naming problem for now :)

from easy_sync import sync_compatible

@sync_compatible(sync_fn = _sync_add)
async def async_add(a: int, b: int) -> int:
    await asyncio.sleep(1)
    return a + b

def _sync_add(a: int, b: int) -> int:
    sleep(1)
    return a + b

def main():
    print(async_add(1, 2).wait())
    print(async_add(3, 4).wait())

main()

Run tests and Contribute

You can use nix develop . or poetry shell under the project root to enter the develop environment.

Currently, if you run pytest you will find that some cases is marked as xfailed, which are tests for WIP usage.

You can change the alternative impl code to your own implementation and re-run pytest.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

easy_sync-0.2.1.tar.gz (8.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

easy_sync-0.2.1-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file easy_sync-0.2.1.tar.gz.

File metadata

  • Download URL: easy_sync-0.2.1.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.9.7-zen1

File hashes

Hashes for easy_sync-0.2.1.tar.gz
Algorithm Hash digest
SHA256 4fe63945620c1291a3041d04d5f28d0232a2e92a514ae25de2ecb809fba77a5c
MD5 6b3453d5035166607774b49fe212bc2c
BLAKE2b-256 84483390ebaa347c352d8d21d72997a18bc248a7961b9f9022c85209a8093cc3

See more details on using hashes here.

File details

Details for the file easy_sync-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: easy_sync-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.9.7-zen1

File hashes

Hashes for easy_sync-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0892c4918285829a217b9be3d432040ab868f582dae6cf1f2b448a98dcb1cfd3
MD5 ba758415c88b077c22f0755a5feec387
BLAKE2b-256 56bf6a93cc2ee9ee083e5c58de9504ea66fb48bde691fa81642f33571f3ab942

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page