def test_dynamodb_list_tables_long(self): # Reduce page size so test doesn't have to make over 100 tables ddb_table._PAGE_SIZE = 5 dynamodb = DynamoDB() with ExitStack() as stack: for i in range(11): class Cls(DynamoModel): _table_name_ = "abc" + str(i) table_ctx = temporary_dynamodb_table(Cls, "def" + str(i)) stack.enter_context(table_ctx) self.assertEqual(len(dynamodb.list_tables()), 11)
def get_movie(title, year): dynamodb = DynamoDB() table = dynamodb[Movie] item: Movie = table[year, title] return item
def query_and_project_movies(year, title_range): dynamodb = DynamoDB() table = dynamodb[Movie] query = (Movie.year == year) & (Movie.title.between(*title_range)) return table.query(query)
def delete_underrated_movie(title, year, rating): dynamodb = DynamoDB() table = dynamodb[Movie] return table.delete_item( (year, title), condition_expression=Movie.info.rating <= rating, )
def remove_actors(title, year, actor_count): dynamodb = DynamoDB() table = dynamodb[Movie] response = table.update_item( (year, title), update_expression=Movie.info.actors[0].remove(), condition_expression=Movie.info.actors.size() >= actor_count, ) return response
def load_movies(movies): dynamodb = DynamoDB() table = dynamodb[Movie] for movie_json in movies: movie = Movie( title=movie_json["title"], year=movie_json["year"], info=movie_json["info"], ) table.put_item(movie)
def update_movie(title, year, rating, plot, actors): dynamodb = DynamoDB() table = dynamodb[Movie] update_expression = (Movie.info.rating.set(rating) & Movie.info.plot.set(plot) & Movie.info.actors.set(actors)) return table.update_item( key=(year, title), update_expression=update_expression, )
def put_movie(title, year, plot, rating): dynamodb = DynamoDB() table = dynamodb[Movie] movie = Movie( title=title, year=year, info={ "plot": plot, "rating": rating, }, ) response = table.put_item(movie) return response
def test_dynamodb_table(self): with self.table_without_sortkey as table: test_item = ModelWithoutSortkey( hashkey="test_value", another_attr=5.5, ) # Table can be used table.put_item(test_item) result_item = table["test_value"] self.assertIsInstance(result_item, ModelWithoutSortkey) self.assertEqual(result_item, test_item) # DynamoDB can access table dynamodb = DynamoDB() ddb_result = dynamodb[ModelWithoutSortkey]["test_value"] self.assertIsInstance(ddb_result, ModelWithoutSortkey) self.assertEqual(ddb_result, test_item)
def _temporary_table( table_name, delay, max_attempts, **table_kwargs, ): dynamodb = DynamoDB() dynamodb.client.create_table(TableName=table_name, **table_kwargs) exists_waiter = dynamodb.client.get_waiter("table_exists") not_exists_waiter = dynamodb.client.get_waiter("table_not_exists") result = exists_waiter.wait( TableName=table_name, WaiterConfig={ "Delay": delay, "MaxAttempts": max_attempts, }, ) if result is not None: raise RuntimeError("Could not create table {!r}".format(table_name)) try: yield finally: dynamodb.client.delete_table(TableName=table_name) result = not_exists_waiter.wait( TableName=table_name, WaiterConfig={ "Delay": delay, "MaxAttempts": max_attempts, }, ) if result is not None: msg = "Could not delete table {!r}" raise RuntimeError(msg.format(table_name))
def test_dynamodb_indexes(self): class Student(DynamoModel): _table_name_ = "Students" # Hash key name = Key() # Sort key year = Key() homeroom = Attr() class ByHomeroomIndex(DynamoModel): _table_name_ = "Students" _index_name_ = "ByHomeroom" homeroom = Key() name = Key() year = Attr() def __eq__(self, other): if isinstance(other, ByHomeroomIndex): return ((self.name == other.name) & (self.homeroom == other.homeroom) & (self.year == other.year)) return NotImplemented with temporary_dynamodb_table( Student, "name", hashkey_type="S", sortkey_name="year", sortkey_type="N", extra_attributes=[ { "AttributeName": "homeroom", "AttributeType": "S", }, ], GlobalSecondaryIndexes=[{ "IndexName": "ByHomeroom", "KeySchema": [ { "AttributeName": "homeroom", "KeyType": "HASH", }, { "AttributeName": "name", "KeyType": "RANGE", }, ], "Projection": { "ProjectionType": "ALL", }, "ProvisionedThroughput": { "ReadCapacityUnits": 123, "WriteCapacityUnits": 123, }, }], ) as students_table: item1 = Student(name="Cecil", year=10, homeroom="Faba") item2 = Student(name="Cecil", year=11, homeroom="Aaa") item3 = Student(name="Cloud", year=12, homeroom="Faba") item4 = Student(name="Aerith", year=12, homeroom="Faba") students_table.put_item(item1) students_table.put_item(item2) students_table.put_item(item3) students_table.put_item(item4) homeroom_index = DynamoDB()[ByHomeroomIndex] query_filter = (ByHomeroomIndex.homeroom == "Faba") & (ByHomeroomIndex.name > "B") scan_filter = ByHomeroomIndex.year > 11 items = list(homeroom_index.query(query_filter, scan_filter)) self.assertEqual(len(items), 1) (item, ) = items expected = ByHomeroomIndex(name="Cloud", year=12, homeroom="Faba") self.assertEqual(item, expected)
def test_dynamodb_list_tables(self): with self.table_with_sortkey: with self.table_without_sortkey: tables = DynamoDB().list_tables() self.assertEqual(tables, ["test_with_sort", "test_without_sort"])
def query_movies(year): dynamodb = DynamoDB() table = dynamodb[Movie] return table.query(Movie.year == year)
def scan_movies(year_range, display_movies): dynamodb = DynamoDB() table = dynamodb[Movie] display_movies(table.scan(Movie.year.between(*year_range)))
def temporary_dynamodb_table( data_model, hashkey_name, hashkey_type="S", sortkey_name=None, sortkey_type="S", delay=5.0, max_attempts=10, extra_attributes=None, **extra_kwargs, ): """ Context manager creating a temporary DynamoDB table for testing. Ensures that the table is created and destroyed before entering and exiting the context. Parameters ---------- data_model : DynamoModel Model to interface with this table hashkey_name : str Name of the hash key of the table hashkey_type : str, optional Type of the hash key ("S", "N", or "B"). Default "S" sortkey_name : str, optional Optional sort key for the temporary table sortkey_type : str, optional Type of the sort key if there is one ("S", "N", or "B"). Default "S" delay : float, optional Delay in seconds between checks if the table exists max_attempts : int, optional Max number of attempts to check if the table exists, after which the client gives up. extra_attributes : dict, optional Additional attribute definitions (boto3 specification) **extra_kwargs : dict Additional keyword arguments to pass to create_table """ # TODO: make filter more specific warnings.simplefilter("ignore", ResourceWarning) table_name = data_model._table_name_ dynamodb = DynamoDB() attribute_definitions = [ { "AttributeName": hashkey_name, "AttributeType": hashkey_type, }, ] key_schema = [ { "AttributeName": hashkey_name, "KeyType": "HASH", }, ] if sortkey_name is not None and sortkey_type is not None: attribute_definitions.append( { "AttributeName": sortkey_name, "AttributeType": sortkey_type, } ) key_schema.append( { "AttributeName": sortkey_name, "KeyType": "RANGE", }, ) if extra_attributes: attribute_definitions.extend(extra_attributes) with _temporary_table( table_name, delay, max_attempts, AttributeDefinitions=attribute_definitions, KeySchema=key_schema, ProvisionedThroughput={"ReadCapacityUnits": 123, "WriteCapacityUnits": 123}, **extra_kwargs, ): yield dynamodb[data_model]
def load_movies(movies): dynamodb = DynamoDB() table = dynamodb[Movie] for movie in movies: table.put_item(movie)