Skip to content

Commit 897e6eb

Browse files
authored
fix: handle zero max_items_evaluated in DynamoDB read_items (#3417)
1 parent 4f7daf7 commit 897e6eb

2 files changed

Lines changed: 50 additions & 3 deletions

File tree

awswrangler/dynamodb/_read.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,18 @@ def _read_items(
392392
items = _read_batch_items(table_name, dynamodb_client, chunked, **kwargs)
393393

394394
else:
395-
if limit:
395+
if limit is not None:
396+
if limit < 0:
397+
raise exceptions.InvalidArgumentValue("`max_items_evaluated` must be greater than or equal to 0.")
398+
if limit == 0:
399+
empty_items: _ItemsListType = []
400+
if chunked:
401+
return _convert_items_chunked(
402+
items_iterator=iter([empty_items]),
403+
as_dataframe=as_dataframe,
404+
arrow_kwargs=arrow_kwargs,
405+
)
406+
return _convert_items(items=empty_items, as_dataframe=as_dataframe, arrow_kwargs=arrow_kwargs)
396407
kwargs["Limit"] = limit
397408
_logger.debug("`max_items_evaluated` argument detected, setting use_threads to False")
398409
use_threads = False
@@ -744,12 +755,20 @@ def read_items( # noqa: PLR0912, PLR0915
744755
**kwargs.get("ExpressionAttributeValues", {}),
745756
**_serialize_item(expression_attribute_values, serializer),
746757
}
747-
if max_items_evaluated:
758+
if max_items_evaluated is not None:
748759
kwargs["Limit"] = max_items_evaluated
749760

750761
_logger.debug("DynamoDB scan/query kwargs: %s", kwargs)
751762
# If kwargs are sufficiently informative, proceed with actual read op
752-
if any((partition_values, key_condition_expression, filter_expression, allow_full_scan, max_items_evaluated)):
763+
if any(
764+
(
765+
partition_values,
766+
key_condition_expression,
767+
filter_expression,
768+
allow_full_scan,
769+
max_items_evaluated is not None,
770+
)
771+
):
753772
return _read_items(
754773
table_name=table_name,
755774
as_dataframe=as_dataframe,

tests/unit/test_moto.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,3 +844,31 @@ def fake_start(*, sql: str, **_) -> str:
844844
# The intended LOCATION (un-doubled quotes) is the only top-level clause.
845845
assert "LOCATION 's3://intended/output/'" in sql
846846
assert "LOCATION 's3://other/'" not in sql
847+
848+
849+
def test_dynamodb_read_items_max_items_evaluated_zero(moto_dynamodb_client, moto_dynamodb_table) -> None:
850+
items = [{"key": 1, "value": "A"}, {"key": 2, "value": "B"}]
851+
wr.dynamodb.put_items(items=items, table_name=moto_dynamodb_table)
852+
853+
# 1. max_items_evaluated=0 without allow_full_scan
854+
df0 = wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0)
855+
assert isinstance(df0, pd.DataFrame)
856+
assert len(df0) == 0
857+
858+
# 2. max_items_evaluated=0 with allow_full_scan=True
859+
df0_scan = wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0, allow_full_scan=True)
860+
assert isinstance(df0_scan, pd.DataFrame)
861+
assert len(df0_scan) == 0
862+
863+
# 3. max_items_evaluated=0 as_dataframe=False
864+
items0 = wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0, as_dataframe=False)
865+
assert items0 == []
866+
867+
# 4. max_items_evaluated=0 chunked=True
868+
chunks = list(wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0, chunked=True))
869+
assert len(chunks) == 1
870+
assert len(chunks[0]) == 0
871+
872+
# 5. max_items_evaluated=-1 raises InvalidArgumentValue
873+
with pytest.raises(wr.exceptions.InvalidArgumentValue):
874+
wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=-1)

0 commit comments

Comments
 (0)