Skip to content

Async Trampoline #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions effect/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"""

from ._base import Effect, perform, NoPerformerFoundError, catch, raise_
from ._sync import NotSynchronousError, sync_perform, sync_performer
from ._sync import NotSynchronousError, async_perform, sync_performer
from ._intents import (
Delay,
perform_delay_with_sleep,
Expand All @@ -27,7 +27,7 @@
__all__ = [
# Order here affects the order that these things show up in the API docs.
"Effect",
"sync_perform",
"async_perform",
"sync_performer",
"base_dispatcher",
"TypeDispatcher",
Expand Down
18 changes: 9 additions & 9 deletions effect/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ def __init__(self, cont):
"""
self._cont = cont

def succeed(self, result):
async def succeed(self, result):
"""
Indicate that the effect has succeeded, and the result is available.
"""
self._cont((False, result))
await self._cont((False, result))

def fail(self, result):
"""
Expand All @@ -77,7 +77,7 @@ class NoPerformerFoundError(Exception):
"""Raised when a performer for an intent couldn't be found."""


def perform(dispatcher, effect):
async def perform(dispatcher, effect):
"""
Perform an effect and invoke callbacks bound to it. You probably don't want
to use this. Instead, use :func:`sync_perform` (or, if you're using
Expand Down Expand Up @@ -120,11 +120,11 @@ def perform(dispatcher, effect):
an exception. Decorators like :func:`sync_performer` simply abstract this away.
"""

def _run_callbacks(bouncer, chain, result):
async def _run_callbacks(bouncer, chain, result):
is_error, value = result

if type(value) is Effect:
bouncer.bounce(
await bouncer.bounce(
_perform, Effect(value.intent, callbacks=value.callbacks + chain)
)
return
Expand All @@ -136,23 +136,23 @@ def _run_callbacks(bouncer, chain, result):
if cb is not None:
result = guard(cb, value)
chain = chain[1:]
bouncer.bounce(_run_callbacks, chain, result)
await bouncer.bounce(_run_callbacks, chain, result)

def _perform(bouncer, effect):
async def _perform(bouncer, effect):
try:
performer = dispatcher(effect.intent)
if performer is None:
raise NoPerformerFoundError(effect.intent)
else:
performer(
await performer(
dispatcher,
effect.intent,
_Box(partial(bouncer.bounce, _run_callbacks, effect.callbacks)),
)
except Exception as e:
_run_callbacks(bouncer, effect.callbacks, (True, e))

trampoline(_perform, effect)
await trampoline(_perform, effect)


def catch(exc_type, callable):
Expand Down
8 changes: 4 additions & 4 deletions effect/_continuation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Bouncer(object):
work = None
_asynchronous = False

def bounce(self, func, *args, **kwargs):
async def bounce(self, func, *args, **kwargs):
"""
Bounce a function off the trampoline -- in other words, signal to the
trampoline that the given function should be run. It will be passed a
Expand All @@ -23,11 +23,11 @@ def bounce(self, func, *args, **kwargs):
)
self.work = (func, args, kwargs)
if self._asynchronous:
trampoline(func, *args, **kwargs)
await trampoline(func, *args, **kwargs)
return


def trampoline(f, *args, **kwargs):
async def trampoline(f, *args, **kwargs):
"""
An asynchronous trampoline.

Expand All @@ -54,7 +54,7 @@ def trampoline(f, *args, **kwargs):
"""
while True:
bouncer = Bouncer()
f(bouncer, *args, **kwargs)
await f(bouncer, *args, **kwargs)
if bouncer.work is not None:
f, args, kwargs = bouncer.work
else:
Expand Down
4 changes: 2 additions & 2 deletions effect/_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class NotSynchronousError(Exception):
"""Performing an effect did not immediately return a value."""


def sync_perform(dispatcher, effect):
async def async_perform(dispatcher, effect):
"""
Perform an effect, and return its ultimate result. If the final result is
an error, the exception will be raised.
Expand All @@ -24,7 +24,7 @@ def sync_perform(dispatcher, effect):
successes = []
errors = []
effect = effect.on(success=successes.append, error=errors.append)
perform(dispatcher, effect)
await perform(dispatcher, effect)
if successes:
return successes[0]
elif errors:
Expand Down