84

I'm a new user in boto3 and i'm using DynamoDB.

I went through over the DynamoDB api and I couldn't find any method which tell me if a table is already exists.

What is the best approach dealing this issue?

Should I try to create a new table and wrap it using try catch ?

roeygol
  • 4,908
  • 9
  • 51
  • 88

8 Answers8

104

From reading the documentation, I can see that there are three methods by which you can check if a table exists.

  1. The CreateTable API throws an error ResourceInUseException if the table already exists. Wrap the create_table method with try except to catch this
  2. You can use the ListTables API to get the list of table names associated with the current account and endpoint. Check if the table name is present in the list of table names you get in the response.
  3. The DescribeTable API will throw an error ResourceNotFoundException if the table name you request doesn't exist.

To me, the first option sounds better if you just want to create a table.

Edit: I see that some people are finding it difficult to catch the exceptions. I will put some code below for you to know how to handle exceptions in boto3.

Example 1

import boto3

dynamodb_client = boto3.client('dynamodb')

try:
    response = dynamodb_client.create_table(
        AttributeDefinitions=[
            {
                'AttributeName': 'Artist',
                'AttributeType': 'S',
            },
            {
                'AttributeName': 'SongTitle',
                'AttributeType': 'S',
            },
        ],
        KeySchema=[
            {
                'AttributeName': 'Artist',
                'KeyType': 'HASH',
            },
            {
                'AttributeName': 'SongTitle',
                'KeyType': 'RANGE',
            },
        ],
        ProvisionedThroughput={
            'ReadCapacityUnits': 5,
            'WriteCapacityUnits': 5,
        },
        TableName='test',
    )
except dynamodb_client.exceptions.ResourceInUseException:
    # do something here as you require
    pass

Example 2

import boto3

dynamodb_client = boto3.client('dynamodb')


table_name = 'test'
existing_tables = dynamodb_client.list_tables()['TableNames']

if table_name not in existing_tables:
    response = dynamodb_client.create_table(
        AttributeDefinitions=[
            {
                'AttributeName': 'Artist',
                'AttributeType': 'S',
            },
            {
                'AttributeName': 'SongTitle',
                'AttributeType': 'S',
            },
        ],
        KeySchema=[
            {
                'AttributeName': 'Artist',
                'KeyType': 'HASH',
            },
            {
                'AttributeName': 'SongTitle',
                'KeyType': 'RANGE',
            },
        ],
        ProvisionedThroughput={
            'ReadCapacityUnits': 5,
            'WriteCapacityUnits': 5,
        },
        TableName=table_name,
    )

Example 3

import boto3

dynamodb_client = boto3.client('dynamodb')

try:
    response = dynamodb_client.describe_table(TableName='test')
except dynamodb_client.exceptions.ResourceNotFoundException:
    # do something here as you require
    pass
Yaron
  • 10,166
  • 9
  • 45
  • 65
anupsabraham
  • 2,781
  • 2
  • 24
  • 35
  • 2
    With `describe_table` I get `AttributeError: 'dynamodb.ServiceResource' object has no attribute 'describe_table'`. – chris Mar 19 '18 at 21:41
  • 10
    That is because you're using service resource instead of client. Check this line in your code: `dynamodb_client = boto3.client('dynamodb')` – anupsabraham Mar 20 '18 at 02:41
  • Example 3 is great, but I was getting a ClientError thrown: ``` dynamodb = boto3.resource(self._dynamodb_resource_name, region_name=self._region, endpoint_url=self._endpoint_url) # Try removing the table and ignore if it does not exist table = dynamodb.Table(self._tableName) try: table.delete() except ClientError as e: if e.response['Error']['Code'] != 'ResourceNotFoundException': raise e ``` – Paul Waldo Dec 24 '18 at 17:31
  • The code doesn't look like what I had posted above. Where did you get the code from? Is it working for you and where is `ClientError` imported from? – anupsabraham Dec 24 '18 at 19:01
  • So these exceptions only work with boto.client and not resource it seems. So I'd imagine it's better just to use boto.client as opposed to boto3.resource? – MasayoMusic Aug 07 '21 at 22:09
  • 2
    The exception handling described will work with the client API, but is there anyway to capture exceptions from the resource API? For example `boto3.resource("dynamodb").Table("table_that_doesnt_exist")` will raise `ResourceNotFoundException` but I can't capture with this use case. – Skynet Oct 04 '21 at 17:44
18
import boto3

from botocore.exceptions import ClientError

TABLE_NAME = "myTableName"
dynamodb = boto3.resource('dynamodb', endpoint_url="https://dynamodb.us-east-1.amazonaws.com")

table = dynamodb.Table(TABLE_NAME)

try:
    response = client.describe_table(TableName=TABLE_NAME)

except ClientError as ce:
if ce.response['Error']['Code'] == 'ResourceNotFoundException':
    print "Table " + TABLE_NAME + " does not exist. Create the table first and try again."
else:
    print "Unknown exception occurred while querying for the " + TABLE_NAME + " table. Printing full error:"
    pprint.pprint(ce.response)
fIwJlxSzApHEZIl
  • 11,861
  • 6
  • 62
  • 71
12

Alternate approach if you do not want to use boto3.client but only boto3.resource:

import boto3

database = boto3.resource('dynamodb', endpoint_url="http://localhost:8000")    

table_name  = 'MyTable'
table_names = [table.name for table in database.tables.all()]

if table_name in table_names:
    print('table', table_name, 'exists')
ssc
  • 9,528
  • 10
  • 64
  • 94
9

You can use describe table API to determine whether the table exists.

Sample code:

from __future__ import print_function # Python 2/3 compatibility
import os
os.environ["TZ"] = "UTC"
import boto3

client = boto3.client('dynamodb', region_name='us-west-2', endpoint_url="http://localhost:8000")



response = client.describe_table(
    TableName='Movies'
)    

print(response)

If table exists:-

  • You will get the response

If table doesn't exists:-

  • You will get ResourceNotFoundException

    botocore.errorfactory.ResourceNotFoundException: An error occurred (ResourceNotF oundException) when calling the DescribeTable operation: Cannot do operations on a non-existent table

Another way:-

Alternatively, you could use table.wait_until_exists(). from the docs:

Waits until this Table is exists. This method calls DynamoDB.Waiter.table_exists.wait() which polls. DynamoDB.Client.describe_table() every 20 seconds until a successful state is reached. An error is returned after 25 failed checks.

See also: AWS API Documentation

Request Syntax

table.wait_until_exists()

Returns

None

Michael Delgado
  • 13,789
  • 3
  • 29
  • 54
notionquest
  • 37,595
  • 6
  • 111
  • 105
  • 6
    I like your code but can't figure out how to import the `botocore.errorfactory.ResourceNotFoundException`. I keep getting `AttributeError: 'module' object has no attribute 'ResourceNotFoundException'`. I'm imported `boto3` and `botocore`. – fIwJlxSzApHEZIl Mar 22 '17 at 23:13
  • @anon58192932 did you figure out how to import that exception? I'm facing the same issue. – Phito Jun 03 '17 at 08:07
  • 1
    @Phito sorry for the delay I just got back into work. Please see my answer that I'll be posting on how to check for the exception. It can't be imported directly as far as I understand. – fIwJlxSzApHEZIl Jun 05 '17 at 15:41
  • @Phito: I have edited my answer to include example codes on how to catch exceptions in boto3. – anupsabraham Aug 06 '17 at 05:17
  • @anupsabraham I didn't find the exact syntax to catch the exception so posting an example here `_cwevents_client: BaseClient = _master_session.client('events', region_name=aws_region) try: _cwevents_client.describe_rule(Name=ruleName) logger.info("Determined that guarddutyAlert rule already exists") except _cwevents_client.exceptions.ResourceNotFoundException: logger.info("Creating the guarddutyAlert CloudWatch rule")` – Gautam Nov 05 '18 at 01:03
  • @Gautam The question is specific to `dynamodb`. Read my accepted answer above. I'm sure you can find similar exceptions in case of `cloudwatch events` too. – anupsabraham Nov 05 '18 at 07:07
6

You can use .table_status attr of any boto3 Table instance object. It returns it's status if exists (CREATING, UPDATING, DELETING, ACTIVE) or throws exception botocore.exceptions.ClientError: Requested resource not found: Table: <YOUR_TABLE_NAME> not found. You can wrap those conditions into try / except to have full info on the current table state.

import boto3
from botocore.exceptions import ClientError

dynamodb = boto3.resource('dynamodb', region_name='us-west-2')
table = dynamodb.Table('your_table_name_str')

try:
  is_table_existing = table.table_status in ("CREATING", "UPDATING",
                                             "DELETING", "ACTIVE")
except ClientError:
  is_table_existing = False
  print "Table %s doesn't exist." % table.name
juggernaut
  • 748
  • 1
  • 10
  • 19
1

Note that it kind of depends on if you are using client or resource. If you use boto3.client(), you can use the 3 methods the accepted answer suggested. If you are using boto3.resource(), you can only use dynamodb_resource.create_table() and check exceptions.

try:
    table = dynamodb_resource.create_table(
        ...
    )
    table.meta.client.get_waiter('table_exists').wait(TableName=your_table_name)
except ResourceInUseException:
    # do sth here
Z.Wei
  • 3,658
  • 2
  • 17
  • 28
0

I know this will have a slight risk if there are more than 10 tables between table.split(0, -1) and table. However, it does save throwing exceptions and the like. Alas the documentation https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTables.html (examples) imply the the first table in the returned list will be the search item, it is not the case..

class Dynamo {

private m_db!: DynamoDB;

private async ensure_table(name: string) {
    const search = await this.db().listTables({
        ExclusiveStartTableName: name.slice(0, -1),
        Limit: 10 });
    const exists = search.TableNames?.includes(name);
    exists || await this.create_table(name);
}

private async create_table(name: string) {
   // create the table here 
}

 
private db(): DynamoDB { 
    return this.m_db || (this.m_db = this.create_db()); 
}


private create_db = (): DynamoDB => { 
    return new DynamoDB({apiVersion: "2012-08-10"}); }
}

}

John
  • 71
  • 2
0

You can use the convenient resource API while still handling and catching the exceptions from the client API level, because you can access the client from the resource! This makes the method of checking if table exists the most elegant I have found:

resource = boto3.resource('dynamodb', region_name='eu-north-1')

def table_exists(table_name: str) -> bool:
    try:
        resource.Table(table_name).table_status
    except resource.meta.client.exceptions.ResourceNotFoundException:
        return False
    return True

print(table_exists('dummy_table'))
Mindaugas Bernatavičius
  • 3,757
  • 4
  • 31
  • 58