Skip to main content

Analytics ETL and collaboration tool for progressive campaigning

Project description

Project Keanu

Welcome to Project Keanu!

Project Keanu constist of:

  • Handbook for analytic terms, metrics and their definitions,
  • Common data model for campaign evaluation,
  • Set of queries to load data from sources (Currently CiviCRM, Identity in the future) to common data model
  • ETL tool to run the queries
  • Set of queries to visualize metrics and key indicators in Metabase
  • Metabase setup tool (mainly import/export of questions, dashboards)


The handbook is not part of this repository. It is developed within WeMove wiki. The release data is unknown.

Common data model

We have developed a common, standard model based on our experience in online campaigning. It should allow to accommodate most if not all of analytical data used to display key indicators to your campaign team. If something is missing for you - you can easily extend it.

The model is defined as MySQL Workbench project in erd/keanu-erd.mwb, and exported to MySQL SQL dile in erd/keanu-schema.sql. We realize the limitation of MySQL only workfiles, yet we were unable to find portable ERD IDE that would fit our needs. The schema can be transformed to PostgreSQL using analyze database tool in an IDE that supports PostgreSQL. Ideally, we should develop further in some portable format.

A basic documentation for tables and columns is embedded in the schema, in table and column comment metadata.

Loader queries

Under queries directory, you will find subdirectories with loaders for different data sources. At the time of writing, we are using CiviCRCM and both sources are using it as a source.

Loaders are meant to be single-concern files which transform source data into destination database (keanu database). One loader can populate the contacts table, or actions table from particular source. A loader has one destination db (usually with Keanu schema), and one source.

Currently we support two kinds of loaders:

  • SQL loader - consists of SQL file, containing special metadata in comments. It is run in the destination database server, and the source data must be available on the same server (in another database/schema).
  • Python loader - consists of Python file, and is run on the local machine. Keanu bundles sqlalchemy and pands libraries in case you need them. Right now keanu does not contain sqlalchemy definitions of keanu schema, so you will need to use sqlalchemy.core instead of the ORM.

Loaders are run in order specified in each loader's metadata (ORDER key), unless they are ingored (IGNORE key). See other metadata keys in sql and py loader reference.

ETL tool to run queries

The cli directory contains command line python app, publishd in PyPI as keanu-etl, which lets you run loaders agains source and destination database in two modes - full load and incremental load (meant to just load new data from source to destination), load keanu schema, and delete it. See Keanu CLI.

Set of queries to visualize metrics and key indicators in Metabase

Under metabase you can find an export of questions and dashboard collections used to visualize data from a Keanu database.

Metabase import/export tool

Keanu CLI app contains subcommand keanu metabase that allows to export and import collections of Metabase questions and dashboards.

Keanu CLI

Keanu command lives in cli directory. It is a multitool consisting of following subcommands:

  • schema - create tables from keanu schema in a database, or drop tables from a database.
  • load - runs loaders to load data into destination db from source(s). It can run in full or incremental mode. Can run loaders all at once or in steps.
  • delete - deletes data loaded by particular loader. Lets you "rewind" the work done by a particular loader (only full mode). This way you can "step back" in loading data.
  • metabase - export, import collections from/to Metabase, query the REST GET api of Metabase.


  1. Install Pipenv command in your system: sudo apt install pipenv
  2. Install dependencies in cli directory: pipenv install


Depending on subcommand, you configure keanu cli with:

  1. environment variables (mostly for credentials eg API keys, or access urls, eg. url to database with user, pass, hostname, db name)
  2. configuration YAML file (when more structured configuration is needed eg. to specify sources and destination for loaders, as well as which loaders are used)
  3. command line switches and arguments

Environment variables reference

  1. API keys and Database access urls

Keanu uses metabase API in its metabase subcommand. Define Metabase url, username and password with these variables:

  • METABASE_ENDPOINT - url of Metabase instance with scheme, eg:
  • METABASE_AUTH_EMAIL - email for login
  • METABASE_AUTH_PASSWORD - password for login

Keanu uses Database credentials in form of database url in format suitable for SQLalchemy. Because keanu can have many sources and another destination, the urls are provided using a yaml configuration.

Configuration file

The configuration file must have .yaml extension and contain alist of elements that define sources of data, destination of data, and transforms, which run a series of loaders. You provide the configuration file as a positional argument to load or delete subcommands.


The source should have a name, and db specification can either be url or schema. In case that source is the same db as destination, we say it is local to that destination, and we can provide just schema name using schema key. You can use ${VARIABLE} syntax to insert env variables (so, for instance, you do not store database credentials in configuration file).

Example: source with database url, named foobarcrm

- source:
    name: foobarcrm
      url: ${DATABASE_URL}

Example: source in the same DB as destination, but in exchange_rates database

- source:
    name: currency_data
    schema: exchange_rates


There can be only one destination in the config file (so there is no need to give it a name). The SQL transforms are run In the destination DB (they are SQL statements run on the DB server). This means sources must be local to the destination for SQL loaders. Keanu cannot yet stream data from one DB and insert it to another DB, but this is a feature we would like to develop in the feature (in this case the transform should run in the source and return a dataset that can be directly inserted to the destination).

The python loaders run inside the keanu cli process, and download/upload data. They can use different db servers for sources and destination.


- destination:
      url: ${DATABASE_URL}


The transform points to directory with loaders and specifies their type. Transform is applied to one source and one destination. Because there can be many sources, transform should specify name of the sources under source key. Transform can point to directory or just one file.

Example: transform will execute all SQL files found under some/directory. It will use foobarcrm as source.

- transform:
    source: foobarcrm
      directory: some/directory

Example: a transform using just one python loader file.

- transform:
    source: foobarcrm
      file: python_scripts/
  1. You can Copy the cli/.env.sample file to .env and change it to taste.

Default setting

However, keanu can also run with minamal default configuration. Running keanu load sql_files is equal to keanu load config1.yaml with config1.yaml:

- source:
      schema: ${SOURCE}
- destination:
      url: ${DATABASE_URL}
- transform:
       directory: ${ARGV[1]}
  • DATABASE_URL - must use schema understood by SQLAlchemy library, required for load and delete subcommands
  • SOURCE - is a name of CiviCRM database (also called schema), required only for SQL loaders


Keanu commands has a set of subcommands, similar to git or heroku.

Running from source

Install dependencies using pipenv insall and open shell with needed requirements with pipenv shell.

Package building

To build the package use python bdist_wheel.

To upload it to PyPI:

  1. Create a ~/.pypirc file:
repository = 
username = pypi-username

To install the package locally:

pip install --upgrade dist/keanu-0.1-py3-none-any.whl

  1. Use python -m twine upload dist/*.

SQL commands

These are the commands related to creating and filling in the Keanu schema (from CiviCRM DB).

schema: manipulating database schema

  • schema -L FILENAME - loads SQL schema file.
  • schema -D - drops all tables from the database.

load: loading data load SQLDIR loads data from CiviCRM to keanu db in ordered steps. Every SQL file in SQLDIR directory has -- ORDER: 12 comment which specifies an order. The default order is 100.


  • -o 10: - order, start from SQL file with order 10 (also see order spec)
  • -n - dry run, do not execute the SQL. Usefull to see the order of scripts
  • -i - incremental, also run the incremental parts of the SQL, normally deleted (they are marked by -- BEGIN INCREMENTAL and -- END INCREMENTAL comments)
  • -d - display a whole SQL statement instead of abbreviation of first line

delete: deleting data delete SQLDIR will go through the SQL scripts in reverse order and execute the commented DELETE and TRUNCATE statements in the scripts.


  • -n - dry run, do not execute the SQL. Usefull to see the order of scripts
  • -o 10: - delete data until the SQL file order (inclusive) and stop
  • -d - display a whole SQL statement instead of abbreviation of first line

Order spec

You can provide just a number to order (-o) option, but you can also provide:

  • a list of numbers such as 10,11,50 and scripts with respective order will be run
  • a range in python format such as 10:16 equal to 10,11,12,13,14,15 (excluding 16)
  • a mix of them: 10:13,31,50:52

SQL file reference:

We add metadata to SQL files in SQL comments. This is usefull because you can still work with the SQL files using tools like MySQL Workbench, or mysql command - the commands will be ignored.

Supported commands are:

-- ORDER: arg - arg should be a 3 digit number. It specifies the order this script will be run. -- DELETE FROM .. - a DELETE statement will be saved to revert this script, so to remove all the data it has added. Must start with all caps DELETE. -- TRUNCATE - similar to above. Please note: TRUNCATE will fail if any other table has reference to this table, even when it's empty. -- IGNORE - the rest of the file will be ignored.

Blocks are also supported. They are marked by a pair of lines:

-- BEGIN keyword
 .. some SQL code here..
-- END keyword

They should be properly nested.

Supported blocks are:

  • BEGIN INCREMENTAL / END INCREMENTAL - marks part of the SQL that will normally be removed, and will be only used if -i (incremental flag) is used while loading. You can have many INCREMENTAL blocks. Example use:
-- this scripts inserts into cookie jar
-- ORDER: 10

INSERT INTO jar (colour, size, external_id)
FROM cookie c
JOIN colour_dictionary cd ON c.colour_id =

-- when we do incremental, we exclude external_id's we already have:
WHERE NOT IN (SELECT external_id FROM jar)
  • BEGIN INITIAL / END INITIAL - marks part of the SQL that will be removed in incremental -i mode.

Enviroment variable interpolation. Similar to shell, simple variable interpolation is supported. ${FOO} will be interpolated into value of FOO environment variable. This is currently used to insert the source schema name with ${SOURCE}.

Metabase commands

These are the commands to export / import Metabase questions and dashboards that are related to the Keanu schema

Export metabase export generates a JSON dump of all the data required to import the collections / dashboards / questions given in options.

The generated JSON is printed on standard output. It contains a property items with the list of objects that got exported, as well as a property mappings with information to translate ids that make sense only in the context of a Metabase instance (table ids, card ids, etc).


  • -c "Some collection" - Exports all the questions and dashboards contained in the named collection and its child collections. You should ensure that the dashboards refer only to questions contained within that collection, unless you plan to import the data within the same Metabase instance. The collection must exist.

Import metabase import reads a JSON dump generated by the export command and import the object into a Metabase instance.


  • -c "Some collection" - The name of the collection into which the objects should be imported. The collection must exist and be empty (no support for overwrite / merge at the moment).
  • -j /path/to/file.json - The JSON file to import.

Product vision

Right now during initial development, we run keanu command from the source directory cli, and the SQL scripts are kept in sql. The vision for the future product is the following:

Keanu will be a command installed gloablly into the system, with pip install keanu. It will work like git or heroku, a multi-tool to do everything conntected to common DB model, ETL, running AI logic, installing dashboards in Metabase (this last function fits this command least, but let's see).

It will download a repository of SQL files, properly divided between general use, CiviCRM users, Identity users, etc, and be able to configure itself with keanu setup - saving information about source and target DBs. It will be able also to upload SQL files that were changed and verion manage them somehow, to help in collaboration (this could be done using git).

Similarly, it will enable import and export of Metabase questions (called cards) and dashboards. Not only their SQL, but also their JSON configuration (using python Metabase API client library).

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

keanu_etl-0.6.0-py3-none-any.whl (43.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page