Skip to content

Commit c440c61

Browse files
author
Vincent MAILLOL
committed
Fix pass callable object to sync_to_async
1 parent b7b15b2 commit c440c61

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

asgiref/sync.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,11 @@ def __init__(
432432
or iscoroutinefunction(getattr(func, "__call__", func))
433433
):
434434
raise TypeError("sync_to_async can only be applied to sync functions.")
435+
436+
functools.update_wrapper(self, func)
435437
self.func = func
436438
self.context = context
437-
functools.update_wrapper(self, func)
439+
438440
self._thread_sensitive = thread_sensitive
439441
markcoroutinefunction(self)
440442
if thread_sensitive and executor is not None:

tests/test_sync_contextvars.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,24 @@ async def async_function():
138138
sync_function = async_to_sync(async_function)
139139
assert sync_function() == 42
140140
assert foo.get() == "baz"
141+
142+
143+
@pytest.mark.asyncio
144+
async def test_sync_to_async_contextvars_with_callable_with_context_attribute():
145+
"""
146+
Tests that a callable object with a `context` attribute
147+
can be wrapped with `sync_to_async` without overwriting the `context` attribute
148+
and still returns the expected result.
149+
"""
150+
# Define sync Callable
151+
class SyncCallable:
152+
def __init__(self):
153+
# Should not be copied to the SyncToAsync wrapper.
154+
self.context = ...
155+
156+
def __call__(self):
157+
return 42
158+
159+
async_function = sync_to_async(SyncCallable())
160+
assert async_function.context is None
161+
assert await async_function() == 42

0 commit comments

Comments
 (0)