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.