diff --git a/config.py b/config.py index e3e47b8..c40e630 100644 --- a/config.py +++ b/config.py @@ -1,20 +1,20 @@ -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- # Microsoft Developer & Platform Evangelism # # Copyright (c) Microsoft Corporation. All rights reserved. # -# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -#---------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------- # The example companies, organizations, products, domain names, # e-mail addresses, logos, people, places, and events depicted # herein are fictitious. No association with any real company, # organization, product, domain name, email address, logo, person, # places, or events is intended or should be inferred. -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- # Please do not include this file if you plan to contribute to this repo to assure your storage account name and key are not inadvertantly shared -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- IS_EMULATED = False -STORAGE_CONNECTION_STRING = '' \ No newline at end of file +STORAGE_CONNECTION_STRING = '' diff --git a/random_data.py b/random_data.py index 21517c7..3cf19c2 100644 --- a/random_data.py +++ b/random_data.py @@ -1,7 +1,10 @@ -import random, string +import random +import string from random import randint # Gets random data to use in samples + + class RandomData: # Gets random characters to use for generating unique name. def get_random_name(self, length): @@ -15,4 +18,4 @@ def get_random_bytes(self, size): result = bytearray(size) for i in range(size): result[i] = rand.randint(0, 255) - return bytes(result) \ No newline at end of file + return bytes(result) diff --git a/start.py b/start.py index aa76fa5..ad1daf7 100644 --- a/start.py +++ b/start.py @@ -1,18 +1,18 @@ -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- # Microsoft Developer & Platform Evangelism # # Copyright (c) Microsoft Corporation. All rights reserved. # -# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -#---------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------- # The example companies, organizations, products, domain names, # e-mail addresses, logos, people, places, and events depicted # herein are fictitious. No association with any real company, # organization, product, domain name, email address, logo, person, # places, or events is intended or should be inferred. -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- import config import azure.common @@ -23,14 +23,15 @@ print('Azure Table Storage samples for Python') -# Create the storage account object and specify its credentials +# Create the storage account object and specify its credentials # to either point to the local Emulator or your Azure subscription if config.IS_EMULATED: account = TableStorageAccount(is_emulated=True) else: account_connection_string = config.STORAGE_CONNECTION_STRING - # Split into key=value pairs removing empties, then split the pairs into a dict - config = dict(s.split('=', 1) for s in account_connection_string.split(';') if s) + # Split into key=value pairs removing empties, then split the pairs into a dict + config = dict(s.split('=', 1) + for s in account_connection_string.split(';') if s) # Authentication account_name = config.get('AccountName') @@ -38,20 +39,23 @@ # Basic URL Configuration endpoint_suffix = config.get('EndpointSuffix') if endpoint_suffix == None: - table_endpoint = config.get('TableEndpoint') - table_prefix = '.table.' - start_index = table_endpoint.find(table_prefix) - end_index = table_endpoint.endswith(':') and len(table_endpoint) or table_endpoint.rfind(':') - endpoint_suffix = table_endpoint[start_index+len(table_prefix):end_index] - account = TableStorageAccount(account_name = account_name, connection_string = account_connection_string, endpoint_suffix=endpoint_suffix) -#Basic Table samples -print ('---------------------------------------------------------------') + table_endpoint = config.get('TableEndpoint') + table_prefix = '.table.' + start_index = table_endpoint.find(table_prefix) + end_index = table_endpoint.endswith(':') and len( + table_endpoint) or table_endpoint.rfind(':') + endpoint_suffix = table_endpoint[start_index + + len(table_prefix):end_index] + account = TableStorageAccount( + account_name=account_name, connection_string=account_connection_string, endpoint_suffix=endpoint_suffix) +# Basic Table samples +print('---------------------------------------------------------------') print('Azure Storage Table samples') table_basic_samples = TableBasicSamples() table_basic_samples.run_all_samples(account) -#Advanced Table samples -print ('---------------------------------------------------------------') +# Advanced Table samples +print('---------------------------------------------------------------') print('Azure Storage Advanced Table samples') table_advanced_samples = TableAdvancedSamples() -table_advanced_samples.run_all_samples(account) \ No newline at end of file +table_advanced_samples.run_all_samples(account) diff --git a/table_advanced_samples.py b/table_advanced_samples.py index cc8e5ba..7a79f95 100644 --- a/table_advanced_samples.py +++ b/table_advanced_samples.py @@ -1,18 +1,18 @@ -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- # Microsoft Developer & Platform Evangelism # # Copyright (c) Microsoft Corporation. All rights reserved. # -# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -#---------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------- # The example companies, organizations, products, domain names, # e-mail addresses, logos, people, places, and events depicted # herein are fictitious. No association with any real company, # organization, product, domain name, email address, logo, person, # places, or events is intended or should be inferred. -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- import config import datetime import time @@ -34,6 +34,8 @@ # - Table Service Python API - http://azure.github.io/azure-storage-python/ref/azure.storage.table.html # - Storage Emulator - http://azure.microsoft.com/en-us/documentation/articles/storage-use-emulator/ # + + class TableAdvancedSamples(): def __init__(self): @@ -43,20 +45,20 @@ def __init__(self): def run_all_samples(self, account): table_service = account.create_table_service() print('Azure Storage Advanced Table samples - Starting.') - + print('\n\n* List tables *\n') self.list_tables(table_service) - + if not account.is_azure_cosmosdb_table(): - print('\n\n* Set service properties *\n') - self.set_service_properties(table_service) - - print('\n\n* Set Cors rules *\n') - self.set_cors_rules(table_service) - - print('\n\n* ACL operations *\n') - self.table_acl_operations(table_service) - + print('\n\n* Set service properties *\n') + self.set_service_properties(table_service) + + print('\n\n* Set Cors rules *\n') + self.set_cors_rules(table_service) + + print('\n\n* ACL operations *\n') + self.table_acl_operations(table_service) + if (config.IS_EMULATED): print('\n\n* Shared Access Signature is not supported in emulator *\n') else: @@ -69,14 +71,14 @@ def run_all_samples(self, account): def list_tables(self, table_service): table_prefix = 'table' + self.random_data.get_random_name(6) - try: + try: # Create tables for i in range(5): table_name = table_prefix + str(i) print('1. Create a table with name - ' + table_name) table_service.create_table(table_name) - - # List all the tables + + # List all the tables print('2. List tables') tables = table_service.list_tables() for table in tables: @@ -89,63 +91,68 @@ def list_tables(self, table_service): table_name = table_prefix + str(i) if(table_service.exists(table_name)): table_service.delete_table(table_name) - + print("List tables sample completed") - + # Manage properties of the Table service, including logging and metrics settings, and the default service version. def set_service_properties(self, table_service): print('1. Get Table service properties') props = table_service.get_table_service_properties() retention = RetentionPolicy(enabled=True, days=5) - logging = Logging(delete=True, read=False, write=True, retention_policy=retention) - hour_metrics = Metrics(enabled=True, include_apis=True, retention_policy=retention) + logging = Logging(delete=True, read=False, write=True, + retention_policy=retention) + hour_metrics = Metrics( + enabled=True, include_apis=True, retention_policy=retention) minute_metrics = Metrics(enabled=False) try: print('2. Ovewrite Table service properties') - table_service.set_table_service_properties(logging=logging, hour_metrics=hour_metrics, minute_metrics=minute_metrics) + table_service.set_table_service_properties( + logging=logging, hour_metrics=hour_metrics, minute_metrics=minute_metrics) finally: print('3. Revert Table service properties back to the original ones') - table_service.set_table_service_properties(logging=props.logging, hour_metrics=props.hour_metrics, minute_metrics=props.minute_metrics) + table_service.set_table_service_properties( + logging=props.logging, hour_metrics=props.hour_metrics, minute_metrics=props.minute_metrics) print('4. Set Table service properties completed') - + # Manage CORS rules on the table service def set_cors_rules(self, table_service): cors_rule = CorsRule( - allowed_origins=['*'], + allowed_origins=['*'], allowed_methods=['POST', 'GET'], allowed_headers=['*'], exposed_headers=['*'], max_age_in_seconds=3600) - + print('1. Get Cors Rules') original_cors_rules = table_service.get_table_service_properties().cors - try: + try: print('2. Overwrite Cors Rules') table_service.set_table_service_properties(cors=[cors_rule]) finally: - #reverting cors rules back to the original ones + # reverting cors rules back to the original ones print('3. Revert Cors Rules back the original ones') - table_service.set_table_service_properties(cors=original_cors_rules) - + table_service.set_table_service_properties( + cors=original_cors_rules) + print("CORS sample completed") # Manage table access policy def table_acl_operations(self, table_service): table_name = 'acltable' + self.random_data.get_random_name(6) - try: + try: print('1. Create a table with name - ' + table_name) table_service.create_table(table_name) - + print('2. Set access policy for table') access_policy = AccessPolicy(permission=TablePermissions.QUERY, - expiry=datetime.datetime.utcnow() + datetime.timedelta(hours=1)) + expiry=datetime.datetime.utcnow() + datetime.timedelta(hours=1)) identifiers = {'id': access_policy} table_service.set_table_acl(table_name, identifiers) @@ -162,48 +169,52 @@ def table_acl_operations(self, table_service): print('5. Delete table') if(table_service.exists(table_name)): table_service.delete_table(table_name) - + print("Table ACL operations sample completed") - + # Manage shared access signature on a table def table_operations_with_sas(self, account): table_name = 'sastable' + self.random_data.get_random_name(6) - + try: # Create a Table Service object table_service = account.create_table_service() - + print('1. Create table with name - ' + table_name) table_service.create_table(table_name) - + # Create a Shared Access Signature for the table print('2. Get sas for table') - + table_sas = table_service.generate_table_shared_access_signature( - table_name, - TablePermissions.QUERY + TablePermissions.ADD + TablePermissions.UPDATE + TablePermissions.DELETE, + table_name, + TablePermissions.QUERY + TablePermissions.ADD + + TablePermissions.UPDATE + TablePermissions.DELETE, datetime.datetime.utcnow() + datetime.timedelta(hours=1)) - shared_account = TableStorageAccount(account_name=account.account_name, sas_token=table_sas, endpoint_suffix=account.endpoint_suffix) + shared_account = TableStorageAccount( + account_name=account.account_name, sas_token=table_sas, endpoint_suffix=account.endpoint_suffix) shared_table_service = shared_account.create_table_service() # Create a sample entity to insert into the table - customer = {'PartitionKey': 'Harp', 'RowKey': '1', 'email' : 'harp@contoso.com', 'phone' : '555-555-5555'} + customer = {'PartitionKey': 'Harp', 'RowKey': '1', + 'email': 'harp@contoso.com', 'phone': '555-555-5555'} # Insert the entity into the table print('3. Insert new entity into table with sas - ' + table_name) shared_table_service.insert_entity(table_name, customer) - + # Demonstrate how to query the entity print('4. Read the inserted entity with sas.') entity = shared_table_service.get_entity(table_name, 'Harp', '1') - + print(entity['email']) print(entity['phone']) # Demonstrate how to update the entity by changing the phone number print('5. Update an existing entity by changing the phone number with sas') - customer = {'PartitionKey': 'Harp', 'RowKey': '1', 'email' : 'harp@contoso.com', 'phone' : '425-123-1234'} + customer = {'PartitionKey': 'Harp', 'RowKey': '1', + 'email': 'harp@contoso.com', 'phone': '425-123-1234'} shared_table_service.update_entity(table_name, customer) # Demonstrate how to delete an entity @@ -214,5 +225,5 @@ def table_operations_with_sas(self, account): print('7. Delete table') if(table_service.exists(table_name)): table_service.delete_table(table_name) - - print("Table operations with sas completed") \ No newline at end of file + + print("Table operations with sas completed") diff --git a/table_basic_samples.py b/table_basic_samples.py index 87ff953..1bb72bd 100644 --- a/table_basic_samples.py +++ b/table_basic_samples.py @@ -1,18 +1,18 @@ -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- # Microsoft Developer & Platform Evangelism # # Copyright (c) Microsoft Corporation. All rights reserved. # -# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -#---------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------- # The example companies, organizations, products, domain names, # e-mail addresses, logos, people, places, and events depicted # herein are fictitious. No association with any real company, # organization, product, domain name, email address, logo, person, # places, or events is intended or should be inferred. -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- import config from random_data import RandomData from azure.storage import CloudStorageAccount @@ -30,6 +30,8 @@ # - Table Service Python API - http://azure.github.io/azure-storage-ruby/ # - Storage Emulator - http://azure.microsoft.com/en-us/documentation/articles/storage-use-emulator/ # + + class TableBasicSamples(): def __init__(self): @@ -49,10 +51,12 @@ def run_all_samples(self, account): try: table_service.create_table(table_name) except Exception as err: - print('Error creating table, ' + table_name + 'check if it already exists') - + print('Error creating table, ' + table_name + + 'check if it already exists') + # Create a sample entity to insert into the table - customer = {'PartitionKey': 'Harp', 'RowKey': '1', 'email' : 'harp@contoso.com', 'phone' : '555-555-5555'} + customer = {'PartitionKey': 'Harp', 'RowKey': '1', + 'email': 'harp@contoso.com', 'phone': '555-555-5555'} # Insert the entity into the table print('Inserting a new entity into table - ' + table_name) @@ -67,12 +71,14 @@ def run_all_samples(self, account): # Demonstrate how to update the entity by changing the phone number print('Update an existing entity by changing the phone number') - customer = {'PartitionKey': 'Harp', 'RowKey': '1', 'email' : 'harp@contoso.com', 'phone' : '425-123-1234'} + customer = {'PartitionKey': 'Harp', 'RowKey': '1', + 'email': 'harp@contoso.com', 'phone': '425-123-1234'} table_service.update_entity(table_name, customer) # Demonstrate how to query the updated entity, filter the results with a filter query and select only the value in the phone column print('Read the updated entity with a filter query') - entities = table_service.query_entities(table_name, filter="PartitionKey eq 'Harp'", select='phone') + entities = table_service.query_entities( + table_name, filter="PartitionKey eq 'Harp'", select='phone') for entity in entities: print(entity['phone']) @@ -83,9 +89,11 @@ def run_all_samples(self, account): except Exception as e: if (config.IS_EMULATED): - print('Error occurred in the sample. If you are using the emulator, please make sure the emulator is running.', e) - else: - print('Error occurred in the sample. Please make sure the account name and key are correct.', e) + print( + 'Error occurred in the sample. If you are using the emulator, please make sure the emulator is running.', e) + else: + print( + 'Error occurred in the sample. Please make sure the account name and key are correct.', e) finally: # Demonstrate deleting the table, if you don't want to have the table deleted comment the below block of code print('Deleting the table.') @@ -93,4 +101,4 @@ def run_all_samples(self, account): table_service.delete_table(table_name) print('Successfully deleted the table') - print('\nAzure Storage Basic Table samples - Completed.\n') \ No newline at end of file + print('\nAzure Storage Basic Table samples - Completed.\n') diff --git a/tablestorageaccount.py b/tablestorageaccount.py index 4cca9d1..80afbb4 100644 --- a/tablestorageaccount.py +++ b/tablestorageaccount.py @@ -1,29 +1,30 @@ -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- # Microsoft Developer & Platform Evangelism # # Copyright (c) Microsoft Corporation. All rights reserved. # -# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -#---------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------- # The example companies, organizations, products, domain names, # e-mail addresses, logos, people, places, and events depicted # herein are fictitious. No association with any real company, # organization, product, domain name, email address, logo, person, # places, or events is intended or should be inferred. -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- from azure.storage import SharedAccessSignature from azure.storage.table import TableService, Entity + class TableStorageAccount(object): """ Provides a factory for creating table with a common account name and connection_string. """ - def __init__(self, account_name=None, connection_string=None, sas_token=None, endpoint_suffix = 'cosmosdb.windows.net', is_emulated=None): + def __init__(self, account_name=None, connection_string=None, sas_token=None, endpoint_suffix='cosmosdb.windows.net', is_emulated=None): ''' :param str account_name: Storage account account name. @@ -40,7 +41,7 @@ def __init__(self, account_name=None, connection_string=None, sas_token=None, en self.account_name = account_name self.connection_string = connection_string self.sas_token = sas_token - self.endpoint_suffix = endpoint_suffix + self.endpoint_suffix = endpoint_suffix self.is_emulated = is_emulated def create_table_service(self): @@ -51,12 +52,11 @@ def create_table_service(self): :return: A service object. :rtype: :class:`~azure.storage.table.tableservice.TableService` ''' - return TableService(account_name = self.account_name, + return TableService(account_name=self.account_name, sas_token=self.sas_token, - endpoint_suffix=self.endpoint_suffix, - connection_string= self.connection_string, + endpoint_suffix=self.endpoint_suffix, + connection_string=self.connection_string, is_emulated=self.is_emulated) def is_azure_cosmosdb_table(self): return self.connection_string != None and "table.cosmosdb" in self.connection_string - \ No newline at end of file