Browse code

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

Michal Ludvig authored on 2008/04/30 23:10:34
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+2008-04-30  Michal Ludvig  <michal@logix.cz>
2
+
3
+	* s3db, S3/SimpleDB.py: Implemented almost full SimpleDB API.
4
+
1 5
 2008-04-29  Michal Ludvig  <michal@logix.cz>
2 6
 
3 7
 	* s3db, S3/SimpleDB.py: Initial support for Amazon SimpleDB. 
... ...
@@ -28,6 +28,10 @@ class SimpleDB(object):
28 28
 	def __init__(self, config):
29 29
 		self.config = config
30 30
 
31
+	## ------------------------------------------------
32
+	## Methods implementing SimpleDB API
33
+	## ------------------------------------------------
34
+
31 35
 	def ListDomains(self, MaxNumberOfDomains = 100):
32 36
 		'''
33 37
 		Lists all domains associated with our Access Key. Returns 
... ...
@@ -35,12 +39,79 @@ class SimpleDB(object):
35 35
 		'''
36 36
 		parameters = SortedDict()
37 37
 		parameters['MaxNumberOfDomains'] = MaxNumberOfDomains
38
-		response = self.send_request("ListDomains", domain = None, parameters = parameters)
39
-		return response
40
-	
38
+		return self.send_request("ListDomains", DomainName = None, parameters = parameters)
39
+
40
+	def CreateDomain(self, DomainName):
41
+		return self.send_request("CreateDomain", DomainName = DomainName)
42
+
43
+	def DeleteDomain(self, DomainName):
44
+		return self.send_request("DeleteDomain", DomainName = DomainName)
45
+
46
+	def PutAttributes(self, DomainName, ItemName, Attributes):
47
+		parameters = SortedDict()
48
+		parameters['ItemName'] = ItemName
49
+		seq = 0
50
+		for attrib in Attributes:
51
+			if type(Attributes[attrib]) == type(list()):
52
+				for value in Attributes[attrib]:
53
+					parameters['Attribute.%d.Name' % seq] = attrib
54
+					parameters['Attribute.%d.Value' % seq] = unicode(value)
55
+					seq += 1
56
+			else:
57
+				parameters['Attribute.%d.Name' % seq] = attrib
58
+				parameters['Attribute.%d.Value' % seq] = unicode(Attributes[attrib])
59
+				seq += 1
60
+		## TODO:
61
+		## - support for Attribute.N.Replace
62
+		## - support for multiple values for one attribute
63
+		return self.send_request("PutAttributes", DomainName = DomainName, parameters = parameters)
64
+
65
+	def GetAttributes(self, DomainName, ItemName, Attributes = []):
66
+		parameters = SortedDict()
67
+		parameters['ItemName'] = ItemName
68
+		seq = 0
69
+		for attrib in Attributes:
70
+			parameters['AttributeName.%d' % seq] = attrib
71
+			seq += 1
72
+		return self.send_request("GetAttributes", DomainName = DomainName, parameters = parameters)
73
+
74
+	def DeleteAttributes(self, DomainName, ItemName, Attributes = {}):
75
+		"""
76
+		Remove specified Attributes from ItemName.
77
+		Attributes parameter can be either:
78
+		- not specified, in which case the whole Item is removed
79
+		- list, e.g. ['Attr1', 'Attr2'] in which case these parameters are removed
80
+		- dict, e.g. {'Attr' : 'One', 'Attr' : 'Two'} in which case the 
81
+		  specified values are removed from multi-value attributes.
82
+		"""
83
+		parameters = SortedDict()
84
+		parameters['ItemName'] = ItemName
85
+		seq = 0
86
+		for attrib in Attributes:
87
+			parameters['Attribute.%d.Name' % seq] = attrib
88
+			if type(Attributes) == type(dict()):
89
+				parameters['Attribute.%d.Value' % seq] = unicode(Attributes[attrib])
90
+			seq += 1
91
+		return self.send_request("DeleteAttributes", DomainName = DomainName, parameters = parameters)
92
+
93
+	def Query(self, DomainName, QueryExpression = None, MaxNumberOfItems = None, NextToken = None):
94
+		parameters = SortedDict()
95
+		if QueryExpression:
96
+			parameters['QueryExpression'] = QueryExpression
97
+		if MaxNumberOfItems:
98
+			parameters['MaxNumberOfItems'] = MaxNumberOfItems
99
+		if NextToken:
100
+			parameters['NextToken'] = NextToken
101
+		return self.send_request("Query", DomainName = DomainName, parameters = parameters)
102
+		## Handle NextToken? Or maybe not - let the upper level do it
103
+
104
+	## ------------------------------------------------
105
+	## Low-level methods for handling SimpleDB requests
106
+	## ------------------------------------------------
107
+
41 108
 	def send_request(self, *args, **kwargs):
42 109
 		request = self.create_request(*args, **kwargs)
43
-		debug("Request: %s" % repr(request))
110
+		#debug("Request: %s" % repr(request))
44 111
 		conn = self.get_connection()
45 112
 		conn.request("GET", self.format_uri(request['uri_params']))
46 113
 		http_response = conn.getresponse()
... ...
@@ -49,24 +120,24 @@ class SimpleDB(object):
49 49
 		response["reason"] = http_response.reason
50 50
 		response["headers"] = convertTupleListToDict(http_response.getheaders())
51 51
 		response["data"] =  http_response.read()
52
-		debug("Response: " + str(response))
53 52
 		conn.close()
54 53
 
55 54
 		if response["status"] < 200 or response["status"] > 299:
55
+			debug("Response: " + str(response))
56 56
 			raise S3Error(response)
57 57
 
58 58
 		return response
59 59
 
60
-	def create_request(self, action, domain, parameters = None):
60
+	def create_request(self, Action, DomainName, parameters = None):
61 61
 		if not parameters:
62 62
 			parameters = SortedDict()
63 63
 		parameters['AWSAccessKeyId'] = self.config.access_key
64 64
 		parameters['Version'] = self.Version
65 65
 		parameters['SignatureVersion'] = self.SignatureVersion
66
-		parameters['Action'] = action
66
+		parameters['Action'] = Action
67 67
 		parameters['Timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
68
-		if domain:
69
-			parameters['DomainName'] = domain
68
+		if DomainName:
69
+			parameters['DomainName'] = DomainName
70 70
 		parameters['Signature'] = self.sign_request(parameters)
71 71
 		parameters.keys_return_lowercase = False
72 72
 		uri_params = urllib.urlencode(parameters)
... ...
@@ -81,7 +152,7 @@ class SimpleDB(object):
81 81
 		parameters.keys_return_lowercase = False
82 82
 		for key in parameters:
83 83
 			h += "%s%s" % (key, parameters[key])
84
-		debug("SignRequest: %s" % h)
84
+		#debug("SignRequest: %s" % h)
85 85
 		return base64.encodestring(hmac.new(self.config.secret_key, h, sha).digest()).strip()
86 86
 
87 87
 	def get_connection(self):
... ...
@@ -98,5 +169,5 @@ class SimpleDB(object):
98 98
 			uri = "http://%s/?%s" % (self.config.simpledb_host, uri_params)
99 99
 		else:
100 100
 			uri = "/?%s" % uri_params
101
-		debug('format_uri(): ' + uri)
101
+		#debug('format_uri(): ' + uri)
102 102
 		return uri
... ...
@@ -1,5 +1,5 @@
1 1
 #!/usr/bin/env python
2
-
2
+# vim: set fileencoding=utf-8 :
3 3
 ## Amazon S3 manager
4 4
 ## Author: Michal Ludvig <michal@logix.cz>
5 5
 ##         http://www.logix.cz/michal
... ...
@@ -18,12 +18,36 @@ from S3.SimpleDB import SimpleDB
18 18
 from S3.Config import Config
19 19
 from S3.Exceptions import *
20 20
 
21
-
21
+def display_response(response):
22
+	print "%s\n%s\n%s" % ('-'*40, response['data'], '-'*40)
23
+	
22 24
 if __name__ == '__main__':
23 25
 	if float("%d.%d" %(sys.version_info[0], sys.version_info[1])) < 2.4:
24 26
 		sys.stderr.write("ERROR: Python 2.4 or higher required, sorry.\n")
25 27
 		sys.exit(1)
26
-	logging.root.setLevel(logging.DEBUG)
27 28
 	cfg = Config(os.getenv("HOME")+"/.s3cfg")
29
+
30
+	logging.root.setLevel(logging.DEBUG)
28 31
 	sdb = SimpleDB(cfg)
29
-	print sdb.ListDomains()
32
+
33
+	try:
34
+		display_response(sdb.ListDomains())
35
+
36
+		display_response(sdb.CreateDomain("logix.cz-test"))
37
+
38
+		display_response(sdb.ListDomains())
39
+
40
+		display_response(sdb.PutAttributes("logix.cz-test", "AbCd", {'First': "One", "Second" : 2, "Third" : u"drei"}))
41
+		display_response(sdb.PutAttributes("logix.cz-test", "XyZ", {'xyz' : ['x', 'y', 'z'], 'Third' : u'traja'}))
42
+
43
+		display_response(sdb.GetAttributes("logix.cz-test", "AbCd", ['Second', 'Third']))
44
+		display_response(sdb.GetAttributes("logix.cz-test", "XyZ"))
45
+
46
+		display_response(sdb.Query("logix.cz-test", "['xyz' = 'z']"))
47
+
48
+		display_response(sdb.DeleteDomain("logix.cz-test"))
49
+
50
+		display_response(sdb.ListDomains())
51
+	except S3Error, e:
52
+		error(e)
53
+		error(e.info)