duo
duo copied to clipboard
A powerful, dynamic, pythonic interface to AWS DynamoDB.
Duo: A powerful, dynamic, pythonic interface to AWS DynamoDB
.. image:: https://travis-ci.org/eykd/duo.svg?branch=master :target: https://travis-ci.org/eykd/duo#
.. image:: https://coveralls.io/repos/github/eykd/duo/badge.svg?branch=master :target: https://coveralls.io/github/eykd/duo?branch=master
Duo provides a few straightforward, Pythonic abstractions for working
with Amazon Web Services' DynamoDB. It's a very light wrapper around
boto.dynamodb.layer2
, so you have full access to that excellent
library when you need it, but you don't have to sweat the details when
you don't.
Stern warning:
No seriously, it's a very light wrapper around
boto.dynamodb.layer2
. If you stray much beyond the usage examples
below, you'd do best to be familiar with Boto's DynamoDB API. The docs
_ are excellent. Reading duo's source
_ may also be helpful. It's
kept short for that reason.
.. _The docs: http://boto.readthedocs.org/en/latest/ref/dynamodb.html .. _duo's source: https://github.com/eykd/duo/blob/master/duo.py
Usage:
duo
is made up of one module::
>>> import duo
The module isn't very big (at the time of this writing, ~700
lines). If you want to know how something works, you should read it
_.
.. _you should read it: https://github.com/eykd/duo/blob/master/duo.py
Pre-create your tables in the AWS console, then write simple classes
to access them. duo.Table
Sub-classes are automatically registered
with the db::
>>> class MyHashKeyTable(duo.Table):
... table_name = 'my_hashkey_table'
... hash_key_name = 'slug'
... range_key_name = None # Implicit default
duo.Item
is a thin wrapper around boto.dynamodb.items.Item
, with
lots of syntactic sugar. duo.Item
sub-classs are automatically
registered with the db::
>>> import datetime
>>> class MyHashKeyItem(duo.Item):
... table_name = 'my_hashkey_table'
... hash_key_name = 'slug'
...
... slug = duo.UnicodeField()
... my_field = duo.UnicodeField(default='foo')
... on_this_date = duo.DateField(default=lambda o: datetime.date.today())
Databases and Tables use dict-like access syntax::
>>> db = duo.DynamoDB(key='access_key', secret='secret_key')
>>> # The correct Table sub-class is matched by table name:
>>> table = duo.DynamoDB['my_hashkey_table']
>>> # The correct Item sub-class is matched by table name:
>>> item = table['new-item']
>>> # Items are actually dict subclasses, but that's not where the
>>> # fun is. They can only store unicode strings and integers:
>>> item['slug']
'new-item'
Specify a field on an Item sub-class to get useful data types::
>>> item.is_new
True
>>> # A field doesn't exist initially...
>>> item['my_field']
Traceback (most recent call last):
File "...", line 1, in <module>
item['my_field']
KeyError: 'my_field'
>>> # But we specified a default.
>>> item.my_field
'foo'
>>> # The default, once accessed, gets populated:
>>> item['my_field']
'foo'
>>> # Or we can set our own value...
>>> item.my_field = 'bar'
>>> item['my_field']
'bar'
>>> # Finally, we save it to DynamoDB.
>>> item.put()
>>> item.is_new
False
Caching:
Duo integrates with any cache that implements a python-memcached
-compatible interface, namely, the following::
import pylibmc
cache = pylibmc.Client(['127.0.0.1'])
cache.get(<keyname>)
cache.set(<keyname>, <duration-in-seconds>)
cache.delete(<keyname>)
Integrate caching by passing the cache to the db constructor::
>>> import duo
>>> db = duo.DynamoDB(key='access_key', secret='secret_key', cache=cache)
You can also specify a cache object on a per-table or per-item basis::
class MyHashKeyTable(duo.Table): ... cache = pylibmc.Client(['127.0.0.1']) ... ... table_name = 'my_hashkey_table' ... hash_key_name = 'slug' ... range_key_name = None # Implicit default
Caching is turned off by default, but you can turn it on by specifying
a cache_duration
as an integer (0 is forever)::
>>> class MyHashKeyItem(duo.Item):
... cache_duration = 30 # 30 seconds
...
... table_name = 'my_hashkey_table'
... hash_key_name = 'slug'
...
... slug = duo.UnicodeField()
... my_field = duo.UnicodeField(default='foo')
... on_this_date = duo.DateField(default=lambda o: datetime.date.today())
Cache keys are determined by hash key, range key, and a cache prefix (set on the Table). By default, the cache prefix is the table name::
>>> table = duo.DynamoDB['my_hashkey_table']
>>> item = table['new-item']
>>> item.cache_prefix is None
True
>>>item._cache_key
'my_hashkey_table_new-item'
>>> MyHashKeyTable.cache_prefix = 'hello_world'
>>> item._get_cache_key()
'hello_world_new-item'
CHANGELOG
0.3.1 ^^^^^
Fixed bug whereby EnumMeta and subclasses were not comparing properly (re: at all) in Python 3.
0.3.0 ^^^^^
Add Python 3 compatibility.
0.2.5 ^^^^^
get_item() now writes to the cache, even though it doesn't read from the cache.
0.2.4 ^^^^^
Added a custom get_item to Table, for specifying consistent reads, etc. Used by getitem, for simpler code!
0.2.3 ^^^^^
One more packaging fix, so pip won't explode. Thanks, cbrinker!
0.2.2 ^^^^^
Table.scan() and .query() should return extended Items.
0.2.1 ^^^^^
Corrections/improvements to setup.py. Packaging is HARD.
0.2 ^^^
Initial public release.