summaryrefslogtreecommitdiff
path: root/test/base/test_concurrency_py3k.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-07-04 12:21:36 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-08-13 18:41:53 -0400
commit5fb0138a3220161703e6ab1087319a669d14e7f4 (patch)
tree25d006b30830ce6bc71f7a69bed9b570e1ae9654 /test/base/test_concurrency_py3k.py
parentcd03b8f0cecbf72ecd6c99c4d3a6338c8278b40d (diff)
downloadsqlalchemy-5fb0138a3220161703e6ab1087319a669d14e7f4.tar.gz
Implement rudimentary asyncio support w/ asyncpg
Using the approach introduced at https://gist.github.com/zzzeek/6287e28054d3baddc07fa21a7227904e We can now create asyncio endpoints that are then handled in "implicit IO" form within the majority of the Core internals. Then coroutines are re-exposed at the point at which we call into asyncpg methods. Patch includes: * asyncpg dialect * asyncio package * engine, result, ORM session classes * new test fixtures, tests * some work with pep-484 and a short plugin for the pyannotate package, which seems to have so-so results Change-Id: Idbcc0eff72c4cad572914acdd6f40ddb1aef1a7d Fixes: #3414
Diffstat (limited to 'test/base/test_concurrency_py3k.py')
-rw-r--r--test/base/test_concurrency_py3k.py103
1 files changed, 103 insertions, 0 deletions
diff --git a/test/base/test_concurrency_py3k.py b/test/base/test_concurrency_py3k.py
new file mode 100644
index 000000000..10b89291e
--- /dev/null
+++ b/test/base/test_concurrency_py3k.py
@@ -0,0 +1,103 @@
+from sqlalchemy import exc
+from sqlalchemy.testing import async_test
+from sqlalchemy.testing import eq_
+from sqlalchemy.testing import expect_raises_message
+from sqlalchemy.testing import fixtures
+from sqlalchemy.util import await_fallback
+from sqlalchemy.util import await_only
+from sqlalchemy.util import greenlet_spawn
+
+
+async def run1():
+ return 1
+
+
+async def run2():
+ return 2
+
+
+def go(*fns):
+ return sum(await_only(fn()) for fn in fns)
+
+
+class TestAsyncioCompat(fixtures.TestBase):
+ @async_test
+ async def test_ok(self):
+
+ eq_(await greenlet_spawn(go, run1, run2), 3)
+
+ @async_test
+ async def test_async_error(self):
+ async def err():
+ raise ValueError("an error")
+
+ with expect_raises_message(ValueError, "an error"):
+ await greenlet_spawn(go, run1, err)
+
+ @async_test
+ async def test_sync_error(self):
+ def go():
+ await_only(run1())
+ raise ValueError("sync error")
+
+ with expect_raises_message(ValueError, "sync error"):
+ await greenlet_spawn(go)
+
+ def test_await_fallback_no_greenlet(self):
+ to_await = run1()
+ await_fallback(to_await)
+
+ def test_await_only_no_greenlet(self):
+ to_await = run1()
+ with expect_raises_message(
+ exc.InvalidRequestError,
+ r"greenlet_spawn has not been called; can't call await_\(\) here.",
+ ):
+ await_only(to_await)
+
+ # ensure no warning
+ await_fallback(to_await)
+
+ @async_test
+ async def test_await_fallback_error(self):
+ to_await = run1()
+
+ await to_await
+
+ async def inner_await():
+ nonlocal to_await
+ to_await = run1()
+ await_fallback(to_await)
+
+ def go():
+ await_fallback(inner_await())
+
+ with expect_raises_message(
+ exc.InvalidRequestError,
+ "greenlet_spawn has not been called and asyncio event loop",
+ ):
+ await greenlet_spawn(go)
+
+ await to_await
+
+ @async_test
+ async def test_await_only_error(self):
+ to_await = run1()
+
+ await to_await
+
+ async def inner_await():
+ nonlocal to_await
+ to_await = run1()
+ await_only(to_await)
+
+ def go():
+ await_only(inner_await())
+
+ with expect_raises_message(
+ exc.InvalidRequestError,
+ r"greenlet_spawn has not been called; can't call await_\(\) here.",
+ ):
+ await greenlet_spawn(go)
+
+ await to_await