Package: aiosql
SQLis code.
Write it, version control it, comment it, and run it using files.
Writing your SQL code in Python programs as strings doesn’t allow you to easily
reuse them in SQL GUIs or CLI tools likepsql.
With aiosql you can organize your SQL statements in.sqlfiles, load them
into your python application as methods to call without losing the ability to
use them as you would any other SQL file.This project supports standardPEP 249andasynciobased drivers forSQLite(sqlite3,aiosqlite,apsw),PostgreSQL(psycopg (3),psycopg2,pg8000,pygresql,asyncpg),MySQL(PyMySQL,mysqlclient,mysql-connector),MariaDB(mariadb) andDuckDB(duckdb),
out of the box.
Note that some detailed feature support may vary depending on the underlying driver
and database engine actual capabilities.This module is an implementation ofKris Jenkins’ yesqlClojurelibrary to thePythonecosystem.
Extensions to support other database drivers can be written by you!
See:Database Driver Adapters.
Feel free to pull request!BadgesUsageInstall frompypi, for instance by runningpip install aiosql.Then write parametric SQL queries in a file and execute it from Python methods,
eg thisgreetings.sqlfile:-- name: get_all_greetings
-- Get all the greetings in the databaseselectgreeting_id,greetingfromgreetingsorderby1;-- name: get_user_by_username^
-- Get a user from the database using a named parameterselectuser_id,username,namefromuserswhereusername=:username;This example has an imaginary SQLite database with greetings and users.
It prints greetings in various languages to the user and showcases the basic
feature of being able to load queries from a SQL file and call them by name
in python code.You can useaiosqlto load the queries in this file for use in your Python
application:importaiosqlimportsqlite3queries=aiosql.from_path("greetings.sql","sqlite3")withsqlite3.connect("greetings.db")asconn:user=queries.get_user_by_username(conn,username="willvaughn")# user: (1, "willvaughn", "William")for_,greetinginqueries.get_all_greetings(conn):# scan [(1, "Hi"), (2, "Aloha"), (3, "Hola"), …]print(f"{greeting},{user[2]}!")# Hi, William!# Aloha, William!# …Or even in an asynchroneous way, with two SQL queries running in parallel
usingaiosqliteandasyncio:importasyncioimportaiosqlimportaiosqlitequeries=aiosql.from_path("greetings.sql","aiosqlite")asyncdefmain():asyncwithaiosqlite.connect("greetings.db")asconn:# Parallel queries!greetings,user=awaitasyncio.gather(queries.get_all_greetings(conn),queries.get_user_by_username(conn,username="willvaughn"))for_,greetingingreetings:print(f"{greeting},{user[2]}!")asyncio.run(main())It may seem inconvenient to provide a connection on each call.
You may have a look at theAnoDBDBclass which wraps both a database connection and query functions in one
connection-like extended object, including managing automatic reconnection if
needed.Why you might want to use thisYou think SQL is pretty good, and writing SQL is an important part of your applications.You don’t want to write your SQL in strings intermixed with your python code.You’re not using an ORM likeSQLAlchemyorDjango,
with large (100k lines) code imprints vs about 800 foraiosql,
and you don’t need to.You want to be able to reuse your SQL in other contexts.
Loading it intopsqlor other database tools.Why you might NOT want to use thisYou’re looking for anORM.You aren’t comfortable writing SQL code.You don’t have anything in your application that requires complicated SQL beyond basic CRUD operations.Dynamically loaded objects built at runtime really bother you.