From: Mike Bayer Date: Tue, 11 Oct 2022 18:22:40 +0000 (-0400) Subject: enable check same thread for aiosqlite X-Git-Tag: rel_2_0_0b1~6^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d132a7cf96678a732b06266fa0a35279268604b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git enable check same thread for aiosqlite to do this we have to invent our own isolation level setter based on their current internals. however now we can ensure thread-safe access. we are trying to resolve an issue where test suite on CI seems to fail around the same time each time. Change-Id: I79c8fc04b9afef0876fb446ad40a7621a772cd34 --- diff --git a/lib/sqlalchemy/dialects/sqlite/aiosqlite.py b/lib/sqlalchemy/dialects/sqlite/aiosqlite.py index 97ea1b2b36..c3926e1215 100644 --- a/lib/sqlalchemy/dialects/sqlite/aiosqlite.py +++ b/lib/sqlalchemy/dialects/sqlite/aiosqlite.py @@ -47,6 +47,9 @@ in Python and use them directly in SQLite queries as described here: :ref:`pysql """ # noqa +import asyncio +from functools import partial + from .base import SQLiteExecutionContext from .pysqlite import SQLiteDialect_pysqlite from ... import pool @@ -187,8 +190,22 @@ class AsyncAdapt_aiosqlite_connection(AdaptedConnection): @isolation_level.setter def isolation_level(self, value): + + # aiosqlite's isolation_level setter works outside the Thread + # that it's supposed to, necessitating setting check_same_thread=False. + # for improved stability, we instead invent our own awaitable version + # using aiosqlite's async queue directly. + + def set_iso(connection, value): + connection.isolation_level = value + + function = partial(set_iso, self._connection._conn, value) + future = asyncio.get_event_loop().create_future() + + self._connection._tx.put_nowait((future, function)) + try: - self._connection.isolation_level = value + return self.await_(future) except Exception as error: self._handle_exception(error) @@ -272,18 +289,6 @@ class AsyncAdapt_aiosqlite_dbapi: def connect(self, *arg, **kw): async_fallback = kw.pop("async_fallback", False) - # Q. WHY do we need this? - # A. Because there is no way to set connection.isolation_level - # otherwise - # Q. BUT HOW do you know it is SAFE ????? - # A. The only operation that isn't safe is the isolation level set - # operation which aiosqlite appears to have let slip through even - # though pysqlite appears to do check_same_thread for this. - # All execute operations etc. should be safe because they all - # go through the single executor thread. - - kw["check_same_thread"] = False - connection = self.aiosqlite.connect(*arg, **kw) # it's a Thread. you'll thank us later