User guide

Introduction

Hopefully the Quick start was enough to get you started.

I do my best to respect standards, so alternative installation methods like easy_install LowVoltage or python setup.py install in the source code should work as well as pip install LowVoltage. You may want to use virtualenv.

Regarding imports, I suggest you import LowVoltage as lv in your production code. All this documentation assumes that everything was imported in the global namespace: from LowVoltage import *. Note that everything is available in the top-level module, so you don’t have to import nested modules.

Beware that LowVoltage is just a client library for DynamoDB, so you have to be familiar with the underlying concepts of this No-SQL database. AWS provides a lot of documentation and this documentation often links to it.

I’d like all communication about LowVoltage to be public so please use GitHub issues for your questions and remarks as well as for reporting bugs.

Why?

  • I wanted to learn DynamoDB
  • I found out Boto is (was?) not up-to-date with newer API parameters and does (did?) not support Python 3
  • I had some time and I love programming

Tenets

Users should be able to do everything that is permited by the API.

There is nothing worse (well, maybe there is...) than knowing how to do something using an API but being incapacited by a client library. So in LowVoltage we provide a first layer, Actions, that maps exactly to the API. Please open an issue if something is missing!

Users should never risk a typo

We provide symbols for all DynamoDB constants.

Users should be able to choose simplicity over flexibility

Even if you want to be able to return_item_collection_metrics_size(), most of the time you don’t care. And processing unprocessed_items should be abstracted away. So we provide Compounds. More details in Actions vs. compounds bellow.

The connection

The main entry point of LowVoltage is the Connection class.

>>> from LowVoltage import *
>>> connection = Connection("us-west-2", EnvironmentCredentials())

Authentication

DynamoDB requires authentication and signing of the requests. In LowVoltage we use simple dependency injection of a credentials provider (EnvironmentCredentials in the example above). This approach is flexible and allows implementation of any credentials rotation policy. LowVoltage comes with credentials providers for simple use cases. See credentials for details.

Error handling

Some errors are retryable: NetworkError or ServerError for example. The Connection accepts a retry_policy parameter to specify this behavior. See retry_policies for details. See also exceptions for a description of the exceptions classes.

Actions vs. compounds

As briefly described in the Tenets, LowVoltage is built in successive layers of increasing abstraction and decreasing flexibility.

The Actions layer provides almost no abstraction over the API. It maps exactly to the DynamoDB actions, parameters and return values. It does convert between Python types and DynamoDB notation though.

>>> table = "LowVoltage.Tests.Doc.1"
>>> connection(GetItem(table, {"h": 0})).item
{u'h': 0, u'gr': 10, u'gh': 0}

The Compounds layer provides helper functions that intend to complete actions in their simplest use cases. For example BatchGetItem is limited to get 100 keys at once and requires processing BatchGetItemResponse.unprocessed_keys, so we provide iterate_batch_get_item() to do that. The tradeoff is that you loose BatchGetItemResponse.consumed_capacity and the ability to get items from several tables at once. Similarly batch_put_item() removes the limit of 25 items in BatchWriteItem but also removes the ability to put and delete from several tables in the same action.

>>> batch_put_item(connection, table, {"h": 0, "a": 42}, {"h": 1, "b": 53})

Actions are instances that are passed to the Connection but compounds are functions that receive the connection as an argument: actions are atomic while compounds are able to perform several actions.

Someday, maybe, we’ll write a Table abstraction and implement an “active record” pattern? It would be even simpler than compounds, but less flexible.

Building actions

DynamoDB actions typically receive a lot of mandatory and optional parameters.

When you build an action, you can pass all mandatory parameters to the constructor. You may want to use named parameters to reduce the risk of giving them in the wrong order.

>>> GetItem("Table", {"h": 0})
<LowVoltage.actions.get_item.GetItem ...>

Optional parameters are exposed only using method chaining to avoid giving them in the wrong order.

>>> GetItem("Table", {"h": 0}).return_consumed_capacity_total()
<LowVoltage.actions.get_item.GetItem ...>

Alternatively, mandatory parameters can be set using method chaining as well.

>>> GetItem().table_name("Table").key({"h": 0})
<LowVoltage.actions.get_item.GetItem ...>

If you try to pass an action with missing mandatory parameters, you’ll get a BuilderError:

>>> connection(GetItem().key({"h": 0}))
Traceback (most recent call last):
  ...
BuilderError: ...

Active resource

Some actions can operate on several resources. BatchGetItem can get items from several tables at once for example. To build those, we need a concept of “active table”: BatchGetItem.keys() will always add keys to get from the active table. The active table is set by BatchGetItem.table().

>>> (BatchGetItem()
...   .table("Table1").keys({"h": 0})
...   .table("Table2").keys({"x": 42})
... )
<LowVoltage.actions.batch_get_item.BatchGetItem ...>

The previous example will get {"h": 0} from Table1 and {"x": 42} from Table2.

Variadic functions

Some methods, like BatchGetItem.keys() are variadic. But a special kind of variadic: not only do they accept any number of parameters, but for greater flexibility those arguments can also be iterable.

>>> (BatchGetItem().table("Table1")
...   .keys({"h": 0})
...   .keys({"h": 1}, {"h": 2})
...   .keys({"h": 3}, [{"h": 4}, {"h": 5}], {"h": 6}, [{"h": 7}])
...   .keys({"h": h} for h in range(8, 12))
...   .keys(({"h": h} for h in range(12, 17)), {"h": 17}, [{"h": h} for h in range(18, 20)])
... )
<LowVoltage.actions.batch_get_item.BatchGetItem ...>

Expressions

@todoc Condition, projection, attribute names, attribute values. @todoc Cross link here, next gen mixins and expression builders.