• R/O
  • HTTP
  • SSH
  • HTTPS

提交

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

winazurestorageのフォーク


Commit MetaInfo

修訂c1d6f9c7e1c128422ec584def3ab81937a02c4f7 (tree)
時間2012-04-19 22:58:09
作者hylom <hylom@hylo...>
Commiterhylom

Log Message

add some lacking table APIs

Change Summary

差異

--- a/winazurestorage.py
+++ b/winazurestorage.py
@@ -150,7 +150,125 @@ class Storage(object):
150150 else:
151151 return "http://%s.%s" % (self._account, self._host)
152152
153-class TableEntity(object): pass
153+class TableEntityException(Exception):
154+ def __init__(self, value):
155+ self.value = value
156+ def __str__(self):
157+ return repr(self.value)
158+
159+class TableEntity(object):
160+ "Table Entity"
161+ def __init__(self, partition_key, row_key, props):
162+ self.partition_key = partition_key
163+ self.row_key = row_key
164+ self.properties = props
165+
166+# class Binary(object):
167+# pass
168+
169+# class Guid(object):
170+# pass
171+
172+ class Boolean(int):
173+ def __str__(self):
174+ if self:
175+ return "true"
176+ else:
177+ return "false"
178+
179+ def __repr__(self):
180+ props = ",".join([ k + ":" + str(self.properties[k]) for k in self.properties])
181+ return ",".join((self.partition_key, self.row_key, props))
182+
183+ def add_property(self, key, value):
184+ self.properties[key] = value
185+
186+ def to_insert_xml(self):
187+ contents = [self._make_property_node(propname, self.properties[propname]) for propname in self.properties]
188+ contents_str = "\n".join(contents)
189+ now_str = datetime.utcnow().isoformat()
190+ xml = """<?xml version="1.0" encoding="utf-8" standalone="yes"?>
191+<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
192+ <title />
193+ <author>
194+ <name />
195+ </author>
196+ <id />
197+ <content type="application/xml">
198+ <m:properties>
199+%(contents)s
200+ <d:PartitionKey>%(partition_key)s</d:PartitionKey>
201+ <d:RowKey>%(row_key)s</d:RowKey>
202+ <d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
203+ </m:properties>
204+ </content>
205+</entry>
206+""" % dict(contents=contents_str, now=now_str, partition_key=self.partition_key, row_key=self.row_key)
207+ if isinstance(xml, unicode):
208+ xml = xml.encode('utf-8')
209+ return xml
210+
211+ def to_update_xml(self):
212+ contents = [self._make_property_node(propname, self.properties[propname]) for propname in self.properties]
213+ contents_str = "\n".join(contents)
214+ now_str = datetime.utcnow().isoformat() + "Z"
215+ xml = """<?xml version="1.0" encoding="utf-8" standalone="yes"?>
216+<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
217+ <title />
218+ <updated>%(now)s</updated>
219+ <author>
220+ <name />
221+ </author>
222+ <id />
223+ <content type="application/xml">
224+ <m:properties>
225+%(contents)s
226+ <d:PartitionKey>%(partition_key)s</d:PartitionKey>
227+ <d:RowKey>%(row_key)s</d:RowKey>
228+ <d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
229+ </m:properties>
230+ </content>
231+</entry>
232+""" % dict(contents=contents_str, now=now_str, partition_key=self.partition_key, row_key=self.row_key)
233+ if isinstance(xml, unicode):
234+ xml = xml.encode('utf-8')
235+ return xml
236+
237+ def _make_property_node(self, name, value):
238+ type = ""
239+ string_repr = ""
240+# if isinstance(value, TableEntity.Binary):
241+# type = "Edm.Binary"
242+# string_repr = str(TableEntity.Binary(value))
243+ if isinstance(value, bool):
244+ type = "Edm.Boolean"
245+ string_repr = str(TableEntity.Boolean(value))
246+ elif isinstance(value, datetime):
247+ type = "Edm.DateTime"
248+ string_repr = value.isoformat()
249+ elif isinstance(value, float):
250+ type = "Edm.Double"
251+ string_repr = str(value)
252+# elif isinstance(value, TableEntity.Guid):
253+# type = "Edm.Guid"
254+# string_repr = str(TableEntity.Boolean(value))
255+ elif isinstance(value, long):
256+ type = "Edm.Int64"
257+ string_repr = str(value)
258+ elif isinstance(value, int):
259+ type = "Edm.Int32"
260+ string_repr = str(value)
261+ elif isinstance(value, str):
262+ type = "Edm.String"
263+ string_repr = value
264+ elif isinstance(value, unicode):
265+ type = "Edm.String"
266+ string_repr = value
267+ if type is not "":
268+ prop_element = """<d:%(name)s m:type="%(type)s">%(value)s</d:%(name)s>"""
269+ return prop_element % dict(name=name, type=type, value=string_repr)
270+ else:
271+ raise TableEntityException("Unexpected property: %s" % (value,))
154272
155273 class QueueMessage(): pass
156274
@@ -300,6 +418,97 @@ class TableStorage(Storage):
300418 dom.unlink()
301419 return entities
302420
421+ def insert_entity(self, table_name, entity):
422+ data = entity.to_insert_xml()
423+ url = "%s/%s" % (self.get_base_url(), table_name)
424+ req = winazurestorage.RequestWithMethod("POST", url, data=data)
425+ req.add_header("Content-Length", "%d" % len(data))
426+ req.add_header("Content-Type", "application/atom+xml")
427+ self._credentials.sign_table_request(req)
428+ try:
429+ response = urlopen(req)
430+ return response.code
431+ except URLError, e:
432+ return e.code
433+
434+ def update_entity(self, table_name, partition_key, row_key, entity):
435+ data = entity.to_update_xml()
436+ url = """%s/%s(PartitionKey='%s',RowKey='%s')""" % (self.get_base_url(), table_name, partition_key, row_key)
437+
438+ req = winazurestorage.RequestWithMethod("PUT", url, data=data)
439+ req.add_header("Content-Length", "%d" % len(data))
440+ req.add_header("Content-Type", "application/atom+xml")
441+ self._credentials.sign_table_request(req)
442+ try:
443+ response = urlopen(req)
444+ return response.code
445+ except URLError, e:
446+ print data
447+ return e.code
448+
449+ def merge_entity(self, table_name, partition_key, row_key, entity):
450+ data = entity.to_update_xml()
451+ url = """%s/%s(PartitionKey='%s',RowKey='%s')""" % (self.get_base_url(), table_name, partition_key, row_key)
452+ req = winazurestorage.RequestWithMethod("MERGE", url, data=data)
453+ req.add_header("Content-Length", "%d" % len(data))
454+ req.add_header("Content-Type", "application/atom+xml")
455+ self._credentials.sign_table_request(req)
456+ try:
457+ response = urlopen(req)
458+ return response.code
459+ except URLError, e:
460+ return e.code
461+
462+ def delete_entity(self, table_name, partition_key, row_key, condition="*"):
463+ data = ""
464+ url = """%s/%s(PartitionKey='%s',RowKey='%s')""" % (self.get_base_url(), table_name, partition_key, row_key)
465+ req = winazurestorage.RequestWithMethod("DELETE", url, data)
466+ req.add_header("Content-Length", "%d" % len(data))
467+ req.add_header("Content-Type", "application/atom+xml")
468+ req.add_header("If-Match", condition)
469+ self._credentials.sign_table_request(req)
470+ try:
471+ response = urlopen(req)
472+ return response.code
473+ except URLError, e:
474+ return e.code
475+
476+ def query_entity(self, table_name, filter):
477+ quoted_filter = urllib.quote(filter)
478+ url = """%s/%s()?$filter=%s""" % (self.get_base_url(), table_name, quoted_filter)
479+ req = winazurestorage.RequestWithMethod("GET", url)
480+ self._credentials.sign_table_request(req)
481+ try:
482+ resp = urlopen(req)
483+ except URLError, e:
484+ return e.code
485+
486+ dom = minidom.parseString(resp.read())
487+ entries = dom.getElementsByTagName("entry")
488+ entities = []
489+ for entry in entries:
490+ entities.append(self._parse_entity(entry))
491+ dom.unlink()
492+ return entities
493+
494+ def top_entity(self, table_name, size):
495+ url = """%s/%s()?$top=%s""" % (self.get_base_url(), table_name, size)
496+ req = winazurestorage.RequestWithMethod("GET", url)
497+ self._credentials.sign_table_request(req)
498+
499+ try:
500+ resp = urlopen(req)
501+ except URLError, e:
502+ return e.code
503+
504+ dom = minidom.parseString(resp.read())
505+ entries = dom.getElementsByTagName("entry")
506+ entities = []
507+ for entry in entries:
508+ entities.append(self._parse_entity(entry))
509+ dom.unlink()
510+ return entities
511+
303512 class BlobStorage(Storage):
304513 def __init__(self, host = DEVSTORE_BLOB_HOST, account_name = DEVSTORE_ACCOUNT, secret_key = DEVSTORE_SECRET_KEY, use_path_style_uris = None):
305514 super(BlobStorage, self).__init__(host, account_name, secret_key, use_path_style_uris)
@@ -416,3 +625,4 @@ def main():
416625
417626 if __name__ == '__main__':
418627 main()
628+