Permalink
Browse files

2008-04-30 Michal Ludvig <michal@logix.cz>

	* s3db, S3/SimpleDB.py: Implemented almost full SimpleDB API.



git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@179 830e0280-6d2a-0410-9c65-932aecc39d9d
  • Loading branch information...
1 parent d2b144d commit add6b7fc078f4eb389e727f25b5e166b9e345993 @mludvig mludvig committed Apr 30, 2008
Showing with 114 additions and 15 deletions.
  1. +4 −0 ChangeLog
  2. +82 −11 S3/SimpleDB.py
  3. +28 −4 s3db
View
@@ -1,3 +1,7 @@
+2008-04-30 Michal Ludvig <michal@logix.cz>
+
+ * s3db, S3/SimpleDB.py: Implemented almost full SimpleDB API.
+
2008-04-29 Michal Ludvig <michal@logix.cz>
* s3db, S3/SimpleDB.py: Initial support for Amazon SimpleDB.
View
@@ -28,19 +28,90 @@ class SimpleDB(object):
def __init__(self, config):
self.config = config
+ ## ------------------------------------------------
+ ## Methods implementing SimpleDB API
+ ## ------------------------------------------------
+
def ListDomains(self, MaxNumberOfDomains = 100):
'''
Lists all domains associated with our Access Key. Returns
domain names up to the limit set by MaxNumberOfDomains.
'''
parameters = SortedDict()
parameters['MaxNumberOfDomains'] = MaxNumberOfDomains
- response = self.send_request("ListDomains", domain = None, parameters = parameters)
- return response
-
+ return self.send_request("ListDomains", DomainName = None, parameters = parameters)
+
+ def CreateDomain(self, DomainName):
+ return self.send_request("CreateDomain", DomainName = DomainName)
+
+ def DeleteDomain(self, DomainName):
+ return self.send_request("DeleteDomain", DomainName = DomainName)
+
+ def PutAttributes(self, DomainName, ItemName, Attributes):
+ parameters = SortedDict()
+ parameters['ItemName'] = ItemName
+ seq = 0
+ for attrib in Attributes:
+ if type(Attributes[attrib]) == type(list()):
+ for value in Attributes[attrib]:
+ parameters['Attribute.%d.Name' % seq] = attrib
+ parameters['Attribute.%d.Value' % seq] = unicode(value)
+ seq += 1
+ else:
+ parameters['Attribute.%d.Name' % seq] = attrib
+ parameters['Attribute.%d.Value' % seq] = unicode(Attributes[attrib])
+ seq += 1
+ ## TODO:
+ ## - support for Attribute.N.Replace
+ ## - support for multiple values for one attribute
+ return self.send_request("PutAttributes", DomainName = DomainName, parameters = parameters)
+
+ def GetAttributes(self, DomainName, ItemName, Attributes = []):
+ parameters = SortedDict()
+ parameters['ItemName'] = ItemName
+ seq = 0
+ for attrib in Attributes:
+ parameters['AttributeName.%d' % seq] = attrib
+ seq += 1
+ return self.send_request("GetAttributes", DomainName = DomainName, parameters = parameters)
+
+ def DeleteAttributes(self, DomainName, ItemName, Attributes = {}):
+ """
+ Remove specified Attributes from ItemName.
+ Attributes parameter can be either:
+ - not specified, in which case the whole Item is removed
+ - list, e.g. ['Attr1', 'Attr2'] in which case these parameters are removed
+ - dict, e.g. {'Attr' : 'One', 'Attr' : 'Two'} in which case the
+ specified values are removed from multi-value attributes.
+ """
+ parameters = SortedDict()
+ parameters['ItemName'] = ItemName
+ seq = 0
+ for attrib in Attributes:
+ parameters['Attribute.%d.Name' % seq] = attrib
+ if type(Attributes) == type(dict()):
+ parameters['Attribute.%d.Value' % seq] = unicode(Attributes[attrib])
+ seq += 1
+ return self.send_request("DeleteAttributes", DomainName = DomainName, parameters = parameters)
+
+ def Query(self, DomainName, QueryExpression = None, MaxNumberOfItems = None, NextToken = None):
+ parameters = SortedDict()
+ if QueryExpression:
+ parameters['QueryExpression'] = QueryExpression
+ if MaxNumberOfItems:
+ parameters['MaxNumberOfItems'] = MaxNumberOfItems
+ if NextToken:
+ parameters['NextToken'] = NextToken
+ return self.send_request("Query", DomainName = DomainName, parameters = parameters)
+ ## Handle NextToken? Or maybe not - let the upper level do it
+
+ ## ------------------------------------------------
+ ## Low-level methods for handling SimpleDB requests
+ ## ------------------------------------------------
+
def send_request(self, *args, **kwargs):
request = self.create_request(*args, **kwargs)
- debug("Request: %s" % repr(request))
+ #debug("Request: %s" % repr(request))
conn = self.get_connection()
conn.request("GET", self.format_uri(request['uri_params']))
http_response = conn.getresponse()
@@ -49,24 +120,24 @@ def send_request(self, *args, **kwargs):
response["reason"] = http_response.reason
response["headers"] = convertTupleListToDict(http_response.getheaders())
response["data"] = http_response.read()
- debug("Response: " + str(response))
conn.close()
if response["status"] < 200 or response["status"] > 299:
+ debug("Response: " + str(response))
raise S3Error(response)
return response
- def create_request(self, action, domain, parameters = None):
+ def create_request(self, Action, DomainName, parameters = None):
if not parameters:
parameters = SortedDict()
parameters['AWSAccessKeyId'] = self.config.access_key
parameters['Version'] = self.Version
parameters['SignatureVersion'] = self.SignatureVersion
- parameters['Action'] = action
+ parameters['Action'] = Action
parameters['Timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
- if domain:
- parameters['DomainName'] = domain
+ if DomainName:
+ parameters['DomainName'] = DomainName
parameters['Signature'] = self.sign_request(parameters)
parameters.keys_return_lowercase = False
uri_params = urllib.urlencode(parameters)
@@ -81,7 +152,7 @@ def sign_request(self, parameters):
parameters.keys_return_lowercase = False
for key in parameters:
h += "%s%s" % (key, parameters[key])
- debug("SignRequest: %s" % h)
+ #debug("SignRequest: %s" % h)
return base64.encodestring(hmac.new(self.config.secret_key, h, sha).digest()).strip()
def get_connection(self):
@@ -98,5 +169,5 @@ def format_uri(self, uri_params):
uri = "http://%s/?%s" % (self.config.simpledb_host, uri_params)
else:
uri = "/?%s" % uri_params
- debug('format_uri(): ' + uri)
+ #debug('format_uri(): ' + uri)
return uri
View
32 s3db
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-
+# vim: set fileencoding=utf-8 :
## Amazon S3 manager
## Author: Michal Ludvig <michal@logix.cz>
## http://www.logix.cz/michal
@@ -18,12 +18,36 @@ from S3.SimpleDB import SimpleDB
from S3.Config import Config
from S3.Exceptions import *
-
+def display_response(response):
+ print "%s\n%s\n%s" % ('-'*40, response['data'], '-'*40)
+
if __name__ == '__main__':
if float("%d.%d" %(sys.version_info[0], sys.version_info[1])) < 2.4:
sys.stderr.write("ERROR: Python 2.4 or higher required, sorry.\n")
sys.exit(1)
- logging.root.setLevel(logging.DEBUG)
cfg = Config(os.getenv("HOME")+"/.s3cfg")
+
+ logging.root.setLevel(logging.DEBUG)
sdb = SimpleDB(cfg)
- print sdb.ListDomains()
+
+ try:
+ display_response(sdb.ListDomains())
+
+ display_response(sdb.CreateDomain("logix.cz-test"))
+
+ display_response(sdb.ListDomains())
+
+ display_response(sdb.PutAttributes("logix.cz-test", "AbCd", {'First': "One", "Second" : 2, "Third" : u"drei"}))
+ display_response(sdb.PutAttributes("logix.cz-test", "XyZ", {'xyz' : ['x', 'y', 'z'], 'Third' : u'traja'}))
+
+ display_response(sdb.GetAttributes("logix.cz-test", "AbCd", ['Second', 'Third']))
+ display_response(sdb.GetAttributes("logix.cz-test", "XyZ"))
+
+ display_response(sdb.Query("logix.cz-test", "['xyz' = 'z']"))
+
+ display_response(sdb.DeleteDomain("logix.cz-test"))
+
+ display_response(sdb.ListDomains())
+ except S3Error, e:
+ error(e)
+ error(e.info)

0 comments on commit add6b7f

Please sign in to comment.