diff --git a/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py b/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py index 861fc034c..ad08f8322 100644 --- a/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py +++ b/tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py @@ -1,7 +1,6 @@ import boto3 import botocore import pytest -import sure # noqa # pylint: disable=unused-import from boto3.dynamodb.conditions import Key from botocore.exceptions import ClientError from unittest import SkipTest @@ -51,10 +50,8 @@ def test_query_gsi_with_wrong_key_attribute_names_throws_exception(): IndexName="GSI-K1", )["Items"] err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Query condition missed key schema element: gsiK1SortKey" - ) + assert err["Code"] == "ValidationException" + assert err["Message"] == "Query condition missed key schema element: gsiK1SortKey" # check using wrong name for partition key throws exception with pytest.raises(ClientError) as exc: @@ -64,9 +61,9 @@ def test_query_gsi_with_wrong_key_attribute_names_throws_exception(): IndexName="GSI-K1", )["Items"] err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Query condition missed key schema element: gsiK1PartitionKey" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] == "Query condition missed key schema element: gsiK1PartitionKey" ) # verify same behaviour for begins_with @@ -77,10 +74,8 @@ def test_query_gsi_with_wrong_key_attribute_names_throws_exception(): IndexName="GSI-K1", )["Items"] err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Query condition missed key schema element: gsiK1SortKey" - ) + assert err["Code"] == "ValidationException" + assert err["Message"] == "Query condition missed key schema element: gsiK1SortKey" # verify same behaviour for between with pytest.raises(ClientError) as exc: @@ -94,10 +89,8 @@ def test_query_gsi_with_wrong_key_attribute_names_throws_exception(): IndexName="GSI-K1", )["Items"] err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Query condition missed key schema element: gsiK1SortKey" - ) + assert err["Code"] == "ValidationException" + assert err["Message"] == "Query condition missed key schema element: gsiK1SortKey" @mock_dynamodb @@ -121,10 +114,8 @@ def test_query_table_with_wrong_key_attribute_names_throws_exception(): ExpressionAttributeValues={":pk": "pk"}, )["Items"] err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Query condition missed key schema element: partitionKey" - ) + assert err["Code"] == "ValidationException" + assert err["Message"] == "Query condition missed key schema element: partitionKey" @mock_dynamodb @@ -137,9 +128,10 @@ def test_empty_expressionattributenames(): with pytest.raises(ClientError) as exc: table.get_item(Key={"id": "my_id"}, ExpressionAttributeNames={}) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "ExpressionAttributeNames can only be specified when using expressions" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "ExpressionAttributeNames can only be specified when using expressions" ) @@ -155,8 +147,8 @@ def test_empty_expressionattributenames_with_empty_projection(): Key={"id": "my_id"}, ProjectionExpression="", ExpressionAttributeNames={} ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal("ExpressionAttributeNames must not be empty") + assert err["Code"] == "ValidationException" + assert err["Message"] == "ExpressionAttributeNames must not be empty" @mock_dynamodb @@ -171,8 +163,8 @@ def test_empty_expressionattributenames_with_projection(): Key={"id": "my_id"}, ProjectionExpression="id", ExpressionAttributeNames={} ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal("ExpressionAttributeNames must not be empty") + assert err["Code"] == "ValidationException" + assert err["Message"] == "ExpressionAttributeNames must not be empty" @mock_dynamodb @@ -191,9 +183,10 @@ def test_update_item_range_key_set(): ExpressionAttributeValues={":one": 1, ":a": "lore ipsum"}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - 'Invalid UpdateExpression: The "ADD" section can only be used once in an update expression;' + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == 'Invalid UpdateExpression: The "ADD" section can only be used once in an update expression;' ) @@ -204,8 +197,8 @@ def test_batch_get_item_non_existing_table(): with pytest.raises(client.exceptions.ResourceNotFoundException) as exc: client.batch_get_item(RequestItems={"my-table": {"Keys": [{"id": {"N": "0"}}]}}) err = exc.value.response["Error"] - assert err["Code"].should.equal("ResourceNotFoundException") - assert err["Message"].should.equal("Requested resource not found") + assert err["Code"] == "ResourceNotFoundException" + assert err["Message"] == "Requested resource not found" @mock_dynamodb @@ -218,8 +211,8 @@ def test_batch_write_item_non_existing_table(): RequestItems={"my-table": [{"PutRequest": {"Item": {}}}]} ) err = exc.value.response["Error"] - assert err["Code"].should.equal("ResourceNotFoundException") - assert err["Message"].should.equal("Requested resource not found") + assert err["Code"] == "ResourceNotFoundException" + assert err["Message"] == "Requested resource not found" @mock_dynamodb @@ -238,9 +231,10 @@ def test_create_table_with_redundant_attributes(): ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Number of attributes in KeySchema does not exactly match number of attributes defined in AttributeDefinitions" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Number of attributes in KeySchema does not exactly match number of attributes defined in AttributeDefinitions" ) with pytest.raises(ClientError) as exc: @@ -263,9 +257,10 @@ def test_create_table_with_redundant_attributes(): ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Some AttributeDefinitions are not used. AttributeDefinitions: [created_at, id, user], keys used: [id, user]" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Some AttributeDefinitions are not used. AttributeDefinitions: [created_at, id, user], keys used: [id, user]" ) @@ -285,9 +280,10 @@ def test_create_table_with_missing_attributes(): ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Invalid KeySchema: Some index key attribute have no definition" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "Invalid KeySchema: Some index key attribute have no definition" ) with pytest.raises(ClientError) as exc: @@ -306,9 +302,10 @@ def test_create_table_with_missing_attributes(): ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [user], AttributeDefinitions: [id]" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [user], AttributeDefinitions: [id]" ) @@ -326,9 +323,10 @@ def test_create_table_with_redundant_and_missing_attributes(): BillingMode="PAY_PER_REQUEST", ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [id], AttributeDefinitions: [created_at]" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [id], AttributeDefinitions: [created_at]" ) with pytest.raises(ClientError) as exc: @@ -349,9 +347,10 @@ def test_create_table_with_redundant_and_missing_attributes(): BillingMode="PAY_PER_REQUEST", ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [user], AttributeDefinitions: [created_at, id]" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [user], AttributeDefinitions: [created_at, id]" ) @@ -381,9 +380,10 @@ def test_put_item_wrong_attribute_type(): with pytest.raises(ClientError) as exc: dynamodb.put_item(TableName="test-table", Item=item) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Type mismatch for key id expected: S actual: N" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Type mismatch for key id expected: S actual: N" ) item = { @@ -395,9 +395,10 @@ def test_put_item_wrong_attribute_type(): with pytest.raises(ClientError) as exc: dynamodb.put_item(TableName="test-table", Item=item) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Type mismatch for key created_at expected: N actual: S" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Type mismatch for key created_at expected: N actual: S" ) @@ -425,10 +426,8 @@ def test_hash_key_cannot_use_begins_with_operations(): table = dynamodb.Table("test-table") with pytest.raises(ClientError) as ex: table.query(KeyConditionExpression=Key("key").begins_with("prefix-")) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "Query key condition not supported" - ) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["Error"]["Message"] == "Query key condition not supported" # Test this again, but with manually supplying an operator @@ -450,8 +449,8 @@ def test_hash_key_can_only_use_equals_operations(operator): ExpressionAttributeValues={":pk": "p"}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal("Query key condition not supported") + assert err["Code"] == "ValidationException" + assert err["Message"] == "Query key condition not supported" @mock_dynamodb @@ -467,9 +466,10 @@ def test_creating_table_with_0_local_indexes(): LocalSecondaryIndexes=[], ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: List of LocalSecondaryIndexes is empty" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: List of LocalSecondaryIndexes is empty" ) @@ -486,9 +486,10 @@ def test_creating_table_with_0_global_indexes(): GlobalSecondaryIndexes=[], ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: List of GlobalSecondaryIndexes is empty" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: List of GlobalSecondaryIndexes is empty" ) @@ -524,9 +525,10 @@ def test_multiple_transactions_on_same_item(): ] ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Transaction request cannot include multiple operations on one item" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "Transaction request cannot include multiple operations on one item" ) @@ -558,10 +560,10 @@ def test_transact_write_items__too_many_transactions(): ] ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.match( - "1 validation error detected at 'transactItems' failed to satisfy constraint: " - "Member must have length less than or equal to 100." + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "1 validation error detected at 'transactItems' failed to satisfy constraint: Member must have length less than or equal to 100." ) @@ -576,8 +578,8 @@ def test_update_item_non_existent_table(): ExpressionAttributeValues={":Body": {"S": ""}}, ) err = exc.value.response["Error"] - assert err["Code"].should.equal("ResourceNotFoundException") - assert err["Message"].should.equal("Requested resource not found") + assert err["Code"] == "ResourceNotFoundException" + assert err["Message"] == "Requested resource not found" @mock_dynamodb @@ -609,14 +611,15 @@ def test_update_item_with_duplicate_expressions(expression): ExpressionAttributeValues={":example_column": "test"}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Invalid UpdateExpression: Two document paths overlap with each other; must remove or rewrite one of these paths; path one: [example_column], path two: [example_column]" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "Invalid UpdateExpression: Two document paths overlap with each other; must remove or rewrite one of these paths; path one: [example_column], path two: [example_column]" ) # The item is not updated item = table.get_item(Key={"pk": "example_id"})["Item"] - item.should.equal({"pk": "example_id", "example_column": "example"}) + assert item == {"pk": "example_id", "example_column": "example"} @mock_dynamodb @@ -635,8 +638,8 @@ def test_put_item_wrong_datatype(): with pytest.raises(ClientError) as exc: client.put_item(TableName="test2", Item={"mykey": {"N": 123}}) err = exc.value.response["Error"] - err["Code"].should.equal("SerializationException") - err["Message"].should.equal("NUMBER_VALUE cannot be converted to String") + assert err["Code"] == "SerializationException" + assert err["Message"] == "NUMBER_VALUE cannot be converted to String" # Same thing - but with a non-key, and nested with pytest.raises(ClientError) as exc: @@ -645,8 +648,8 @@ def test_put_item_wrong_datatype(): Item={"mykey": {"N": "123"}, "nested": {"M": {"sth": {"N": 5}}}}, ) err = exc.value.response["Error"] - err["Code"].should.equal("SerializationException") - err["Message"].should.equal("NUMBER_VALUE cannot be converted to String") + assert err["Code"] == "SerializationException" + assert err["Message"] == "NUMBER_VALUE cannot be converted to String" @mock_dynamodb @@ -663,9 +666,10 @@ def test_put_item_empty_set(): with pytest.raises(ClientError) as exc: table.put_item(Item={"Key": "some-irrelevant_key", "attr2": {"SS": set([])}}) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: An number set may not be empty" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: An number set may not be empty" ) @@ -689,9 +693,10 @@ def test_update_expression_with_trailing_comma(): ExpressionAttributeValues={":val1": 3, ":val2": 4}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - 'Invalid UpdateExpression: Syntax error; token: "", near: ","' + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == 'Invalid UpdateExpression: Syntax error; token: "", near: ","' ) @@ -717,20 +722,22 @@ def test_batch_put_item_with_empty_value(): with table.batch_writer() as batch: batch.put_item(Item={"pk": "", "sk": "sth"}) err = exc.value.response["Error"] - err["Message"].should.equal( - "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: pk" + assert ( + err["Message"] + == "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: pk" ) - err["Code"].should.equal("ValidationException") + assert err["Code"] == "ValidationException" # Empty SortKey throws an error with pytest.raises(botocore.exceptions.ClientError) as exc: with table.batch_writer() as batch: batch.put_item(Item={"pk": "sth", "sk": ""}) err = exc.value.response["Error"] - err["Message"].should.equal( - "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: sk" + assert ( + err["Message"] + == "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: sk" ) - err["Code"].should.equal("ValidationException") + assert err["Code"] == "ValidationException" # Empty regular parameter workst just fine though with table.batch_writer() as batch: @@ -759,10 +766,8 @@ def test_query_begins_with_without_brackets(): ExpressionAttributeValues={":pk": {"S": "test1"}, ":sk": {"S": "test2"}}, ) err = exc.value.response["Error"] - err["Message"].should.equal( - 'Invalid KeyConditionExpression: Syntax error; token: "sk"' - ) - err["Code"].should.equal("ValidationException") + assert err["Message"] == 'Invalid KeyConditionExpression: Syntax error; token: "sk"' + assert err["Code"] == "ValidationException" @mock_dynamodb @@ -834,9 +839,10 @@ def test_transact_write_items_with_empty_gsi_key(): with pytest.raises(ClientError) as exc: client.transact_write_items(TransactItems=transact_items) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values are not valid. A value specified for a secondary index key is not supported. The AttributeValue for a key attribute cannot contain an empty string value. IndexName: gsi_index, IndexKey: unique_id" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values are not valid. A value specified for a secondary index key is not supported. The AttributeValue for a key attribute cannot contain an empty string value. IndexName: gsi_index, IndexKey: unique_id" ) @@ -869,14 +875,14 @@ def test_update_primary_key_with_sortkey(): ExpressionAttributeValues={":val1": "different"}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Cannot update attribute pk. This attribute is part of the key" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Cannot update attribute pk. This attribute is part of the key" ) - table.get_item(Key={"pk": "testchangepk", "sk": "else"})["Item"].should.equal( - {"pk": "testchangepk", "sk": "else"} - ) + item = table.get_item(Key={"pk": "testchangepk", "sk": "else"})["Item"] + assert item == {"pk": "testchangepk", "sk": "else"} @mock_dynamodb @@ -902,14 +908,14 @@ def test_update_primary_key(): ExpressionAttributeValues={":val1": "different"}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Cannot update attribute pk. This attribute is part of the key" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Cannot update attribute pk. This attribute is part of the key" ) - table.get_item(Key={"pk": "testchangepk"})["Item"].should.equal( - {"pk": "testchangepk"} - ) + item = table.get_item(Key={"pk": "testchangepk"})["Item"] + assert item == {"pk": "testchangepk"} @mock_dynamodb @@ -928,15 +934,15 @@ def test_put_item__string_as_integer_value(): with pytest.raises(ClientError) as exc: client.put_item(TableName="without_sk", Item={"pk": {"S": 123}}) err = exc.value.response["Error"] - err["Code"].should.equal("SerializationException") - err["Message"].should.equal("NUMBER_VALUE cannot be converted to String") + assert err["Code"] == "SerializationException" + assert err["Message"] == "NUMBER_VALUE cannot be converted to String" # A primary key cannot be of type S, but then point to a dictionary with pytest.raises(ClientError) as exc: client.put_item(TableName="without_sk", Item={"pk": {"S": {"S": "asdf"}}}) err = exc.value.response["Error"] - err["Code"].should.equal("SerializationException") - err["Message"].should.equal("Start of structure or map found where not expected") + assert err["Code"] == "SerializationException" + assert err["Message"] == "Start of structure or map found where not expected" # Note that a normal attribute name can be an 'S', which follows the same pattern # Nested 'S'-s like this are allowed for non-key attributes @@ -981,9 +987,10 @@ def test_gsi_key_cannot_be_empty(): }, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: Type mismatch for Index Key hello Expected: S Actual: NULL IndexName: hello-index" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: Type mismatch for Index Key hello Expected: S Actual: NULL IndexName: hello-index" ) @@ -1013,9 +1020,10 @@ def test_list_append_errors_for_unknown_attribute_value(): ReturnValues="UPDATED_NEW", ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "The provided expression refers to an attribute that does not exist in the item" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "The provided expression refers to an attribute that does not exist in the item" ) # append to unknown list via ExpressionAttributeNames @@ -1029,9 +1037,10 @@ def test_list_append_errors_for_unknown_attribute_value(): ReturnValues="UPDATED_NEW", ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "The provided expression refers to an attribute that does not exist in the item" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "The provided expression refers to an attribute that does not exist in the item" ) # append to unknown list, even though end result is known @@ -1044,9 +1053,10 @@ def test_list_append_errors_for_unknown_attribute_value(): ReturnValues="UPDATED_NEW", ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "The provided expression refers to an attribute that does not exist in the item" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "The provided expression refers to an attribute that does not exist in the item" ) # We can append to a known list, into an unknown/new list diff --git a/tests/test_dynamodb/exceptions/test_key_length_exceptions.py b/tests/test_dynamodb/exceptions/test_key_length_exceptions.py index de7e1b1a7..f3749f846 100644 --- a/tests/test_dynamodb/exceptions/test_key_length_exceptions.py +++ b/tests/test_dynamodb/exceptions/test_key_length_exceptions.py @@ -1,5 +1,4 @@ import boto3 -import sure # noqa # pylint: disable=unused-import import pytest from moto import mock_dynamodb @@ -40,11 +39,12 @@ def test_item_add_long_string_hash_key_exception(): "ReceivedTime": {"S": "12/9/2011 11:36:03 PM"}, }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # deliberately no space between "of" and "2048" - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes" ) @@ -87,11 +87,12 @@ def test_item_add_long_string_nonascii_hash_key_exception(): }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # deliberately no space between "of" and "2048" - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes" ) @@ -135,10 +136,11 @@ def test_item_add_long_string_range_key_exception(): }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes" ) @@ -204,10 +206,11 @@ def test_put_long_string_gsi_range_key_exception(): }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes" ) @@ -243,11 +246,12 @@ def test_update_item_with_long_string_hash_key_exception(): ExpressionAttributeValues={":New": {"S": "hello"}}, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # deliberately no space between "of" and "2048" - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes" ) @@ -288,11 +292,12 @@ def test_update_item_with_long_string_range_key_exception(): ExpressionAttributeValues={":New": {"S": "hello"}}, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # deliberately no space between "of" and "2048" - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes" ) @@ -312,9 +317,9 @@ def test_item_add_empty_key_exception(): TableName=name, Key={"forum_name": {"S": ""}}, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values are not valid. The AttributeValue for a key attribute " - "cannot contain an empty string value. Key: forum_name" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: forum_name" ) diff --git a/tests/test_dynamodb/models/test_key_condition_expression_parser.py b/tests/test_dynamodb/models/test_key_condition_expression_parser.py index 2ceb2a5d9..fdb82ff5b 100644 --- a/tests/test_dynamodb/models/test_key_condition_expression_parser.py +++ b/tests/test_dynamodb/models/test_key_condition_expression_parser.py @@ -15,9 +15,9 @@ class TestHashKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal(eav[":id"]) - comparison.should.equal(None) - range_values.should.equal([]) + assert desired_hash_key == eav[":id"] + assert comparison is None + assert range_values == [] def test_unknown_hash_key(self): kce = "wrongName = :id" @@ -29,9 +29,7 @@ class TestHashKey: schema=self.schema, expression_attribute_names=dict(), ) - exc.value.message.should.equal( - "Query condition missed key schema element: job_id" - ) + assert exc.value.message == "Query condition missed key schema element: job_id" def test_unknown_hash_value(self): # TODO: is this correct? I'd assume that this should throw an error instead @@ -44,9 +42,9 @@ class TestHashKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal({"S": ":unknown"}) - comparison.should.equal(None) - range_values.should.equal([]) + assert desired_hash_key == {"S": ":unknown"} + assert comparison is None + assert range_values == [] class TestHashAndRangeKey: @@ -65,9 +63,7 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - exc.value.message.should.equal( - "Query condition missed key schema element: job_id" - ) + assert exc.value.message == "Query condition missed key schema element: job_id" @pytest.mark.parametrize( "expr", @@ -86,8 +82,8 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - exc.value.message.should.equal( - "Query condition missed key schema element: start_date" + assert ( + exc.value.message == "Query condition missed key schema element: start_date" ) @pytest.mark.parametrize( @@ -108,9 +104,9 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal("pk") - comparison.should.equal("BEGINS_WITH") - range_values.should.equal(["19"]) + assert desired_hash_key == "pk" + assert comparison == "BEGINS_WITH" + assert range_values == ["19"] @pytest.mark.parametrize("fn", ["Begins_with", "Begins_With", "BEGINS_WITH"]) def test_begin_with__wrong_case(self, fn): @@ -122,8 +118,9 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - exc.value.message.should.equal( - f"Invalid KeyConditionExpression: Invalid function name; function: {fn}" + assert ( + exc.value.message + == f"Invalid KeyConditionExpression: Invalid function name; function: {fn}" ) @pytest.mark.parametrize( @@ -142,9 +139,9 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal("pk") - comparison.should.equal("BETWEEN") - range_values.should.equal(["19", "21"]) + assert desired_hash_key == "pk" + assert comparison == "BETWEEN" + assert range_values == ["19", "21"] @pytest.mark.parametrize("operator", [" < ", " <=", "= ", ">", ">="]) def test_numeric_comparisons(self, operator): @@ -156,9 +153,9 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal("pk") - comparison.should.equal(operator.strip()) - range_values.should.equal(["19"]) + assert desired_hash_key == "pk" + assert comparison == operator.strip() + assert range_values == ["19"] @pytest.mark.parametrize( "expr", @@ -177,7 +174,7 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal("pk") + assert desired_hash_key == "pk" @pytest.mark.parametrize( "expr", @@ -195,7 +192,7 @@ class TestHashAndRangeKey: schema=self.schema, expression_attribute_names=dict(), ) - desired_hash_key.should.equal("pk") + assert desired_hash_key == "pk" class TestNamesAndValues: @@ -211,6 +208,6 @@ class TestNamesAndValues: schema=self.schema, expression_attribute_names=ean, ) - desired_hash_key.should.equal(eav[":id"]) - comparison.should.equal(None) - range_values.should.equal([]) + assert desired_hash_key == eav[":id"] + assert comparison is None + assert range_values == [] diff --git a/tests/test_dynamodb/test_dynamodb.py b/tests/test_dynamodb/test_dynamodb.py index 3b53e3772..e0787bf0a 100644 --- a/tests/test_dynamodb/test_dynamodb.py +++ b/tests/test_dynamodb/test_dynamodb.py @@ -5,7 +5,6 @@ from decimal import Decimal import boto3 from boto3.dynamodb.conditions import Attr, Key import re -import sure # noqa # pylint: disable=unused-import from moto import mock_dynamodb, settings from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID from moto.dynamodb import dynamodb_backends @@ -32,7 +31,7 @@ def test_list_tables_boto3(names): AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) - conn.list_tables()["TableNames"].should.equal(names) + assert conn.list_tables()["TableNames"] == names @mock_dynamodb @@ -47,16 +46,16 @@ def test_list_tables_paginated(): ) res = conn.list_tables(Limit=2) - res.should.have.key("TableNames").equal(["name1", "name2"]) - res.should.have.key("LastEvaluatedTableName").equal("name2") + assert res["TableNames"] == ["name1", "name2"] + assert res["LastEvaluatedTableName"] == "name2" res = conn.list_tables(Limit=1, ExclusiveStartTableName="name1") - res.should.have.key("TableNames").equal(["name2"]) - res.should.have.key("LastEvaluatedTableName").equal("name2") + assert res["TableNames"] == ["name2"] + assert res["LastEvaluatedTableName"] == "name2" res = conn.list_tables(ExclusiveStartTableName="name1") - res.should.have.key("TableNames").equal(["name2", "name3"]) - res.shouldnt.have.key("LastEvaluatedTableName") + assert res["TableNames"] == ["name2", "name3"] + assert "LastEvaluatedTableName" not in res @mock_dynamodb @@ -64,10 +63,11 @@ def test_describe_missing_table_boto3(): conn = boto3.client("dynamodb", region_name="us-west-2") with pytest.raises(ClientError) as ex: conn.describe_table(TableName="messages") - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "Requested resource not found: Table: messages not found" + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "Requested resource not found: Table: messages not found" ) @@ -200,10 +200,11 @@ def test_item_add_empty_string_hash_key_exception(): }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.match( - "One or more parameter values were invalid: An AttributeValue may not contain an empty string" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: An AttributeValue may not contain an empty string. Key: forum_name" ) @@ -241,10 +242,11 @@ def test_item_add_empty_string_range_key_exception(): }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.match( - "One or more parameter values were invalid: An AttributeValue may not contain an empty string" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: An AttributeValue may not contain an empty string. Key: ReceivedTime" ) @@ -393,22 +395,20 @@ def test_put_item_with_streams(): result = conn.get_item(TableName=name, Key={"forum_name": {"S": "LOLCat Forum"}}) - result["Item"].should.be.equal( - { - "forum_name": {"S": "LOLCat Forum"}, - "subject": {"S": "Check this out!"}, - "Body": {"S": "http://url_to_lolcat.gif"}, - "SentBy": {"S": "test"}, - "Data": {"M": {"Key1": {"S": "Value1"}, "Key2": {"S": "Value2"}}}, - } - ) + assert result["Item"] == { + "forum_name": {"S": "LOLCat Forum"}, + "subject": {"S": "Check this out!"}, + "Body": {"S": "http://url_to_lolcat.gif"}, + "SentBy": {"S": "test"}, + "Data": {"M": {"Key1": {"S": "Value1"}, "Key2": {"S": "Value2"}}}, + } if not settings.TEST_SERVER_MODE: table = dynamodb_backends[ACCOUNT_ID]["us-west-2"].get_table(name) - len(table.stream_shard.items).should.be.equal(1) + assert len(table.stream_shard.items) == 1 stream_record = table.stream_shard.items[0].record - stream_record["eventName"].should.be.equal("INSERT") - stream_record["dynamodb"]["SizeBytes"].should.be.equal(447) + assert stream_record["eventName"] == "INSERT" + assert stream_record["dynamodb"]["SizeBytes"] == 447 @mock_dynamodb @@ -447,14 +447,16 @@ def test_basic_projection_expression_using_get_item(): ProjectionExpression="body, subject", ) - result["Item"].should.be.equal({"subject": "123", "body": "some test message"}) + assert result["Item"] == {"subject": "123", "body": "some test message"} # The projection expression should not remove data from storage result = table.get_item(Key={"forum_name": "the-key", "subject": "123"}) - result["Item"].should.be.equal( - {"forum_name": "the-key", "subject": "123", "body": "some test message"} - ) + assert result["Item"] == { + "forum_name": "the-key", + "subject": "123", + "body": "some test message", + } # Running this against AWS DDB gives an exception so make sure it also fails.: with pytest.raises(client.exceptions.ClientError): @@ -521,8 +523,8 @@ def test_basic_projection_expressions_using_scan(): ) bodies = [item["body"] for item in results["Items"]] - bodies.should.contain("some test message") - bodies.should.contain("yet another test message") + assert "some test message" in bodies + assert "yet another test message" in bodies assert "subject" not in results["Items"][0] assert "forum_name" not in results["Items"][0] assert "subject" not in results["Items"][1] @@ -571,22 +573,20 @@ def test_nested_projection_expression_using_get_item(): Key={"forum_name": "key1"}, ProjectionExpression="nested.level1.id, nested.level2", )["Item"] - result.should.equal( - {"nested": {"level1": {"id": "id1"}, "level2": {"id": "id2", "include": "all"}}} - ) + assert result == { + "nested": {"level1": {"id": "id1"}, "level2": {"id": "id2", "include": "all"}} + } # Assert actual data has not been deleted result = table.get_item(Key={"forum_name": "key1"})["Item"] - result.should.equal( - { - "foo": "bar", - "forum_name": "key1", - "nested": { - "level1": {"id": "id1", "att": "irrelevant"}, - "level2": {"id": "id2", "include": "all"}, - "level3": {"id": "irrelevant"}, - }, - } - ) + assert result == { + "foo": "bar", + "forum_name": "key1", + "nested": { + "level1": {"id": "id1", "att": "irrelevant"}, + "level2": {"id": "id2", "include": "all"}, + "level3": {"id": "irrelevant"}, + }, + } @mock_dynamodb @@ -663,14 +663,14 @@ def test_nested_projection_expression_using_query(): # Create the DynamoDB table. dynamodb.create_table( TableName="users", - KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}], - AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}], + KeySchema=[{"AttributeName": "name", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "name", "AttributeType": "S"}], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) table = dynamodb.Table("users") table.put_item( Item={ - "forum_name": "key1", + "name": "key1", "nested": { "level1": {"id": "id1", "att": "irrelevant"}, "level2": {"id": "id2", "include": "all"}, @@ -681,7 +681,7 @@ def test_nested_projection_expression_using_query(): ) table.put_item( Item={ - "forum_name": "key2", + "name": "key2", "nested": {"id": "id2", "incode": "code2"}, "foo": "bar", } @@ -689,30 +689,27 @@ def test_nested_projection_expression_using_query(): # Test a query returning all items result = table.query( - KeyConditionExpression=Key("forum_name").eq("key1"), + KeyConditionExpression=Key("name").eq("key1"), ProjectionExpression="nested.level1.id, nested.level2", )["Items"][0] assert "nested" in result - result["nested"].should.equal( - {"level1": {"id": "id1"}, "level2": {"id": "id2", "include": "all"}} - ) + assert result["nested"] == { + "level1": {"id": "id1"}, + "level2": {"id": "id2", "include": "all"}, + } assert "foo" not in result # Assert actual data has not been deleted - result = table.query(KeyConditionExpression=Key("forum_name").eq("key1"))["Items"][ - 0 - ] - result.should.equal( - { - "foo": "bar", - "forum_name": "key1", - "nested": { - "level1": {"id": "id1", "att": "irrelevant"}, - "level2": {"id": "id2", "include": "all"}, - "level3": {"id": "irrelevant"}, - }, - } - ) + result = table.query(KeyConditionExpression=Key("name").eq("key1"))["Items"][0] + assert result == { + "foo": "bar", + "name": "key1", + "nested": { + "level1": {"id": "id1", "att": "irrelevant"}, + "level2": {"id": "id2", "include": "all"}, + "level3": {"id": "irrelevant"}, + }, + } @mock_dynamodb @@ -751,31 +748,27 @@ def test_nested_projection_expression_using_scan(): FilterExpression=Key("forum_name").eq("key1"), ProjectionExpression="nested.level1.id, nested.level2", )["Items"] - results.should.equal( - [ - { - "nested": { - "level1": {"id": "id1"}, - "level2": {"include": "all", "id": "id2"}, - } + assert results == [ + { + "nested": { + "level1": {"id": "id1"}, + "level2": {"include": "all", "id": "id2"}, } - ] - ) + } + ] # Assert original data is still there results = table.scan(FilterExpression=Key("forum_name").eq("key1"))["Items"] - results.should.equal( - [ - { - "forum_name": "key1", - "foo": "bar", - "nested": { - "level1": {"att": "irrelevant", "id": "id1"}, - "level2": {"include": "all", "id": "id2"}, - "level3": {"id": "irrelevant"}, - }, - } - ] - ) + assert results == [ + { + "forum_name": "key1", + "foo": "bar", + "nested": { + "level1": {"att": "irrelevant", "id": "id1"}, + "level2": {"include": "all", "id": "id2"}, + "level3": {"id": "irrelevant"}, + }, + } + ] @mock_dynamodb @@ -820,9 +813,11 @@ def test_basic_projection_expression_using_get_item_with_attr_expression_names() ExpressionAttributeNames={"#rl": "body", "#rt": "attachment"}, ) - result["Item"].should.be.equal( - {"subject": "123", "body": "some test message", "attachment": "something"} - ) + assert result["Item"] == { + "subject": "123", + "body": "some test message", + "attachment": "something", + } @mock_dynamodb @@ -869,11 +864,8 @@ def test_basic_projection_expressions_using_query_with_attr_expression_names(): ExpressionAttributeNames={"#rl": "body", "#rt": "attachment"}, ) - assert "body" in results["Items"][0] assert results["Items"][0]["body"] == "some test message" - assert "subject" in results["Items"][0] assert results["Items"][0]["subject"] == "123" - assert "attachment" in results["Items"][0] assert results["Items"][0]["attachment"] == "something" @@ -917,32 +909,30 @@ def test_nested_projection_expression_using_get_item_with_attr_expression(): ProjectionExpression="#nst.level1.id, #nst.#lvl2", ExpressionAttributeNames={"#nst": "nested", "#lvl2": "level2"}, )["Item"] - result.should.equal( - {"nested": {"level1": {"id": "id1"}, "level2": {"id": "id2", "include": "all"}}} - ) + assert result == { + "nested": {"level1": {"id": "id1"}, "level2": {"id": "id2", "include": "all"}} + } # Assert actual data has not been deleted result = table.get_item(Key={"forum_name": "key1"})["Item"] - result.should.equal( - { - "foo": "bar", - "forum_name": "key1", - "nested": { - "level1": {"id": "id1", "att": "irrelevant"}, - "level2": {"id": "id2", "include": "all"}, - "level3": { - "id": "irrelevant", - "children": [{"Name": "child_a"}, {"Name": "child_b"}], - }, + assert result == { + "foo": "bar", + "forum_name": "key1", + "nested": { + "level1": {"id": "id1", "att": "irrelevant"}, + "level2": {"id": "id2", "include": "all"}, + "level3": { + "id": "irrelevant", + "children": [{"Name": "child_a"}, {"Name": "child_b"}], }, - } - ) + }, + } # Test a get_item retrieving children result = table.get_item( Key={"forum_name": "key1"}, ProjectionExpression="nested.level3.children[0].Name", )["Item"] - result.should.equal({"nested": {"level3": {"children": [{"Name": "child_a"}]}}}) + assert result == {"nested": {"level3": {"children": [{"Name": "child_a"}]}}} @mock_dynamodb @@ -952,14 +942,14 @@ def test_nested_projection_expression_using_query_with_attr_expression_names(): # Create the DynamoDB table. dynamodb.create_table( TableName="users", - KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}], - AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}], + KeySchema=[{"AttributeName": "name", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "name", "AttributeType": "S"}], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) table = dynamodb.Table("users") table.put_item( Item={ - "forum_name": "key1", + "name": "key1", "nested": { "level1": {"id": "id1", "att": "irrelevant"}, "level2": {"id": "id2", "include": "all"}, @@ -970,7 +960,7 @@ def test_nested_projection_expression_using_query_with_attr_expression_names(): ) table.put_item( Item={ - "forum_name": "key2", + "name": "key2", "nested": {"id": "id2", "incode": "code2"}, "foo": "bar", } @@ -978,31 +968,27 @@ def test_nested_projection_expression_using_query_with_attr_expression_names(): # Test a query returning all items result = table.query( - KeyConditionExpression=Key("forum_name").eq("key1"), + KeyConditionExpression=Key("name").eq("key1"), ProjectionExpression="#nst.level1.id, #nst.#lvl2", ExpressionAttributeNames={"#nst": "nested", "#lvl2": "level2"}, )["Items"][0] - assert "nested" in result - result["nested"].should.equal( - {"level1": {"id": "id1"}, "level2": {"id": "id2", "include": "all"}} - ) + assert result["nested"] == { + "level1": {"id": "id1"}, + "level2": {"id": "id2", "include": "all"}, + } assert "foo" not in result # Assert actual data has not been deleted - result = table.query(KeyConditionExpression=Key("forum_name").eq("key1"))["Items"][ - 0 - ] - result.should.equal( - { - "foo": "bar", - "forum_name": "key1", - "nested": { - "level1": {"id": "id1", "att": "irrelevant"}, - "level2": {"id": "id2", "include": "all"}, - "level3": {"id": "irrelevant"}, - }, - } - ) + result = table.query(KeyConditionExpression=Key("name").eq("key1"))["Items"][0] + assert result == { + "foo": "bar", + "name": "key1", + "nested": { + "level1": {"id": "id1", "att": "irrelevant"}, + "level2": {"id": "id2", "include": "all"}, + "level3": {"id": "irrelevant"}, + }, + } @mock_dynamodb @@ -1103,31 +1089,27 @@ def test_nested_projection_expression_using_scan_with_attr_expression_names(): ProjectionExpression="nested.level1.id, nested.level2", ExpressionAttributeNames={"#nst": "nested", "#lvl2": "level2"}, )["Items"] - results.should.equal( - [ - { - "nested": { - "level1": {"id": "id1"}, - "level2": {"include": "all", "id": "id2"}, - } + assert results == [ + { + "nested": { + "level1": {"id": "id1"}, + "level2": {"include": "all", "id": "id2"}, } - ] - ) + } + ] # Assert original data is still there results = table.scan(FilterExpression=Key("forum_name").eq("key1"))["Items"] - results.should.equal( - [ - { - "forum_name": "key1", - "foo": "bar", - "nested": { - "level1": {"att": "irrelevant", "id": "id1"}, - "level2": {"include": "all", "id": "id2"}, - "level3": {"id": "irrelevant"}, - }, - } - ] - ) + assert results == [ + { + "forum_name": "key1", + "foo": "bar", + "nested": { + "level1": {"att": "irrelevant", "id": "id1"}, + "level2": {"include": "all", "id": "id2"}, + "level3": {"id": "irrelevant"}, + }, + } + ] @mock_dynamodb @@ -1143,10 +1125,11 @@ def test_put_empty_item(): with pytest.raises(ClientError) as ex: table.put_item(Item={}) - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Missing the key structure_id in the item" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Missing the key structure_id in the item" ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") + assert ex.value.response["Error"]["Code"] == "ValidationException" @mock_dynamodb @@ -1162,10 +1145,11 @@ def test_put_item_nonexisting_hash_key(): with pytest.raises(ClientError) as ex: table.put_item(Item={"a_terribly_misguided_id_attribute": "abcdef"}) - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Missing the key structure_id in the item" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Missing the key structure_id in the item" ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") + assert ex.value.response["Error"]["Code"] == "ValidationException" @mock_dynamodb @@ -1187,10 +1171,11 @@ def test_put_item_nonexisting_range_key(): with pytest.raises(ClientError) as ex: table.put_item(Item={"structure_id": "abcdef"}) - ex.value.response["Error"]["Message"].should.equal( - "One or more parameter values were invalid: Missing the key added_at in the item" + assert ( + ex.value.response["Error"]["Message"] + == "One or more parameter values were invalid: Missing the key added_at in the item" ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") + assert ex.value.response["Error"]["Code"] == "ValidationException" def test_filter_expression(): @@ -1219,45 +1204,45 @@ def test_filter_expression(): filter_expr = moto.dynamodb.comparisons.get_filter_expression( "NOT attribute_not_exists(Id)", {}, {} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # NOT test 2 filter_expr = moto.dynamodb.comparisons.get_filter_expression( "NOT (Id = :v0)", {}, {":v0": {"N": "8"}} ) - filter_expr.expr(row1).should.be(False) # Id = 8 so should be false + assert filter_expr.expr(row1) is False # Id = 8 so should be false # AND test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "Id > :v0 AND Subs < :v1", {}, {":v0": {"N": "5"}, ":v1": {"N": "7"}} ) - filter_expr.expr(row1).should.be(True) - filter_expr.expr(row2).should.be(False) + assert filter_expr.expr(row1) is True + assert filter_expr.expr(row2) is False # lowercase AND test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "Id > :v0 and Subs < :v1", {}, {":v0": {"N": "5"}, ":v1": {"N": "7"}} ) - filter_expr.expr(row1).should.be(True) - filter_expr.expr(row2).should.be(False) + assert filter_expr.expr(row1) is True + assert filter_expr.expr(row2) is False # OR test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "Id = :v0 OR Id=:v1", {}, {":v0": {"N": "5"}, ":v1": {"N": "8"}} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # BETWEEN test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "Id BETWEEN :v0 AND :v1", {}, {":v0": {"N": "5"}, ":v1": {"N": "10"}} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # BETWEEN integer test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "Id BETWEEN :v0 AND :v1", {}, {":v0": {"N": "0"}, ":v1": {"N": "10"}} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # PAREN test filter_expr = moto.dynamodb.comparisons.get_filter_expression( @@ -1265,7 +1250,7 @@ def test_filter_expression(): {}, {":v0": {"N": "8"}, ":v1": {"N": "5"}}, ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # IN test filter_expr = moto.dynamodb.comparisons.get_filter_expression( @@ -1273,38 +1258,38 @@ def test_filter_expression(): {}, {":v0": {"N": "7"}, ":v1": {"N": "8"}, ":v2": {"N": "9"}}, ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # attribute function tests (with extra spaces) filter_expr = moto.dynamodb.comparisons.get_filter_expression( "attribute_exists(Id) AND attribute_not_exists (UnknownAttribute)", {}, {} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True filter_expr = moto.dynamodb.comparisons.get_filter_expression( "attribute_type(Id, :v0)", {}, {":v0": {"S": "N"}} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # beginswith function test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "begins_with(Des, :v0)", {}, {":v0": {"S": "Some"}} ) - filter_expr.expr(row1).should.be(True) - filter_expr.expr(row2).should.be(False) + assert filter_expr.expr(row1) is True + assert filter_expr.expr(row2) is False # contains function test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "contains(KV, :v0)", {}, {":v0": {"S": "test1"}} ) - filter_expr.expr(row1).should.be(True) - filter_expr.expr(row2).should.be(False) + assert filter_expr.expr(row1) is True + assert filter_expr.expr(row2) is False # size function test filter_expr = moto.dynamodb.comparisons.get_filter_expression( "size(Des) > size(KV)", {}, {} ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # Expression from @batkuip filter_expr = moto.dynamodb.comparisons.get_filter_expression( @@ -1312,13 +1297,13 @@ def test_filter_expression(): {"#n0": "Subs", "#n1": "fanout_ts"}, {":v0": {"N": "7"}}, ) - filter_expr.expr(row1).should.be(True) + assert filter_expr.expr(row1) is True # Expression from to check contains on string value filter_expr = moto.dynamodb.comparisons.get_filter_expression( "contains(#n0, :v0)", {"#n0": "Des"}, {":v0": {"S": "Some"}} ) - filter_expr.expr(row1).should.be(True) - filter_expr.expr(row2).should.be(False) + assert filter_expr.expr(row1) is True + assert filter_expr.expr(row2) is False @mock_dynamodb @@ -1595,12 +1580,12 @@ def test_scan_filter_should_not_return_non_existing_attributes(): table.put_item(Item=item) # Verify a few operations # Assert we only find the item that has this attribute - table.scan(FilterExpression=Attr("my-attr").lt(43))["Items"].should.equal([item]) - table.scan(FilterExpression=Attr("my-attr").lte(42))["Items"].should.equal([item]) - table.scan(FilterExpression=Attr("my-attr").gte(42))["Items"].should.equal([item]) - table.scan(FilterExpression=Attr("my-attr").gt(41))["Items"].should.equal([item]) + assert table.scan(FilterExpression=Attr("my-attr").lt(43))["Items"] == [item] + assert table.scan(FilterExpression=Attr("my-attr").lte(42))["Items"] == [item] + assert table.scan(FilterExpression=Attr("my-attr").gte(42))["Items"] == [item] + assert table.scan(FilterExpression=Attr("my-attr").gt(41))["Items"] == [item] # Sanity check that we can't find the item if the FE is wrong - table.scan(FilterExpression=Attr("my-attr").gt(43))["Items"].should.equal([]) + assert table.scan(FilterExpression=Attr("my-attr").gt(43))["Items"] == [] @mock_dynamodb @@ -1626,7 +1611,7 @@ def test_bad_scan_filter(): # Bad expression with pytest.raises(ClientError) as exc: table.scan(FilterExpression="client test") - exc.value.response["Error"]["Code"].should.equal("ValidationException") + assert exc.value.response["Error"]["Code"] == "ValidationException" @mock_dynamodb @@ -1647,7 +1632,7 @@ def test_duplicate_create(): ProvisionedThroughput={"ReadCapacityUnits": 123, "WriteCapacityUnits": 123}, ) - try: + with pytest.raises(ClientError) as exc: client.create_table( TableName="test1", AttributeDefinitions=[ @@ -1660,10 +1645,8 @@ def test_duplicate_create(): ], ProvisionedThroughput={"ReadCapacityUnits": 123, "WriteCapacityUnits": 123}, ) - except ClientError as err: - err.response["Error"]["Code"].should.equal("ResourceInUseException") - else: - raise RuntimeError("Should have raised ResourceInUseException") + err = exc.value.response["Error"] + assert err["Code"] == "ResourceInUseException" @mock_dynamodb @@ -1687,14 +1670,11 @@ def test_delete_table(): client.delete_table(TableName="test1") resp = client.list_tables() - len(resp["TableNames"]).should.equal(0) + assert len(resp["TableNames"]) == 0 - try: + with pytest.raises(ClientError) as err: client.delete_table(TableName="test1") - except ClientError as err: - err.response["Error"]["Code"].should.equal("ResourceNotFoundException") - else: - raise RuntimeError("Should have raised ResourceNotFoundException") + assert err.value.response["Error"]["Code"] == "ResourceNotFoundException" @mock_dynamodb @@ -1732,22 +1712,22 @@ def test_delete_item(): Key={"client": "client1", "app": "app1"}, ReturnValues="ALL_NEW" ) err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal("Return values set to invalid value") + assert err["Code"] == "ValidationException" + assert err["Message"] == "Return values set to invalid value" # Test deletion and returning old value response = table.delete_item( Key={"client": "client1", "app": "app1"}, ReturnValues="ALL_OLD" ) - response["Attributes"].should.contain("client") - response["Attributes"].should.contain("app") + assert "client" in response["Attributes"] + assert "app" in response["Attributes"] response = table.scan() assert response["Count"] == 1 # Test deletion returning nothing response = table.delete_item(Key={"client": "client1", "app": "app2"}) - len(response["Attributes"]).should.equal(0) + assert len(response["Attributes"]) == 0 response = table.scan() assert response["Count"] == 0 @@ -1790,10 +1770,10 @@ def test_describe_limits(): client = boto3.client("dynamodb", region_name="eu-central-1") resp = client.describe_limits() - resp["AccountMaxReadCapacityUnits"].should.equal(20000) - resp["AccountMaxWriteCapacityUnits"].should.equal(20000) - resp["TableMaxWriteCapacityUnits"].should.equal(10000) - resp["TableMaxReadCapacityUnits"].should.equal(10000) + assert resp["AccountMaxReadCapacityUnits"] == 20000 + assert resp["AccountMaxWriteCapacityUnits"] == 20000 + assert resp["TableMaxWriteCapacityUnits"] == 10000 + assert resp["TableMaxReadCapacityUnits"] == 10000 @mock_dynamodb @@ -1820,8 +1800,8 @@ def test_set_ttl(): ) resp = client.describe_time_to_live(TableName="test1") - resp["TimeToLiveDescription"]["TimeToLiveStatus"].should.equal("ENABLED") - resp["TimeToLiveDescription"]["AttributeName"].should.equal("expire") + assert resp["TimeToLiveDescription"]["TimeToLiveStatus"] == "ENABLED" + assert resp["TimeToLiveDescription"]["AttributeName"] == "expire" client.update_time_to_live( TableName="test1", @@ -1829,7 +1809,7 @@ def test_set_ttl(): ) resp = client.describe_time_to_live(TableName="test1") - resp["TimeToLiveDescription"]["TimeToLiveStatus"].should.equal("DISABLED") + assert resp["TimeToLiveDescription"]["TimeToLiveStatus"] == "DISABLED" @mock_dynamodb @@ -1853,12 +1833,10 @@ def test_describe_continuous_backups(): response = client.describe_continuous_backups(TableName=table_name) # then - response["ContinuousBackupsDescription"].should.equal( - { - "ContinuousBackupsStatus": "ENABLED", - "PointInTimeRecoveryDescription": {"PointInTimeRecoveryStatus": "DISABLED"}, - } - ) + assert response["ContinuousBackupsDescription"] == { + "ContinuousBackupsStatus": "ENABLED", + "PointInTimeRecoveryDescription": {"PointInTimeRecoveryStatus": "DISABLED"}, + } @mock_dynamodb @@ -1872,10 +1850,10 @@ def test_describe_continuous_backups_errors(): # then ex = e.value - ex.operation_name.should.equal("DescribeContinuousBackups") - ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.response["Error"]["Code"].should.contain("TableNotFoundException") - ex.response["Error"]["Message"].should.equal("Table not found: not-existing-table") + assert ex.operation_name == "DescribeContinuousBackups" + assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.response["Error"]["Code"] == "TableNotFoundException" + assert ex.response["Error"]["Message"] == "Table not found: not-existing-table" @mock_dynamodb @@ -1902,17 +1880,17 @@ def test_update_continuous_backups(): ) # then - response["ContinuousBackupsDescription"]["ContinuousBackupsStatus"].should.equal( - "ENABLED" + assert ( + response["ContinuousBackupsDescription"]["ContinuousBackupsStatus"] == "ENABLED" ) point_in_time = response["ContinuousBackupsDescription"][ "PointInTimeRecoveryDescription" ] earliest_datetime = point_in_time["EarliestRestorableDateTime"] - earliest_datetime.should.be.a(datetime) + assert isinstance(earliest_datetime, datetime) latest_datetime = point_in_time["LatestRestorableDateTime"] - latest_datetime.should.be.a(datetime) - point_in_time["PointInTimeRecoveryStatus"].should.equal("ENABLED") + assert isinstance(latest_datetime, datetime) + assert point_in_time["PointInTimeRecoveryStatus"] == "ENABLED" # when # a second update should not change anything @@ -1922,15 +1900,15 @@ def test_update_continuous_backups(): ) # then - response["ContinuousBackupsDescription"]["ContinuousBackupsStatus"].should.equal( - "ENABLED" + assert ( + response["ContinuousBackupsDescription"]["ContinuousBackupsStatus"] == "ENABLED" ) point_in_time = response["ContinuousBackupsDescription"][ "PointInTimeRecoveryDescription" ] - point_in_time["EarliestRestorableDateTime"].should.equal(earliest_datetime) - point_in_time["LatestRestorableDateTime"].should.equal(latest_datetime) - point_in_time["PointInTimeRecoveryStatus"].should.equal("ENABLED") + assert point_in_time["EarliestRestorableDateTime"] == earliest_datetime + assert point_in_time["LatestRestorableDateTime"] == latest_datetime + assert point_in_time["PointInTimeRecoveryStatus"] == "ENABLED" # when response = client.update_continuous_backups( @@ -1939,12 +1917,10 @@ def test_update_continuous_backups(): ) # then - response["ContinuousBackupsDescription"].should.equal( - { - "ContinuousBackupsStatus": "ENABLED", - "PointInTimeRecoveryDescription": {"PointInTimeRecoveryStatus": "DISABLED"}, - } - ) + assert response["ContinuousBackupsDescription"] == { + "ContinuousBackupsStatus": "ENABLED", + "PointInTimeRecoveryDescription": {"PointInTimeRecoveryStatus": "DISABLED"}, + } @mock_dynamodb @@ -1961,10 +1937,10 @@ def test_update_continuous_backups_errors(): # then ex = e.value - ex.operation_name.should.equal("UpdateContinuousBackups") - ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.response["Error"]["Code"].should.contain("TableNotFoundException") - ex.response["Error"]["Message"].should.equal("Table not found: not-existing-table") + assert ex.operation_name == "UpdateContinuousBackups" + assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.response["Error"]["Code"] == "TableNotFoundException" + assert ex.response["Error"]["Message"] == "Table not found: not-existing-table" # https://github.com/getmoto/moto/issues/1043 @@ -1998,8 +1974,8 @@ def test_query_missing_expr_names(): ExpressionAttributeValues={":client": {"S": "test1"}}, ) - resp["Count"].should.equal(1) - resp["Items"][0]["client"]["S"].should.equal("test1") + assert resp["Count"] == 1 + assert resp["Items"][0]["client"]["S"] == "test1" resp = client.query( TableName="test1", @@ -2007,8 +1983,8 @@ def test_query_missing_expr_names(): ExpressionAttributeNames={":name": "client"}, ) - resp["Count"].should.equal(1) - resp["Items"][0]["client"]["S"].should.equal("test2") + assert resp["Count"] == 1 + assert resp["Items"][0]["client"]["S"] == "test2" # https://github.com/getmoto/moto/issues/2328 @@ -2030,7 +2006,7 @@ def test_update_item_with_list(): ) resp = table.get_item(Key={"key": "the-key"}) - resp["Item"].should.equal({"key": "the-key", "list": [1, 2]}) + assert resp["Item"] == {"key": "the-key", "list": [1, 2]} # https://github.com/getmoto/moto/issues/2328 @@ -2054,7 +2030,7 @@ def test_update_item_with_no_action_passed_with_list(): ) resp = table.get_item(Key={"key": "the-key"}) - resp["Item"].should.equal({"key": "the-key", "list": [1, 2]}) + assert resp["Item"] == {"key": "the-key", "list": [1, 2]} # https://github.com/getmoto/moto/issues/1342 @@ -2087,7 +2063,7 @@ def test_update_item_on_map(): ) resp = table.scan() - resp["Items"][0]["body"].should.equal({"nested": {"data": "test"}}) + assert resp["Items"][0]["body"] == {"nested": {"data": "test"}} # Nonexistent nested attributes are supported for existing top-level attributes. table.update_item( @@ -2122,9 +2098,9 @@ def test_update_item_on_map(): ) resp = table.scan() - resp["Items"][0]["body"].should.equal( - {"nested": {"data": "new_value", "nonexistentnested": {"data": "other_value"}}} - ) + assert resp["Items"][0]["body"] == { + "nested": {"data": "new_value", "nonexistentnested": {"data": "other_value"}} + } # Test nested value for a nonexistent attribute throws a ClientError. with pytest.raises(client.exceptions.ClientError): @@ -2218,8 +2194,8 @@ def test_update_return_attributes(): with pytest.raises(ClientError) as ex: update("col1", "val6", "WRONG") err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal("Return values set to invalid value") + assert err["Code"] == "ValidationException" + assert err["Message"] == "Return values set to invalid value" # https://github.com/getmoto/moto/issues/3448 @@ -2259,8 +2235,8 @@ def test_update_return_updated_new_attributes_when_same(): with pytest.raises(ClientError) as ex: update("a", ["a", "c"], "WRONG") err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal("Return values set to invalid value") + assert err["Code"] == "ValidationException" + assert err["Message"] == "Return values set to invalid value" @mock_dynamodb @@ -2294,11 +2270,9 @@ def test_put_return_attributes(): Item={"id": {"S": "foo"}, "col1": {"S": "val3"}}, ReturnValues="ALL_NEW", ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "Return values set to invalid value" - ) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.value.response["Error"]["Message"] == "Return values set to invalid value" @mock_dynamodb @@ -2422,15 +2396,12 @@ def test_query_gsi_with_range_key(): ":gsi_range_key": {"S": "range1"}, }, ) - res.should.have.key("Count").equal(1) - res.should.have.key("Items") - res["Items"][0].should.equal( - { - "id": {"S": "test1"}, - "gsi_hash_key": {"S": "key1"}, - "gsi_range_key": {"S": "range1"}, - } - ) + assert res["Count"] == 1 + assert res["Items"][0] == { + "id": {"S": "test1"}, + "gsi_hash_key": {"S": "key1"}, + "gsi_range_key": {"S": "range1"}, + } @mock_dynamodb @@ -2461,10 +2432,11 @@ def test_scan_by_non_exists_index(): with pytest.raises(ClientError) as ex: dynamodb.scan(TableName="test", IndexName="non_exists_index") - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "The table does not have the specified index: non_exists_index" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "The table does not have the specified index: non_exists_index" ) @@ -2500,9 +2472,10 @@ def test_query_by_non_exists_index(): KeyConditionExpression="CarModel=M", ) - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["Error"]["Message"].should.equal( - "Invalid index: non_exists_index for table: test. Available indexes are: test_gsi" + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ( + ex.value.response["Error"]["Message"] + == "Invalid index: non_exists_index for table: test. Available indexes are: test_gsi" ) @@ -2538,8 +2511,8 @@ def test_index_with_unknown_attributes_should_fail(): BillingMode="PAY_PER_REQUEST", ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.contain(expected_exception) + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert expected_exception in ex.value.response["Error"]["Message"] @mock_dynamodb @@ -2561,10 +2534,10 @@ def test_update_list_index__set_existing_index(): ) # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo"}})["Item"] - result["id"].should.equal({"S": "foo"}) - result["itemlist"].should.equal( - {"L": [{"S": "bar1"}, {"S": "bar2_update"}, {"S": "bar3"}]} - ) + assert result["id"] == {"S": "foo"} + assert result["itemlist"] == { + "L": [{"S": "bar1"}, {"S": "bar2_update"}, {"S": "bar3"}] + } @mock_dynamodb @@ -2588,10 +2561,12 @@ def test_update_list_index__set_existing_nested_index(): ) # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo2"}})["Item"] - result["id"].should.equal({"S": "foo2"}) - result["itemmap"]["M"]["itemlist"]["L"].should.equal( - [{"S": "bar1"}, {"S": "bar2_update"}, {"S": "bar3"}] - ) + assert result["id"] == {"S": "foo2"} + assert result["itemmap"]["M"]["itemlist"]["L"] == [ + {"S": "bar1"}, + {"S": "bar2_update"}, + {"S": "bar3"}, + ] @mock_dynamodb @@ -2678,13 +2653,13 @@ def test_update_list_index__set_double_nested_index(): # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo2"}})["Item"] assert result["id"] == {"S": "foo2"} - len(result["itemmap"]["M"]["itemlist"]["L"]).should.equal(2) - result["itemmap"]["M"]["itemlist"]["L"][0].should.equal( - {"M": {"foo": {"S": "bar11"}, "foos": {"S": "bar12"}}} - ) # unchanged - result["itemmap"]["M"]["itemlist"]["L"][1].should.equal( - {"M": {"foo": {"S": "bar21"}, "foos": {"S": "bar22"}}} - ) # updated + assert len(result["itemmap"]["M"]["itemlist"]["L"]) == 2 + assert result["itemmap"]["M"]["itemlist"]["L"][0] == { + "M": {"foo": {"S": "bar11"}, "foos": {"S": "bar12"}} + } # unchanged + assert result["itemmap"]["M"]["itemlist"]["L"][1] == { + "M": {"foo": {"S": "bar21"}, "foos": {"S": "bar22"}} + } # updated @mock_dynamodb @@ -2703,9 +2678,10 @@ def test_update_list_index__set_index_of_a_string(): ) client.get_item(TableName=table_name, Key={"id": {"S": "foo2"}})["Item"] - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "The document path provided in the update expression is invalid for update" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ( + ex.value.response["Error"]["Message"] + == "The document path provided in the update expression is invalid for update" ) @@ -2724,7 +2700,7 @@ def test_remove_top_level_attribute(): ) # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo"}})["Item"] - result.should.equal({"id": {"S": "foo"}}) + assert result == {"id": {"S": "foo"}} @mock_dynamodb @@ -2743,7 +2719,7 @@ def test_remove_top_level_attribute_non_existent(): ExpressionAttributeNames={"#i": "item"}, ) result = client.get_item(TableName=table_name, Key={"id": {"S": "foo"}})["Item"] - result.should.equal(ddb_item) + assert result == ddb_item @mock_dynamodb @@ -2764,8 +2740,8 @@ def test_remove_list_index__remove_existing_index(): ) # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo"}})["Item"] - result["id"].should.equal({"S": "foo"}) - result["itemlist"].should.equal({"L": [{"S": "bar1"}, {"S": "bar3"}]}) + assert result["id"] == {"S": "foo"} + assert result["itemlist"] == {"L": [{"S": "bar1"}, {"S": "bar3"}]} @mock_dynamodb @@ -2809,8 +2785,8 @@ def test_remove_list_index__remove_existing_nested_index(): ) # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo2"}})["Item"] - result["id"].should.equal({"S": "foo2"}) - result["itemmap"]["M"]["itemlist"]["L"].should.equal([{"S": "bar1"}]) + assert result["id"] == {"S": "foo2"} + assert result["itemmap"]["M"]["itemlist"]["L"] == [{"S": "bar1"}] @mock_dynamodb @@ -2841,12 +2817,13 @@ def test_remove_list_index__remove_existing_double_nested_index(): # result = client.get_item(TableName=table_name, Key={"id": {"S": "foo2"}})["Item"] assert result["id"] == {"S": "foo2"} - assert result["itemmap"]["M"]["itemlist"]["L"][0]["M"].should.equal( - {"foo00": {"S": "bar1"}, "foo01": {"S": "bar2"}} - ) # untouched - assert result["itemmap"]["M"]["itemlist"]["L"][1]["M"].should.equal( - {"foo11": {"S": "bar2"}} - ) # changed + # untouched + assert result["itemmap"]["M"]["itemlist"]["L"][0]["M"] == { + "foo00": {"S": "bar1"}, + "foo01": {"S": "bar2"}, + } + # changed + assert result["itemmap"]["M"]["itemlist"]["L"][1]["M"] == {"foo11": {"S": "bar2"}} @mock_dynamodb @@ -2966,19 +2943,17 @@ def test_item_size_is_under_400KB(): def assert_failure_due_to_item_size(func, **kwargs): with pytest.raises(ClientError) as ex: func(**kwargs) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "Item size has exceeded the maximum allowed size" - ) + err = ex.value.response["Error"] + assert err["Code"] == "ValidationException" + assert err["Message"] == "Item size has exceeded the maximum allowed size" def assert_failure_due_to_item_size_to_update(func, **kwargs): with pytest.raises(ClientError) as ex: func(**kwargs) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "Item size to update has exceeded the maximum allowed size" - ) + err = ex.value.response["Error"] + assert err["Code"] == "ValidationException" + assert err["Message"] == "Item size to update has exceeded the maximum allowed size" @mock_dynamodb @@ -3007,14 +2982,12 @@ def test_update_supports_complex_expression_attribute_values(): result = client.get_item( TableName="TestTable", Key={"SHA256": {"S": "sha-of-file"}} )["Item"] - result.should.equal( - { - "MyStringSet": {"SS": ["string1", "string2"]}, - "MyMap": {"M": {"EntryKey": {"SS": ["thing1", "thing2"]}}}, - "SHA256": {"S": "sha-of-file"}, - "MD5": {"S": "md5-of-file"}, - } - ) + assert result == { + "MyStringSet": {"SS": ["string1", "string2"]}, + "MyMap": {"M": {"EntryKey": {"SS": ["thing1", "thing2"]}}}, + "SHA256": {"S": "sha-of-file"}, + "MD5": {"S": "md5-of-file"}, + } @mock_dynamodb @@ -3043,19 +3016,17 @@ def test_update_supports_list_append(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"crontab": {"L": [{"S": "bar1"}, {"S": "bar2"}]}} - ) + assert updated_item["Attributes"] == { + "crontab": {"L": [{"S": "bar1"}, {"S": "bar2"}]} + } # Verify item is appended to the existing list result = client.get_item( TableName="TestTable", Key={"SHA256": {"S": "sha-of-file"}} )["Item"] - result.should.equal( - { - "SHA256": {"S": "sha-of-file"}, - "crontab": {"L": [{"S": "bar1"}, {"S": "bar2"}]}, - } - ) + assert result == { + "SHA256": {"S": "sha-of-file"}, + "crontab": {"L": [{"S": "bar1"}, {"S": "bar2"}]}, + } @mock_dynamodb @@ -3088,18 +3059,16 @@ def test_update_supports_nested_list_append(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"a": {"M": {"b": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}} - ) + assert updated_item["Attributes"] == { + "a": {"M": {"b": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}} + } result = client.get_item( TableName="TestTable", Key={"id": {"S": "nested_list_append"}} )["Item"] - result.should.equal( - { - "id": {"S": "nested_list_append"}, - "a": {"M": {"b": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}, - } - ) + assert result == { + "id": {"S": "nested_list_append"}, + "a": {"M": {"b": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}, + } @mock_dynamodb @@ -3132,19 +3101,17 @@ def test_update_supports_multiple_levels_nested_list_append(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"a": {"M": {"b": {"M": {"c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}}}} - ) + assert updated_item["Attributes"] == { + "a": {"M": {"b": {"M": {"c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}}} + } # Verify item is appended to the existing list result = client.get_item( TableName="TestTable", Key={"id": {"S": "nested_list_append"}} )["Item"] - result.should.equal( - { - "id": {"S": "nested_list_append"}, - "a": {"M": {"b": {"M": {"c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}}}, - } - ) + assert result == { + "id": {"S": "nested_list_append"}, + "a": {"M": {"b": {"M": {"c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}}}, + } @mock_dynamodb @@ -3178,24 +3145,22 @@ def test_update_supports_nested_list_append_onto_another_list(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"a": {"M": {"c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}}} - ) + assert updated_item["Attributes"] == { + "a": {"M": {"c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}}} + } # Verify item is appended to the existing list result = client.get_item( TableName="TestTable", Key={"id": {"S": "list_append_another"}} )["Item"] - result.should.equal( - { - "id": {"S": "list_append_another"}, - "a": { - "M": { - "b": {"L": [{"S": "bar1"}]}, - "c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}, - } - }, - } - ) + assert result == { + "id": {"S": "list_append_another"}, + "a": { + "M": { + "b": {"L": [{"S": "bar1"}]}, + "c": {"L": [{"S": "bar1"}, {"S": "bar2"}]}, + } + }, + } @mock_dynamodb @@ -3232,9 +3197,9 @@ def test_update_supports_list_append_maps(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"a": {"L": [{"M": {"b": {"S": "bar1"}}}, {"M": {"b": {"S": "bar2"}}}]}} - ) + assert updated_item["Attributes"] == { + "a": {"L": [{"M": {"b": {"S": "bar1"}}}, {"M": {"b": {"S": "bar2"}}}]} + } # Verify item is appended to the existing list result = client.query( TableName="TestTable", @@ -3244,15 +3209,13 @@ def test_update_supports_list_append_maps(): ":r": {"S": "range_key"}, }, )["Items"] - result.should.equal( - [ - { - "a": {"L": [{"M": {"b": {"S": "bar1"}}}, {"M": {"b": {"S": "bar2"}}}]}, - "rid": {"S": "range_key"}, - "id": {"S": "nested_list_append"}, - } - ] - ) + assert result == [ + { + "a": {"L": [{"M": {"b": {"S": "bar1"}}}, {"M": {"b": {"S": "bar2"}}}]}, + "rid": {"S": "range_key"}, + "id": {"S": "nested_list_append"}, + } + ] @mock_dynamodb @@ -3308,13 +3271,14 @@ def test_update_supports_list_append_with_nested_if_not_exists_operation(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"nest1": {"nest2": {"event_history": ["some_value"]}}} - ) + assert updated_item["Attributes"] == { + "nest1": {"nest2": {"event_history": ["some_value"]}} + } - table.get_item(Key={"Id": "item-id"})["Item"].should.equal( - {"Id": "item-id", "nest1": {"nest2": {"event_history": ["some_value"]}}} - ) + assert table.get_item(Key={"Id": "item-id"})["Item"] == { + "Id": "item-id", + "nest1": {"nest2": {"event_history": ["some_value"]}}, + } @mock_dynamodb @@ -3340,13 +3304,14 @@ def test_update_supports_list_append_with_nested_if_not_exists_operation_and_pro ) # Verify updated item is correct - updated_item["Attributes"].should.equal( - {"event_history": ["other_value", "some_value"]} - ) + assert updated_item["Attributes"] == { + "event_history": ["other_value", "some_value"] + } - table.get_item(Key={"Id": "item-id"})["Item"].should.equal( - {"Id": "item-id", "event_history": ["other_value", "some_value"]} - ) + assert table.get_item(Key={"Id": "item-id"})["Item"] == { + "Id": "item-id", + "event_history": ["other_value", "some_value"], + } @mock_dynamodb @@ -3365,7 +3330,7 @@ def test_update_item_if_original_value_is_none(): UpdateExpression="SET job_name = :output", ExpressionAttributeValues={":output": "updated"}, ) - table.scan()["Items"][0]["job_name"].should.equal("updated") + assert table.scan()["Items"][0]["job_name"] == "updated" @mock_dynamodb @@ -3387,9 +3352,9 @@ def test_update_nested_item_if_original_value_is_none(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal({"job_details": {"job_name": "updated"}}) + assert updated_item["Attributes"] == {"job_details": {"job_name": "updated"}} - table.scan()["Items"][0]["job_details"]["job_name"].should.equal("updated") + assert table.scan()["Items"][0]["job_details"]["job_name"] == "updated" @mock_dynamodb @@ -3412,14 +3377,15 @@ def test_allow_update_to_item_with_different_type(): ) # Verify updated item is correct - updated_item["Attributes"].should.equal({"job_details": {"job_name": "updated"}}) + assert updated_item["Attributes"] == {"job_details": {"job_name": "updated"}} - table.get_item(Key={"job_id": "a"})["Item"]["job_details"][ - "job_name" - ].should.be.equal("updated") - table.get_item(Key={"job_id": "b"})["Item"]["job_details"][ - "job_name" - ].should.be.equal({"nested": "yes"}) + assert ( + table.get_item(Key={"job_id": "a"})["Item"]["job_details"]["job_name"] + == "updated" + ) + assert table.get_item(Key={"job_id": "b"})["Item"]["job_details"]["job_name"] == { + "nested": "yes" + } @mock_dynamodb @@ -3436,10 +3402,11 @@ def test_query_catches_when_no_filters(): with pytest.raises(ClientError) as ex: table.query(TableName="original-rbu-dev") - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "Either KeyConditions or QueryFilter should be present" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "Either KeyConditions or QueryFilter should be present" ) @@ -3466,10 +3433,10 @@ def test_invalid_transact_get_items(): ] ) - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.match( - r"failed to satisfy constraint: Member must have length less than or equal to 25", - re.I, + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + "Member must have length less than or equal to 25" + in ex.value.response["Error"]["Message"] ) with pytest.raises(ClientError) as ex: @@ -3480,9 +3447,9 @@ def test_invalid_transact_get_items(): ] ) - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal("Requested resource not found") + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.value.response["Error"]["Message"] == "Requested resource not found" @mock_dynamodb @@ -3536,9 +3503,9 @@ def test_valid_transact_get_items(): }, ] ) - res["Responses"][0]["Item"].should.equal({"id": {"S": "1"}, "sort_key": {"S": "1"}}) - len(res["Responses"]).should.equal(2) - res["Responses"][1].should.equal({}) + assert res["Responses"][0]["Item"] == {"id": {"S": "1"}, "sort_key": {"S": "1"}} + assert len(res["Responses"]) == 2 + assert res["Responses"][1] == {} res = client.transact_get_items( TransactItems=[ @@ -3563,11 +3530,11 @@ def test_valid_transact_get_items(): ] ) - res["Responses"][0]["Item"].should.equal({"id": {"S": "1"}, "sort_key": {"S": "1"}}) + assert res["Responses"][0]["Item"] == {"id": {"S": "1"}, "sort_key": {"S": "1"}} - res["Responses"][1]["Item"].should.equal({"id": {"S": "1"}, "sort_key": {"S": "2"}}) + assert res["Responses"][1]["Item"] == {"id": {"S": "1"}, "sort_key": {"S": "2"}} - res["Responses"][2]["Item"].should.equal({"id": {"S": "1"}, "sort_key": {"S": "1"}}) + assert res["Responses"][2]["Item"] == {"id": {"S": "1"}, "sort_key": {"S": "1"}} res = client.transact_get_items( TransactItems=[ @@ -3593,13 +3560,17 @@ def test_valid_transact_get_items(): ReturnConsumedCapacity="TOTAL", ) - res["ConsumedCapacity"][0].should.equal( - {"TableName": "test1", "CapacityUnits": 4.0, "ReadCapacityUnits": 4.0} - ) + assert res["ConsumedCapacity"][0] == { + "TableName": "test1", + "CapacityUnits": 4.0, + "ReadCapacityUnits": 4.0, + } - res["ConsumedCapacity"][1].should.equal( - {"TableName": "test2", "CapacityUnits": 2.0, "ReadCapacityUnits": 2.0} - ) + assert res["ConsumedCapacity"][1] == { + "TableName": "test2", + "CapacityUnits": 2.0, + "ReadCapacityUnits": 2.0, + } res = client.transact_get_items( TransactItems=[ @@ -3625,23 +3596,19 @@ def test_valid_transact_get_items(): ReturnConsumedCapacity="INDEXES", ) - res["ConsumedCapacity"][0].should.equal( - { - "TableName": "test1", - "CapacityUnits": 4.0, - "ReadCapacityUnits": 4.0, - "Table": {"CapacityUnits": 4.0, "ReadCapacityUnits": 4.0}, - } - ) + assert res["ConsumedCapacity"][0] == { + "TableName": "test1", + "CapacityUnits": 4.0, + "ReadCapacityUnits": 4.0, + "Table": {"CapacityUnits": 4.0, "ReadCapacityUnits": 4.0}, + } - res["ConsumedCapacity"][1].should.equal( - { - "TableName": "test2", - "CapacityUnits": 2.0, - "ReadCapacityUnits": 2.0, - "Table": {"CapacityUnits": 2.0, "ReadCapacityUnits": 2.0}, - } - ) + assert res["ConsumedCapacity"][1] == { + "TableName": "test2", + "CapacityUnits": 2.0, + "ReadCapacityUnits": 2.0, + "Table": {"CapacityUnits": 2.0, "ReadCapacityUnits": 2.0}, + } @mock_dynamodb @@ -3696,9 +3663,7 @@ def test_gsi_verify_negative_number_order(): KeyConditionExpression=Key("gsiK1PartitionKey").eq("gsi-k1"), IndexName="GSI-K1" ) # Items should be ordered with the lowest number first - [float(item["gsiK1SortKey"]) for item in resp["Items"]].should.equal( - [-0.7, -0.6, 0.7] - ) + assert [float(item["gsiK1SortKey"]) for item in resp["Items"]] == [-0.7, -0.6, 0.7] @mock_dynamodb @@ -3725,7 +3690,7 @@ def test_transact_write_items_put(): ) # Assert all are present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(5) + assert len(items) == 5 @mock_dynamodb @@ -3763,22 +3728,20 @@ def test_transact_write_items_put_conditional_expressions(): ] ) # Assert the exception is correct - ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") + assert ex.value.response["Error"]["Code"] == "TransactionCanceledException" reasons = ex.value.response["CancellationReasons"] - reasons.should.have.length_of(5) - reasons.should.contain( - { - "Code": "ConditionalCheckFailed", - "Message": "The conditional request failed", - "Item": {"id": {"S": "foo2"}, "foo": {"S": "bar"}}, - } - ) - reasons.should.contain({"Code": "None"}) - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert len(reasons) == 5 + assert { + "Code": "ConditionalCheckFailed", + "Message": "The conditional request failed", + "Item": {"id": {"S": "foo2"}, "foo": {"S": "bar"}}, + } in reasons + assert {"Code": "None"} in reasons + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # Assert all are present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"id": {"S": "foo2"}}) + assert len(items) == 1 + assert items[0] == {"id": {"S": "foo2"}} @mock_dynamodb @@ -3817,22 +3780,20 @@ def test_transact_write_items_put_conditional_expressions_return_values_on_condi ] ) # Assert the exception is correct - ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") + assert ex.value.response["Error"]["Code"] == "TransactionCanceledException" reasons = ex.value.response["CancellationReasons"] - reasons.should.have.length_of(5) - reasons.should.contain( - { - "Code": "ConditionalCheckFailed", - "Message": "The conditional request failed", - "Item": {"id": {"S": "foo2"}}, - } - ) - reasons.should.contain({"Code": "None"}) - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert len(reasons) == 5 + assert { + "Code": "ConditionalCheckFailed", + "Message": "The conditional request failed", + "Item": {"id": {"S": "foo2"}}, + } in reasons + assert {"Code": "None"} in reasons + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # Assert all are present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"id": {"S": "foo2"}}) + assert len(items) == 1 + assert items[0] == {"id": {"S": "foo2"}} @mock_dynamodb @@ -3871,8 +3832,8 @@ def test_transact_write_items_conditioncheck_passes(): ) # Assert all are present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}}) + assert len(items) == 1 + assert items[0] == {"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}} @mock_dynamodb @@ -3915,13 +3876,13 @@ def test_transact_write_items_conditioncheck_fails(): ] ) # Assert the exception is correct - ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "TransactionCanceledException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # Assert the original email address is still present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}}) + assert len(items) == 1 + assert items[0] == {"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}} @mock_dynamodb @@ -3944,7 +3905,7 @@ def test_transact_write_items_delete(): ) # Assert the item is deleted items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(0) + assert len(items) == 0 @mock_dynamodb @@ -3974,7 +3935,7 @@ def test_transact_write_items_delete_with_successful_condition_expression(): ) # Assert the item is deleted items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(0) + assert len(items) == 0 @mock_dynamodb @@ -4008,12 +3969,12 @@ def test_transact_write_items_delete_with_failed_condition_expression(): ] ) # Assert the exception is correct - ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "TransactionCanceledException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # Assert the original item is still present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}}) + assert len(items) == 1 + assert items[0] == {"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}} @mock_dynamodb @@ -4044,8 +4005,8 @@ def test_transact_write_items_update(): ) # Assert the item is updated items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"id": {"S": "foo"}, "email_address": {"S": "test@moto.com"}}) + assert len(items) == 1 + assert items[0] == {"id": {"S": "foo"}, "email_address": {"S": "test@moto.com"}} @mock_dynamodb @@ -4081,12 +4042,12 @@ def test_transact_write_items_update_with_failed_condition_expression(): ] ) # Assert the exception is correct - ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + assert ex.value.response["Error"]["Code"] == "TransactionCanceledException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 # Assert the original item is still present items = dynamodb.scan(TableName="test-table")["Items"] - items.should.have.length_of(1) - items[0].should.equal({"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}}) + assert len(items) == 1 + assert items[0] == {"email_address": {"S": "test@moto.com"}, "id": {"S": "foo"}} @mock_dynamodb @@ -4123,8 +4084,8 @@ def test_dynamodb_max_1mb_limit(): KeyConditionExpression=Key("partition_key").eq("partition_key_val") ) # We shouldn't get everything back - the total result set is well over 1MB - len(items).should.be.greater_than(response["Count"]) - response["LastEvaluatedKey"].shouldnt.be(None) + assert len(items) > response["Count"] + assert response["LastEvaluatedKey"] is not None def assert_raise_syntax_error(client_error, token, near): @@ -4141,8 +4102,8 @@ def assert_raise_syntax_error(client_error, token, near): 'Invalid UpdateExpression: Syntax error; token: "{token}", near: "{near}"' ) expected_syntax_error = syntax_error_template.format(token=token, near=near) - assert client_error.response["Error"]["Code"] == "ValidationException" - assert expected_syntax_error == client_error.response["Error"]["Message"] + assert client_error["Code"] == "ValidationException" + assert expected_syntax_error == client_error["Message"] @mock_dynamodb @@ -4160,15 +4121,14 @@ def test_update_expression_with_numeric_literal_instead_of_value(): BillingMode="PAY_PER_REQUEST", ) - try: + with pytest.raises(ClientError) as exc: dynamodb.update_item( TableName="moto-test", Key={"id": {"S": "1"}}, UpdateExpression="SET MyStr = myNum + 1", ) - assert False, "Validation exception not thrown" - except dynamodb.exceptions.ClientError as e: - assert_raise_syntax_error(e, "1", "+ 1") + err = exc.value.response["Error"] + assert_raise_syntax_error(err, "1", "+ 1") @mock_dynamodb @@ -4185,15 +4145,14 @@ def test_update_expression_with_multiple_set_clauses_must_be_comma_separated(): BillingMode="PAY_PER_REQUEST", ) - try: + with pytest.raises(ClientError) as exc: dynamodb.update_item( TableName="moto-test", Key={"id": {"S": "1"}}, UpdateExpression="SET MyStr = myNum Mystr2 myNum2", ) - assert False, "Validation exception not thrown" - except dynamodb.exceptions.ClientError as e: - assert_raise_syntax_error(e, "Mystr2", "myNum Mystr2 myNum2") + err = exc.value.response["Error"] + assert_raise_syntax_error(err, "Mystr2", "myNum Mystr2 myNum2") @mock_dynamodb @@ -4202,7 +4161,7 @@ def test_list_tables_exclusive_start_table_name_empty(): resp = client.list_tables(Limit=1, ExclusiveStartTableName="whatever") - len(resp["TableNames"]).should.equal(0) + assert len(resp["TableNames"]) == 0 def assert_correct_client_error( @@ -4368,15 +4327,14 @@ def test_update_expression_with_space_in_attribute_name(): Item={"id": {"S": "1"}, "my Num": {"S": "1"}, "MyStr": {"S": "aaa"}}, ) - try: + with pytest.raises(ClientError) as exc: dynamodb.update_item( TableName="moto-test", Key={"id": {"S": "1"}}, UpdateExpression="SET MyStr = my Num", ) - assert False, "Validation exception not thrown" - except dynamodb.exceptions.ClientError as e: - assert_raise_syntax_error(e, "Num", "my Num") + err = exc.value.response["Error"] + assert_raise_syntax_error(err, "Num", "my Num") @mock_dynamodb @@ -4476,8 +4434,8 @@ def test_update_item_atomic_counter(): ExpressionAttributeValues={":inc1": {"N": "1.2"}, ":inc2": {"N": "0.05"}}, ) updated_item = ddb_mock.get_item(TableName=table, Key=key)["Item"] - updated_item["n_i"]["N"].should.equal("6.2") - updated_item["n_f"]["N"].should.equal("5.35") + assert updated_item["n_i"]["N"] == "6.2" + assert updated_item["n_f"]["N"] == "5.35" @mock_dynamodb @@ -4502,10 +4460,8 @@ def test_update_item_atomic_counter_return_values(): ExpressionAttributeValues={":inc": {"N": "1"}}, ReturnValues="UPDATED_OLD", ) - assert ( - "v" in response["Attributes"] - ), "v has been updated, and should be returned here" - response["Attributes"]["v"]["N"].should.equal("5") + # v has been updated, and should be returned here + assert response["Attributes"]["v"]["N"] == "5" # second update response = ddb_mock.update_item( @@ -4515,10 +4471,8 @@ def test_update_item_atomic_counter_return_values(): ExpressionAttributeValues={":inc": {"N": "1"}}, ReturnValues="UPDATED_OLD", ) - assert ( - "v" in response["Attributes"] - ), "v has been updated, and should be returned here" - response["Attributes"]["v"]["N"].should.equal("6") + # v has been updated, and should be returned here + assert response["Attributes"]["v"]["N"] == "6" # third update response = ddb_mock.update_item( @@ -4528,10 +4482,8 @@ def test_update_item_atomic_counter_return_values(): ExpressionAttributeValues={":inc": {"N": "1"}}, ReturnValues="UPDATED_NEW", ) - assert ( - "v" in response["Attributes"] - ), "v has been updated, and should be returned here" - response["Attributes"]["v"]["N"].should.equal("8") + # v has been updated, and should be returned here + assert response["Attributes"]["v"]["N"] == "8" @mock_dynamodb @@ -4644,10 +4596,11 @@ def test_transact_write_items_fails_with_transaction_canceled_exception(): }, ] ) - ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal( - "Transaction cancelled, please refer cancellation reasons for specific reasons [None, ConditionalCheckFailed]" + assert ex.value.response["Error"]["Code"] == "TransactionCanceledException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ( + ex.value.response["Error"]["Message"] + == "Transaction cancelled, please refer cancellation reasons for specific reasons [None, ConditionalCheckFailed]" ) @@ -4689,15 +4642,13 @@ def test_gsi_projection_type_keys_only(): items = table.query( KeyConditionExpression=Key("gsiK1PartitionKey").eq("gsi-pk"), IndexName="GSI-K1" )["Items"] - items.should.have.length_of(1) + assert len(items) == 1 # Item should only include GSI Keys and Table Keys, as per the ProjectionType - items[0].should.equal( - { - "gsiK1PartitionKey": "gsi-pk", - "gsiK1SortKey": "gsi-sk", - "partitionKey": "pk-1", - } - ) + assert items[0] == { + "gsiK1PartitionKey": "gsi-pk", + "gsiK1SortKey": "gsi-sk", + "partitionKey": "pk-1", + } @mock_dynamodb @@ -4743,27 +4694,23 @@ def test_gsi_projection_type_include(): KeyConditionExpression=Key("gsiK1PartitionKey").eq("gsi-pk"), IndexName="GSI-INC", )["Items"] - items.should.have.length_of(1) + assert len(items) == 1 # Item should only include keys and additionally projected attributes only - items[0].should.equal( - { - "gsiK1PartitionKey": "gsi-pk", - "gsiK1SortKey": "gsi-sk", - "partitionKey": "pk-1", - "projectedAttribute": "lore ipsum", - } - ) + assert items[0] == { + "gsiK1PartitionKey": "gsi-pk", + "gsiK1SortKey": "gsi-sk", + "partitionKey": "pk-1", + "projectedAttribute": "lore ipsum", + } # Same when scanning the table items = table.scan(IndexName="GSI-INC")["Items"] - items[0].should.equal( - { - "gsiK1PartitionKey": "gsi-pk", - "gsiK1SortKey": "gsi-sk", - "partitionKey": "pk-1", - "projectedAttribute": "lore ipsum", - } - ) + assert items[0] == { + "gsiK1PartitionKey": "gsi-pk", + "gsiK1SortKey": "gsi-sk", + "partitionKey": "pk-1", + "projectedAttribute": "lore ipsum", + } @mock_dynamodb @@ -4807,17 +4754,18 @@ def test_lsi_projection_type_keys_only(): items = table.query( KeyConditionExpression=Key("partitionKey").eq("pk-1"), IndexName="LSI" )["Items"] - items.should.have.length_of(1) # Item should only include GSI Keys and Table Keys, as per the ProjectionType - items[0].should.equal( + assert items == [ {"partitionKey": "pk-1", "sortKey": "sk-1", "lsiK1SortKey": "lsi-sk"} - ) + ] # Same when scanning the table items = table.scan(IndexName="LSI")["Items"] - items[0].should.equal( - {"lsiK1SortKey": "lsi-sk", "partitionKey": "pk-1", "sortKey": "sk-1"} - ) + assert items[0] == { + "lsiK1SortKey": "lsi-sk", + "partitionKey": "pk-1", + "sortKey": "sk-1", + } @mock_dynamodb @@ -4846,8 +4794,8 @@ def test_set_attribute_is_dropped_if_empty_after_update_expression(attr_name): ) resp = client.scan(TableName=table_name, ProjectionExpression="customer, orders") item = resp["Items"][0] - item.should.have.key("customer") - item.should.have.key("orders") + assert "customer" in item + assert "orders" in item client.update_item( TableName=table_name, @@ -4858,8 +4806,8 @@ def test_set_attribute_is_dropped_if_empty_after_update_expression(attr_name): ) resp = client.scan(TableName=table_name, ProjectionExpression="customer, orders") item = resp["Items"][0] - item.should.have.key("customer") - item.should_not.have.key("orders") + assert "customer" in item + assert "orders" not in item @mock_dynamodb @@ -4882,9 +4830,9 @@ def test_transact_get_items_should_return_empty_map_for_non_existent_item(): {"Get": {"Key": {"id": {"S": "2"}}, "TableName": table_name}}, ] ).get("Responses", []) - items.should.have.length_of(2) - items[0].should.equal({"Item": item}) - items[1].should.equal({}) + assert len(items) == 2 + assert items[0] == {"Item": item} + assert items[1] == {} @mock_dynamodb @@ -4928,7 +4876,7 @@ def test_update_item_add_to_list_using_legacy_attribute_updates(): ) resp = table.get_item(Key={"id": "list_add"}) - resp["Item"]["attr"].should.equal(["a", "b", "c", "d", "e"]) + assert resp["Item"]["attr"] == ["a", "b", "c", "d", "e"] @mock_dynamodb @@ -4957,7 +4905,7 @@ def test_update_item_add_to_num_set_using_legacy_attribute_updates(): ) resp = table.get_item(Key={"id": "set_add"}) - resp["Item"]["attr"].should.equal({1, 2, 3, 4, 5}) + assert resp["Item"]["attr"] == {1, 2, 3, 4, 5} table.update_item( TableName="TestTable", @@ -4966,7 +4914,7 @@ def test_update_item_add_to_num_set_using_legacy_attribute_updates(): ) resp = table.get_item(Key={"id": "set_add"}) - resp["Item"]["attr"].should.equal({1, 4, 5}) + assert resp["Item"]["attr"] == {1, 4, 5} @mock_dynamodb @@ -4974,8 +4922,8 @@ def test_get_item_for_non_existent_table_raises_error(): client = boto3.client("dynamodb", "us-east-1") with pytest.raises(ClientError) as ex: client.get_item(TableName="non-existent", Key={"site-id": {"S": "foo"}}) - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["Error"]["Message"].should.equal("Requested resource not found") + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["Error"]["Message"] == "Requested resource not found" @mock_dynamodb @@ -5000,9 +4948,10 @@ def test_error_when_providing_expression_and_nonexpression_params(): ExpressionAttributeValues={":order": {"SS": ["item"]}}, ) err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "Can not use both expression and non-expression parameters in the same request: Non-expression parameters: {AttributeUpdates} Expression parameters: {UpdateExpression}" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "Can not use both expression and non-expression parameters in the same request: Non-expression parameters: {AttributeUpdates} Expression parameters: {UpdateExpression}" ) @@ -5028,7 +4977,7 @@ def test_attribute_item_delete(): AttributeUpdates={"extra": {"Action": "DELETE"}}, ) items = conn.scan(TableName=name)["Items"] - items.should.equal([{"name": {"S": "foo"}}]) + assert items == [{"name": {"S": "foo"}}] @mock_dynamodb @@ -5073,8 +5022,8 @@ def test_gsi_key_can_be_updated(): ) item = conn.scan(TableName=name)["Items"][0] - item["index_key"].should.equal({"S": "new_value"}) - item["main_key"].should.equal({"S": "testkey1"}) + assert item["index_key"] == {"S": "new_value"} + assert item["main_key"] == {"S": "testkey1"} @mock_dynamodb @@ -5119,9 +5068,10 @@ def test_gsi_key_cannot_be_empty(): ExpressionAttributeValues={":new_index_key": {"S": ""}}, ) err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values are not valid. The update expression attempted to update a secondary index key to a value that is not supported. The AttributeValue for a key attribute cannot contain an empty string value." + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values are not valid. The update expression attempted to update a secondary index key to a value that is not supported. The AttributeValue for a key attribute cannot contain an empty string value." ) @@ -5131,8 +5081,8 @@ def test_create_backup_for_non_existent_table_raises_error(): with pytest.raises(ClientError) as ex: client.create_backup(TableName="non-existent", BackupName="backup") error = ex.value.response["Error"] - error["Code"].should.equal("TableNotFoundException") - error["Message"].should.equal("Table not found: non-existent") + assert error["Code"] == "TableNotFoundException" + assert error["Message"] == "Table not found: non-existent" @mock_dynamodb @@ -5148,12 +5098,12 @@ def test_create_backup(): backup_name = "backup-test-table" resp = client.create_backup(TableName=table_name, BackupName=backup_name) details = resp.get("BackupDetails") - details.should.have.key("BackupArn").should.contain(table_name) - details.should.have.key("BackupName").should.equal(backup_name) - details.should.have.key("BackupSizeBytes").should.be.a(int) - details.should.have.key("BackupStatus") - details.should.have.key("BackupType").should.equal("USER") - details.should.have.key("BackupCreationDateTime").should.be.a(datetime) + assert table_name in details["BackupArn"] + assert details["BackupName"] == backup_name + assert isinstance(details["BackupSizeBytes"], int) + assert "BackupStatus" in details + assert details["BackupType"] == "USER" + assert isinstance(details["BackupCreationDateTime"], datetime) @mock_dynamodb @@ -5172,8 +5122,8 @@ def test_create_multiple_backups_with_same_name(): backup = client.create_backup(TableName=table_name, BackupName=backup_name).get( "BackupDetails" ) - backup["BackupName"].should.equal(backup_name) - backup_arns.should_not.contain(backup["BackupArn"]) + assert backup["BackupName"] == backup_name + assert backup["BackupArn"] not in backup_arns backup_arns.append(backup["BackupArn"]) @@ -5184,8 +5134,8 @@ def test_describe_backup_for_non_existent_backup_raises_error(): with pytest.raises(ClientError) as ex: client.describe_backup(BackupArn=non_existent_arn) error = ex.value.response["Error"] - error["Code"].should.equal("BackupNotFoundException") - error["Message"].should.equal(f"Backup not found: {non_existent_arn}") + assert error["Code"] == "BackupNotFoundException" + assert error["Message"] == f"Backup not found: {non_existent_arn}" @mock_dynamodb @@ -5207,29 +5157,27 @@ def test_describe_backup(): resp = client.describe_backup(BackupArn=backup_arn) description = resp.get("BackupDescription") details = description.get("BackupDetails") - details.should.have.key("BackupArn").should.contain(table_name) - details.should.have.key("BackupName").should.equal(backup_name) - details.should.have.key("BackupSizeBytes").should.be.a(int) - details.should.have.key("BackupStatus") - details.should.have.key("BackupType").should.equal("USER") - details.should.have.key("BackupCreationDateTime").should.be.a(datetime) + assert table_name in details["BackupArn"] + assert details["BackupName"] == backup_name + assert isinstance(details["BackupSizeBytes"], int) + assert "BackupStatus" in details + assert details["BackupType"] == "USER" + assert isinstance(details["BackupCreationDateTime"], datetime) source = description.get("SourceTableDetails") - source.should.have.key("TableName").should.equal(table_name) - source.should.have.key("TableArn").should.equal(table["TableArn"]) - source.should.have.key("TableSizeBytes").should.be.a(int) - source.should.have.key("KeySchema").should.equal(table["KeySchema"]) - source.should.have.key("TableCreationDateTime").should.equal( - table["CreationDateTime"] - ) - source.should.have.key("ProvisionedThroughput").should.be.a(dict) - source.should.have.key("ItemCount").should.equal(table["ItemCount"]) + assert source["TableName"] == table_name + assert source["TableArn"] == table["TableArn"] + assert isinstance(source["TableSizeBytes"], int) + assert source["KeySchema"] == table["KeySchema"] + assert source["TableCreationDateTime"] == table["CreationDateTime"] + assert isinstance(source["ProvisionedThroughput"], dict) + assert source["ItemCount"] == table["ItemCount"] @mock_dynamodb def test_list_backups_for_non_existent_table(): client = boto3.client("dynamodb", "us-east-1") resp = client.list_backups(TableName="non-existent") - resp["BackupSummaries"].should.have.length_of(0) + assert len(resp["BackupSummaries"]) == 0 @mock_dynamodb @@ -5247,19 +5195,19 @@ def test_list_backups(): for backup_name in backup_names: client.create_backup(TableName=table_name, BackupName=backup_name) resp = client.list_backups(BackupType="USER") - resp["BackupSummaries"].should.have.length_of(4) + assert len(resp["BackupSummaries"]) == 4 for table_name in table_names: resp = client.list_backups(TableName=table_name) - resp["BackupSummaries"].should.have.length_of(2) + assert len(resp["BackupSummaries"]) == 2 for summary in resp["BackupSummaries"]: - summary.should.have.key("TableName").should.equal(table_name) - summary.should.have.key("TableArn").should.contain(table_name) - summary.should.have.key("BackupName").should.be.within(backup_names) - summary.should.have.key("BackupArn") - summary.should.have.key("BackupCreationDateTime").should.be.a(datetime) - summary.should.have.key("BackupStatus") - summary.should.have.key("BackupType").should.be.within(["USER", "SYSTEM"]) - summary.should.have.key("BackupSizeBytes").should.be.a(int) + assert summary["TableName"] == table_name + assert table_name in summary["TableArn"] + assert summary["BackupName"] in backup_names + assert "BackupArn" in summary + assert isinstance(summary["BackupCreationDateTime"], datetime) + assert "BackupStatus" in summary + assert summary["BackupType"] in ["USER", "SYSTEM"] + assert isinstance(summary["BackupSizeBytes"], int) @mock_dynamodb @@ -5271,8 +5219,8 @@ def test_restore_table_from_non_existent_backup_raises_error(): TargetTableName="from-backup", BackupArn=non_existent_arn ) error = ex.value.response["Error"] - error["Code"].should.equal("BackupNotFoundException") - error["Message"].should.equal(f"Backup not found: {non_existent_arn}") + assert error["Code"] == "BackupNotFoundException" + assert error["Message"] == f"Backup not found: {non_existent_arn}" @mock_dynamodb @@ -5292,8 +5240,8 @@ def test_restore_table_from_backup_raises_error_when_table_already_exists(): TargetTableName=table_name, BackupArn=backup["BackupArn"] ) error = ex.value.response["Error"] - error["Code"].should.equal("TableAlreadyExistsException") - error["Message"].should.equal(f"Table already exists: {table_name}") + assert error["Code"] == "TableAlreadyExistsException" + assert error["Message"] == f"Table already exists: {table_name}" @mock_dynamodb @@ -5320,20 +5268,18 @@ def test_restore_table_from_backup(): restored = client.restore_table_from_backup( TargetTableName=restored_table_name, BackupArn=backup_arn ).get("TableDescription") - restored.should.have.key("AttributeDefinitions").should.equal( - table["AttributeDefinitions"] - ) - restored.should.have.key("TableName").should.equal(restored_table_name) - restored.should.have.key("KeySchema").should.equal(table["KeySchema"]) - restored.should.have.key("TableStatus") - restored.should.have.key("ItemCount").should.equal(5) - restored.should.have.key("TableArn").should.contain(restored_table_name) - restored.should.have.key("RestoreSummary").should.be.a(dict) + assert restored["AttributeDefinitions"] == table["AttributeDefinitions"] + assert restored["TableName"] == restored_table_name + assert restored["KeySchema"] == table["KeySchema"] + assert "TableStatus" in restored + assert restored["ItemCount"] == 5 + assert restored_table_name in restored["TableArn"] + assert isinstance(restored["RestoreSummary"], dict) summary = restored.get("RestoreSummary") - summary.should.have.key("SourceBackupArn").should.equal(backup_arn) - summary.should.have.key("SourceTableArn").should.equal(table["TableArn"]) - summary.should.have.key("RestoreDateTime").should.be.a(datetime) - summary.should.have.key("RestoreInProgress").should.equal(False) + assert summary["SourceBackupArn"] == backup_arn + assert summary["SourceTableArn"] == table["TableArn"] + assert isinstance(summary["RestoreDateTime"], datetime) + assert summary["RestoreInProgress"] is False @mock_dynamodb @@ -5354,16 +5300,16 @@ def test_restore_table_to_point_in_time(): restored = client.restore_table_to_point_in_time( TargetTableName=restored_table_name, SourceTableName=table_name ).get("TableDescription") - restored.should.have.key("TableName").should.equal(restored_table_name) - restored.should.have.key("KeySchema").should.equal(table["KeySchema"]) - restored.should.have.key("TableStatus") - restored.should.have.key("ItemCount").should.equal(5) - restored.should.have.key("TableArn").should.contain(restored_table_name) - restored.should.have.key("RestoreSummary").should.be.a(dict) + assert restored["TableName"] == restored_table_name + assert restored["KeySchema"] == table["KeySchema"] + assert "TableStatus" in restored + assert restored["ItemCount"] == 5 + assert restored_table_name in restored["TableArn"] + assert isinstance(restored["RestoreSummary"], dict) summary = restored.get("RestoreSummary") - summary.should.have.key("SourceTableArn").should.equal(table["TableArn"]) - summary.should.have.key("RestoreDateTime").should.be.a(datetime) - summary.should.have.key("RestoreInProgress").should.equal(False) + assert summary["SourceTableArn"] == table["TableArn"] + assert isinstance(summary["RestoreDateTime"], datetime) + assert summary["RestoreInProgress"] is False @mock_dynamodb @@ -5376,8 +5322,8 @@ def test_restore_table_to_point_in_time_raises_error_when_source_not_exist(): TargetTableName=restored_table_name, SourceTableName=table_name ) error = ex.value.response["Error"] - error["Code"].should.equal("SourceTableNotFoundException") - error["Message"].should.equal(f"Source table not found: {table_name}") + assert error["Code"] == "SourceTableNotFoundException" + assert error["Message"] == f"Source table not found: {table_name}" @mock_dynamodb @@ -5402,8 +5348,8 @@ def test_restore_table_to_point_in_time_raises_error_when_dest_exist(): TargetTableName=restored_table_name, SourceTableName=table_name ) error = ex.value.response["Error"] - error["Code"].should.equal("TableAlreadyExistsException") - error["Message"].should.equal(f"Table already exists: {restored_table_name}") + assert error["Code"] == "TableAlreadyExistsException" + assert error["Message"] == f"Table already exists: {restored_table_name}" @mock_dynamodb @@ -5413,8 +5359,8 @@ def test_delete_non_existent_backup_raises_error(): with pytest.raises(ClientError) as ex: client.delete_backup(BackupArn=non_existent_arn) error = ex.value.response["Error"] - error["Code"].should.equal("BackupNotFoundException") - error["Message"].should.equal(f"Backup not found: {non_existent_arn}") + assert error["Code"] == "BackupNotFoundException" + assert error["Message"] == f"Backup not found: {non_existent_arn}" @mock_dynamodb @@ -5431,19 +5377,19 @@ def test_delete_backup(): for backup_name in backup_names: client.create_backup(TableName=table_name, BackupName=backup_name) resp = client.list_backups(TableName=table_name, BackupType="USER") - resp["BackupSummaries"].should.have.length_of(2) + assert len(resp["BackupSummaries"]) == 2 backup_to_delete = resp["BackupSummaries"][0]["BackupArn"] backup_deleted = client.delete_backup(BackupArn=backup_to_delete).get( "BackupDescription" ) - backup_deleted.should.have.key("SourceTableDetails") - backup_deleted.should.have.key("BackupDetails") + assert "SourceTableDetails" in backup_deleted + assert "BackupDetails" in backup_deleted details = backup_deleted["BackupDetails"] - details.should.have.key("BackupArn").should.equal(backup_to_delete) - details.should.have.key("BackupName").should.be.within(backup_names) - details.should.have.key("BackupStatus").should.equal("DELETED") + assert details["BackupArn"] == backup_to_delete + assert details["BackupName"] in backup_names + assert details["BackupStatus"] == "DELETED" resp = client.list_backups(TableName=table_name, BackupType="USER") - resp["BackupSummaries"].should.have.length_of(1) + assert len(resp["BackupSummaries"]) == 1 @mock_dynamodb @@ -5481,17 +5427,17 @@ def test_source_and_restored_table_items_are_not_linked(): guids_added_after_restore = add_guids_to_table(restored_table_name, 5) source_table_items = client.scan(TableName=source_table_name) - source_table_items.should.have.key("Count").should.equal(10) + assert source_table_items["Count"] == 10 source_table_guids = [x["id"]["S"] for x in source_table_items["Items"]] - set(source_table_guids).should.equal( - set(guids_original) | set(guids_added_after_backup) + assert set(source_table_guids) == set(guids_original) | set( + guids_added_after_backup ) restored_table_items = client.scan(TableName=restored_table_name) - restored_table_items.should.have.key("Count").should.equal(10) + assert restored_table_items["Count"] == 10 restored_table_guids = [x["id"]["S"] for x in restored_table_items["Items"]] - set(restored_table_guids).should.equal( - set(guids_original) | set(guids_added_after_restore) + assert set(restored_table_guids) == set(guids_original) | set( + guids_added_after_restore ) @@ -5500,14 +5446,12 @@ def test_source_and_restored_table_items_are_not_linked(): def test_describe_endpoints(region): client = boto3.client("dynamodb", region) res = client.describe_endpoints()["Endpoints"] - res.should.equal( - [ - { - "Address": f"dynamodb.{region}.amazonaws.com", - "CachePeriodInMinutes": 1440, - }, - ] - ) + assert res == [ + { + "Address": f"dynamodb.{region}.amazonaws.com", + "CachePeriodInMinutes": 1440, + }, + ] @mock_dynamodb @@ -5537,9 +5481,9 @@ def test_update_non_existing_item_raises_error_and_does_not_contain_item_afterwa table = boto3.resource("dynamodb", region_name="us-west-2").Table(name) with pytest.raises(ClientError) as err: table.update_item(**update_expression) - err.value.response["Error"]["Code"].should.equal("ValidationException") + assert err.value.response["Error"]["Code"] == "ValidationException" - conn.scan(TableName=name)["Items"].should.have.length_of(0) + assert len(conn.scan(TableName=name)["Items"]) == 0 @mock_dynamodb @@ -5565,9 +5509,8 @@ def test_batch_write_item(): for idx, name in enumerate(tables): table = conn.Table(f"table-{idx}") res = table.get_item(Key={"id": str(idx)}) - assert res["Item"].should.equal({"id": str(idx)}) - scan = table.scan() - assert scan["Count"].should.equal(1) + assert res["Item"] == {"id": str(idx)} + assert table.scan()["Count"] == 1 conn.batch_write_item( RequestItems={ @@ -5579,8 +5522,7 @@ def test_batch_write_item(): for idx, name in enumerate(tables): table = conn.Table(f"table-{idx}") - scan = table.scan() - assert scan["Count"].should.equal(0) + assert table.scan()["Count"] == 0 @mock_dynamodb @@ -5633,14 +5575,16 @@ def test_gsi_lastevaluatedkey(): ) items = response["Items"] - items.should.have.length_of(1) - items[0].should.equal( - {"main_key": "testkey1", "extra_data": "testdata", "index_key": "indexkey"} - ) + assert len(items) == 1 + assert items[0] == { + "main_key": "testkey1", + "extra_data": "testdata", + "index_key": "indexkey", + } last_evaluated_key = response["LastEvaluatedKey"] - last_evaluated_key.should.have.length_of(2) - last_evaluated_key.should.equal({"main_key": "testkey1", "index_key": "indexkey"}) + assert len(last_evaluated_key) == 2 + assert last_evaluated_key == {"main_key": "testkey1", "index_key": "indexkey"} @mock_dynamodb @@ -5687,11 +5631,11 @@ def test_filter_expression_execution_order(): ) query_items_1 = query_response_1["Items"] - query_items_1.should.have.length_of(0) + assert len(query_items_1) == 0 query_last_evaluated_key = query_response_1["LastEvaluatedKey"] - query_last_evaluated_key.should.have.length_of(2) - query_last_evaluated_key.should.equal({"hash_key": "keyvalue", "range_key": "A"}) + assert len(query_last_evaluated_key) == 2 + assert query_last_evaluated_key == {"hash_key": "keyvalue", "range_key": "A"} query_response_2 = table.query( Limit=1, @@ -5701,10 +5645,12 @@ def test_filter_expression_execution_order(): ) query_items_2 = query_response_2["Items"] - query_items_2.should.have.length_of(1) - query_items_2[0].should.equal( - {"hash_key": "keyvalue", "filtered_attribute": "Z", "range_key": "B"} - ) + assert len(query_items_2) == 1 + assert query_items_2[0] == { + "hash_key": "keyvalue", + "filtered_attribute": "Z", + "range_key": "B", + } # test scan @@ -5713,11 +5659,11 @@ def test_filter_expression_execution_order(): ) scan_items_1 = scan_response_1["Items"] - scan_items_1.should.have.length_of(0) + assert len(scan_items_1) == 0 scan_last_evaluated_key = scan_response_1["LastEvaluatedKey"] - scan_last_evaluated_key.should.have.length_of(2) - scan_last_evaluated_key.should.equal({"hash_key": "keyvalue", "range_key": "A"}) + assert len(scan_last_evaluated_key) == 2 + assert scan_last_evaluated_key == {"hash_key": "keyvalue", "range_key": "A"} scan_response_2 = table.scan( Limit=1, @@ -5726,10 +5672,9 @@ def test_filter_expression_execution_order(): ) scan_items_2 = scan_response_2["Items"] - scan_items_2.should.have.length_of(1) - scan_items_2[0].should.equal( + assert scan_items_2 == [ {"hash_key": "keyvalue", "filtered_attribute": "Z", "range_key": "B"} - ) + ] @mock_dynamodb diff --git a/tests/test_dynamodb/test_dynamodb_batch_get_item.py b/tests/test_dynamodb/test_dynamodb_batch_get_item.py index b91e03175..0bb678ba5 100644 --- a/tests/test_dynamodb/test_dynamodb_batch_get_item.py +++ b/tests/test_dynamodb/test_dynamodb_batch_get_item.py @@ -1,5 +1,4 @@ import boto3 -import sure # noqa # pylint: disable=unused-import import pytest from moto import mock_dynamodb @@ -64,11 +63,11 @@ def test_batch_items_throws_exception_when_requesting_100_items_for_single_table } } ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") + assert ex.value.response["Error"]["Code"] == "ValidationException" msg = ex.value.response["Error"]["Message"] - msg.should.contain("1 validation error detected: Value") - msg.should.contain( - "at 'requestItems.users.member.keys' failed to satisfy constraint: Member must have length less than or equal to 100" + assert ( + msg + == "1 validation error detected: Value at 'requestItems.users.member.keys' failed to satisfy constraint: Member must have length less than or equal to 100" ) @@ -92,10 +91,9 @@ def test_batch_items_throws_exception_when_requesting_100_items_across_all_table }, } ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "Too many items requested for the BatchGetItem call" - ) + err = ex.value.response["Error"] + assert err["Code"] == "ValidationException" + assert err["Message"] == "Too many items requested for the BatchGetItem call" @mock_dynamodb @@ -116,11 +114,13 @@ def test_batch_items_with_basic_projection_expression(): } )["Responses"]["users"] - returned_items.should.have.length_of(3) - [item["username"]["S"] for item in returned_items].should.be.equal( - ["user1", "user2", "user3"] - ) - [item.get("foo") for item in returned_items].should.be.equal([None, None, None]) + assert len(returned_items) == 3 + assert [item["username"]["S"] for item in returned_items] == [ + "user1", + "user2", + "user3", + ] + assert [item.get("foo") for item in returned_items] == [None, None, None] # The projection expression should not remove data from storage returned_items = dynamodb.batch_get_item( @@ -137,10 +137,12 @@ def test_batch_items_with_basic_projection_expression(): } )["Responses"]["users"] - [item["username"]["S"] for item in returned_items].should.be.equal( - ["user1", "user2", "user3"] - ) - [item["foo"]["S"] for item in returned_items].should.be.equal(["bar", "bar", "bar"]) + assert [item["username"]["S"] for item in returned_items] == [ + "user1", + "user2", + "user3", + ] + assert [item["foo"]["S"] for item in returned_items] == ["bar", "bar", "bar"] @mock_dynamodb @@ -162,11 +164,13 @@ def test_batch_items_with_basic_projection_expression_and_attr_expression_names( } )["Responses"]["users"] - returned_items.should.have.length_of(3) - [item["username"]["S"] for item in returned_items].should.be.equal( - ["user1", "user2", "user3"] - ) - [item.get("foo") for item in returned_items].should.be.equal([None, None, None]) + assert len(returned_items) == 3 + assert [item["username"]["S"] for item in returned_items] == [ + "user1", + "user2", + "user3", + ] + assert [item.get("foo") for item in returned_items] == [None, None, None] @mock_dynamodb @@ -184,10 +188,9 @@ def test_batch_items_should_throw_exception_for_duplicate_request(): } } ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "Provided list of item keys contains duplicates" - ) + err = ex.value.response["Error"] + assert err["Code"] == "ValidationException" + assert err["Message"] == "Provided list of item keys contains duplicates" @mock_dynamodb @@ -218,14 +221,14 @@ def test_batch_items_should_return_16mb_max(): } ) - resp["Responses"]["users"].should.have.length_of(55) + assert len(resp["Responses"]["users"]) == 55 unprocessed_keys = resp["UnprocessedKeys"]["users"]["Keys"] # 75 requested, 55 returned --> 20 unprocessed - unprocessed_keys.should.have.length_of(20) + assert len(unprocessed_keys) == 20 # Keys 55-75 are unprocessed - unprocessed_keys.should.contain({"username": {"S": "largedata55"}}) - unprocessed_keys.should.contain({"username": {"S": "largedata65"}}) + assert {"username": {"S": "largedata55"}} in unprocessed_keys + assert {"username": {"S": "largedata65"}} in unprocessed_keys # Keys 0-55 are processed in the regular response, so they shouldn't show up here - unprocessed_keys.shouldnt.contain({"username": {"S": "largedata45"}}) + assert {"username": {"S": "largedata45"}} not in unprocessed_keys diff --git a/tests/test_dynamodb/test_dynamodb_cloudformation.py b/tests/test_dynamodb/test_dynamodb_cloudformation.py index bddc931a6..9a4c4415a 100644 --- a/tests/test_dynamodb/test_dynamodb_cloudformation.py +++ b/tests/test_dynamodb/test_dynamodb_cloudformation.py @@ -1,6 +1,5 @@ import boto3 import json -import sure # noqa # pylint: disable=unused-import from moto import mock_cloudformation, mock_dynamodb @@ -40,11 +39,11 @@ def test_delete_stack_dynamo_template_boto3(): StackName="test_stack", TemplateBody=json.dumps(template_create_table) ) table_desc = dynamodb_client.list_tables() - len(table_desc.get("TableNames")).should.equal(1) + assert len(table_desc.get("TableNames")) == 1 conn.delete_stack(StackName="test_stack") table_desc = dynamodb_client.list_tables() - len(table_desc.get("TableNames")).should.equal(0) + assert len(table_desc.get("TableNames")) == 0 conn.create_stack( StackName="test_stack", TemplateBody=json.dumps(template_create_table) diff --git a/tests/test_dynamodb/test_dynamodb_condition_expressions.py b/tests/test_dynamodb/test_dynamodb_condition_expressions.py index 43d8b856b..57f2a2ebb 100644 --- a/tests/test_dynamodb/test_dynamodb_condition_expressions.py +++ b/tests/test_dynamodb/test_dynamodb_condition_expressions.py @@ -3,7 +3,6 @@ import re import boto3 import pytest -import sure # noqa # pylint: disable=unused-import from moto import mock_dynamodb @@ -38,7 +37,7 @@ def test_condition_expression_with_dot_in_attr_name(): ) item = table.get_item(Key={"id": "key-0"})["Item"] - item.should.equal({"id": "key-0", "first": {}}) + assert item == {"id": "key-0", "first": {}} @mock_dynamodb @@ -232,8 +231,8 @@ def test_condition_expressions(): def _assert_conditional_check_failed_exception(exc): err = exc.value.response["Error"] - err["Code"].should.equal("ConditionalCheckFailedException") - err["Message"].should.equal("The conditional request failed") + assert err["Code"] == "ConditionalCheckFailedException" + assert err["Message"] == "The conditional request failed" @mock_dynamodb @@ -274,9 +273,7 @@ def update_numerical_con_expr(key, con_expr, res, table): ExpressionAttributeValues={":zero": 0, ":one": 1}, ConditionExpression=con_expr, ) - table.get_item(Key={"partitionKey": key})["Item"]["myAttr"].should.equal( - Decimal(res) - ) + assert table.get_item(Key={"partitionKey": key})["Item"]["myAttr"] == Decimal(res) @mock_dynamodb @@ -404,7 +401,7 @@ def test_condition_expression_with_reserved_keyword_as_attr_name(): # table is unchanged item = table.get_item(Key={"id": "key-0"})["Item"] - item.should.equal(record) + assert item == record # using attribute names solves the issue table.update_item( @@ -422,4 +419,4 @@ def test_condition_expression_with_reserved_keyword_as_attr_name(): ) item = table.get_item(Key={"id": "key-0"})["Item"] - item.should.equal({"id": "key-0", "first": {}}) + assert item == {"id": "key-0", "first": {}} diff --git a/tests/test_dynamodb/test_dynamodb_consumedcapacity.py b/tests/test_dynamodb/test_dynamodb_consumedcapacity.py index 41d3a13c0..ae69427d6 100644 --- a/tests/test_dynamodb/test_dynamodb_consumedcapacity.py +++ b/tests/test_dynamodb/test_dynamodb_consumedcapacity.py @@ -1,6 +1,5 @@ import boto3 import pytest -import sure # noqa # pylint: disable=unused-import from botocore.exceptions import ClientError from moto import mock_dynamodb @@ -24,9 +23,10 @@ def test_error_on_wrong_value_for_consumed_capacity(): with pytest.raises(ClientError) as ex: table.put_item(Item=item, ReturnConsumedCapacity="Garbage") err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "1 validation error detected: Value 'Garbage' at 'returnConsumedCapacity' failed to satisfy constraint: Member must satisfy enum value set: [INDEXES, TOTAL, NONE]" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "1 validation error detected: Value 'Garbage' at 'returnConsumedCapacity' failed to satisfy constraint: Member must satisfy enum value set: [INDEXES, TOTAL, NONE]" ) @@ -46,10 +46,10 @@ def test_consumed_capacity_get_unknown_item(): ) # Should still return ConsumedCapacity, even if it does not return an item - response.should.have.key("ConsumedCapacity") - response["ConsumedCapacity"].should.equal( - {"TableName": "test_table", "CapacityUnits": 0.5} - ) + assert response["ConsumedCapacity"] == { + "TableName": "test_table", + "CapacityUnits": 0.5, + } @mock_dynamodb @@ -135,15 +135,14 @@ def validate_response( response, should_have_capacity, should_have_table, is_index=False, value=1.0 ): if should_have_capacity: - response.should.have.key("ConsumedCapacity") - response["ConsumedCapacity"]["TableName"].should.equal("jobs") - response["ConsumedCapacity"]["CapacityUnits"].should.equal(value) + capacity = response["ConsumedCapacity"] + assert capacity["TableName"] == "jobs" + assert capacity["CapacityUnits"] == value if should_have_table: - response["ConsumedCapacity"]["Table"].should.equal({"CapacityUnits": value}) + assert capacity["Table"] == {"CapacityUnits": value} if is_index: - response["ConsumedCapacity"].should.have.key("LocalSecondaryIndexes") - response["ConsumedCapacity"]["LocalSecondaryIndexes"].should.equal( - {"job_name-index": {"CapacityUnits": value}} - ) + assert capacity["LocalSecondaryIndexes"] == { + "job_name-index": {"CapacityUnits": value} + } else: - response.shouldnt.have.key("ConsumedCapacity") + assert "ConsumedCapacity" not in response diff --git a/tests/test_dynamodb/test_dynamodb_create_table.py b/tests/test_dynamodb/test_dynamodb_create_table.py index fb71c7de1..1cb8eb16c 100644 --- a/tests/test_dynamodb/test_dynamodb_create_table.py +++ b/tests/test_dynamodb/test_dynamodb_create_table.py @@ -1,6 +1,5 @@ import boto3 from botocore.exceptions import ClientError -import sure # noqa # pylint: disable=unused-import from datetime import datetime import pytest @@ -26,31 +25,29 @@ def test_create_table_standard(): ) actual = client.describe_table(TableName="messages")["Table"] - actual.should.have.key("AttributeDefinitions").equal( - [ - {"AttributeName": "id", "AttributeType": "S"}, - {"AttributeName": "subject", "AttributeType": "S"}, - ] + assert actual["AttributeDefinitions"] == [ + {"AttributeName": "id", "AttributeType": "S"}, + {"AttributeName": "subject", "AttributeType": "S"}, + ] + assert isinstance(actual["CreationDateTime"], datetime) + assert actual["GlobalSecondaryIndexes"] == [] + assert actual["LocalSecondaryIndexes"] == [] + assert actual["ProvisionedThroughput"] == { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 1, + "WriteCapacityUnits": 5, + } + assert actual["TableSizeBytes"] == 0 + assert actual["TableName"] == "messages" + assert actual["TableStatus"] == "ACTIVE" + assert ( + actual["TableArn"] == f"arn:aws:dynamodb:us-east-1:{ACCOUNT_ID}:table/messages" ) - actual.should.have.key("CreationDateTime").be.a(datetime) - actual.should.have.key("GlobalSecondaryIndexes").equal([]) - actual.should.have.key("LocalSecondaryIndexes").equal([]) - actual.should.have.key("ProvisionedThroughput").equal( - {"NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 5} - ) - actual.should.have.key("TableSizeBytes").equal(0) - actual.should.have.key("TableName").equal("messages") - actual.should.have.key("TableStatus").equal("ACTIVE") - actual.should.have.key("TableArn").equal( - f"arn:aws:dynamodb:us-east-1:{ACCOUNT_ID}:table/messages" - ) - actual.should.have.key("KeySchema").equal( - [ - {"AttributeName": "id", "KeyType": "HASH"}, - {"AttributeName": "subject", "KeyType": "RANGE"}, - ] - ) - actual.should.have.key("ItemCount").equal(0) + assert actual["KeySchema"] == [ + {"AttributeName": "id", "KeyType": "HASH"}, + {"AttributeName": "subject", "KeyType": "RANGE"}, + ] + assert actual["ItemCount"] == 0 @mock_dynamodb @@ -81,43 +78,39 @@ def test_create_table_with_local_index(): ) actual = client.describe_table(TableName="messages")["Table"] - actual.should.have.key("AttributeDefinitions").equal( - [ - {"AttributeName": "id", "AttributeType": "S"}, - {"AttributeName": "subject", "AttributeType": "S"}, - {"AttributeName": "threads", "AttributeType": "S"}, - ] + assert actual["AttributeDefinitions"] == [ + {"AttributeName": "id", "AttributeType": "S"}, + {"AttributeName": "subject", "AttributeType": "S"}, + {"AttributeName": "threads", "AttributeType": "S"}, + ] + assert isinstance(actual["CreationDateTime"], datetime) + assert actual["GlobalSecondaryIndexes"] == [] + assert actual["LocalSecondaryIndexes"] == [ + { + "IndexName": "threads_index", + "KeySchema": [ + {"AttributeName": "id", "KeyType": "HASH"}, + {"AttributeName": "threads", "KeyType": "RANGE"}, + ], + "Projection": {"ProjectionType": "ALL"}, + } + ] + assert actual["ProvisionedThroughput"] == { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 1, + "WriteCapacityUnits": 5, + } + assert actual["TableSizeBytes"] == 0 + assert actual["TableName"] == "messages" + assert actual["TableStatus"] == "ACTIVE" + assert ( + actual["TableArn"] == f"arn:aws:dynamodb:us-east-1:{ACCOUNT_ID}:table/messages" ) - actual.should.have.key("CreationDateTime").be.a(datetime) - actual.should.have.key("GlobalSecondaryIndexes").equal([]) - actual.should.have.key("LocalSecondaryIndexes").equal( - [ - { - "IndexName": "threads_index", - "KeySchema": [ - {"AttributeName": "id", "KeyType": "HASH"}, - {"AttributeName": "threads", "KeyType": "RANGE"}, - ], - "Projection": {"ProjectionType": "ALL"}, - } - ] - ) - actual.should.have.key("ProvisionedThroughput").equal( - {"NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 5} - ) - actual.should.have.key("TableSizeBytes").equal(0) - actual.should.have.key("TableName").equal("messages") - actual.should.have.key("TableStatus").equal("ACTIVE") - actual.should.have.key("TableArn").equal( - f"arn:aws:dynamodb:us-east-1:{ACCOUNT_ID}:table/messages" - ) - actual.should.have.key("KeySchema").equal( - [ - {"AttributeName": "id", "KeyType": "HASH"}, - {"AttributeName": "subject", "KeyType": "RANGE"}, - ] - ) - actual.should.have.key("ItemCount").equal(0) + assert actual["KeySchema"] == [ + {"AttributeName": "id", "KeyType": "HASH"}, + {"AttributeName": "subject", "KeyType": "RANGE"}, + ] + assert actual["ItemCount"] == 0 @mock_dynamodb @@ -143,20 +136,18 @@ def test_create_table_with_gsi(): } ], ) - table["TableDescription"]["GlobalSecondaryIndexes"].should.equal( - [ - { - "KeySchema": [{"KeyType": "HASH", "AttributeName": "subject"}], - "IndexName": "test_gsi", - "Projection": {"ProjectionType": "ALL"}, - "IndexStatus": "ACTIVE", - "ProvisionedThroughput": { - "ReadCapacityUnits": 0, - "WriteCapacityUnits": 0, - }, - } - ] - ) + assert table["TableDescription"]["GlobalSecondaryIndexes"] == [ + { + "KeySchema": [{"KeyType": "HASH", "AttributeName": "subject"}], + "IndexName": "test_gsi", + "Projection": {"ProjectionType": "ALL"}, + "IndexStatus": "ACTIVE", + "ProvisionedThroughput": { + "ReadCapacityUnits": 0, + "WriteCapacityUnits": 0, + }, + } + ] table = dynamodb.create_table( TableName="users2", @@ -181,20 +172,18 @@ def test_create_table_with_gsi(): } ], ) - table["TableDescription"]["GlobalSecondaryIndexes"].should.equal( - [ - { - "KeySchema": [{"KeyType": "HASH", "AttributeName": "subject"}], - "IndexName": "test_gsi", - "Projection": {"ProjectionType": "ALL"}, - "IndexStatus": "ACTIVE", - "ProvisionedThroughput": { - "ReadCapacityUnits": 3, - "WriteCapacityUnits": 5, - }, - } - ] - ) + assert table["TableDescription"]["GlobalSecondaryIndexes"] == [ + { + "KeySchema": [{"KeyType": "HASH", "AttributeName": "subject"}], + "IndexName": "test_gsi", + "Projection": {"ProjectionType": "ALL"}, + "IndexStatus": "ACTIVE", + "ProvisionedThroughput": { + "ReadCapacityUnits": 3, + "WriteCapacityUnits": 5, + }, + } + ] @mock_dynamodb @@ -212,16 +201,16 @@ def test_create_table_with_stream_specification(): }, ) - resp["TableDescription"].should.have.key("StreamSpecification") - resp["TableDescription"]["StreamSpecification"].should.equal( - {"StreamEnabled": True, "StreamViewType": "NEW_AND_OLD_IMAGES"} - ) - resp["TableDescription"].should.contain("LatestStreamLabel") - resp["TableDescription"].should.contain("LatestStreamArn") + assert resp["TableDescription"]["StreamSpecification"] == { + "StreamEnabled": True, + "StreamViewType": "NEW_AND_OLD_IMAGES", + } + assert "LatestStreamLabel" in resp["TableDescription"] + assert "LatestStreamArn" in resp["TableDescription"] resp = conn.delete_table(TableName="test-streams") - resp["TableDescription"].should.contain("StreamSpecification") + assert "StreamSpecification" in resp["TableDescription"] @mock_dynamodb @@ -239,7 +228,7 @@ def test_create_table_with_tags(): resp = client.list_tags_of_resource( ResourceArn=resp["TableDescription"]["TableArn"] ) - resp.should.have.key("Tags").equals([{"Key": "tk", "Value": "tv"}]) + assert resp["Tags"] == [{"Key": "tk", "Value": "tv"}] @mock_dynamodb @@ -259,12 +248,12 @@ def test_create_table_pay_per_request(): ) actual = client.describe_table(TableName="test1")["Table"] - actual.should.have.key("BillingModeSummary").equals( - {"BillingMode": "PAY_PER_REQUEST"} - ) - actual.should.have.key("ProvisionedThroughput").equals( - {"NumberOfDecreasesToday": 0, "ReadCapacityUnits": 0, "WriteCapacityUnits": 0} - ) + assert actual["BillingModeSummary"] == {"BillingMode": "PAY_PER_REQUEST"} + assert actual["ProvisionedThroughput"] == { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 0, + "WriteCapacityUnits": 0, + } @mock_dynamodb @@ -284,10 +273,12 @@ def test_create_table__provisioned_throughput(): ) actual = client.describe_table(TableName="test1")["Table"] - actual.should.have.key("BillingModeSummary").equals({"BillingMode": "PROVISIONED"}) - actual.should.have.key("ProvisionedThroughput").equals( - {"NumberOfDecreasesToday": 0, "ReadCapacityUnits": 2, "WriteCapacityUnits": 3} - ) + assert actual["BillingModeSummary"] == {"BillingMode": "PROVISIONED"} + assert actual["ProvisionedThroughput"] == { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 2, + "WriteCapacityUnits": 3, + } @mock_dynamodb @@ -305,9 +296,10 @@ def test_create_table_without_specifying_throughput(): StreamSpecification={"StreamEnabled": False, "StreamViewType": "NEW_IMAGE"}, ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "One or more parameter values were invalid: ReadCapacityUnits and WriteCapacityUnits must both be specified when BillingMode is PROVISIONED" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "One or more parameter values were invalid: ReadCapacityUnits and WriteCapacityUnits must both be specified when BillingMode is PROVISIONED" ) @@ -330,9 +322,10 @@ def test_create_table_error_pay_per_request_with_provisioned_param(): BillingMode="PAY_PER_REQUEST", ) err = exc.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.equal( - "ProvisionedThroughput cannot be specified when BillingMode is PAY_PER_REQUEST" + assert err["Code"] == "ValidationException" + assert ( + err["Message"] + == "ProvisionedThroughput cannot be specified when BillingMode is PAY_PER_REQUEST" ) @@ -354,7 +347,7 @@ def test_create_table_with_ssespecification__false(): ) actual = client.describe_table(TableName="test1")["Table"] - actual.shouldnt.have.key("SSEDescription") + assert "SSEDescription" not in actual @mock_dynamodb @@ -375,12 +368,11 @@ def test_create_table_with_ssespecification__true(): ) actual = client.describe_table(TableName="test1")["Table"] - actual.should.have.key("SSEDescription") - actual["SSEDescription"].should.have.key("Status").equals("ENABLED") - actual["SSEDescription"].should.have.key("SSEType").equals("KMS") - actual["SSEDescription"].should.have.key("KMSMasterKeyArn").match( - "^arn:aws:kms" - ) # Default KMS key for DynamoDB + assert "SSEDescription" in actual + assert actual["SSEDescription"]["Status"] == "ENABLED" + assert actual["SSEDescription"]["SSEType"] == "KMS" + # Default KMS key for DynamoDB + assert actual["SSEDescription"]["KMSMasterKeyArn"].startswith("arn:aws:kms") @mock_dynamodb @@ -401,10 +393,10 @@ def test_create_table_with_ssespecification__custom_kms_key(): ) actual = client.describe_table(TableName="test1")["Table"] - actual.should.have.key("SSEDescription") - actual["SSEDescription"].should.have.key("Status").equals("ENABLED") - actual["SSEDescription"].should.have.key("SSEType").equals("KMS") - actual["SSEDescription"].should.have.key("KMSMasterKeyArn").equals("custom-kms-key") + assert "SSEDescription" in actual + assert actual["SSEDescription"]["Status"] == "ENABLED" + assert actual["SSEDescription"]["SSEType"] == "KMS" + assert actual["SSEDescription"]["KMSMasterKeyArn"] == "custom-kms-key" @mock_dynamodb @@ -424,23 +416,19 @@ def test_create_table__specify_non_key_column(): ) actual = client.describe_table(TableName="tab")["Table"] - actual["KeySchema"].should.equal( - [ - {"AttributeName": "PK", "KeyType": "HASH"}, - {"AttributeName": "SomeColumn", "KeyType": "N"}, - ] - ) + assert actual["KeySchema"] == [ + {"AttributeName": "PK", "KeyType": "HASH"}, + {"AttributeName": "SomeColumn", "KeyType": "N"}, + ] if not settings.TEST_SERVER_MODE: ddb = dynamodb_backends[ACCOUNT_ID]["us-east-2"] - ddb.tables["tab"].attr.should.contain( - {"AttributeName": "PK", "AttributeType": "S"} - ) - ddb.tables["tab"].attr.should.contain( - {"AttributeName": "SomeColumn", "AttributeType": "N"} - ) + assert {"AttributeName": "PK", "AttributeType": "S"} in ddb.tables["tab"].attr + assert {"AttributeName": "SomeColumn", "AttributeType": "N"} in ddb.tables[ + "tab" + ].attr # It should recognize PK is the Hash Key - ddb.tables["tab"].hash_key_attr.should.equal("PK") + assert ddb.tables["tab"].hash_key_attr == "PK" # It should recognize that SomeColumn is not a Range Key - ddb.tables["tab"].has_range_key.should.equal(False) - ddb.tables["tab"].range_key_names.should.equal([]) + assert ddb.tables["tab"].has_range_key is False + assert ddb.tables["tab"].range_key_names == [] diff --git a/tests/test_dynamodb/test_dynamodb_executor.py b/tests/test_dynamodb/test_dynamodb_executor.py index 75c5d84c0..caed8b2cd 100644 --- a/tests/test_dynamodb/test_dynamodb_executor.py +++ b/tests/test_dynamodb/test_dynamodb_executor.py @@ -454,12 +454,12 @@ def test_normalize_with_one_action(table): item=item, table=table, ).validate() - validated_ast.children.should.have.length_of(1) - validated_ast.children[0].should.be.a(UpdateExpressionAddClause) + assert len(validated_ast.children) == 1 + assert isinstance(validated_ast.children[0], UpdateExpressionAddClause) validated_ast.normalize() - validated_ast.children.should.have.length_of(1) - validated_ast.children[0].should.be.a(UpdateExpressionAddAction) + assert len(validated_ast.children) == 1 + assert isinstance(validated_ast.children[0], UpdateExpressionAddAction) def test_normalize_with_multiple_actions__order_is_preserved(table): @@ -481,22 +481,22 @@ def test_normalize_with_multiple_actions__order_is_preserved(table): item=item, table=table, ).validate() - validated_ast.children.should.have.length_of(2) + assert len(validated_ast.children) == 2 # add clause first - validated_ast.children[0].should.be.a(UpdateExpressionAddClause) + assert isinstance(validated_ast.children[0], UpdateExpressionAddClause) # rest of the expression next - validated_ast.children[1].should.be.a(UpdateExpression) + assert isinstance(validated_ast.children[1], UpdateExpression) validated_ast.normalize() - validated_ast.children.should.have.length_of(5) + assert len(validated_ast.children) == 5 # add action first - validated_ast.children[0].should.be.a(UpdateExpressionAddAction) + assert isinstance(validated_ast.children[0], UpdateExpressionAddAction) # Removal actions in reverse order - validated_ast.children[1].should.be.a(UpdateExpressionRemoveAction) - validated_ast.children[1]._get_value().should.equal(3) - validated_ast.children[2].should.be.a(UpdateExpressionRemoveAction) - validated_ast.children[2]._get_value().should.equal(2) - validated_ast.children[3].should.be.a(UpdateExpressionRemoveAction) - validated_ast.children[3]._get_value().should.equal(1) + assert isinstance(validated_ast.children[1], UpdateExpressionRemoveAction) + assert validated_ast.children[1]._get_value() == 3 + assert isinstance(validated_ast.children[2], UpdateExpressionRemoveAction) + assert validated_ast.children[2]._get_value() == 2 + assert isinstance(validated_ast.children[3], UpdateExpressionRemoveAction) + assert validated_ast.children[3]._get_value() == 1 # Set action last, as per insertion order - validated_ast.children[4].should.be.a(UpdateExpressionSetAction) + assert isinstance(validated_ast.children[4], UpdateExpressionSetAction) diff --git a/tests/test_dynamodb/test_dynamodb_expression_tokenizer.py b/tests/test_dynamodb/test_dynamodb_expression_tokenizer.py index 9a7740cf9..08c274f31 100644 --- a/tests/test_dynamodb/test_dynamodb_expression_tokenizer.py +++ b/tests/test_dynamodb/test_dynamodb_expression_tokenizer.py @@ -1,3 +1,5 @@ +import pytest + from moto.dynamodb.exceptions import ( InvalidTokenException, InvalidExpressionAttributeNameKey, @@ -108,12 +110,10 @@ def test_expression_tokenizer_single_set_action_with_underscore_in_identifier(): def test_expression_tokenizer_leading_underscore_in_attribute_name_expression(): """Leading underscore is not allowed for an attribute name""" set_action = "SET attrName = _idid" - try: + with pytest.raises(InvalidTokenException) as te: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "_" - assert te.near == "= _idid" + assert te.value.token == "_" + assert te.value.near == "= _idid" def test_expression_tokenizer_leading_underscore_in_attribute_value_expression(): @@ -188,11 +188,9 @@ def test_expression_tokenizer_single_set_action_attribute_name_invalid_key(): ExpressionAttributeNames contains invalid key: Syntax error; key: "#va#l2" """ set_action = "SET #va#l2 = 3" - try: + with pytest.raises(InvalidExpressionAttributeNameKey) as e: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidExpressionAttributeNameKey as e: - assert e.key == "#va#l2" + assert e.value.key == "#va#l2" def test_expression_tokenizer_single_set_action_attribute_name_invalid_key_double_hash(): @@ -200,11 +198,9 @@ def test_expression_tokenizer_single_set_action_attribute_name_invalid_key_doubl ExpressionAttributeNames contains invalid key: Syntax error; key: "#va#l" """ set_action = "SET #va#l = 3" - try: + with pytest.raises(InvalidExpressionAttributeNameKey) as e: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidExpressionAttributeNameKey as e: - assert e.key == "#va#l" + assert e.value.key == "#va#l" def test_expression_tokenizer_single_set_action_attribute_name_valid_key(): @@ -245,39 +241,31 @@ def test_expression_tokenizer_single_set_action_attribute_name_leading_underscor def test_expression_tokenizer_just_a_pipe(): set_action = "|" - try: + with pytest.raises(InvalidTokenException) as te: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "|" - assert te.near == "|" + assert te.value.token == "|" + assert te.value.near == "|" def test_expression_tokenizer_just_a_pipe_with_leading_white_spaces(): set_action = " |" - try: + with pytest.raises(InvalidTokenException) as te: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "|" - assert te.near == " |" + assert te.value.token == "|" + assert te.value.near == " |" def test_expression_tokenizer_just_a_pipe_for_set_expression(): set_action = "SET|" - try: + with pytest.raises(InvalidTokenException) as te: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "|" - assert te.near == "SET|" + assert te.value.token == "|" + assert te.value.near == "SET|" def test_expression_tokenizer_just_an_attribute_and_a_pipe_for_set_expression(): set_action = "SET a|" - try: + with pytest.raises(InvalidTokenException) as te: ExpressionTokenizer.make_list(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "|" - assert te.near == "a|" + assert te.value.token == "|" + assert te.value.near == "a|" diff --git a/tests/test_dynamodb/test_dynamodb_expressions.py b/tests/test_dynamodb/test_dynamodb_expressions.py index eeaa2abfc..020e8b185 100644 --- a/tests/test_dynamodb/test_dynamodb_expressions.py +++ b/tests/test_dynamodb/test_dynamodb_expressions.py @@ -1,3 +1,5 @@ +import pytest + from moto.dynamodb.exceptions import InvalidTokenException from moto.dynamodb.parsing.expressions import UpdateExpressionParser from moto.dynamodb.parsing.reserved_keywords import ReservedKeywords @@ -14,392 +16,314 @@ def test_get_reserved_keywords(): def test_update_expression_numeric_literal_in_expression(): set_action = "SET attrName = 3" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "3" - assert te.near == "= 3" + assert te.value.token == "3" + assert te.value.near == "= 3" def test_expression_tokenizer_multi_number_numeric_literal_in_expression(): set_action = "SET attrName = 34" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "34" - assert te.near == "= 34" + assert te.value.token == "34" + assert te.value.near == "= 34" def test_expression_tokenizer_numeric_literal_unclosed_square_bracket(): set_action = "SET MyStr[ 3" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "" - assert te.near == "3" + assert te.value.token == "" + assert te.value.near == "3" def test_expression_tokenizer_wrong_closing_bracket_with_space(): set_action = "SET MyStr[3 )" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == ")" - assert te.near == "3 )" + assert te.value.token == ")" + assert te.value.near == "3 )" def test_expression_tokenizer_wrong_closing_bracket(): set_action = "SET MyStr[3)" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == ")" - assert te.near == "3)" + assert te.value.token == ")" + assert te.value.near == "3)" def test_expression_tokenizer_only_numeric_literal_for_set(): set_action = "SET 2" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "2" - assert te.near == "SET 2" + assert te.value.token == "2" + assert te.value.near == "SET 2" def test_expression_tokenizer_only_numeric_literal(): set_action = "2" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "2" - assert te.near == "2" + assert te.value.token == "2" + assert te.value.near == "2" def test_expression_tokenizer_set_closing_round_bracket(): set_action = "SET )" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == ")" - assert te.near == "SET )" + assert te.value.token == ")" + assert te.value.near == "SET )" def test_expression_tokenizer_set_closing_followed_by_numeric_literal(): set_action = "SET ) 3" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == ")" - assert te.near == "SET ) 3" + assert te.value.token == ")" + assert te.value.near == "SET ) 3" def test_expression_tokenizer_numeric_literal_unclosed_square_bracket_trailing_space(): set_action = "SET MyStr[ 3 " - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "" - assert te.near == "3 " + assert te.value.token == "" + assert te.value.near == "3 " def test_expression_tokenizer_unbalanced_round_brackets_only_opening(): set_action = "SET MyStr = (:_val" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "" - assert te.near == ":_val" + assert te.value.token == "" + assert te.value.near == ":_val" def test_expression_tokenizer_unbalanced_round_brackets_only_opening_trailing_space(): set_action = "SET MyStr = (:_val " - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "" - assert te.near == ":_val " + assert te.value.token == "" + assert te.value.near == ":_val " def test_expression_tokenizer_unbalanced_square_brackets_only_opening(): set_action = "SET MyStr = [:_val" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "[" - assert te.near == "= [:_val" + assert te.value.token == "[" + assert te.value.near == "= [:_val" def test_expression_tokenizer_unbalanced_square_brackets_only_opening_trailing_spaces(): set_action = "SET MyStr = [:_val " - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "[" - assert te.near == "= [:_val" + assert te.value.token == "[" + assert te.value.near == "= [:_val" def test_expression_tokenizer_unbalanced_round_brackets_multiple_opening(): set_action = "SET MyStr = (:_val + (:val2" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "" - assert te.near == ":val2" + assert te.value.token == "" + assert te.value.near == ":val2" def test_expression_tokenizer_unbalanced_round_brackets_only_closing(): set_action = "SET MyStr = ):_val" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == ")" - assert te.near == "= ):_val" + assert te.value.token == ")" + assert te.value.near == "= ):_val" def test_expression_tokenizer_unbalanced_square_brackets_only_closing(): set_action = "SET MyStr = ]:_val" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "]" - assert te.near == "= ]:_val" + assert te.value.token == "]" + assert te.value.near == "= ]:_val" def test_expression_tokenizer_unbalanced_round_brackets_only_closing_followed_by_other_parts(): set_action = "SET MyStr = ):_val + :val2" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == ")" - assert te.near == "= ):_val" + assert te.value.token == ")" + assert te.value.near == "= ):_val" def test_update_expression_starts_with_keyword_reset_followed_by_identifier(): update_expression = "RESET NonExistent" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "RESET" - assert te.near == "RESET NonExistent" + assert te.value.token == "RESET" + assert te.value.near == "RESET NonExistent" def test_update_expression_starts_with_keyword_reset_followed_by_identifier_and_value(): update_expression = "RESET NonExistent value" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "RESET" - assert te.near == "RESET NonExistent" + assert te.value.token == "RESET" + assert te.value.near == "RESET NonExistent" def test_update_expression_starts_with_leading_spaces_and_keyword_reset_followed_by_identifier_and_value(): update_expression = " RESET NonExistent value" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "RESET" - assert te.near == " RESET NonExistent" + assert te.value.token == "RESET" + assert te.value.near == " RESET NonExistent" def test_update_expression_with_only_keyword_reset(): update_expression = "RESET" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "RESET" - assert te.near == "RESET" + assert te.value.token == "RESET" + assert te.value.near == "RESET" def test_update_nested_expression_with_selector_just_should_fail_parsing_at_numeric_literal_value(): update_expression = "SET a[0].b = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "5" - assert te.near == "= 5" + assert te.value.token == "5" + assert te.value.near == "= 5" def test_update_nested_expression_with_selector_and_spaces_should_only_fail_parsing_at_numeric_literal_value(): update_expression = "SET a [ 2 ]. b = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "5" - assert te.near == "= 5" + assert te.value.token == "5" + assert te.value.near == "= 5" def test_update_nested_expression_with_double_selector_and_spaces_should_only_fail_parsing_at_numeric_literal_value(): update_expression = "SET a [2][ 3 ]. b = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "5" - assert te.near == "= 5" + assert te.value.token == "5" + assert te.value.near == "= 5" def test_update_nested_expression_should_only_fail_parsing_at_numeric_literal_value(): update_expression = "SET a . b = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "5" - assert te.near == "= 5" + assert te.value.token == "5" + assert te.value.near == "= 5" def test_nested_selectors_in_update_expression_should_fail_at_nesting(): update_expression = "SET a [ [2] ]. b = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "[" - assert te.near == "[ [2" + assert te.value.token == "[" + assert te.value.near == "[ [2" def test_update_expression_number_in_selector_cannot_be_splite(): update_expression = "SET a [2 1]. b = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "1" - assert te.near == "2 1]" + assert te.value.token == "1" + assert te.value.near == "2 1]" def test_update_expression_cannot_have_successive_attributes(): update_expression = "SET #a a = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "a" - assert te.near == "#a a =" + assert te.value.token == "a" + assert te.value.near == "#a a =" def test_update_expression_path_with_both_attribute_and_attribute_name_should_only_fail_at_numeric_value(): update_expression = "SET #a.a = 5" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(update_expression) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "5" - assert te.near == "= 5" + assert te.value.token == "5" + assert te.value.near == "= 5" def test_expression_tokenizer_2_same_operators_back_to_back(): set_action = "SET MyStr = NoExist + + :_val " - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "+" - assert te.near == "+ + :_val" + assert te.value.token == "+" + assert te.value.near == "+ + :_val" def test_expression_tokenizer_2_different_operators_back_to_back(): set_action = "SET MyStr = NoExist + - :_val " - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "-" - assert te.near == "+ - :_val" + assert te.value.token == "-" + assert te.value.near == "+ - :_val" def test_update_expression_remove_does_not_allow_operations(): remove_action = "REMOVE NoExist + " - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(remove_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "+" - assert te.near == "NoExist + " + assert te.value.token == "+" + assert te.value.near == "NoExist + " def test_update_expression_add_does_not_allow_attribute_after_path(): """value here is not really a value since a value starts with a colon (:)""" add_expr = "ADD attr val foobar" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(add_expr) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "val" - assert te.near == "attr val foobar" + assert te.value.token == "val" + assert te.value.near == "attr val foobar" def test_update_expression_add_does_not_allow_attribute_foobar_after_value(): add_expr = "ADD attr :val foobar" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(add_expr) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "foobar" - assert te.near == ":val foobar" + assert te.value.token == "foobar" + assert te.value.near == ":val foobar" def test_update_expression_delete_does_not_allow_attribute_after_path(): """value here is not really a value since a value starts with a colon (:)""" delete_expr = "DELETE attr val" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(delete_expr) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "val" - assert te.near == "attr val" + assert te.value.token == "val" + assert te.value.near == "attr val" def test_update_expression_delete_does_not_allow_attribute_foobar_after_value(): delete_expr = "DELETE attr :val foobar" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(delete_expr) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "foobar" - assert te.near == ":val foobar" + assert te.value.token == "foobar" + assert te.value.near == ":val foobar" def test_update_expression_parsing_is_not_keyword_aware(): """path and VALUE are keywords. Yet a token error will be thrown for the numeric literal 1.""" delete_expr = "SET path = VALUE 1" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(delete_expr) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "1" - assert te.near == "VALUE 1" + assert te.value.token == "1" + assert te.value.near == "VALUE 1" def test_expression_if_not_exists_is_not_valid_in_remove_statement(): set_action = "REMOVE if_not_exists(a,b)" - try: + with pytest.raises(InvalidTokenException) as te: UpdateExpressionParser.make(set_action) - assert False, "Exception not raised correctly" - except InvalidTokenException as te: - assert te.token == "(" - assert te.near == "if_not_exists(a" + assert te.value.token == "(" + assert te.value.near == "if_not_exists(a" diff --git a/tests/test_dynamodb/test_dynamodb_statements.py b/tests/test_dynamodb/test_dynamodb_statements.py index 871026ad2..48879ec34 100644 --- a/tests/test_dynamodb/test_dynamodb_statements.py +++ b/tests/test_dynamodb/test_dynamodb_statements.py @@ -5,7 +5,6 @@ from unittest import TestCase class TestSelectStatements: - mock = mock_dynamodb() @classmethod diff --git a/tests/test_dynamodb/test_dynamodb_table_with_range_key.py b/tests/test_dynamodb/test_dynamodb_table_with_range_key.py index 80beeb812..addcf3199 100644 --- a/tests/test_dynamodb/test_dynamodb_table_with_range_key.py +++ b/tests/test_dynamodb/test_dynamodb_table_with_range_key.py @@ -3,7 +3,6 @@ from decimal import Decimal import boto3 from boto3.dynamodb.conditions import Key from botocore.exceptions import ClientError -import sure # noqa # pylint: disable=unused-import import pytest from moto import mock_dynamodb @@ -33,8 +32,8 @@ def test_get_item_without_range_key_boto3(): with pytest.raises(ClientError) as ex: table.get_item(Key={"id": hash_key}) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal("Validation Exception") + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ex.value.response["Error"]["Message"] == "Validation Exception" @mock_dynamodb @@ -59,23 +58,23 @@ def test_query_filter_boto3(): table.put_item(Item={"pk": "pk", "sk": f"sk-{i}"}) res = table.query(KeyConditionExpression=Key("pk").eq("pk")) - res["Items"].should.have.length_of(3) + assert len(res["Items"]) == 3 res = table.query(KeyConditionExpression=Key("pk").eq("pk") & Key("sk").lt("sk-1")) - res["Items"].should.have.length_of(1) - res["Items"].should.equal([{"pk": "pk", "sk": "sk-0"}]) + assert len(res["Items"]) == 1 + assert res["Items"] == [{"pk": "pk", "sk": "sk-0"}] res = table.query(KeyConditionExpression=Key("pk").eq("pk") & Key("sk").lte("sk-1")) - res["Items"].should.have.length_of(2) - res["Items"].should.equal([{"pk": "pk", "sk": "sk-0"}, {"pk": "pk", "sk": "sk-1"}]) + assert len(res["Items"]) == 2 + assert res["Items"] == [{"pk": "pk", "sk": "sk-0"}, {"pk": "pk", "sk": "sk-1"}] res = table.query(KeyConditionExpression=Key("pk").eq("pk") & Key("sk").gt("sk-1")) - res["Items"].should.have.length_of(1) - res["Items"].should.equal([{"pk": "pk", "sk": "sk-2"}]) + assert len(res["Items"]) == 1 + assert res["Items"] == [{"pk": "pk", "sk": "sk-2"}] res = table.query(KeyConditionExpression=Key("pk").eq("pk") & Key("sk").gte("sk-1")) - res["Items"].should.have.length_of(2) - res["Items"].should.equal([{"pk": "pk", "sk": "sk-1"}, {"pk": "pk", "sk": "sk-2"}]) + assert len(res["Items"]) == 2 + assert res["Items"] == [{"pk": "pk", "sk": "sk-1"}, {"pk": "pk", "sk": "sk-2"}] @mock_dynamodb @@ -108,7 +107,7 @@ def test_boto3_conditions(): ) expected = ["123", "456", "789"] for index, item in enumerate(results["Items"]): - item["subject"].should.equal(expected[index]) + assert item["subject"] == expected[index] # Return all items again, but in reverse results = table.query( @@ -116,7 +115,7 @@ def test_boto3_conditions(): ScanIndexForward=False, ) for index, item in enumerate(reversed(results["Items"])): - item["subject"].should.equal(expected[index]) + assert item["subject"] == expected[index] # Filter the subjects to only return some of the results results = table.query( @@ -124,32 +123,32 @@ def test_boto3_conditions(): & Key("subject").gt("234"), ConsistentRead=True, ) - results["Count"].should.equal(2) + assert results["Count"] == 2 # Filter to return no results results = table.query( KeyConditionExpression=Key("forum_name").eq("the-key") & Key("subject").gt("9999") ) - results["Count"].should.equal(0) + assert results["Count"] == 0 results = table.query( KeyConditionExpression=Key("forum_name").eq("the-key") & Key("subject").begins_with("12") ) - results["Count"].should.equal(1) + assert results["Count"] == 1 results = table.query( KeyConditionExpression=Key("subject").begins_with("7") & Key("forum_name").eq("the-key") ) - results["Count"].should.equal(1) + assert results["Count"] == 1 results = table.query( KeyConditionExpression=Key("forum_name").eq("the-key") & Key("subject").between("567", "890") ) - results["Count"].should.equal(1) + assert results["Count"] == 1 @mock_dynamodb @@ -199,7 +198,7 @@ def test_boto3_conditions_ignorecase(): ":end": {"S": "200"}, }, ) - results["Count"].should.equal(2) + assert results["Count"] == 2 with pytest.raises(ClientError) as ex: dynamodb.query( @@ -210,20 +209,19 @@ def test_boto3_conditions_ignorecase(): ":subject": {"S": "1"}, }, ) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "Invalid KeyConditionExpression: Invalid function name; function: BegIns_WiTh" + assert ex.value.response["Error"]["Code"] == "ValidationException" + assert ( + ex.value.response["Error"]["Message"] + == "Invalid KeyConditionExpression: Invalid function name; function: BegIns_WiTh" ) @mock_dynamodb def test_boto3_put_item_with_conditions(): - import botocore - dynamodb = boto3.resource("dynamodb", region_name="us-east-1") # Create the DynamoDB table. - table = dynamodb.create_table( + dynamodb.create_table( TableName="users", KeySchema=[ {"AttributeName": "forum_name", "KeyType": "HASH"}, @@ -244,15 +242,21 @@ def test_boto3_put_item_with_conditions(): ConditionExpression="attribute_not_exists(forum_name) AND attribute_not_exists(subject)", ) - table.put_item.when.called_with( - Item={"forum_name": "the-key", "subject": "123"}, - ConditionExpression="attribute_not_exists(forum_name) AND attribute_not_exists(subject)", - ).should.throw(botocore.exceptions.ClientError) + with pytest.raises(ClientError) as exc: + table.put_item( + Item={"forum_name": "the-key", "subject": "123"}, + ConditionExpression="attribute_not_exists(forum_name) AND attribute_not_exists(subject)", + ) + err = exc.value.response["Error"] + assert err["Code"] == "ConditionalCheckFailedException" - table.put_item.when.called_with( - Item={"forum_name": "bogus-key", "subject": "bogus", "test": "123"}, - ConditionExpression="attribute_exists(forum_name) AND attribute_exists(subject)", - ).should.throw(botocore.exceptions.ClientError) + with pytest.raises(ClientError) as exc: + table.put_item( + Item={"forum_name": "bogus-key", "subject": "bogus", "test": "123"}, + ConditionExpression="attribute_exists(forum_name) AND attribute_exists(subject)", + ) + err = exc.value.response["Error"] + assert err["Code"] == "ConditionalCheckFailedException" def _create_table_with_range_key(): @@ -316,15 +320,13 @@ def test_update_item_range_key_set(): (k, str(v) if isinstance(v, Decimal) else v) for k, v in table.get_item(Key=item_key)["Item"].items() ) - dict(returned_item).should.equal( - { - "username": "johndoe2", - "forum_name": "the-key", - "subject": "123", - "created": "4", - "mapfield": {"key": "value"}, - } - ) + assert returned_item == { + "username": "johndoe2", + "forum_name": "the-key", + "subject": "123", + "created": "4", + "mapfield": {"key": "value"}, + } @mock_dynamodb @@ -348,15 +350,13 @@ def test_update_item_does_not_exist_is_created(): (k, str(v) if isinstance(v, Decimal) else v) for k, v in table.get_item(Key=item_key)["Item"].items() ) - dict(returned_item).should.equal( - { - "username": "johndoe2", - "forum_name": "the-key", - "subject": "123", - "created": "4", - "mapfield": {"key": "value"}, - } - ) + assert returned_item == { + "username": "johndoe2", + "forum_name": "the-key", + "subject": "123", + "created": "4", + "mapfield": {"key": "value"}, + } @mock_dynamodb @@ -377,9 +377,11 @@ def test_update_item_add_value(): (k, str(v) if isinstance(v, Decimal) else v) for k, v in table.get_item(Key=item_key)["Item"].items() ) - dict(returned_item).should.equal( - {"numeric_field": "1", "forum_name": "the-key", "subject": "123"} - ) + assert returned_item == { + "numeric_field": "1", + "forum_name": "the-key", + "subject": "123", + } @mock_dynamodb @@ -404,13 +406,11 @@ def test_update_item_add_value_string_set(): (k, str(v) if isinstance(v, Decimal) else v) for k, v in table.get_item(Key=item_key)["Item"].items() ) - dict(returned_item).should.equal( - { - "string_set": set(["str1", "str2", "str3"]), - "forum_name": "the-key", - "subject": "123", - } - ) + assert returned_item == { + "string_set": set(["str1", "str2", "str3"]), + "forum_name": "the-key", + "subject": "123", + } @mock_dynamodb @@ -435,9 +435,11 @@ def test_update_item_delete_value_string_set(): (k, str(v) if isinstance(v, Decimal) else v) for k, v in table.get_item(Key=item_key)["Item"].items() ) - dict(returned_item).should.equal( - {"string_set": set(["str1"]), "forum_name": "the-key", "subject": "123"} - ) + assert returned_item == { + "string_set": set(["str1"]), + "forum_name": "the-key", + "subject": "123", + } @mock_dynamodb @@ -454,9 +456,11 @@ def test_update_item_add_value_does_not_exist_is_created(): (k, str(v) if isinstance(v, Decimal) else v) for k, v in table.get_item(Key=item_key)["Item"].items() ) - dict(returned_item).should.equal( - {"numeric_field": "2", "forum_name": "the-key", "subject": "123"} - ) + assert returned_item == { + "numeric_field": "2", + "forum_name": "the-key", + "subject": "123", + } @mock_dynamodb @@ -472,27 +476,30 @@ def test_update_item_with_expression(): UpdateExpression="SET field = :field_value", ExpressionAttributeValues={":field_value": 2}, ) - dict(table.get_item(Key=item_key)["Item"]).should.equal( - {"field": Decimal("2"), "forum_name": "the-key", "subject": "123"} - ) + assert table.get_item(Key=item_key)["Item"] == { + "field": Decimal("2"), + "forum_name": "the-key", + "subject": "123", + } table.update_item( Key=item_key, UpdateExpression="SET field = :field_value", ExpressionAttributeValues={":field_value": 3}, ) - dict(table.get_item(Key=item_key)["Item"]).should.equal( - {"field": Decimal("3"), "forum_name": "the-key", "subject": "123"} - ) + assert table.get_item(Key=item_key)["Item"] == { + "field": Decimal("3"), + "forum_name": "the-key", + "subject": "123", + } def assert_failure_due_to_key_not_in_schema(func, **kwargs): with pytest.raises(ClientError) as ex: func(**kwargs) - ex.value.response["Error"]["Code"].should.equal("ValidationException") - ex.value.response["Error"]["Message"].should.equal( - "The provided key element does not match the schema" - ) + err = ex.value.response["Error"] + assert err["Code"] == "ValidationException" + assert err["Message"] == "The provided key element does not match the schema" @mock_dynamodb @@ -518,7 +525,7 @@ def test_update_item_add_with_expression(): ExpressionAttributeValues={":v": {"item4"}}, ) current_item["str_set"] = current_item["str_set"].union({"item4"}) - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item # Update item to add a string value to a non-existing set table.update_item( @@ -527,7 +534,7 @@ def test_update_item_add_with_expression(): ExpressionAttributeValues={":v": {"item4"}}, ) current_item["non_existing_str_set"] = {"item4"} - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item # Update item to add a num value to a num set table.update_item( @@ -536,7 +543,7 @@ def test_update_item_add_with_expression(): ExpressionAttributeValues={":v": {6}}, ) current_item["num_set"] = current_item["num_set"].union({6}) - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item # Update item to add a value to a number value table.update_item( @@ -545,35 +552,59 @@ def test_update_item_add_with_expression(): ExpressionAttributeValues={":v": 20}, ) current_item["num_val"] = current_item["num_val"] + 20 - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item - # Attempt to add a number value to a string set, should raise Client Error - table.update_item.when.called_with( - Key=item_key, - UpdateExpression="ADD str_set :v", - ExpressionAttributeValues={":v": 20}, - ).should.have.raised(ClientError) - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + # Attempt to add a number value to a string set + with pytest.raises(ClientError) as exc: + table.update_item( + Key=item_key, + UpdateExpression="ADD str_set :v", + ExpressionAttributeValues={":v": 20}, + ) + err = exc.value.response["Error"] + assert ( + err["Message"] + == "An operand in the update expression has an incorrect data type" + ) - # Attempt to add a number set to the string set, should raise a ClientError - table.update_item.when.called_with( - Key=item_key, - UpdateExpression="ADD str_set :v", - ExpressionAttributeValues={":v": {20}}, - ).should.have.raised(ClientError) - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item + + # Attempt to add a number set to the string set + with pytest.raises(ClientError) as exc: + table.update_item( + Key=item_key, + UpdateExpression="ADD str_set :v", + ExpressionAttributeValues={":v": {20}}, + ) + err = exc.value.response["Error"] + assert ( + err["Message"] + == "An operand in the update expression has an incorrect data type" + ) + + assert table.get_item(Key=item_key)["Item"] == current_item # Attempt to update with a bad expression - table.update_item.when.called_with( - Key=item_key, UpdateExpression="ADD str_set bad_value" - ).should.have.raised(ClientError) + with pytest.raises(ClientError) as exc: + table.update_item(Key=item_key, UpdateExpression="ADD str_set bad_value") + err = exc.value.response["Error"] + assert ( + err["Message"] + == 'Invalid UpdateExpression: Syntax error; token: "bad_value", near: "str_set bad_value"' + ) # Attempt to add a string value instead of a string set - table.update_item.when.called_with( - Key=item_key, - UpdateExpression="ADD str_set :v", - ExpressionAttributeValues={":v": "new_string"}, - ).should.have.raised(ClientError) + with pytest.raises(ClientError) as exc: + table.update_item( + Key=item_key, + UpdateExpression="ADD str_set :v", + ExpressionAttributeValues={":v": "new_string"}, + ) + err = exc.value.response["Error"] + assert ( + err["Message"] + == "An operand in the update expression has an incorrect data type" + ) @mock_dynamodb @@ -599,10 +630,9 @@ def test_update_item_add_with_nested_sets(): current_item["nested"]["str_set"] = current_item["nested"]["str_set"].union( {"item4"} ) - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item # Update item to add a string value to a non-existing set - # Should raise table.update_item( Key=item_key, UpdateExpression="ADD #ns.#ne :v", @@ -610,7 +640,7 @@ def test_update_item_add_with_nested_sets(): ExpressionAttributeValues={":v": {"new_item"}}, ) current_item["nested"]["non_existing_str_set"] = {"new_item"} - assert dict(table.get_item(Key=item_key)["Item"]) == current_item + assert table.get_item(Key=item_key)["Item"] == current_item @mock_dynamodb @@ -636,7 +666,7 @@ def test_update_item_delete_with_nested_sets(): current_item["nested"]["str_set"] = current_item["nested"]["str_set"].difference( {"item3"} ) - dict(table.get_item(Key=item_key)["Item"]).should.equal(current_item) + assert table.get_item(Key=item_key)["Item"] == current_item @mock_dynamodb @@ -662,7 +692,7 @@ def test_update_item_delete_with_expression(): ExpressionAttributeValues={":v": {"item2"}}, ) current_item["str_set"] = current_item["str_set"].difference({"item2"}) - dict(table.get_item(Key=item_key)["Item"]).should.equal(current_item) + assert table.get_item(Key=item_key)["Item"] == current_item # Update item to delete a num value from a num set table.update_item( @@ -671,28 +701,46 @@ def test_update_item_delete_with_expression(): ExpressionAttributeValues={":v": {2}}, ) current_item["num_set"] = current_item["num_set"].difference({2}) - dict(table.get_item(Key=item_key)["Item"]).should.equal(current_item) + assert table.get_item(Key=item_key)["Item"] == current_item # Try to delete on a number, this should fail - table.update_item.when.called_with( - Key=item_key, - UpdateExpression="DELETE num_val :v", - ExpressionAttributeValues={":v": 20}, - ).should.have.raised(ClientError) - dict(table.get_item(Key=item_key)["Item"]).should.equal(current_item) + with pytest.raises(ClientError) as exc: + table.update_item( + Key=item_key, + UpdateExpression="DELETE num_val :v", + ExpressionAttributeValues={":v": 20}, + ) + err = exc.value.response["Error"] + assert ( + err["Message"] + == "Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: operator: DELETE, operand type: NUMBER" + ) + + assert table.get_item(Key=item_key)["Item"] == current_item # Try to delete a string set from a number set - table.update_item.when.called_with( - Key=item_key, - UpdateExpression="DELETE num_set :v", - ExpressionAttributeValues={":v": {"del_str"}}, - ).should.have.raised(ClientError) - dict(table.get_item(Key=item_key)["Item"]).should.equal(current_item) + with pytest.raises(ClientError) as exc: + table.update_item( + Key=item_key, + UpdateExpression="DELETE num_set :v", + ExpressionAttributeValues={":v": {"del_str"}}, + ) + err = exc.value.response["Error"] + assert ( + err["Message"] + == "An operand in the update expression has an incorrect data type" + ) + + assert table.get_item(Key=item_key)["Item"] == current_item # Attempt to update with a bad expression - table.update_item.when.called_with( - Key=item_key, UpdateExpression="DELETE num_val badvalue" - ).should.have.raised(ClientError) + with pytest.raises(ClientError) as exc: + table.update_item(Key=item_key, UpdateExpression="DELETE num_val badvalue") + err = exc.value.response["Error"] + assert ( + err["Message"] + == 'Invalid UpdateExpression: Syntax error; token: "badvalue", near: "num_val badvalue"' + ) @mock_dynamodb @@ -748,7 +796,7 @@ def test_boto3_query_gsi_range_comparison(): ) expected = ["456", "789", "123"] for index, item in enumerate(results["Items"]): - item["subject"].should.equal(expected[index]) + assert item["subject"] == expected[index] # Return all johndoe items again, but in reverse results = table.query( @@ -757,7 +805,7 @@ def test_boto3_query_gsi_range_comparison(): IndexName="TestGSI", ) for index, item in enumerate(reversed(results["Items"])): - item["subject"].should.equal(expected[index]) + assert item["subject"] == expected[index] # Filter the creation to only return some of the results # And reverse order of hash + range key @@ -766,20 +814,20 @@ def test_boto3_query_gsi_range_comparison(): ConsistentRead=True, IndexName="TestGSI", ) - results["Count"].should.equal(2) + assert results["Count"] == 2 # Filter to return no results results = table.query( KeyConditionExpression=Key("username").eq("janedoe") & Key("created").gt(9), IndexName="TestGSI", ) - results["Count"].should.equal(0) + assert results["Count"] == 0 results = table.query( KeyConditionExpression=Key("username").eq("janedoe") & Key("created").eq(5), IndexName="TestGSI", ) - results["Count"].should.equal(1) + assert results["Count"] == 1 # Test range key sorting results = table.query( @@ -788,7 +836,7 @@ def test_boto3_query_gsi_range_comparison(): ) expected = [Decimal("1"), Decimal("2"), Decimal("3")] for index, item in enumerate(results["Items"]): - item["created"].should.equal(expected[index]) + assert item["created"] == expected[index] @mock_dynamodb @@ -810,8 +858,8 @@ def test_boto3_update_table_throughput(): ) table = dynamodb.Table("users") - table.provisioned_throughput["ReadCapacityUnits"].should.equal(5) - table.provisioned_throughput["WriteCapacityUnits"].should.equal(6) + assert table.provisioned_throughput["ReadCapacityUnits"] == 5 + assert table.provisioned_throughput["WriteCapacityUnits"] == 6 table.update( ProvisionedThroughput={"ReadCapacityUnits": 10, "WriteCapacityUnits": 11} @@ -819,8 +867,8 @@ def test_boto3_update_table_throughput(): table = dynamodb.Table("users") - table.provisioned_throughput["ReadCapacityUnits"].should.equal(10) - table.provisioned_throughput["WriteCapacityUnits"].should.equal(11) + assert table.provisioned_throughput["ReadCapacityUnits"] == 10 + assert table.provisioned_throughput["WriteCapacityUnits"] == 11 @mock_dynamodb @@ -859,11 +907,11 @@ def test_boto3_update_table_gsi_throughput(): table = dynamodb.Table("users") gsi_throughput = table.global_secondary_indexes[0]["ProvisionedThroughput"] - gsi_throughput["ReadCapacityUnits"].should.equal(3) - gsi_throughput["WriteCapacityUnits"].should.equal(4) + assert gsi_throughput["ReadCapacityUnits"] == 3 + assert gsi_throughput["WriteCapacityUnits"] == 4 - table.provisioned_throughput["ReadCapacityUnits"].should.equal(5) - table.provisioned_throughput["WriteCapacityUnits"].should.equal(6) + assert table.provisioned_throughput["ReadCapacityUnits"] == 5 + assert table.provisioned_throughput["WriteCapacityUnits"] == 6 table.update( GlobalSecondaryIndexUpdates=[ @@ -882,12 +930,12 @@ def test_boto3_update_table_gsi_throughput(): table = dynamodb.Table("users") # Primary throughput has not changed - table.provisioned_throughput["ReadCapacityUnits"].should.equal(5) - table.provisioned_throughput["WriteCapacityUnits"].should.equal(6) + assert table.provisioned_throughput["ReadCapacityUnits"] == 5 + assert table.provisioned_throughput["WriteCapacityUnits"] == 6 gsi_throughput = table.global_secondary_indexes[0]["ProvisionedThroughput"] - gsi_throughput["ReadCapacityUnits"].should.equal(10) - gsi_throughput["WriteCapacityUnits"].should.equal(11) + assert gsi_throughput["ReadCapacityUnits"] == 10 + assert gsi_throughput["WriteCapacityUnits"] == 11 @mock_dynamodb @@ -909,8 +957,8 @@ def test_update_table_gsi_create(): ) table = dynamodb.Table("users") - table.global_secondary_indexes.should.have.length_of(0) - table.attribute_definitions.should.have.length_of(2) + assert len(table.global_secondary_indexes) == 0 + assert len(table.attribute_definitions) == 2 table.update( AttributeDefinitions=[ @@ -939,12 +987,12 @@ def test_update_table_gsi_create(): table = dynamodb.Table("users") table.reload() - table.global_secondary_indexes.should.have.length_of(1) - table.attribute_definitions.should.have.length_of(4) + assert len(table.global_secondary_indexes) == 1 + assert len(table.attribute_definitions) == 4 gsi_throughput = table.global_secondary_indexes[0]["ProvisionedThroughput"] - assert gsi_throughput["ReadCapacityUnits"].should.equal(3) - assert gsi_throughput["WriteCapacityUnits"].should.equal(4) + assert gsi_throughput["ReadCapacityUnits"] == 3 + assert gsi_throughput["WriteCapacityUnits"] == 4 # Check update works table.update( @@ -963,13 +1011,13 @@ def test_update_table_gsi_create(): table = dynamodb.Table("users") gsi_throughput = table.global_secondary_indexes[0]["ProvisionedThroughput"] - assert gsi_throughput["ReadCapacityUnits"].should.equal(10) - assert gsi_throughput["WriteCapacityUnits"].should.equal(11) + assert gsi_throughput["ReadCapacityUnits"] == 10 + assert gsi_throughput["WriteCapacityUnits"] == 11 table.update(GlobalSecondaryIndexUpdates=[{"Delete": {"IndexName": "TestGSI"}}]) table = dynamodb.Table("users") - table.global_secondary_indexes.should.have.length_of(0) + assert len(table.global_secondary_indexes) == 0 @mock_dynamodb @@ -1006,12 +1054,12 @@ def test_update_table_gsi_throughput(): ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 6}, ) table = dynamodb.Table("users") - table.global_secondary_indexes.should.have.length_of(1) + assert len(table.global_secondary_indexes) == 1 table.update(GlobalSecondaryIndexUpdates=[{"Delete": {"IndexName": "TestGSI"}}]) table = dynamodb.Table("users") - table.global_secondary_indexes.should.have.length_of(0) + assert len(table.global_secondary_indexes) == 0 @mock_dynamodb @@ -1028,22 +1076,21 @@ def test_query_pagination(): ) page1 = table.query(KeyConditionExpression=Key("forum_name").eq("the-key"), Limit=6) - page1["Count"].should.equal(6) - page1["Items"].should.have.length_of(6) - page1.should.have.key("LastEvaluatedKey") + assert page1["Count"] == 6 + assert len(page1["Items"]) == 6 page2 = table.query( KeyConditionExpression=Key("forum_name").eq("the-key"), Limit=6, ExclusiveStartKey=page1["LastEvaluatedKey"], ) - page2["Count"].should.equal(4) - page2["Items"].should.have.length_of(4) - page2.should_not.have.key("LastEvaluatedKey") + assert page2["Count"] == 4 + assert len(page2["Items"]) == 4 + assert "LastEvaluatedKey" not in page2 results = page1["Items"] + page2["Items"] subjects = set([int(r["subject"]) for r in results]) - subjects.should.equal(set(range(10))) + assert subjects == set(range(10)) @mock_dynamodb @@ -1188,7 +1235,6 @@ def test_update_item_throws_exception_when_updating_hash_or_range_key( ExpressionAttributeValues={":New": {"S": "2"}}, ) err = ex.value.response["Error"] - err["Code"].should.equal("ValidationException") - err["Message"].should.match( - r"One or more parameter values were invalid: Cannot update attribute (r|h). This attribute is part of the key" - ) + assert err["Code"] == "ValidationException" + assert "Cannot update attribute" in err["Message"] + assert "This attribute is part of the key" in err["Message"] diff --git a/tests/test_dynamodb/test_dynamodb_table_without_range_key.py b/tests/test_dynamodb/test_dynamodb_table_without_range_key.py index 780f8f963..99ded99ea 100644 --- a/tests/test_dynamodb/test_dynamodb_table_without_range_key.py +++ b/tests/test_dynamodb/test_dynamodb_table_without_range_key.py @@ -1,12 +1,10 @@ import boto3 -from boto3.dynamodb.conditions import Key -import sure # noqa # pylint: disable=unused-import import pytest +from boto3.dynamodb.conditions import Key from datetime import datetime from botocore.exceptions import ClientError from moto import mock_dynamodb from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID -import botocore @mock_dynamodb @@ -35,41 +33,37 @@ def test_create_table(): actual = client.describe_table(TableName="messages")["Table"] - actual.should.have.key("AttributeDefinitions").equal( - [ - {"AttributeName": "id", "AttributeType": "S"}, - {"AttributeName": "gsi_col", "AttributeType": "S"}, - ] + assert actual["AttributeDefinitions"] == [ + {"AttributeName": "id", "AttributeType": "S"}, + {"AttributeName": "gsi_col", "AttributeType": "S"}, + ] + assert isinstance(actual["CreationDateTime"], datetime) + assert actual["GlobalSecondaryIndexes"] == [ + { + "IndexName": "test_gsi", + "KeySchema": [{"AttributeName": "gsi_col", "KeyType": "HASH"}], + "Projection": {"ProjectionType": "ALL"}, + "IndexStatus": "ACTIVE", + "ProvisionedThroughput": { + "ReadCapacityUnits": 1, + "WriteCapacityUnits": 1, + }, + } + ] + assert actual["LocalSecondaryIndexes"] == [] + assert actual["ProvisionedThroughput"] == { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 1, + "WriteCapacityUnits": 1, + } + assert actual["TableSizeBytes"] == 0 + assert actual["TableName"] == "messages" + assert actual["TableStatus"] == "ACTIVE" + assert ( + actual["TableArn"] == f"arn:aws:dynamodb:us-east-2:{ACCOUNT_ID}:table/messages" ) - actual.should.have.key("CreationDateTime").be.a(datetime) - actual.should.have.key("GlobalSecondaryIndexes").equal( - [ - { - "IndexName": "test_gsi", - "KeySchema": [{"AttributeName": "gsi_col", "KeyType": "HASH"}], - "Projection": {"ProjectionType": "ALL"}, - "IndexStatus": "ACTIVE", - "ProvisionedThroughput": { - "ReadCapacityUnits": 1, - "WriteCapacityUnits": 1, - }, - } - ] - ) - actual.should.have.key("LocalSecondaryIndexes").equal([]) - actual.should.have.key("ProvisionedThroughput").equal( - {"NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1} - ) - actual.should.have.key("TableSizeBytes").equal(0) - actual.should.have.key("TableName").equal("messages") - actual.should.have.key("TableStatus").equal("ACTIVE") - actual.should.have.key("TableArn").equal( - f"arn:aws:dynamodb:us-east-2:{ACCOUNT_ID}:table/messages" - ) - actual.should.have.key("KeySchema").equal( - [{"AttributeName": "id", "KeyType": "HASH"}] - ) - actual.should.have.key("ItemCount").equal(0) + assert actual["KeySchema"] == [{"AttributeName": "id", "KeyType": "HASH"}] + assert actual["ItemCount"] == 0 @mock_dynamodb @@ -81,17 +75,17 @@ def test_delete_table(): AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) - conn.list_tables()["TableNames"].should.have.length_of(1) + assert len(conn.list_tables()["TableNames"]) == 1 conn.delete_table(TableName="messages") - conn.list_tables()["TableNames"].should.have.length_of(0) + assert conn.list_tables()["TableNames"] == [] with pytest.raises(ClientError) as ex: conn.delete_table(TableName="messages") - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal("Requested resource not found") + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.value.response["Error"]["Message"] == "Requested resource not found" @mock_dynamodb @@ -112,11 +106,13 @@ def test_item_add_and_describe_and_update(): table.put_item(Item=data) returned_item = table.get_item(Key={"id": "LOLCat Forum"}) - returned_item.shouldnt.have.key("ConsumedCapacity") + assert "ConsumedCapacity" not in returned_item - dict(returned_item["Item"]).should.equal( - {"id": "LOLCat Forum", "Body": "http://url_to_lolcat.gif", "SentBy": "User A"} - ) + assert returned_item["Item"] == { + "id": "LOLCat Forum", + "Body": "http://url_to_lolcat.gif", + "SentBy": "User A", + } table.update_item( Key={"id": "LOLCat Forum"}, @@ -125,9 +121,11 @@ def test_item_add_and_describe_and_update(): ) returned_item = table.get_item(Key={"id": "LOLCat Forum"}) - returned_item["Item"].should.equal( - {"id": "LOLCat Forum", "Body": "http://url_to_lolcat.gif", "SentBy": "User B"} - ) + assert returned_item["Item"] == { + "id": "LOLCat Forum", + "Body": "http://url_to_lolcat.gif", + "SentBy": "User B", + } @mock_dynamodb @@ -144,9 +142,9 @@ def test_item_put_without_table(): }, ) - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal("Requested resource not found") + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.value.response["Error"]["Message"] == "Requested resource not found" @mock_dynamodb @@ -156,9 +154,9 @@ def test_get_item_with_undeclared_table(): with pytest.raises(ClientError) as ex: conn.get_item(TableName="messages", Key={"forum_name": {"S": "LOLCat Forum"}}) - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal("Requested resource not found") + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.value.response["Error"]["Message"] == "Requested resource not found" @mock_dynamodb @@ -179,11 +177,11 @@ def test_delete_item(): } table.put_item(Item=item_data) - table.item_count.should.equal(1) + assert table.item_count == 1 table.delete_item(Key={"id": "LOLCat Forum"}) - table.item_count.should.equal(0) + assert table.item_count == 0 table.delete_item(Key={"id": "LOLCat Forum"}) @@ -209,9 +207,9 @@ def test_scan_with_undeclared_table(): with pytest.raises(ClientError) as ex: conn.scan(TableName="messages") - ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException") - ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) - ex.value.response["Error"]["Message"].should.equal("Requested resource not found") + assert ex.value.response["Error"]["Code"] == "ResourceNotFoundException" + assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400 + assert ex.value.response["Error"]["Message"] == "Requested resource not found" @mock_dynamodb @@ -224,7 +222,7 @@ def test_get_key_schema(): ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) - table.key_schema.should.equal([{"AttributeName": "id", "KeyType": "HASH"}]) + assert table.key_schema == [{"AttributeName": "id", "KeyType": "HASH"}] @mock_dynamodb @@ -259,7 +257,7 @@ def test_update_item_double_nested_remove(): "username": {"S": "steve"}, "Meta": {"M": {"Name": {"M": {"Last": {"S": "Urkel"}}}}}, } - dict(returned_item["Item"]).should.equal(expected_item) + assert returned_item["Item"] == expected_item @mock_dynamodb @@ -283,7 +281,7 @@ def test_update_item_set(): ) returned_item = table.get_item(Key=key_map)["Item"] - dict(returned_item).should.equal({"username": "steve", "foo": "bar", "blah": "baz"}) + assert returned_item == {"username": "steve", "foo": "bar", "blah": "baz"} @mock_dynamodb @@ -296,7 +294,7 @@ def test_create_table__using_resource(): AttributeDefinitions=[{"AttributeName": "username", "AttributeType": "S"}], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) - table.name.should.equal("users") + assert table.name == "users" def _create_user_table(): @@ -319,9 +317,8 @@ def test_conditions(): table.put_item(Item={"username": "janedoe"}) response = table.query(KeyConditionExpression=Key("username").eq("johndoe")) - response["Count"].should.equal(1) - response["Items"].should.have.length_of(1) - response["Items"][0].should.equal({"username": "johndoe"}) + assert response["Count"] == 1 + assert response["Items"] == [{"username": "johndoe"}] @mock_dynamodb @@ -333,7 +330,7 @@ def test_put_item_conditions_pass(): Expected={"foo": {"ComparisonOperator": "EQ", "AttributeValueList": ["bar"]}}, ) final_item = table.get_item(Key={"username": "johndoe"}) - assert dict(final_item)["Item"]["foo"].should.equal("baz") + assert final_item["Item"]["foo"] == "baz" @mock_dynamodb @@ -345,7 +342,7 @@ def test_put_item_conditions_pass_because_expect_not_exists_by_compare_to_null() Expected={"whatever": {"ComparisonOperator": "NULL"}}, ) final_item = table.get_item(Key={"username": "johndoe"}) - assert dict(final_item)["Item"]["foo"].should.equal("baz") + assert final_item["Item"]["foo"] == "baz" @mock_dynamodb @@ -357,53 +354,67 @@ def test_put_item_conditions_pass_because_expect_exists_by_compare_to_not_null() Expected={"foo": {"ComparisonOperator": "NOT_NULL"}}, ) final_item = table.get_item(Key={"username": "johndoe"}) - assert dict(final_item)["Item"]["foo"].should.equal("baz") + assert final_item["Item"]["foo"] == "baz" @mock_dynamodb def test_put_item_conditions_fail(): table = _create_user_table() table.put_item(Item={"username": "johndoe", "foo": "bar"}) - table.put_item.when.called_with( - Item={"username": "johndoe", "foo": "baz"}, - Expected={"foo": {"ComparisonOperator": "NE", "AttributeValueList": ["bar"]}}, - ).should.throw(botocore.client.ClientError) + with pytest.raises(ClientError) as exc: + table.put_item( + Item={"username": "johndoe", "foo": "baz"}, + Expected={ + "foo": {"ComparisonOperator": "NE", "AttributeValueList": ["bar"]} + }, + ) + err = exc.value.response["Error"] + assert err["Code"] == "ConditionalCheckFailedException" @mock_dynamodb def test_update_item_conditions_fail(): table = _create_user_table() table.put_item(Item={"username": "johndoe", "foo": "baz"}) - table.update_item.when.called_with( - Key={"username": "johndoe"}, - UpdateExpression="SET foo=:bar", - Expected={"foo": {"Value": "bar"}}, - ExpressionAttributeValues={":bar": "bar"}, - ).should.throw(botocore.client.ClientError) + with pytest.raises(ClientError) as exc: + table.update_item( + Key={"username": "johndoe"}, + UpdateExpression="SET foo=:bar", + Expected={"foo": {"Value": "bar"}}, + ExpressionAttributeValues={":bar": "bar"}, + ) + err = exc.value.response["Error"] + assert err["Code"] == "ConditionalCheckFailedException" @mock_dynamodb def test_update_item_conditions_fail_because_expect_not_exists(): table = _create_user_table() table.put_item(Item={"username": "johndoe", "foo": "baz"}) - table.update_item.when.called_with( - Key={"username": "johndoe"}, - UpdateExpression="SET foo=:bar", - Expected={"foo": {"Exists": False}}, - ExpressionAttributeValues={":bar": "bar"}, - ).should.throw(botocore.client.ClientError) + with pytest.raises(ClientError) as exc: + table.update_item( + Key={"username": "johndoe"}, + UpdateExpression="SET foo=:bar", + Expected={"foo": {"Exists": False}}, + ExpressionAttributeValues={":bar": "bar"}, + ) + err = exc.value.response["Error"] + assert err["Code"] == "ConditionalCheckFailedException" @mock_dynamodb def test_update_item_conditions_fail_because_expect_not_exists_by_compare_to_null(): table = _create_user_table() table.put_item(Item={"username": "johndoe", "foo": "baz"}) - table.update_item.when.called_with( - Key={"username": "johndoe"}, - UpdateExpression="SET foo=:bar", - Expected={"foo": {"ComparisonOperator": "NULL"}}, - ExpressionAttributeValues={":bar": "bar"}, - ).should.throw(botocore.client.ClientError) + with pytest.raises(ClientError) as exc: + table.update_item( + Key={"username": "johndoe"}, + UpdateExpression="SET foo=:bar", + Expected={"foo": {"ComparisonOperator": "NULL"}}, + ExpressionAttributeValues={":bar": "bar"}, + ) + err = exc.value.response["Error"] + assert err["Code"] == "ConditionalCheckFailedException" @mock_dynamodb @@ -417,7 +428,7 @@ def test_update_item_conditions_pass(): ExpressionAttributeValues={":baz": "baz"}, ) returned_item = table.get_item(Key={"username": "johndoe"}) - assert dict(returned_item)["Item"]["foo"].should.equal("baz") + assert returned_item["Item"]["foo"] == "baz" @mock_dynamodb @@ -431,7 +442,7 @@ def test_update_item_conditions_pass_because_expect_not_exists(): ExpressionAttributeValues={":baz": "baz"}, ) returned_item = table.get_item(Key={"username": "johndoe"}) - assert dict(returned_item)["Item"]["foo"].should.equal("baz") + assert returned_item["Item"]["foo"] == "baz" @mock_dynamodb @@ -445,7 +456,7 @@ def test_update_item_conditions_pass_because_expect_not_exists_by_compare_to_nul ExpressionAttributeValues={":baz": "baz"}, ) returned_item = table.get_item(Key={"username": "johndoe"}) - assert dict(returned_item)["Item"]["foo"].should.equal("baz") + assert returned_item["Item"]["foo"] == "baz" @mock_dynamodb @@ -459,7 +470,7 @@ def test_update_item_conditions_pass_because_expect_exists_by_compare_to_not_nul ExpressionAttributeValues={":baz": "baz"}, ) returned_item = table.get_item(Key={"username": "johndoe"}) - assert dict(returned_item)["Item"]["foo"].should.equal("baz") + assert returned_item["Item"]["foo"] == "baz" @mock_dynamodb @@ -496,7 +507,7 @@ def test_update_settype_item_with_conditions(): }, ) returned_item = table.get_item(Key={"username": "johndoe"}) - assert dict(returned_item)["Item"]["foo"].should.equal(set(["baz"])) + assert returned_item["Item"]["foo"] == set(["baz"]) @mock_dynamodb @@ -508,18 +519,17 @@ def test_scan_pagination(): table.put_item(Item={"username": u}) page1 = table.scan(Limit=6) - page1["Count"].should.equal(6) - page1["Items"].should.have.length_of(6) - page1.should.have.key("LastEvaluatedKey") + assert page1["Count"] == 6 + assert len(page1["Items"]) == 6 page2 = table.scan(Limit=6, ExclusiveStartKey=page1["LastEvaluatedKey"]) - page2["Count"].should.equal(4) - page2["Items"].should.have.length_of(4) - page2.should_not.have.key("LastEvaluatedKey") + assert page2["Count"] == 4 + assert len(page2["Items"]) == 4 + assert "LastEvaluatedKey" not in page2 results = page1["Items"] + page2["Items"] usernames = set([r["username"] for r in results]) - usernames.should.equal(set(expected_usernames)) + assert usernames == set(expected_usernames) @mock_dynamodb diff --git a/tests/test_dynamodb/test_dynamodb_update_expressions.py b/tests/test_dynamodb/test_dynamodb_update_expressions.py index 82cd0c42d..74ce504bc 100644 --- a/tests/test_dynamodb/test_dynamodb_update_expressions.py +++ b/tests/test_dynamodb/test_dynamodb_update_expressions.py @@ -1,5 +1,4 @@ import boto3 -import sure # noqa # pylint: disable=unused-import from moto import mock_dynamodb @@ -27,6 +26,7 @@ def test_update_different_map_elements_in_single_request(): ExpressionAttributeValues={":h": "H", ":w": "W"}, ReturnValues="ALL_NEW", ) - updated["Attributes"].should.equal( - {"id": "example_id", "d": {"hello": "H", "world": "W"}} - ) + assert updated["Attributes"] == { + "id": "example_id", + "d": {"hello": "H", "world": "W"}, + } diff --git a/tests/test_dynamodb/test_dynamodb_update_table.py b/tests/test_dynamodb/test_dynamodb_update_table.py index 52af798d9..509bb0f5a 100644 --- a/tests/test_dynamodb/test_dynamodb_update_table.py +++ b/tests/test_dynamodb/test_dynamodb_update_table.py @@ -1,5 +1,4 @@ import boto3 -import sure # noqa # pylint: disable=unused-import from moto import mock_dynamodb @@ -27,10 +26,11 @@ def test_update_table__billing_mode(): ) actual = client.describe_table(TableName="test")["Table"] - actual.should.have.key("BillingModeSummary").equals({"BillingMode": "PROVISIONED"}) - actual.should.have.key("ProvisionedThroughput").equals( - {"ReadCapacityUnits": 1, "WriteCapacityUnits": 1} - ) + assert actual["BillingModeSummary"] == {"BillingMode": "PROVISIONED"} + assert actual["ProvisionedThroughput"] == { + "ReadCapacityUnits": 1, + "WriteCapacityUnits": 1, + } @mock_dynamodb @@ -42,15 +42,15 @@ def test_update_table_throughput(): AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) - table.provisioned_throughput["ReadCapacityUnits"].should.equal(5) - table.provisioned_throughput["WriteCapacityUnits"].should.equal(5) + assert table.provisioned_throughput["ReadCapacityUnits"] == 5 + assert table.provisioned_throughput["WriteCapacityUnits"] == 5 table.update( ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 6} ) - table.provisioned_throughput["ReadCapacityUnits"].should.equal(5) - table.provisioned_throughput["WriteCapacityUnits"].should.equal(6) + assert table.provisioned_throughput["ReadCapacityUnits"] == 5 + assert table.provisioned_throughput["WriteCapacityUnits"] == 6 @mock_dynamodb diff --git a/tests/test_dynamodb/test_server.py b/tests/test_dynamodb/test_server.py index aa50c6606..ef0a30c35 100644 --- a/tests/test_dynamodb/test_server.py +++ b/tests/test_dynamodb/test_server.py @@ -1,5 +1,4 @@ import json -import sure # noqa # pylint: disable=unused-import from moto import mock_dynamodb import moto.server as server @@ -13,22 +12,20 @@ def test_table_list(): backend = server.create_backend_app("dynamodb") test_client = backend.test_client() res = test_client.get("/") - res.status_code.should.equal(404) + assert res.status_code == 404 headers = {"X-Amz-Target": "TestTable.ListTables"} res = test_client.get("/", headers=headers) - res.data.should.contain(b"TableNames") - res.headers.should.have.key("X-Amz-Crc32") + assert b"TableNames" in res.data + assert "X-Amz-Crc32" in res.headers headers = {"X-Amz-Target": "DynamoDB_20120810.DescribeTable"} res = test_client.post( "/", headers=headers, data=json.dumps({"TableName": "test-table2"}) ) - res.headers.should.have.key("X-Amzn-ErrorType").equals("ResourceNotFoundException") + assert res.headers["X-Amzn-ErrorType"] == "ResourceNotFoundException" body = json.loads(res.data.decode("utf-8")) - body.should.equal( - { - "__type": "com.amazonaws.dynamodb.v20120810#ResourceNotFoundException", - "message": "Requested resource not found: Table: test-table2 not found", - } - ) + assert body == { + "__type": "com.amazonaws.dynamodb.v20120810#ResourceNotFoundException", + "message": "Requested resource not found: Table: test-table2 not found", + }