Skip to main content

Call synchronous Python from async code, without blocking

Project description

aevent lets you call boring synchronous Python from async code. Without blocking or splatting async and await onto it. Ideally, this works without modifying the synchronous code.

Put another way, aevent is to gevent what anyio is to greenlet.

That is, it replaces standard Python functions with calls to anyio instead of gevent.

Some limitations apply.

Usage

Before any other imports, insert this code block into your main code:

import aevent
aevent.setup('trio')  # or asyncio, if you must

This will annoy various code checkers, but that can’t be helped.

Start your main loop using aevent.run, or call await aevent.per_task() in the task(s) that need to use patched code.

The aevent.native and aevent.patched context managers can be used to temporarily disable or re-enable aevent’s patches.

Support functions

aevent monkey-patches anyio’s TaskGroup.spawn in two ways.

  • the child task is instrumented to support greenback.

  • spawn returns a cancel scope. You can use it to cancel the new task.

Call aevent.per_task in your child task if you start tasks some other way.

Threading

Threads are translated to tasks. In order for that to work, you must start your program with aevent.run, or run the sync code in question within an aevent.runner async context manager. Runners may be nested.

Supported modules

  • time

    • sleep

  • threading

  • queue

  • atexit

  • socket

  • select

    • poll

Not yet supported

  • select

    • anything else

  • dns

  • os

    • read

    • write

  • ssl

  • subprocess

  • signal

Subclassing patched classes

Directly subclassing one of the classes patched by aevent does not work and requires special consideration. Consider this code:

class my_thread(threading.Thread):
   def run(self):
       ...

For use with aevent you can choose the original Thread implementation:

orig_Thread = getattr(threading.Thread, "_aevent_orig", threading.Thread)
class my_thread(orig_Thread):
  ...

or the aevent-ified version:

new_Thread = threading.Thread._aevent_new # fails when aevent is not loaded
class my_thread(new_Thread):
  ...

or you might want to create two separate implementations, and switch based on the aevent context:

class _orig_my_thread(threading.Thread._aevent_orig):
   ...
class _new_my_thread(threading.Thread._aevent_new):
   ...
my_thread = aevent.patch__new_my_thread, name="my_thread", orig=_orig_my_thread)

If you generate local subclasses on the fly, you can simplify this to:

def some_code():
    class my_thread(threading.Thread._aevent_select()):
        def run(self):
            ...
    job = my_tread()
    my_thread.start()

Other affected modules

You need to import any module which requires non-patched code before importing aevent.

Modules which are known to be affected:

  • multiprocessing

Internals

aevent’s monkey patching is done mainly on the module/class level. gevent prefers to patch individual methods. This may cause some reduced compatibility compared to gevent.

aevent works by prepending its local _monkey directory to the import path. These modules try to afford the same public interface as the ones they’re replacing while calling the corresponding anyio functions through greenback_.

Context switching back to async-flavored code is done by way of greenback.

aevent runs on Python 3.7 ff.

Testing

The test suite runs with trio as backend. Due to aevent’s monkeypatching, switching backends around is not supported. However, you can set the environment variable AEVENT_BACKEND to asyncio to run the test suite with that.

The test suite pulls in a copy of pyroute2 (no changes, other than fixing bugs unrelated to aevent) and tests against its test suite, thereby (mostly) ensuring that this particular package works with aevent.

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

aevent-0.1.1.tar.gz (19.8 kB view details)

Uploaded Source

File details

Details for the file aevent-0.1.1.tar.gz.

File metadata

  • Download URL: aevent-0.1.1.tar.gz
  • Upload date:
  • Size: 19.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.4.2 requests/2.21.0 setuptools/52.0.0 requests-toolbelt/0.8.0 tqdm/4.28.1 CPython/3.9.1+

File hashes

Hashes for aevent-0.1.1.tar.gz
Algorithm Hash digest
SHA256 8f54df25454dbae1585f80ce9d193852fc243704c88551b343545f6687e07103
MD5 a52d81c678940bd413024b0cd2381217
BLAKE2b-256 b22f0e27e1dd69725b802be89b2022fc2940dcf594bd29ee80692dcbe3205750

See more details on using hashes here.

Supported by

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