Package: anosql
A Python library for using SQLInspired by the excellentYesqllibrary by Kris Jenkins.  In my mother
tongue,anomeansyes.If you are on python3.6+ or needanosqlto work withasyncio-based database drivers, see the related project,aiosql.Complete documentation is available atRead The Docs.Installation$ pip install anosqlUsageBasicsGiven aqueries.sqlfile:-- name: get-all-greetings
-- Get all the greetings in the databaseSELECT*FROMgreetings;-- name: select-users
-- Get all the users from the database,
-- and return it as a dictSELECT*FROMUSERS;We can issue SQL queries, like so:importanosqlimportpsycopg2importsqlite3# PostgreSQLconn=psycopg2.connect('...')queries=anosql.from_path('queries.sql','psycopg2')# Or, Sqlite3...conn=sqlite3.connect('cool.db')queries=anosql.from_path('queries.sql','sqlite3')queries.get_all_greetings(conn)# => [(1, 'Hi')]queries.get_all_greetings.__doc__# => Get all the greetings in the databasequeries.get_all_greetings.sql# => SELECT * FROM greetings;queries.available_queries# => ['get_all_greetings']ParametersOften, you want to change parts of the query dynamically, particularly values in
theWHEREclause.  You can use parameters to do this:-- name: get-greetings-for-language
-- Get all the greetings in the database for given languageSELECT*FROMgreetingsWHERElang=%s;And they become positional parameters:visitor_language="en"queries.get_greetings_for_language(conn,visitor_language)Named ParametersTo make queries with many parameters more understandable and maintainable, you
can give the parameters names:-- name: get-greetings-for-language-and-length
-- Get all the greetings in the database for given language and lengthSELECT*FROMgreetingsWHERElang=:langANDlen(greeting)<=:length_limit;If you were writing a Postgresql query, you could also format the parameters as%s(lang)and%s(length_limit).Then, call your queries like you would any Python function with named
parameters:visitor_language="en"greetings_for_texting=queries.get_greetings_for_language_and_length(conn,lang=visitor_language,length_limit=140)Update/Insert/DeleteIn order to runUPDATE,INSERT, orDELETEstatements, you need to
add!to the end of your query name.  Anosql will then execute it properly.
It will also return the number of affected rows.Insert queries returning autogenerated valuesIf you want the auto-generated primary key to be returned after you run an
insert query, you can add<!to the end of your query name.-- name: create-user<!INSERTINTOperson(name)VALUES(:name)Adding custom query loaders.Out of the box,anosqlsupports SQLite and PostgreSQL via the stdlibsqlite3database driver
andpsycopg2. If you would like to extendanosqlto communicate with other types of databases,
you may create a driver adapter class and register it withanosql.core.register_driver_adapter().Driver adapters are duck-typed classes which adhere to the below interface. Looking atanosql/adapterspackage
is a good place to get started by looking at how thepsycopg2andsqlite3adapters work.To register a new loader:import anosql
import anosql.core

class MyDbAdapter():
    def process_sql(self, name, op_type, sql):
        pass

    def select(self, conn, sql, parameters):
        pass

    @contextmanager
    def select_cursor(self, conn, sql, parameters):
        pass

    def insert_update_delete(self, conn, sql, parameters):
        pass

    def insert_update_delete_many(self, conn, sql, parameters):
        pass

    def insert_returning(self, conn, sql, parameters):
        pass

    def execute_script(self, conn, sql):
        pass


anosql.core.register_driver_adapter("mydb", MyDbAdapter)

# To use make a connection to your db, and pass "mydb" as the db_type:
import mydbdriver
conn = mydbriver.connect("...")

anosql.load_queries("path/to/sql/", "mydb")
greetings = anosql.get_greetings(conn)

conn.close()If your adapter constructor takes arguments, you can register a function which can build
your adapter instance:def adapter_factory():
    return MyDbAdapter("foo", 42)

anosql.register_driver_adapter("mydb", adapter_factory)Tests$ pip install tox
$ toxLicenseBSD, short and sweet