Skip to content

Commit ed926f0

Browse files
authored
DynamoDB: update_item() now validates empty string sets (#8031)
1 parent 9d7a102 commit ed926f0

2 files changed

Lines changed: 32 additions & 27 deletions

File tree

moto/dynamodb/responses.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,23 +122,24 @@ def validate_put_has_empty_keys(
122122
raise MockValidationException(msg.format(empty_key))
123123

124124

125-
def put_has_empty_attrs(field_updates: Dict[str, Any], table: Table) -> bool:
125+
def validate_put_has_empty_attrs(field_updates: Dict[str, Any], table: Table) -> None:
126126
# Example invalid attribute: [{'M': {'SS': {'NS': []}}}]
127-
def _validate_attr(attr: Dict[str, Any]) -> bool:
128-
if "NS" in attr and attr["NS"] == []:
129-
return True
127+
def _validate_attr(attr: Dict[str, Any]) -> None:
128+
for set_type, error in [("NS", "number"), ("SS", "string")]:
129+
if set_type in attr and attr[set_type] == []:
130+
raise MockValidationException(
131+
f"One or more parameter values were invalid: An {error} set may not be empty"
132+
)
133+
130134
else:
131-
return any(
132-
[_validate_attr(val) for val in attr.values() if isinstance(val, dict)]
133-
)
135+
for val in attr.values():
136+
if isinstance(val, dict):
137+
_validate_attr(val)
134138

135139
if table:
136-
key_names = table.attribute_keys
137-
attrs_to_check = [
138-
val for attr, val in field_updates.items() if attr not in key_names
139-
]
140-
return any([_validate_attr(attr) for attr in attrs_to_check])
141-
return False
140+
for attr, val in field_updates.items():
141+
if attr not in table.attribute_keys:
142+
_validate_attr(val)
142143

143144

144145
def validate_put_has_gsi_keys_set_to_none(item: Dict[str, Any], table: Table) -> None:
@@ -475,10 +476,7 @@ def put_item(self) -> str:
475476

476477
table = self.dynamodb_backend.get_table(name)
477478
validate_put_has_empty_keys(item, table)
478-
if put_has_empty_attrs(item, table):
479-
raise MockValidationException(
480-
"One or more parameter values were invalid: An number set may not be empty"
481-
)
479+
validate_put_has_empty_attrs(item, table)
482480
validate_put_has_gsi_keys_set_to_none(item, table)
483481

484482
overwrite = "Expected" not in self.body

tests/test_dynamodb/exceptions/test_dynamodb_exceptions.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -694,26 +694,33 @@ def test_put_item_wrong_datatype():
694694
assert err["Message"] == "NUMBER_VALUE cannot be converted to String"
695695

696696

697-
@mock_aws
698-
def test_put_item_empty_set():
697+
@dynamodb_aws_verified()
698+
@pytest.mark.aws_verified
699+
def test_put_item_empty_set(table_name=None):
699700
client = boto3.client("dynamodb", region_name="us-east-1")
700701
dynamodb = boto3.resource("dynamodb", region_name="us-east-1")
701-
client.create_table(
702-
TableName="test-table",
703-
KeySchema=[{"AttributeName": "Key", "KeyType": "HASH"}],
704-
AttributeDefinitions=[{"AttributeName": "Key", "AttributeType": "S"}],
705-
BillingMode="PAY_PER_REQUEST",
706-
)
707-
table = dynamodb.Table("test-table")
702+
703+
table = dynamodb.Table(table_name)
708704
with pytest.raises(ClientError) as exc:
709-
table.put_item(Item={"Key": "some-irrelevant_key", "attr2": {"SS": set([])}})
705+
table.put_item(Item={"pk": "some-irrelevant_key", "attr2": {"SS": set([])}})
710706
err = exc.value.response["Error"]
711707
assert err["Code"] == "ValidationException"
712708
assert (
713709
err["Message"]
714710
== "One or more parameter values were invalid: An number set may not be empty"
715711
)
716712

713+
with pytest.raises(ClientError) as exc:
714+
client.put_item(
715+
TableName=table_name, Item={"pk": {"S": "foo"}, "stringSet": {"SS": []}}
716+
)
717+
err = exc.value.response["Error"]
718+
assert err["Code"] == "ValidationException"
719+
assert (
720+
err["Message"]
721+
== "One or more parameter values were invalid: An string set may not be empty"
722+
)
723+
717724

718725
@mock_aws
719726
def test_put_item_returns_old_item():

0 commit comments

Comments
 (0)