Skip to content

Commit

Permalink
Remove asgiref dependency from non Django code
Browse files Browse the repository at this point in the history
  • Loading branch information
medihack committed Oct 19, 2024
1 parent df98e61 commit 6acbf87
Show file tree
Hide file tree
Showing 9 changed files with 20 additions and 26 deletions.
6 changes: 3 additions & 3 deletions docs/discussions.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,11 @@ When you define an asynchronous connector, Procrastinate will try to
seamlessly give you the right connector for your context. When you call
the synchronous API, it will either create a sync connector based on your
async connector, or let you use the async connector directly with
`asgiref.sync.async_to_sync`.
`asyncio.run`.
:::

For running jobs, support of synchronous task functions is through
`asgiref.sync.sync_to_async`. This means your synchronous function will be
`asyncio.to_thread`. This means your synchronous function will be
executed by an asynchronous worker in a thread. Because of the [Global
Interpreter Lock][global interpreter lock], you will not benefit from parallelism, but you will still be able
to parallelize (thread-safe) I/Os.
Expand Down Expand Up @@ -290,7 +290,7 @@ Procrastinate:
driver. Under the hood, we have factored as much as possible the non-I/O
parts of the code, so that the synchronous and asynchronous versions are
only separate in the way they handle I/Os.
- For executing a synchronous task: we use `asgiref.sync.sync_to_async` to run the
- For executing a synchronous task: we use `asyncio.to_thread` to run the
synchronous code in a thread.
- There are a few case where we facilitate calling Procrastinate from
synchronous codebases, by providing a synchronous API, where we'll create an
Expand Down
6 changes: 3 additions & 3 deletions docs/howto/advanced/sync_defer.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ be using a synchronous connector.

If you request the synchronous connector after opening the app, you will get
the asynchronous connector, with a compatibility layer to make synchronous
operations. This will only work if you call it inside a function decorated
with `asgiref.sync.sync_to_async` (such as inside a sync job). Otherwise,
you will likely get a `RuntimeError`.
operations. This will only work if you call it inside a function that runs
in its own thread (such as inside a sync job). Otherwise, you will likely
get a `RuntimeError`.
:::
4 changes: 2 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions procrastinate/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
)

import dateutil.parser
from asgiref import sync

from procrastinate import exceptions
from procrastinate.types import TimeDeltaParams
Expand Down Expand Up @@ -96,15 +95,19 @@ def async_to_sync(awaitable: Callable[..., Awaitable[T]], *args, **kwargs) -> T:
Given a callable returning an awaitable, call the callable, await it
synchronously. Returns the result after it's done.
"""
return sync.async_to_sync(awaitable)(*args, **kwargs)

async def wrapper() -> T:
return await awaitable(*args, **kwargs)

return asyncio.run(wrapper())


async def sync_to_async(func: Callable[..., T], *args, **kwargs) -> T:
"""
Given a callable, return a callable that will call the original one in an
async context.
"""
return await sync.sync_to_async(func, thread_sensitive=False)(*args, **kwargs)
return await asyncio.to_thread(func, *args, **kwargs)


def causes(exc: BaseException | None):
Expand Down
6 changes: 1 addition & 5 deletions procrastinate_demos/demo_async/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@
import json
import logging

import asgiref.sync

from . import app as app_module
from . import tasks

ainput = asgiref.sync.sync_to_async(input)


async def main():
logging.info("Running app in async context")
Expand All @@ -22,7 +18,7 @@ async def main():
print("Enter an empty line to quit")
print()
while True:
response = (await ainput("Your input: ")).strip()
response = (await asyncio.to_thread(input, "Your input: ")).strip()
if not response:
break
command, *args = (response).split(maxsplit=1)
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ procrastinate = 'procrastinate.cli:main'
python = "^3.9"
aiopg = { version = "*", optional = true }
anyio = "*"
asgiref = "*"
asgiref = { version = "*", optional = true }
attrs = "*"
contextlib2 = { version = "*", python = "<3.10" }
croniter = "*"
Expand All @@ -39,7 +39,7 @@ typing-extensions = "*"
sphinx = { version = "*", optional = true }

[tool.poetry.extras]
django = ["django"]
django = ["asgiref", "django"]
sqlalchemy = ["sqlalchemy"]
aiopg = ["aiopg", "psycopg2-binary"]
psycopg2 = ["psycopg2-binary"]
Expand Down
3 changes: 1 addition & 2 deletions tests/acceptance/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import time

import pytest
from asgiref.sync import sync_to_async

import procrastinate
from procrastinate.contrib import psycopg2
Expand Down Expand Up @@ -70,7 +69,7 @@ def _inner_sum_task_sync(a, b):
sum_results.append(a + b)

# Only works if the worker runs the sync task in a separate thread
await sync_to_async(_inner_sum_task_sync)(a, b)
await asyncio.to_thread(_inner_sum_task_sync, a, b)

asyncio.run(_sum_task_async(a, b))

Expand Down
4 changes: 1 addition & 3 deletions tests/integration/contrib/aiopg/test_aiopg_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import functools
import json

import asgiref.sync
import attr
import pytest

Expand Down Expand Up @@ -101,7 +100,6 @@ async def test_get_sync_connector(aiopg_connector_factory):

aiopg_connector = await aiopg_connector_factory(open=False)

@asgiref.sync.sync_to_async
def f():
sync_conn = aiopg_connector.get_sync_connector()
sync_conn.open()
Expand All @@ -110,7 +108,7 @@ def f():
finally:
sync_conn.close()

await f()
await asyncio.to_thread(f)
assert list(result[0].values()) == [1]


Expand Down
4 changes: 1 addition & 3 deletions tests/integration/test_psycopg_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import functools
import json

import asgiref.sync
import attr
import pytest

Expand Down Expand Up @@ -112,7 +111,6 @@ async def test_wrap_exceptions(psycopg_connector):


async def test_execute_query_sync(psycopg_connector):
@asgiref.sync.sync_to_async()
def sync():
assert (
psycopg_connector.execute_query(
Expand All @@ -130,7 +128,7 @@ def sync():
)
assert result == [{"obj_description": "foo"}]

await sync()
await asyncio.to_thread(sync)


async def test_execute_query_interpolate(psycopg_connector):
Expand Down

0 comments on commit 6acbf87

Please sign in to comment.