Usage

Shillelagh implements the Python DB API 2.0 specification and a custom SQLAlchemy dialect. It also comes with a simple command-line utility to run queries from the console.

DB API 2.0

The DB API 2.0 specification defines standard mechanisms to create database connections and to work with cursors. Here’s a simple example that creates a table, inserts some data, and queries it:

from shillelagh.backends.apsw.db import connect

connection = connect(":memory:")
cursor = connection.cursor()

query = "CREATE TABLE a_table (A int, B string)"
cursor.execute(query)

query = "INSERT INTO a_table VALUES (?, ?)"
cursor.execute(query, (1, "one"))
cursor.execute(query, (2, "two"))

query = "SELECT * FROM a_table"
for row in cursor.execute(query):
    print(row)

You can use a file instead of :memory::

from shillelagh.backends.apsw.db import connect

connection = connect("/path/to/file.sqlite")

Note that using a file is not recommended for security reasons. Shillelagh works by creating virtual tables, and if a given resource requires credentials for access they will be stored in the table name.

Configuration

By default all available adapters are loaded by Shillelagh. It’s possible to limit the adapters that you want to load by passing a list of strings to the adapters argument when creating the connection:

from shillelagh.adapters.registry import registry
from shillelagh.backends.apsw.db import connect

# show names of available adapters
print(registry.loaders.keys())

# enable on the CSV and the WeatherAPI adapters
connection = connect(":memory:", adapters=["csvfile", "weatherapi"])

Some adapters allow optional configuration to be passed via keyword arguments. For example, we can specify an API key for WeatherAPI:

from shillelagh.backends.apsw.db import connect

connection = connect(":memory:", adapter_kwargs={"weatherapi": {"api_key": "XXX"}})

You can find the accepted arguments in the documentation of each one the Adapters.

When loading adapters, you can also specify the safe keyword. When set to true, this will ensure that only “safe” adapters are loaded — ie, adapters that have no access to the filesystem. The keyword also ensures that an exception is raised whenever there are repeated adapters with the same name, to prevent a malicious party from introducing an adapter with the same name as an authorized one:

from shillelagh.adapters.registry import registry
from shillelagh.adapters.file.csvfile import CSVFile
from shillelagh.backends.apsw.db import connect

registry.add('csvfile', CSVFile)
registry.add('csvfile', FakeAdapter)
connect(':memory:', adapters=['csvfile'], safe=True)

The code above will raise an exception saying “Multiple adapters found with name csvfile”. This is needed because adapters can be loaded from third-party libraries via entry points, and not just from the Shillelagh library.

Registering new adapters

Shillelagh uses a plugin registry similar to SQLAlchemy’s. Adapters that are registered via entry points are registered automatically, but you can manually register adapter classes:

from shillelagh.adapters.base import Adapter
from shillelagh.adapters.registry import registry

class CustomAdapter(Adapter):
    ...

# add an adapter class directly
registry.add('customadapter', CustomAdapter)

# add an adapter class by passing the module path and class name
registry.register('someotheradapter', 'path.to.module', 'ClassName')

SQLAlchemy

Shillelagh implements a SQLAlchemy dialect called shillelagh:

from sqlalchemy.engine import create_engine

engine = create_engine("shillelagh://")
connection = engine.connect()

query = "SELECT * FROM a_table"
for row in connection.execute(query):
    print(row)

Configuration

The SQLAlchemy engine can be configured in the same way as the DB API 2.0 connect function, defining the adapters to be loaded, passing custom keyword arguments to the adapters, or loading only safe adapters. For example, if you want to connect only to Google Spreadsheets, using credentials from a service account:

from sqlalchemy.engine import create_engine

engine = create_engine(
    "shillelagh://",
     adapters=["gsheetsapi"],
     adapter_kwargs={
         "gsheetsapi": {
             "service_account_file": "/path/to/credentials.json",
             "subject": "user@example.com",
         },
     },
)

Alternatively, Shillelagh also comes with a custom Google Sheets dialect for SQLAlchemy. See Google Sheets for more details.

Command-line utility

Shillelagh comes with a simple command-line utility aptly named shillelagh:

$ shillelagh
sql> SELECT * FROM "https://docs.google.com/spreadsheets/d/1_rN3lm0R_bU3NemO0s9pbFkY5LQPcuy1pscv8ZXPtg8/edit#gid=0";
country      cnt
---------  -----
BR             1
BR             3
IN             5
ZA             6
CR            10
sql>

The shillelagh application has very simple autocomplete, and runs the query on return.

Configuration

The command-line utility can be configured through a YAML file stored in ~/.config/shillelagh/shillelagh.yaml. The contents of the file correspond to the adapter_kwargs argument, eg:

gsheetsapi:
  service_account_file: /path/to/credentials.json
  subject: user@example.com
weatherapi:
  api_key: XXX

Custom functions

Shillelagh exposes a few custom functions that can be called via SQL.

Sleep

The sleep function is useful to create long-running queries, in order to test time outs in your application.

sql> SELECT sleep(120);

This will return None after 2 minutes.

Retrieving metadata

The get_metadata function returns metadata about a special table as a JSON string, including which adapter handles it:

sql> SELECT GET_METADATA("https://docs.google.com/spreadsheets/d/1_rN3lm0R_bU3NemO0s9pbFkY5LQPcuy1pscv8ZXPtg8/edit#gid=0");
GET_METADATA("https://docs.google.com/spreadsheets/d/1_rN3lm0R_bU3NemO0s9pbFkY5LQPcuy1pscv8ZXPtg8/edit#gid=0")
--------------------------------------------------------------------------------------------------------------
{
    "extra": {
        "Spreadsheet title": "Shillelagh GSheets",
        "Sheet title": "Simple sheet"
    },
    "adapter": "GSheetsAPI"
}

Finding out the version

Sometimes it’s useful to identify the version of Shillelagh that’s running on a system, in order to troubleshoot it. You can do that with version():

sql> SELECT VERSION();
VERSION()
-----------
1.0.0