summaryrefslogtreecommitdiff
path: root/test/base/test_concurrency_py3k.py
diff options
context:
space:
mode:
authorFederico Caselli <cfederico87@gmail.com>2022-04-15 00:29:01 +0200
committerFederico Caselli <cfederico87@gmail.com>2022-04-17 10:44:42 +0200
commit73f2b5bcdcc431ec77c62ffd49bdcbf4718fbfc1 (patch)
treec0cddb5695e80213bbfc19e2d246c9be93379094 /test/base/test_concurrency_py3k.py
parentc538f810bce57472c8960a0a6c4c61024b00f3ed (diff)
downloadsqlalchemy-73f2b5bcdcc431ec77c62ffd49bdcbf4718fbfc1.tar.gz
Allow contextvars to be set in events when using asyncio
Allow setting contextvar values inside async adapted event handlers. Previously the value set to the contextvar would not be properly propagated. Fixes: #7937 Change-Id: I787aa869f8d057579e13e32c749f05f184ffd02a
Diffstat (limited to 'test/base/test_concurrency_py3k.py')
-rw-r--r--test/base/test_concurrency_py3k.py38
1 files changed, 31 insertions, 7 deletions
diff --git a/test/base/test_concurrency_py3k.py b/test/base/test_concurrency_py3k.py
index 79601019e..6a3098a6a 100644
--- a/test/base/test_concurrency_py3k.py
+++ b/test/base/test_concurrency_py3k.py
@@ -1,4 +1,6 @@
import asyncio
+import contextvars
+import random
import threading
from sqlalchemy import exc
@@ -88,7 +90,8 @@ class TestAsyncioCompat(fixtures.TestBase):
to_await = run1()
with expect_raises_message(
exc.MissingGreenlet,
- r"greenlet_spawn has not been called; can't call await_\(\) here.",
+ "greenlet_spawn has not been called; "
+ r"can't call await_only\(\) here.",
):
await_only(to_await)
@@ -133,7 +136,8 @@ class TestAsyncioCompat(fixtures.TestBase):
with expect_raises_message(
exc.InvalidRequestError,
- r"greenlet_spawn has not been called; can't call await_\(\) here.",
+ "greenlet_spawn has not been called; "
+ r"can't call await_only\(\) here.",
):
await greenlet_spawn(go)
@@ -141,24 +145,44 @@ class TestAsyncioCompat(fixtures.TestBase):
@async_test
async def test_contextvars(self):
- import asyncio
- import contextvars
-
var = contextvars.ContextVar("var")
- concurrency = 5
+ concurrency = 500
+ # NOTE: sleep here is not necessary. It's used to simulate IO
+ # ensuring that task are not run sequentially
async def async_inner(val):
+ await asyncio.sleep(random.uniform(0.005, 0.015))
eq_(val, var.get())
return var.get()
+ async def async_set(val):
+ await asyncio.sleep(random.uniform(0.005, 0.015))
+ var.set(val)
+
def inner(val):
retval = await_only(async_inner(val))
eq_(val, var.get())
eq_(retval, val)
+
+ # set the value in a sync function
+ newval = val + concurrency
+ var.set(newval)
+ syncset = await_only(async_inner(newval))
+ eq_(newval, var.get())
+ eq_(syncset, newval)
+
+ # set the value in an async function
+ retval = val + 2 * concurrency
+ await_only(async_set(retval))
+ eq_(var.get(), retval)
+ eq_(await_only(async_inner(retval)), retval)
+
return retval
async def task(val):
+ await asyncio.sleep(random.uniform(0.005, 0.015))
var.set(val)
+ await asyncio.sleep(random.uniform(0.005, 0.015))
return await greenlet_spawn(inner, val)
values = {
@@ -167,7 +191,7 @@ class TestAsyncioCompat(fixtures.TestBase):
[task(i) for i in range(concurrency)]
)
}
- eq_(values, set(range(concurrency)))
+ eq_(values, set(range(concurrency * 2, concurrency * 3)))
@async_test
async def test_require_await(self):