diff --git a/LowVoltage/attribute_types.py b/LowVoltage/attribute_types.py index 6615ec5..3089589 100644 --- a/LowVoltage/attribute_types.py +++ b/LowVoltage/attribute_types.py @@ -2,13 +2,6 @@ # Copyright 2013-2014 Vincent Jacques -# @todo BINARY = "B" -BOOLEAN = "BOOL" -# @todo BINARY_SET = "BS" -LIST = "L" -MAP = "M" -NUMBER = "N" -NUMBER_SET = "NS" -NULL = "NULL" STRING = "S" -STRING_SET = "SS" +NUMBER = "N" +BINARY = "B" diff --git a/LowVoltage/operations/batch_operations.py b/LowVoltage/operations/batch_operations.py index 168c4f2..427edd1 100644 --- a/LowVoltage/operations/batch_operations.py +++ b/LowVoltage/operations/batch_operations.py @@ -118,7 +118,7 @@ def testReturnConsumedCapacityNone(self): def testKeys(self): self.assertEqual( - BatchGetItem().table("Table2").keys({"hash": "h21"}).table("Table1").keys({"hash": "h11"}, {"hash": "h12"}).table("Table2").keys([{"hash": "h22"}, {"hash": "h23"}]).build(), + BatchGetItem().table("Table2").keys({"hash": u"h21"}).table("Table1").keys({"hash": u"h11"}, {"hash": u"h12"}).table("Table2").keys([{"hash": u"h22"}, {"hash": u"h23"}]).build(), { "RequestItems": { "Table1": { @@ -188,28 +188,28 @@ def tearDown(self): self.connection.request(LowVoltage.operations.admin_operations.DeleteTable("Aaa")) def testSimpleBatchGet(self): - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "1", "a": "xxx"})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "2", "a": "yyy"})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "3", "a": "zzz"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"1", "a": "xxx"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"2", "a": "yyy"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"3", "a": "zzz"})) - r = self.connection.request(BatchGetItem().table("Aaa").keys({"h": "1"}, {"h": "2"}, {"h": "3"})) + r = self.connection.request(BatchGetItem().table("Aaa").keys({"h": u"1"}, {"h": u"2"}, {"h": u"3"})) with cover("r", r) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.responses.keys(), ["Aaa"]) self.assertEqual( sorted(r.responses["Aaa"], key=lambda i: i["h"]), - [{"h": "1", "a": "xxx"}, {"h": "2", "a": "yyy"}, {"h": "3", "a": "zzz"}] + [{"h": u"1", "a": "xxx"}, {"h": u"2", "a": "yyy"}, {"h": u"3", "a": "zzz"}] ) self.assertEqual(r.unprocessed_keys, {}) def testBatchGetWithProjections(self): - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "1", "a": "a1", "b": "b1", "c": "c1"})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "2", "a": "a2", "b": "b2", "c": "c2"})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "3", "a": "a3", "b": "b3", "c": "c3"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"1", "a": "a1", "b": "b1", "c": "c1"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"2", "a": "a2", "b": "b2", "c": "c2"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"3", "a": "a3", "b": "b3", "c": "c3"})) r = self.connection.request( - BatchGetItem().table("Aaa").keys({"h": "1"}, {"h": "2"}, {"h": "3"}).expression_attribute_name("p", "b").project("h").project("a", ["#p"]) + BatchGetItem().table("Aaa").keys({"h": u"1"}, {"h": u"2"}, {"h": u"3"}).expression_attribute_name("p", "b").project("h").project("a", ["#p"]) ) with cover("r", r) as r: @@ -217,7 +217,7 @@ def testBatchGetWithProjections(self): self.assertEqual(r.responses.keys(), ["Aaa"]) self.assertEqual( sorted(r.responses["Aaa"], key=lambda i: i["h"]), - [{"h": "1", "a": "a1", "b": "b1"}, {"h": "2", "a": "a2", "b": "b2"}, {"h": "3", "a": "a3", "b": "b3"}] + [{"h": u"1", "a": "a1", "b": "b1"}, {"h": u"2", "a": "a2", "b": "b2"}, {"h": u"3", "a": "a3", "b": "b3"}] ) self.assertEqual(r.unprocessed_keys, {}) @@ -324,7 +324,7 @@ def testReturnItemCollectionMetricsNone(self): def testDelete(self): self.assertEqual( - BatchWriteItem().table("Table").delete({"hash": "h1"}).table("Table").delete([{"hash": "h2"}]).build(), + BatchWriteItem().table("Table").delete({"hash": u"h1"}).table("Table").delete([{"hash": u"h2"}]).build(), { "RequestItems": { "Table": [ @@ -337,7 +337,7 @@ def testDelete(self): def testPut(self): self.assertEqual( - BatchWriteItem().table("Table").put({"hash": "h1"}, [{"hash": "h2"}]).build(), + BatchWriteItem().table("Table").put({"hash": u"h1"}, [{"hash": u"h2"}]).build(), { "RequestItems": { "Table": [ @@ -361,7 +361,7 @@ def tearDown(self): def testSimpleBatchPut(self): r = self.connection.request( BatchWriteItem().table("Aaa") - .put({"h": "1", "a": "xxx"}, {"h": "2", "a": "yyy"}, {"h": "3", "a": "zzz"}) + .put({"h": u"1", "a": "xxx"}, {"h": u"2", "a": "yyy"}, {"h": u"3", "a": "zzz"}) ) with cover("r", r) as r: @@ -370,16 +370,16 @@ def testSimpleBatchPut(self): self.assertEqual(r.unprocessed_items, {}) self.assertEqual( - self.connection.request(LowVoltage.operations.item_operations.GetItem("Aaa", {"h": "1"})).item, + self.connection.request(LowVoltage.operations.item_operations.GetItem("Aaa", {"h": u"1"})).item, {"h": "1", "a": "xxx"} ) def testSimpleBatchDelete(self): - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "1", "a": "xxx"})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "2", "a": "yyy"})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "3", "a": "zzz"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"1", "a": "xxx"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"2", "a": "yyy"})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"3", "a": "zzz"})) - r = self.connection.request(BatchWriteItem().table("Aaa").delete({"h": "1"}, {"h": "2"}, {"h": "3"})) + r = self.connection.request(BatchWriteItem().table("Aaa").delete({"h": u"1"}, {"h": u"2"}, {"h": u"3"})) with cover("r", r) as r: self.assertEqual(r.consumed_capacity, None) @@ -387,7 +387,7 @@ def testSimpleBatchDelete(self): self.assertEqual(r.unprocessed_items, {}) self.assertEqual( - self.connection.request(LowVoltage.operations.item_operations.GetItem("Aaa", {"h": "1"})).item, + self.connection.request(LowVoltage.operations.item_operations.GetItem("Aaa", {"h": u"1"})).item, None ) @@ -601,7 +601,7 @@ def testKeyGt(self): def testKeyBeginsWith(self): self.assertEqual( - Query("Aaa").key_begins_with("name", "prefix").build(), + Query("Aaa").key_begins_with("name", u"prefix").build(), { "TableName": "Aaa", "KeyConditions": {"name": {"ComparisonOperator": "BEGINS_WITH", "AttributeValueList": [{"S": "prefix"}]}}, @@ -618,7 +618,7 @@ def testKeyBetween(self): ) def testExclusiveStartKey(self): - self.assertEqual(Query("Aaa").exclusive_start_key({"h": "v"}).build(), {"TableName": "Aaa", "ExclusiveStartKey": {"h": {"S": "v"}}}) + self.assertEqual(Query("Aaa").exclusive_start_key({"h": u"v"}).build(), {"TableName": "Aaa", "ExclusiveStartKey": {"h": {"S": "v"}}}) def testLimit(self): self.assertEqual(Query("Aaa").limit(4).build(), {"TableName": "Aaa", "Limit": 4}) @@ -633,7 +633,7 @@ def testExpressionAttributeName(self): self.assertEqual(Query("Aaa").expression_attribute_name("n", "p").build(), {"TableName": "Aaa", "ExpressionAttributeNames": {"#n": "p"}}) def testExpressionAttributeValue(self): - self.assertEqual(Query("Aaa").expression_attribute_value("n", "p").build(), {"TableName": "Aaa", "ExpressionAttributeValues": {":n": {"S": "p"}}}) + self.assertEqual(Query("Aaa").expression_attribute_value("n", u"p").build(), {"TableName": "Aaa", "ExpressionAttributeValues": {":n": {"S": "p"}}}) def testProject(self): self.assertEqual(Query("Aaa").project("a").build(), {"TableName": "Aaa", "ProjectionExpression": "a"}) @@ -665,20 +665,20 @@ def setUp(self): .provisioned_throughput(1, 2) ) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "0", "r": 41, "v": 0})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "0", "r": 42, "v": 1})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "0", "r": 43, "v": 2})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "0", "r": 44, "v": 3})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "0", "r": 45, "v": 4})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "1", "r": 42, "v": 2})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "2", "r": 42, "v": 3})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"0", "r": 41, "v": 0})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"0", "r": 42, "v": 1})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"0", "r": 43, "v": 2})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"0", "r": 44, "v": 3})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"0", "r": 45, "v": 4})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"1", "r": 42, "v": 2})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"2", "r": 42, "v": 3})) def tearDown(self): self.connection.request(LowVoltage.operations.admin_operations.DeleteTable("Aaa")) def testSimpleQuery(self): r = self.connection.request( - Query("Aaa").key_eq("h", "1") + Query("Aaa").key_eq("h", u"1") ) with cover("r", r) as r: @@ -690,7 +690,7 @@ def testSimpleQuery(self): def testComplexQuery(self): r = self.connection.request( - Query("Aaa").key_eq("h", "0").key_between("r", 42, 44) + Query("Aaa").key_eq("h", u"0").key_between("r", 42, 44) .scan_index_forward_false() .project("r", "v") .filter_expression("#p<>:v") @@ -703,7 +703,7 @@ def testComplexQuery(self): self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 1) self.assertEqual(r.items[0], {"r": 44, "v": 3}) - self.assertEqual(r.last_evaluated_key, {"h": "0", "r": 43}) + self.assertEqual(r.last_evaluated_key, {"h": u"0", "r": 43}) self.assertEqual(r.scanned_count, 2) @@ -819,7 +819,7 @@ def testSegment(self): self.assertEqual(Scan("Aaa").segment(1, 2).build(), {"TableName": "Aaa", "Segment": 1, "TotalSegments": 2}) def testExclusiveStartKey(self): - self.assertEqual(Scan("Aaa").exclusive_start_key({"h": "v"}).build(), {"TableName": "Aaa", "ExclusiveStartKey": {"h": {"S": "v"}}}) + self.assertEqual(Scan("Aaa").exclusive_start_key({"h": u"v"}).build(), {"TableName": "Aaa", "ExclusiveStartKey": {"h": {"S": "v"}}}) def testLimit(self): self.assertEqual(Scan("Aaa").limit(4).build(), {"TableName": "Aaa", "Limit": 4}) @@ -833,7 +833,7 @@ def testExpressionAttributeName(self): self.assertEqual(Scan("Aaa").expression_attribute_name("n", "p").build(), {"TableName": "Aaa", "ExpressionAttributeNames": {"#n": "p"}}) def testExpressionAttributeValue(self): - self.assertEqual(Scan("Aaa").expression_attribute_value("n", "p").build(), {"TableName": "Aaa", "ExpressionAttributeValues": {":n": {"S": "p"}}}) + self.assertEqual(Scan("Aaa").expression_attribute_value("n", u"p").build(), {"TableName": "Aaa", "ExpressionAttributeValues": {":n": {"S": "p"}}}) def testProject(self): self.assertEqual(Scan("Aaa").project("a").build(), {"TableName": "Aaa", "ProjectionExpression": "a"}) @@ -851,10 +851,10 @@ def setUp(self): LowVoltage.operations.admin_operations.CreateTable("Aaa").hash_key("h", _atyp.STRING).provisioned_throughput(1, 2) ) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "0", "v": 0})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "1", "v": 1})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "2", "v": 2})) - self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": "3", "v": 3})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"0", "v": 0})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"1", "v": 1})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"2", "v": 2})) + self.connection.request(LowVoltage.operations.item_operations.PutItem("Aaa", {"h": u"3", "v": 3})) def tearDown(self): self.connection.request(LowVoltage.operations.admin_operations.DeleteTable("Aaa")) @@ -868,7 +868,7 @@ def testSimpleScan(self): self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 4) items = sorted((r.items[i] for i in range(4)), key=lambda i: i["h"]) - self.assertEqual(items, [{"h": "0", "v": 0}, {"h": "1", "v": 1}, {"h": "2", "v": 2}, {"h": "3", "v": 3}]) + self.assertEqual(items, [{"h": u"0", "v": 0}, {"h": u"1", "v": 1}, {"h": u"2", "v": 2}, {"h": u"3", "v": 3}]) self.assertEqual(r.last_evaluated_key, None) self.assertEqual(r.scanned_count, 4) @@ -878,40 +878,40 @@ def testPaginatedSegmentedScan(self): Scan("Aaa").segment(0, 2).limit(1) ) r02 = self.connection.request( - Scan("Aaa").segment(0, 2).exclusive_start_key({"h": "1"}) + Scan("Aaa").segment(0, 2).exclusive_start_key({"h": u"1"}) ) r11 = self.connection.request( Scan("Aaa").segment(1, 2).limit(1) ) r12 = self.connection.request( - Scan("Aaa").segment(1, 2).exclusive_start_key({"h": "0"}) + Scan("Aaa").segment(1, 2).exclusive_start_key({"h": u"0"}) ) with cover("r01", r01) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 1) - self.assertEqual(r.items[0], {"h": "1", "v": 1}) - self.assertEqual(r.last_evaluated_key, {"h": "1"}) + self.assertEqual(r.items[0], {"h": u"1", "v": 1}) + self.assertEqual(r.last_evaluated_key, {"h": u"1"}) self.assertEqual(r.scanned_count, 1) with cover("r02", r02) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 1) - self.assertEqual(r.items[0], {"h": "3", "v": 3}) + self.assertEqual(r.items[0], {"h": u"3", "v": 3}) self.assertEqual(r.last_evaluated_key, None) self.assertEqual(r.scanned_count, 1) with cover("r11", r11) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 1) - self.assertEqual(r.items[0], {"h": "0", "v": 0}) - self.assertEqual(r.last_evaluated_key, {"h": "0"}) + self.assertEqual(r.items[0], {"h": u"0", "v": 0}) + self.assertEqual(r.last_evaluated_key, {"h": u"0"}) self.assertEqual(r.scanned_count, 1) with cover("r12", r12) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 1) - self.assertEqual(r.items[0], {"h": "2", "v": 2}) + self.assertEqual(r.items[0], {"h": u"2", "v": 2}) self.assertEqual(r.last_evaluated_key, None) self.assertEqual(r.scanned_count, 1) @@ -923,8 +923,8 @@ def testFilteredScan(self): with cover("r", r) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.count, 2) - self.assertEqual(r.items[0], {"h": "3"}) - self.assertEqual(r.items[1], {"h": "2"}) + self.assertEqual(r.items[0], {"h": u"3"}) + self.assertEqual(r.items[1], {"h": u"2"}) self.assertEqual(r.last_evaluated_key, None) self.assertEqual(r.scanned_count, 4) diff --git a/LowVoltage/operations/conversion.py b/LowVoltage/operations/conversion.py index d17f9f3..7667888 100755 --- a/LowVoltage/operations/conversion.py +++ b/LowVoltage/operations/conversion.py @@ -2,7 +2,9 @@ # Copyright 2013-2014 Vincent Jacques +import base64 import numbers +import sys import unittest @@ -13,9 +15,17 @@ def _convert_dict_to_db(attributes): } +if sys.hexversion < 0x03000000: + BINARY_TYPE = str +else: + BINARY_TYPE = bytes + + def _convert_value_to_db(value): - if isinstance(value, basestring): + if isinstance(value, unicode): return {"S": value} + elif isinstance(value, BINARY_TYPE): + return {"B": base64.b64encode(value).decode("utf8")} elif isinstance(value, bool): return {"BOOL": value} elif isinstance(value, numbers.Integral): @@ -27,8 +37,10 @@ def _convert_value_to_db(value): raise TypeError elif all(isinstance(v, numbers.Integral) for v in value): return {"NS": [str(n) for n in value]} - elif all(isinstance(v, basestring) for v in value): - return {"SS": list(value)} + elif all(isinstance(v, unicode) for v in value): + return {"SS": [s for s in value]} + elif all(isinstance(v, BINARY_TYPE) for v in value): + return {"BS": [base64.b64encode(b).decode("utf8") for b in value]} else: raise TypeError elif isinstance(value, list): @@ -49,6 +61,8 @@ def _convert_db_to_dict(attributes): def _convert_db_to_value(value): if "S" in value: return value["S"] + elif "B" in value: + return bytes(base64.b64decode(value["B"])) elif "BOOL" in value: return value["BOOL"] elif "N" in value: @@ -58,7 +72,9 @@ def _convert_db_to_value(value): elif "NS" in value: return set(int(v) for v in value["NS"]) elif "SS" in value: - return set(v for v in value["SS"]) + return set(value["SS"]) + elif "BS" in value: + return set(bytes(base64.b64decode(v)) for v in value["BS"]) elif "L" in value: return [_convert_db_to_value(v) for v in value["L"]] elif "M" in value: @@ -69,14 +85,16 @@ def _convert_db_to_value(value): class ConversionUnitTests(unittest.TestCase): def testConvertValueToDb(self): - self.assertEqual(_convert_value_to_db("foo"), {"S": "foo"}) + self.assertEqual(_convert_value_to_db(u"éoà"), {"S": u"éoà"}) + self.assertEqual(_convert_value_to_db(b"\xFF\x00\xAB"), {"B": u"/wCr"}) self.assertEqual(_convert_value_to_db(True), {"BOOL": True}) self.assertEqual(_convert_value_to_db(False), {"BOOL": False}) self.assertEqual(_convert_value_to_db(42), {"N": "42"}) self.assertEqual(_convert_value_to_db(None), {"NULL": True}) self.assertIn(_convert_value_to_db(set([42, 43])), [{"NS": ["42", "43"]}, {"NS": ["43", "42"]}]) self.assertIn(_convert_value_to_db(frozenset([42, 43])), [{"NS": ["42", "43"]}, {"NS": ["43", "42"]}]) - self.assertIn(_convert_value_to_db(set(["foo", "bar"])), [{"SS": ["foo", "bar"]}, {"SS": ["bar", "foo"]}]) + self.assertIn(_convert_value_to_db(set([u"éoà", u"bar"])), [{"SS": [u"éoà", u"bar"]}, {"SS": [u"bar", u"éoà"]}]) + self.assertIn(_convert_value_to_db(set([b"\xFF\x00\xAB", b"bar"])), [{"BS": [u"/wCr", u"YmFy"]}, {"BS": [u"YmFy", u"/wCr"]}]) self.assertEqual(_convert_value_to_db([True, 42]), {"L": [{"BOOL": True}, {"N": "42"}]}) self.assertEqual(_convert_value_to_db({"a": True, "b": 42}), {"M": {"a": {"BOOL": True}, "b": {"N": "42"}}}) with self.assertRaises(TypeError): @@ -89,13 +107,15 @@ def testConvertValueToDb(self): _convert_value_to_db((1, 2)) def testConvertDbToValue(self): - self.assertEqual(_convert_db_to_value({"S": "foo"}), "foo") + self.assertEqual(_convert_db_to_value({"S": u"éoà"}), u"éoà") + self.assertEqual(_convert_db_to_value({"B": u"/wCr"}), b"\xFF\x00\xAB") self.assertEqual(_convert_db_to_value({"BOOL": True}), True) self.assertEqual(_convert_db_to_value({"BOOL": False}), False) self.assertEqual(_convert_db_to_value({"N": "42"}), 42) self.assertEqual(_convert_db_to_value({"NULL": True}), None) self.assertEqual(_convert_db_to_value({"NS": ["42", "43"]}), set([42, 43])) - self.assertEqual(_convert_db_to_value({"SS": ["foo", "bar"]}), set(["foo", "bar"])) + self.assertEqual(_convert_db_to_value({"SS": [u"éoà", u"bar"]}), set([u"éoà", u"bar"])) + self.assertEqual(_convert_db_to_value({"BS": [u"/wCr", u"YmFy"]}), set([b"\xFF\x00\xAB", b"bar"])) self.assertEqual(_convert_db_to_value({"L": [{"BOOL": True}, {"N": "42"}]}), [True, 42]) self.assertEqual(_convert_db_to_value({"M": {"a": {"BOOL": True}, "b": {"N": "42"}}}), {"a": True, "b": 42}) with self.assertRaises(TypeError): diff --git a/LowVoltage/operations/expression_mixins.py b/LowVoltage/operations/expression_mixins.py index f84e850..bedc0f7 100644 --- a/LowVoltage/operations/expression_mixins.py +++ b/LowVoltage/operations/expression_mixins.py @@ -35,13 +35,13 @@ def testDefault(self): def testValues(self): self.assertEqual( ExpressionAttributeValuesMixin() - .expression_attribute_value("n1", "v1") - .expression_attribute_value("n2", "v2") + .expression_attribute_value("n1", u"v1") + .expression_attribute_value("n2", 42) ._build_expression_attribute_values(), { "ExpressionAttributeValues": { ":n1": {"S": "v1"}, - ":n2": {"S": "v2"}, + ":n2": {"N": "42"}, }, } ) diff --git a/LowVoltage/operations/item_operations.py b/LowVoltage/operations/item_operations.py index 3b9d705..03e4642 100644 --- a/LowVoltage/operations/item_operations.py +++ b/LowVoltage/operations/item_operations.py @@ -93,7 +93,7 @@ def testKey(self): def testReturnValuesNone(self): self.assertEqual( - DeleteItem("Table", {"hash": "h"}).return_values_none().build(), + DeleteItem("Table", {"hash": u"h"}).return_values_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -103,7 +103,7 @@ def testReturnValuesNone(self): def testReturnConsumedCapacityNone(self): self.assertEqual( - DeleteItem("Table", {"hash": "h"}).return_consumed_capacity_none().build(), + DeleteItem("Table", {"hash": u"h"}).return_consumed_capacity_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -113,7 +113,7 @@ def testReturnConsumedCapacityNone(self): def testReturnItemCollectionMetricsNone(self): self.assertEqual( - DeleteItem("Table", {"hash": "h"}).return_item_collection_metrics_none().build(), + DeleteItem("Table", {"hash": u"h"}).return_item_collection_metrics_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -123,7 +123,7 @@ def testReturnItemCollectionMetricsNone(self): def testExpressionAttributeValue(self): self.assertEqual( - DeleteItem("Table", {"hash": 42}).expression_attribute_value("v", "value").build(), + DeleteItem("Table", {"hash": 42}).expression_attribute_value("v", u"value").build(), { "TableName": "Table", "Key": {"hash": {"N": "42"}}, @@ -162,9 +162,9 @@ def tearDown(self): self.connection.request(LowVoltage.operations.admin_operations.DeleteTable("Aaa")) def testSimpleDelete(self): - self.connection.request(PutItem("Aaa", {"h": "simple", "a": "yyy"})) + self.connection.request(PutItem("Aaa", {"h": u"simple", "a": "yyy"})) - r = self.connection.request(DeleteItem("Aaa", {"h": "simple"})) + r = self.connection.request(DeleteItem("Aaa", {"h": u"simple"})) with cover("r", r) as r: self.assertEqual(r.attributes, None) @@ -172,12 +172,12 @@ def testSimpleDelete(self): self.assertEqual(r.item_collection_metrics, None) def testReturnOldValues(self): - self.connection.request(PutItem("Aaa", {"h": "get", "a": "yyy"})) + self.connection.request(PutItem("Aaa", {"h": u"return", "a": "yyy"})) - r = self.connection.request(DeleteItem("Aaa", {"h": "get"}).return_values_all_old()) + r = self.connection.request(DeleteItem("Aaa", {"h": u"return"}).return_values_all_old()) with cover("r", r) as r: - self.assertEqual(r.attributes, {"h": "get", "a": "yyy"}) + self.assertEqual(r.attributes, {"h": "return", "a": "yyy"}) self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.item_collection_metrics, None) @@ -253,7 +253,7 @@ def testKey(self): def testReturnConsumedCapacityNone(self): self.assertEqual( - GetItem("Table", {"hash": "h"}).return_consumed_capacity_none().build(), + GetItem("Table", {"hash": u"h"}).return_consumed_capacity_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -263,7 +263,7 @@ def testReturnConsumedCapacityNone(self): def testConsistentReadTrue(self): self.assertEqual( - GetItem("Table", {"hash": "h"}).consistent_read_true().build(), + GetItem("Table", {"hash": u"h"}).consistent_read_true().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -273,7 +273,7 @@ def testConsistentReadTrue(self): def testConsistentReadFalse(self): self.assertEqual( - GetItem("Table", {"hash": "h"}).consistent_read_false().build(), + GetItem("Table", {"hash": u"h"}).consistent_read_false().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -283,7 +283,7 @@ def testConsistentReadFalse(self): def testProject(self): self.assertEqual( - GetItem("Table", {"hash": "h"}).project("abc").build(), + GetItem("Table", {"hash": u"h"}).project("abc").build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -312,18 +312,18 @@ def tearDown(self): self.connection.request(LowVoltage.operations.admin_operations.DeleteTable("Aaa")) def testSimpleGet(self): - self.connection.request(PutItem("Aaa", {"h": "get", "a": "yyy"})) + self.connection.request(PutItem("Aaa", {"h": u"get", "a": "yyy"})) - r = self.connection.request(GetItem("Aaa", {"h": "get"})) + r = self.connection.request(GetItem("Aaa", {"h": u"get"})) with cover("r", r) as r: self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.item, {"h": "get", "a": "yyy"}) def testGetWithProjections(self): - self.connection.request(PutItem("Aaa", {"h": "attrs", "a": "yyy", "b": {"c": ["d1", "d2", "d3"]}, "e": 42, "f": "nope"})) + self.connection.request(PutItem("Aaa", {"h": u"attrs", "a": "yyy", "b": {"c": ["d1", "d2", "d3"]}, "e": 42, "f": "nope"})) - r = self.connection.request(GetItem("Aaa", {"h": "attrs"}).project("b.c[1]", "e")) + r = self.connection.request(GetItem("Aaa", {"h": u"attrs"}).project("b.c[1]", "e")) with cover("r", r) as r: self.assertEqual(r.consumed_capacity, None) @@ -392,7 +392,7 @@ def testName(self): def testItem(self): self.assertEqual( - PutItem("Table", {"hash": "value"}).build(), + PutItem("Table", {"hash": u"value"}).build(), { "TableName": "Table", "Item": {"hash": {"S": "value"}}, @@ -401,7 +401,7 @@ def testItem(self): def testReturnValuesNone(self): self.assertEqual( - PutItem("Table", {"hash": "h"}).return_values_none().build(), + PutItem("Table", {"hash": u"h"}).return_values_none().build(), { "TableName": "Table", "Item": {"hash": {"S": "h"}}, @@ -411,7 +411,7 @@ def testReturnValuesNone(self): def testReturnConsumedCapacityNone(self): self.assertEqual( - PutItem("Table", {"hash": "h"}).return_consumed_capacity_none().build(), + PutItem("Table", {"hash": u"h"}).return_consumed_capacity_none().build(), { "TableName": "Table", "Item": {"hash": {"S": "h"}}, @@ -421,7 +421,7 @@ def testReturnConsumedCapacityNone(self): def testReturnItemCollectionMetricsNone(self): self.assertEqual( - PutItem("Table", {"hash": "h"}).return_item_collection_metrics_none().build(), + PutItem("Table", {"hash": u"h"}).return_item_collection_metrics_none().build(), { "TableName": "Table", "Item": {"hash": {"S": "h"}}, @@ -431,7 +431,7 @@ def testReturnItemCollectionMetricsNone(self): def testExpressionAttributeValue(self): self.assertEqual( - PutItem("Table", {"hash": 42}).expression_attribute_value("v", "value").build(), + PutItem("Table", {"hash": 42}).expression_attribute_value("v", u"value").build(), { "TableName": "Table", "Item": {"hash": {"N": "42"}}, @@ -470,55 +470,59 @@ def tearDown(self): self.connection.request(LowVoltage.operations.admin_operations.DeleteTable("Aaa")) def testSimplePut(self): - r = self.connection.request(PutItem("Aaa", {"h": "simple"})) + r = self.connection.request(PutItem("Aaa", {"h": u"simple"})) with cover("r", r) as r: self.assertEqual(r.attributes, None) self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.item_collection_metrics, None) - self.assertEqual(self.connection.request(GetItem("Aaa", {"h": "simple"})).item, {"h": "simple"}) + self.assertEqual(self.connection.request(GetItem("Aaa", {"h": u"simple"})).item, {"h": u"simple"}) def testPutAllTypes(self): # @todo B and BS self.connection.request(PutItem("Aaa", { - "h": "all", - "s": "foo", - "b1": True, - "b2": False, - "n": 42, + "h": u"all", + "string": u"àoé", + "binary": b"\xFF\x00\xFF", + "binary set": set([b"\xFF", b"\xAB"]), + "bool 1": True, + "bool 2": False, + "number": 42, "null": None, - "ns": set([42, 43]), - "ss": set(["foo", "bar"]), - "l": [True, 42], - "m": {"a": True, "b": 42}, + "number set": set([42, 43]), + "string set": set([u"éoà", u"bar"]), + "list": [True, 42], + "map": {"a": True, "b": 42}, })) self.assertEqual( - self.connection.request(GetItem("Aaa", {"h": "all"})).item, + self.connection.request(GetItem("Aaa", {"h": u"all"})).item, { - "h": "all", - "s": "foo", - "b1": True, - "b2": False, - "n": 42, + "h": u"all", + "string": u"àoé", + "binary": b"\xFF\x00\xFF", + "binary set": set([b"\xFF", b"\xAB"]), + "bool 1": True, + "bool 2": False, + "number": 42, "null": None, - "ns": set([42, 43]), - "ss": set(["foo", "bar"]), - "l": [True, 42], - "m": {"a": True, "b": 42}, + "number set": set([42, 43]), + "string set": set([u"éoà", u"bar"]), + "list": [True, 42], + "map": {"a": True, "b": 42}, } ) def testReturnOldValues(self): - self.connection.request(PutItem("Aaa", {"h": "return", "a": "yyy"})) + self.connection.request(PutItem("Aaa", {"h": u"return", "a": b"yyy"})) r = self.connection.request( - PutItem("Aaa", {"h": "return", "b": "xxx"}).return_values_all_old() + PutItem("Aaa", {"h": u"return", "b": b"xxx"}).return_values_all_old() ) with cover("r", r) as r: - self.assertEqual(r.attributes, {"h": "return", "a": "yyy"}) + self.assertEqual(r.attributes, {"h": u"return", "a": b"yyy"}) self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.item_collection_metrics, None) @@ -722,7 +726,7 @@ def testSeveralDeletes(self): def testExpressionAttributeValue(self): self.assertEqual( - UpdateItem("Table", {"hash": 42}).expression_attribute_value("v", "value").build(), + UpdateItem("Table", {"hash": 42}).expression_attribute_value("v", u"value").build(), { "TableName": "Table", "Key": {"hash": {"N": "42"}}, @@ -752,7 +756,7 @@ def testConditionExpression(self): def testReturnValuesNone(self): self.assertEqual( - UpdateItem("Table", {"hash": "h"}).return_values_none().build(), + UpdateItem("Table", {"hash": u"h"}).return_values_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -762,7 +766,7 @@ def testReturnValuesNone(self): def testReturnConsumedCapacityNone(self): self.assertEqual( - UpdateItem("Table", {"hash": "h"}).return_consumed_capacity_none().build(), + UpdateItem("Table", {"hash": u"h"}).return_consumed_capacity_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -772,7 +776,7 @@ def testReturnConsumedCapacityNone(self): def testReturnItemCollectionMetricsNone(self): self.assertEqual( - UpdateItem("Table", {"hash": "h"}).return_item_collection_metrics_none().build(), + UpdateItem("Table", {"hash": u"h"}).return_item_collection_metrics_none().build(), { "TableName": "Table", "Key": {"hash": {"S": "h"}}, @@ -792,7 +796,7 @@ def tearDown(self): def testSet(self): r = self.connection.request( - UpdateItem("Aaa", {"h": "set"}) + UpdateItem("Aaa", {"h": u"set"}) .set("a", "v") .set("#p", "w") .expression_attribute_value("v", "aaa") @@ -806,7 +810,7 @@ def testSet(self): self.assertEqual(r.item_collection_metrics, None) self.assertEqual( - self.connection.request(GetItem("Aaa", {"h": "set"})).item, + self.connection.request(GetItem("Aaa", {"h": u"set"})).item, {"h": "set", "a": "aaa", "b": "bbb"} ) @@ -815,7 +819,7 @@ def testComplexUpdate(self): PutItem( "Aaa", { - "h": "complex", + "h": u"complex", "a": "a", "b": "b", "c": "c", @@ -828,7 +832,7 @@ def testComplexUpdate(self): ) r = self.connection.request( - UpdateItem("Aaa", {"h": "complex"}) + UpdateItem("Aaa", {"h": u"complex"}) .set("a", "s") .set("b", "i") .remove("c") @@ -845,7 +849,7 @@ def testComplexUpdate(self): self.assertEqual( r.attributes, { - "h": "complex", + "h": u"complex", "a": set([42, 43]), "b": 52, "d": set([41, 42, 43]), @@ -858,10 +862,10 @@ def testComplexUpdate(self): self.assertEqual(r.item_collection_metrics, None) def testConditionExpression(self): - self.connection.request(PutItem("Aaa", {"h": "expr", "a": 42, "b": 42})) + self.connection.request(PutItem("Aaa", {"h": u"expr", "a": 42, "b": 42})) r = self.connection.request( - UpdateItem("Aaa", {"h": "expr"}) + UpdateItem("Aaa", {"h": u"expr"}) .set("checked", "true") .expression_attribute_value("true", True) .condition_expression("a=b") @@ -871,7 +875,7 @@ def testConditionExpression(self): with cover("r", r) as r: self.assertEqual( r.attributes, - {"h": "expr", "a": 42, "b": 42, "checked": True} + {"h": u"expr", "a": 42, "b": 42, "checked": True} ) self.assertEqual(r.consumed_capacity, None) self.assertEqual(r.item_collection_metrics, None)