Skip to content
Merged
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
1 change: 0 additions & 1 deletion asynq/batching.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from . import _debug
from . import profiler


__traceback_hide__ = True

_debug_options = _debug.options
Expand Down
75 changes: 55 additions & 20 deletions asynq/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

import asyncio
import inspect
from typing import Any, Coroutine
import logging
from collections.abc import Coroutine
from typing import Any

import qcore.decorators
import qcore.helpers as core_helpers
Expand All @@ -25,6 +27,7 @@
from .asynq_to_async import AsyncioMode, is_asyncio_mode, resolve_awaitables

__traceback_hide__ = True
logger = logging.getLogger("asynq")


def lazy(fn):
Expand Down Expand Up @@ -147,12 +150,13 @@ def is_pure_async_fn(self):
class PureAsyncDecorator(qcore.decorators.DecoratorBase):
binder_cls = PureAsyncDecoratorBinder

def __init__(self, fn, task_cls, kwargs={}, asyncio_fn=None):
def __init__(self, fn, task_cls, kwargs={}, asyncio_fn=None, allow_sync_call=False):
qcore.decorators.DecoratorBase.__init__(self, fn)
self.task_cls = task_cls
self.needs_wrapper = core_inspection.is_cython_or_generator(fn)
self.kwargs = kwargs
self.asyncio_fn = asyncio_fn
self.allow_sync_call = allow_sync_call

def name(self):
return "@asynq(pure=True)"
Expand Down Expand Up @@ -202,8 +206,8 @@ def asyncio(self, *args, **kwargs) -> Coroutine[Any, Any, Any]:
class AsyncDecorator(PureAsyncDecorator):
binder_cls = AsyncDecoratorBinder

def __init__(self, fn, cls, kwargs={}, asyncio_fn=None):
super().__init__(fn, cls, kwargs, asyncio_fn)
def __init__(self, fn, cls, kwargs={}, asyncio_fn=None, allow_sync_call=False):
super().__init__(fn, cls, kwargs, asyncio_fn, allow_sync_call)

def is_pure_async_fn(self):
return False
Expand All @@ -216,9 +220,16 @@ def name(self):

def __call__(self, *args, **kwargs):
if is_asyncio_mode():
raise RuntimeError("asyncio mode does not support synchronous calls")

return self._call_pure(args, kwargs).value()
if self.allow_sync_call:
logger.warning(
f"asyncio mode does not support synchronous calls: {self.fn.__name__} at {inspect.getsourcefile(self.fn)}"
)
else:
raise RuntimeError(
f"asyncio mode does not support synchronous calls: {self.fn.__name__} at {inspect.getsourcefile(self.fn)}"
)
else:
return self._call_pure(args, kwargs).value()


class AsyncAndSyncPairDecoratorBinder(AsyncDecoratorBinder):
Expand All @@ -232,14 +243,24 @@ def __call__(self, *args, **kwargs):
class AsyncAndSyncPairDecorator(AsyncDecorator):
binder_cls = AsyncAndSyncPairDecoratorBinder

def __init__(self, fn, cls, sync_fn, kwargs={}, asyncio_fn=None):
AsyncDecorator.__init__(self, fn, cls, kwargs, asyncio_fn)
def __init__(
self, fn, cls, sync_fn, kwargs={}, asyncio_fn=None, allow_sync_call=False
):
AsyncDecorator.__init__(self, fn, cls, kwargs, asyncio_fn, allow_sync_call)
self.sync_fn = sync_fn

def __call__(self, *args, **kwargs):
if is_asyncio_mode():
raise RuntimeError("asyncio mode does not support synchronous calls")
return self.sync_fn(*args, **kwargs)
if self.allow_sync_call:
logger.warning(
f"asyncio mode does not support synchronous calls: {self.fn.__name__} at {inspect.getsourcefile(self.fn)}"
)
else:
raise RuntimeError(
f"asyncio mode does not support synchronous calls: {self.fn.__name__} at {inspect.getsourcefile(self.fn)}"
)
else:
return self.sync_fn(*args, **kwargs)

def __get__(self, owner, cls):
# This is needed so that we can use objects with __get__ as the sync_fn. If we just rely on
Expand All @@ -262,9 +283,11 @@ def __get__(self, owner, cls):


class AsyncProxyDecorator(AsyncDecorator):
def __init__(self, fn, asyncio_fn=None):
def __init__(self, fn, asyncio_fn=None, allow_sync_call=False):
# we don't need the task class but still need to pass it to the superclass
AsyncDecorator.__init__(self, fn, None, asyncio_fn=asyncio_fn)
AsyncDecorator.__init__(
self, fn, None, asyncio_fn=asyncio_fn, allow_sync_call=allow_sync_call
)

def asyncio(self, *args, **kwargs) -> Coroutine[Any, Any, Any]:
if self.asyncio_fn is None:
Expand All @@ -288,16 +311,23 @@ def _call_pure(self, args, kwargs):


class AsyncAndSyncPairProxyDecorator(AsyncProxyDecorator):
def __init__(self, fn, sync_fn, asyncio_fn=None):
AsyncProxyDecorator.__init__(self, fn, asyncio_fn=asyncio_fn)
def __init__(self, fn, sync_fn, asyncio_fn=None, allow_sync_call=False):
AsyncProxyDecorator.__init__(
self, fn, asyncio_fn=asyncio_fn, allow_sync_call=allow_sync_call
)
self.sync_fn = sync_fn

def __call__(self, *args, **kwargs):
return self.sync_fn(*args, **kwargs)


def asynq(
pure=False, sync_fn=None, cls=async_task.AsyncTask, asyncio_fn=None, **kwargs
pure=False,
sync_fn=None,
cls=async_task.AsyncTask,
asyncio_fn=None,
allow_sync_call=False,
**kwargs,
):
"""Async task decorator.
Converts a method returning generator object to
Expand All @@ -317,18 +347,23 @@ def decorate(fn):
return qcore.decorators.decorate(PureAsyncDecorator, cls, kwargs)(fn)
elif sync_fn is None:
decorated = qcore.decorators.decorate(
AsyncDecorator, cls, kwargs, asyncio_fn
AsyncDecorator, cls, kwargs, asyncio_fn, allow_sync_call
)(fn)
return decorated
else:
return qcore.decorators.decorate(
AsyncAndSyncPairDecorator, cls, sync_fn, kwargs, asyncio_fn
AsyncAndSyncPairDecorator,
cls,
sync_fn,
kwargs,
asyncio_fn,
allow_sync_call,
)(fn)

return decorate


def async_proxy(pure=False, sync_fn=None, asyncio_fn=None):
def async_proxy(pure=False, sync_fn=None, asyncio_fn=None, allow_sync_call=False):
if sync_fn is not None:
assert pure is False, "sync_fn=? cannot be used together with pure=True"

Expand All @@ -339,7 +374,7 @@ def decorate(fn):
return qcore.decorators.decorate(AsyncProxyDecorator, asyncio_fn)(fn)
else:
return qcore.decorators.decorate(
AsyncAndSyncPairProxyDecorator, sync_fn, asyncio_fn
AsyncAndSyncPairProxyDecorator, sync_fn, asyncio_fn, allow_sync_call
)(fn)

return decorate
Expand Down
8 changes: 8 additions & 0 deletions asynq/decorators.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class PureAsyncDecorator(qcore.decorators.DecoratorBase, Generic[_T, _P]):
task_cls: Optional[type[futures.FutureBase]],
kwargs: Mapping[str, Any] = ...,
asyncio_fn: Optional[Callable[_P, Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
) -> None: ...
@overload
def __init__(
Expand All @@ -54,6 +55,7 @@ class PureAsyncDecorator(qcore.decorators.DecoratorBase, Generic[_T, _P]):
task_cls: Optional[type[futures.FutureBase]],
kwargs: Mapping[str, Any] = ...,
asyncio_fn: Optional[Callable[_P, Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
) -> None: ...
def name(self) -> str: ...
def is_pure_async_fn(self) -> bool: ...
Expand Down Expand Up @@ -84,6 +86,7 @@ class AsyncDecorator(PureAsyncDecorator[_T, _P]):
cls: Optional[type[futures.FutureBase]],
kwargs: Mapping[str, Any] = ...,
asyncio_fn: Optional[Callable[_P, Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
): ...
@overload
def __init__(
Expand All @@ -92,6 +95,7 @@ class AsyncDecorator(PureAsyncDecorator[_T, _P]):
cls: Optional[type[futures.FutureBase]],
kwargs: Mapping[str, Any] = ...,
asyncio_fn: Optional[Callable[_P, Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
): ...
def is_pure_async_fn(self) -> bool: ...
def asynq(self, *args: Any, **kwargs: Any) -> async_task.AsyncTask[_T]: ...
Expand All @@ -117,6 +121,7 @@ class AsyncProxyDecorator(AsyncDecorator[_T, _P]):
self,
fn: Callable[..., futures.FutureBase[_T]],
asyncio_fn: Optional[Callable[..., Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
) -> None: ...

class AsyncAndSyncPairProxyDecorator(AsyncProxyDecorator[_T, _P]):
Expand All @@ -125,6 +130,7 @@ class AsyncAndSyncPairProxyDecorator(AsyncProxyDecorator[_T, _P]):
fn: Callable[..., futures.FutureBase[_T]],
sync_fn: Callable[..., _T],
asyncio_fn: Optional[Callable[..., Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
) -> None: ...
def __call__(self, *args: Any, **kwargs: Any) -> _T: ...

Expand All @@ -142,6 +148,7 @@ def asynq(
sync_fn: Optional[Callable[_P, _T]] = ...,
cls: type[futures.FutureBase] = ...,
asyncio_fn: Optional[Callable[_P, Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
**kwargs: Any,
) -> _MkAsyncDecorator: ...
@overload
Expand All @@ -151,6 +158,7 @@ def asynq(
sync_fn: Optional[Callable[_P, _T]] = ...,
cls: type[futures.FutureBase] = ...,
asyncio_fn: Optional[Callable[_P, Coroutine[Any, Any, _T]]] = ...,
allow_sync_call: bool = ...,
**kwargs: Any,
) -> _MkPureAsyncDecorator: ...
@overload
Expand Down
1 change: 0 additions & 1 deletion asynq/futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from . import debug
from . import _debug


__traceback_hide__ = True


Expand Down
1 change: 0 additions & 1 deletion asynq/scoped_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

from . import contexts


_empty_context = qcore.empty_context


Expand Down
1 change: 0 additions & 1 deletion asynq/tests/debug_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from asynq import scheduler
from .caching import ExternalCacheBase, LocalCache


# Caches


Expand Down
1 change: 0 additions & 1 deletion asynq/tests/test_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from asynq import asynq, async_proxy, ConstFuture
from collections import deque


# TODO(alex): finish w/this test


Expand Down
1 change: 0 additions & 1 deletion asynq/tests/test_contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from .debug_cache import mc
from .caching import ExternalCacheBatchItem


current_context = None
change_amount = 0

Expand Down
1 change: 0 additions & 1 deletion asynq/tests/test_multiple_inheritance.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from asynq import asynq


called = {}


Expand Down
1 change: 0 additions & 1 deletion asynq/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from . import async_task
from . import _debug


_debug_options = _debug.options


Expand Down