diff --git a/sdk/tables/azure-data-tables/azure/data/tables/_deserialize.py b/sdk/tables/azure-data-tables/azure/data/tables/_deserialize.py index fa65406bcbde..8adf6db3fac2 100644 --- a/sdk/tables/azure-data-tables/azure/data/tables/_deserialize.py +++ b/sdk/tables/azure-data-tables/azure/data/tables/_deserialize.py @@ -16,7 +16,6 @@ from ._entity import EntityProperty, EdmType, TableEntity from ._common_conversion import _decode_base64_to_bytes -from ._generated.models import TableProperties from ._error import TableErrorCode if TYPE_CHECKING: @@ -62,11 +61,11 @@ def _deserialize_table_creation(response, _, headers): def _from_entity_binary(value): - return EntityProperty(EdmType.BINARY, _decode_base64_to_bytes(value)) + return EntityProperty(_decode_base64_to_bytes(value)) def _from_entity_int32(value): - return EntityProperty(EdmType.INT32, int(value)) + return EntityProperty(int(value)) zero = datetime.timedelta(0) # same as 00:00 diff --git a/sdk/tables/azure-data-tables/azure/data/tables/_entity.py b/sdk/tables/azure-data-tables/azure/data/tables/_entity.py index faed3d8ae453..230eb402e16d 100644 --- a/sdk/tables/azure-data-tables/azure/data/tables/_entity.py +++ b/sdk/tables/azure-data-tables/azure/data/tables/_entity.py @@ -4,6 +4,9 @@ # license information. # -------------------------------------------------------------------------- from enum import Enum +from datetime import datetime +from uuid import UUID +import six from ._error import _ERROR_ATTRIBUTE_MISSING @@ -75,17 +78,41 @@ class EntityProperty(object): """ def __init__(self, - type=None, # type: Union[str,EdmType] # pylint:disable=W0622 - value=None # type: Any - ): + value=None, # type: Any + type=None, # type: Union[str,EdmType] # pylint:disable=W0622 + ): """ Represents an Azure Table. Returned by list_tables. :param Union[str, EdmType] type: The type of the property. :param Any value: The value of the property. """ - self.type = type self.value = value + if type is not None: + self.type = type + elif isinstance(value, six.text_type): + try: + self.value = UUID(value) + self.type = EdmType.GUID + except ValueError: + self.type = EdmType.STRING + elif isinstance(value, six.binary_type): + self.type = EdmType.BINARY + elif isinstance(value, bool): + self.type = EdmType.BOOLEAN + elif isinstance(value, six.integer_types): + self.type = EdmType.INT64 + elif isinstance(value, datetime): + self.type = EdmType.DATETIME + elif isinstance(value, float): + self.type = EdmType.DOUBLE + else: + raise ValueError( + """Type of {} could not be inferred. Acceptable types are bytes, int, uuid.UUID, + datetime, string, int32, int64, float, and boolean. Refer to + azure.data.tables.EdmType for more information. + """.format(value) + ) class EdmType(str, Enum): diff --git a/sdk/tables/azure-data-tables/tests/test_table_batch.py b/sdk/tables/azure-data-tables/tests/test_table_batch.py index 62d20bd42bd3..ba8603f9703f 100644 --- a/sdk/tables/azure-data-tables/tests/test_table_batch.py +++ b/sdk/tables/azure-data-tables/tests/test_table_batch.py @@ -16,6 +16,7 @@ from azure.core import MatchConditions from azure.core.exceptions import ( ResourceExistsError) +from azure.data.tables import EdmType, TableEntity, EntityProperty from _shared.testcase import GlobalStorageAccountPreparer, TableTestCase, LogCaptured @@ -78,7 +79,7 @@ def _create_random_entity_dict(self, pk=None, rk=None): 'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()), 'birthday': datetime(1970, 10, 4, tzinfo=tzutc()), 'binary': b'binary', - 'other': EntityProperty(EdmType.INT32, 20), + 'other': EntityProperty(20, EdmType.INT32), 'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833') } return Entity(**properties) @@ -148,6 +149,33 @@ def _assert_updated_entity(self, entity): self.assertIsInstance(entity.timestamp, datetime) #--Test cases for batch --------------------------------------------- + + def test_inferred_types(self): + # Arrange + # Act + entity = TableEntity() + entity.PartitionKey = '003' + entity.RowKey = 'batch_all_operations_together-1' + entity.test = EntityProperty(True) + entity.test2 = EntityProperty(b'abcdef') + entity.test3 = EntityProperty(u'c9da6455-213d-42c9-9a79-3e9149a57833') + entity.test4 = EntityProperty(datetime(1973, 10, 4, tzinfo=tzutc())) + entity.test5 = EntityProperty(u"stringystring") + entity.test6 = EntityProperty(3.14159) + entity.test7 = EntityProperty(100) + entity.test8 = EntityProperty(10, EdmType.INT32) + + # Assert + self.assertEqual(entity.test.type, EdmType.BOOLEAN) + self.assertEqual(entity.test2.type, EdmType.BINARY) + self.assertEqual(entity.test3.type, EdmType.GUID) + self.assertEqual(entity.test4.type, EdmType.DATETIME) + self.assertEqual(entity.test5.type, EdmType.STRING) + self.assertEqual(entity.test6.type, EdmType.DOUBLE) + self.assertEqual(entity.test7.type, EdmType.INT64) + self.assertEqual(entity.test8.type, EdmType.INT32) + + @pytest.mark.skip("pending") @GlobalStorageAccountPreparer() def test_batch_insert(self, resource_group, location, storage_account, storage_account_key): @@ -158,10 +186,10 @@ def test_batch_insert(self, resource_group, location, storage_account, storage_a entity = Entity() entity.PartitionKey = '001' entity.RowKey = 'batch_insert' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() batch = self.table.create_batch() @@ -185,10 +213,10 @@ def test_batch_update(self, resource_group, location, storage_account, storage_a entity = Entity() entity.PartitionKey = '001' entity.RowKey = 'batch_update' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() self.table.create_item(entity) @@ -218,10 +246,10 @@ def test_batch_merge(self, resource_group, location, storage_account, storage_ac entity = Entity() entity.PartitionKey = '001' entity.RowKey = 'batch_merge' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() self.table.create_item(entity) @@ -313,7 +341,7 @@ def test_batch_insert_replace(self, resource_group, location, storage_account, s entity.test = True entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() batch = self.table.create_batch() @@ -343,7 +371,7 @@ def test_batch_insert_merge(self, resource_group, location, storage_account, sto entity.test = True entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() batch = self.table.create_batch() @@ -370,10 +398,10 @@ def test_batch_delete(self, resource_group, location, storage_account, storage_a entity = Entity() entity.PartitionKey = '001' entity.RowKey = 'batch_delete' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() self.table.create_item(entity) @@ -399,10 +427,10 @@ def test_batch_inserts(self, resource_group, location, storage_account, storage_ # Act entity = Entity() entity.PartitionKey = 'batch_inserts' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) batch = self.table.create_batch() for i in range(100): @@ -428,10 +456,10 @@ def test_batch_all_operations_together(self, resource_group, location, storage_a entity = Entity() entity.PartitionKey = '003' entity.RowKey = 'batch_all_operations_together-1' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() self.table.create_item(entity) entity.RowKey = 'batch_all_operations_together-2' @@ -476,10 +504,10 @@ def test_batch_all_operations_together_context_manager(self, resource_group, loc entity = Entity() entity.PartitionKey = '003' entity.RowKey = 'batch_all_operations_together-1' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() self.table.create_item(entity) entity.RowKey = 'batch_all_operations_together-2' @@ -525,10 +553,10 @@ def test_batch_reuse(self, resource_group, location, storage_account, storage_ac entity = Entity() entity.PartitionKey = '003' entity.RowKey = 'batch_all_operations_together-1' - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'value' entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime.utcnow() batch = TableBatchClient() diff --git a/sdk/tables/azure-data-tables/tests/test_table_entity.py b/sdk/tables/azure-data-tables/tests/test_table_entity.py index c199a57d506f..7009161fdfff 100644 --- a/sdk/tables/azure-data-tables/tests/test_table_entity.py +++ b/sdk/tables/azure-data-tables/tests/test_table_entity.py @@ -115,7 +115,7 @@ def _create_random_entity_dict(self, pk=None, rk=None): 'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()), 'birthday': datetime(1970, 10, 4, tzinfo=tzutc()), 'binary': b'binary', - 'other': EntityProperty(type=EdmType.INT32, value=20), + 'other': EntityProperty(value=20, type=EdmType.INT32), 'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833') } return TableEntity(**properties) @@ -160,7 +160,7 @@ def _assert_default_entity(self, entity, headers=None): self.assertEqual(entity['birthday'], datetime(1970, 10, 4, tzinfo=tzutc())) self.assertEqual(entity['binary'].value, b'binary') self.assertIsInstance(entity['other'], EntityProperty) - self.assertEqual(entity['other'].type, EdmType.INT32) + self.assertEqual(entity['other'].type, EdmType.INT64) self.assertEqual(entity['other'].value, 20) self.assertEqual(entity['clsid'], uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')) # self.assertTrue('metadata' in entity.odata) @@ -188,7 +188,7 @@ def _assert_default_entity_json_full_metadata(self, entity, headers=None): self.assertEqual(entity['birthday'], datetime(1970, 10, 4, tzinfo=tzutc())) self.assertEqual(entity['binary'].value, b'binary') self.assertIsInstance(entity['other'], EntityProperty) - self.assertEqual(entity['other'].type, EdmType.INT32) + self.assertEqual(entity['other'].type, EdmType.INT64) self.assertEqual(entity['other'].value, 20) self.assertEqual(entity['clsid'], uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')) # self.assertTrue('metadata' in entity.odata) @@ -222,7 +222,7 @@ def _assert_default_entity_json_no_metadata(self, entity, headers=None): self.assertTrue(entity['birthday'].endswith('00Z')) self.assertEqual(entity['binary'], b64encode(b'binary').decode('utf-8')) self.assertIsInstance(entity['other'], EntityProperty) - self.assertEqual(entity['other'].type, EdmType.INT32) + self.assertEqual(entity['other'].type, EdmType.INT64) self.assertEqual(entity['other'].value, 20) self.assertEqual(entity['clsid'], 'c9da6455-213d-42c9-9a79-3e9149a57833') # self.assertIsNone(entity.odata) @@ -273,7 +273,7 @@ def _assert_merged_entity(self, entity): self.assertEqual(entity.Birthday, datetime(1973, 10, 4, tzinfo=tzutc())) self.assertEqual(entity.birthday, datetime(1991, 10, 4, tzinfo=tzutc())) self.assertIsInstance(entity.other, EntityProperty) - self.assertEqual(entity.other.type, EdmType.INT32) + self.assertEqual(entity.other.type, EdmType.INT64) self.assertEqual(entity.other.value, 20) self.assertIsInstance(entity.clsid, uuid.UUID) self.assertEqual(str(entity.clsid), 'c9da6455-213d-42c9-9a79-3e9149a57833') @@ -417,13 +417,13 @@ def test_insert_entity_with_large_int32_value_throws(self, resource_group, locat try: # Act dict32 = self._create_random_base_entity_dict() - dict32['large'] = EntityProperty(EdmType.INT32, 2 ** 31) + dict32['large'] = EntityProperty(2 ** 31, EdmType.INT32) # Assert with self.assertRaises(TypeError): self.table.create_entity(entity=dict32) - dict32['large'] = EntityProperty(EdmType.INT32, -(2 ** 31 + 1)) + dict32['large'] = EntityProperty(-(2 ** 31 + 1), EdmType.INT32) with self.assertRaises(TypeError): self.table.create_entity(entity=dict32) finally: @@ -438,13 +438,13 @@ def test_insert_entity_with_large_int64_value_throws(self, resource_group, locat try: # Act dict64 = self._create_random_base_entity_dict() - dict64['large'] = EntityProperty(EdmType.INT64, 2 ** 63) + dict64['large'] = EntityProperty(2 ** 63) # Assert with self.assertRaises(TypeError): self.table.create_entity(entity=dict64) - dict64['large'] = EntityProperty(EdmType.INT64, -(2 ** 63 + 1)) + dict64['large'] = EntityProperty(-(2 ** 63 + 1)) with self.assertRaises(TypeError): self.table.create_entity(entity=dict64) finally: @@ -1304,10 +1304,10 @@ def test_query_entities_large(self, resource_group, location, storage_account, s entity = Entity() entity.PartitionKey = 'large' entity.RowKey = 'batch{0}-item{1}'.format(j, i) - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'hello world;' * 100 entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime(2016, 12, 31, 11, 59, 59, 0) batch.create_entity(entity) self.ts.commit_batch(table_name, batch) diff --git a/sdk/tables/azure-data-tables/tests/test_table_entity_async.py b/sdk/tables/azure-data-tables/tests/test_table_entity_async.py index e6b6272e7250..df61b825def8 100644 --- a/sdk/tables/azure-data-tables/tests/test_table_entity_async.py +++ b/sdk/tables/azure-data-tables/tests/test_table_entity_async.py @@ -117,7 +117,7 @@ def _create_random_entity_dict(self, pk=None, rk=None): 'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()), 'birthday': datetime(1970, 10, 4, tzinfo=tzutc()), 'binary': b'binary', - 'other': EntityProperty(type=EdmType.INT32, value=20), + 'other': EntityProperty(value=20, type=EdmType.INT32), 'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833') } return TableEntity(**properties) @@ -163,7 +163,7 @@ def _assert_default_entity(self, entity, headers=None): self.assertEqual(entity['birthday'], datetime(1970, 10, 4, tzinfo=tzutc())) self.assertEqual(entity['binary'].value, b'binary') # TODO: added the ".value" portion, verify this is correct self.assertIsInstance(entity['other'], EntityProperty) - self.assertEqual(entity['other'].type, EdmType.INT32) + self.assertEqual(entity['other'].type, EdmType.INT64) self.assertEqual(entity['other'].value, 20) self.assertEqual(entity['clsid'], uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')) # self.assertTrue('metadata' in entity.odata) @@ -192,7 +192,7 @@ def _assert_default_entity_json_full_metadata(self, entity, headers=None): self.assertEqual(entity['birthday'], datetime(1970, 10, 4, tzinfo=tzutc())) self.assertEqual(entity['binary'].value, b'binary') self.assertIsInstance(entity['other'], EntityProperty) - self.assertEqual(entity['other'].type, EdmType.INT32) + self.assertEqual(entity['other'].type, EdmType.INT64) self.assertEqual(entity['other'].value, 20) self.assertEqual(entity['clsid'], uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')) # self.assertTrue('metadata' in entity.odata) @@ -227,7 +227,7 @@ def _assert_default_entity_json_no_metadata(self, entity, headers=None): self.assertTrue(entity['birthday'].endswith('00Z')) self.assertEqual(entity['binary'], b64encode(b'binary').decode('utf-8')) self.assertIsInstance(entity['other'], EntityProperty) - self.assertEqual(entity['other'].type, EdmType.INT32) + self.assertEqual(entity['other'].type, EdmType.INT64) self.assertEqual(entity['other'].value, 20) self.assertEqual(entity['clsid'], 'c9da6455-213d-42c9-9a79-3e9149a57833') # self.assertIsNone(entity.odata) @@ -277,7 +277,7 @@ def _assert_merged_entity(self, entity): self.assertEqual(entity.Birthday, datetime(1973, 10, 4, tzinfo=tzutc())) self.assertEqual(entity.birthday, datetime(1991, 10, 4, tzinfo=tzutc())) self.assertIsInstance(entity.other, EntityProperty) - self.assertEqual(entity.other.type, EdmType.INT32) + self.assertEqual(entity.other.type, EdmType.INT64) self.assertEqual(entity.other.value, 20) self.assertIsInstance(entity.clsid, uuid.UUID) self.assertEqual(str(entity.clsid), 'c9da6455-213d-42c9-9a79-3e9149a57833') @@ -391,13 +391,13 @@ async def test_insert_entity_with_large_int32_value_throws(self, resource_group, try: # Act dict32 = self._create_random_base_entity_dict() - dict32['large'] = EntityProperty(EdmType.INT32, 2 ** 31) + dict32['large'] = EntityProperty(2 ** 31, EdmType.INT32) # TODO: this is outside the range of int32 # Assert with self.assertRaises(TypeError): await self.table.create_entity(entity=dict32) - dict32['large'] = EntityProperty(EdmType.INT32, -(2 ** 31 + 1)) + dict32['large'] = EntityProperty(-(2 ** 31 + 1), EdmType.INT32) # TODO: this is outside the range of int32 with self.assertRaises(TypeError): await self.table.create_entity(entity=dict32) finally: @@ -412,13 +412,13 @@ async def test_insert_entity_with_large_int64_value_throws(self, resource_group, try: # Act dict64 = self._create_random_base_entity_dict() - dict64['large'] = EntityProperty(EdmType.INT64, 2 ** 63) + dict64['large'] = EntityProperty(2 ** 63) # Assert with self.assertRaises(TypeError): await self.table.create_entity(entity=dict64) - dict64['large'] = EntityProperty(EdmType.INT64, -(2 ** 63 + 1)) + dict64['large'] = EntityProperty(-(2 ** 63 + 1)) with self.assertRaises(TypeError): await self.table.create_entity(entity=dict64) finally: @@ -1305,10 +1305,10 @@ def test_query_entities_large(self, resource_group, location, storage_account, s entity = TableEntity() entity.PartitionKey = 'large' entity.RowKey = 'batch{0}-item{1}'.format(j, i) - entity.test = EntityProperty(EdmType.BOOLEAN, 'true') + entity.test = EntityProperty(True) entity.test2 = 'hello world;' * 100 entity.test3 = 3 - entity.test4 = EntityProperty(EdmType.INT64, '1234567890') + entity.test4 = EntityProperty(1234567890) entity.test5 = datetime(2016, 12, 31, 11, 59, 59, 0) batch.create_entity(entity) self.ts.commit_batch(table_name, batch)