Package: easqlite
easqliteA simple Executor-based async sqlite wrapper.This is used very similarly to the standardsqlite3module.By default,ThreadPoolExecutor(max_workers=1)is used as the executor.  If you
pass your own executor, you are responsible for shutting it down and ensuring it
only uses one thread.Differences fromsqlite3:connectis not a function, but just an alias to theConnectionclass.Connectcheck_same_threaddefaults to__debug__instead ofTrueConnection's constructor takes an optionalexecutorargument.Every method, function, context manager, property accessor, and iterator is
awaitable.Connection.interruptoperates immediately without beingawaited, and its
returned coroutine is actually a no-op.Every call that takes a factory uses the factory for the internal calls, and
defers to a statically defined wrapper class.  The internal calls will still
use the factories.All objects with aclosemethod are async context managers.All properties are now methods with an optional setter parameter, so they
are properly awaitable and set and get on the same thread.An exception to this isCursor.connection, which is still a property.Blob.__getitem__is async, butBlob.__setitem__can not be.Blob.setis
provided instead, with the exact same semantics (it can be passed aslice).
You can useBlob.__setitem__, but it doesn't actually directly set the blob,
but rather queues a set to be run on flush.  Any other coroutine flushes the
blob, or you can use an explicitBlob.flush, or just let the blob exit its
context manager.Blob.__len__andBlob.__bool__block on the executor.Blob.lenandblob.boolare async replacements for these.Connection,Cursor, andBlobare lazy.  They will not open on
construction, but will open when awaited, or when entered as an asynchronous
context manager.All these objects must be either awaited or used as an asynchronous context manager:# OK: The cursor was awaitedcursor=awaitconnection.cursor()awaitcursor.execute(sql)asyncforrowincursor:do_something_with(row)# ERROR: the cursor is not openedcursor=connection.cursor()awaitcursor.execute(sql)asyncforrowincursor:do_something_with(row)# OK: The cursor was entered (the preferred style)asyncwithconnection.cursor()ascursor:awaitcursor.execute(sql)asyncforrowincursor:do_something_with(row)# The connection.execute family are coroutines, and must be awaited.# OK: The coroutine was awaited, and returns an open cursor.asyncwithawaitconnection.execute(sql)ascursor:asyncforrowincursor:do_something_with(row)# ERROR: The connection.execute result is a coroutine.  It is not a context managerasyncwithconnection.execute(sql)ascursor:asyncforrowincursor:do_something_with(row)# OK: connection.execute opens its cursor, it can just be iterated.asyncforrowinawaitconnection.execute(sql):do_something_with(row)# ERROR: __aiter__ is not defined on a running coroutine.  It must be awaited.asyncforrowinconnection.execute(sql):do_something_with(row)This can be used nearly identically to the regular sqlite module if you sprinkle
anawaiton every function call, but it is preferred to use the async context
managers everywhere possible.  You can't easily go wrong when using the context
managers.Constants are not re-exported, so this library should usually be used in
conjunction with the core sqlite3 library.This is very similar in spirit to theaiosqliteproject, but this one takes a
more earnest attempt at deferring responsibility to other components.  This one
also should be more responsive on close, because it doesn't rely on a timeout to
shut itself off.This one also pushes much more extremely on async use, and defers everything it
can to the executor thread, even properties.If you want a more mature and battle-tested package, useaiosqlite.  In my
rough tests, it performs better than this package as well.