Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions awswrangler/dynamodb/_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,18 @@ def _read_items(
items = _read_batch_items(table_name, dynamodb_client, chunked, **kwargs)

else:
if limit:
if limit is not None:
if limit < 0:
raise exceptions.InvalidArgumentValue("`max_items_evaluated` must be greater than or equal to 0.")
if limit == 0:
empty_items: _ItemsListType = []
if chunked:
return _convert_items_chunked(
items_iterator=iter([empty_items]),
as_dataframe=as_dataframe,
arrow_kwargs=arrow_kwargs,
)
return _convert_items(items=empty_items, as_dataframe=as_dataframe, arrow_kwargs=arrow_kwargs)
kwargs["Limit"] = limit
_logger.debug("`max_items_evaluated` argument detected, setting use_threads to False")
use_threads = False
Expand Down Expand Up @@ -744,12 +755,20 @@ def read_items( # noqa: PLR0912, PLR0915
**kwargs.get("ExpressionAttributeValues", {}),
**_serialize_item(expression_attribute_values, serializer),
}
if max_items_evaluated:
if max_items_evaluated is not None:
kwargs["Limit"] = max_items_evaluated

_logger.debug("DynamoDB scan/query kwargs: %s", kwargs)
# If kwargs are sufficiently informative, proceed with actual read op
if any((partition_values, key_condition_expression, filter_expression, allow_full_scan, max_items_evaluated)):
if any(
(
partition_values,
key_condition_expression,
filter_expression,
allow_full_scan,
max_items_evaluated is not None,
)
):
return _read_items(
table_name=table_name,
as_dataframe=as_dataframe,
Expand Down
28 changes: 28 additions & 0 deletions tests/unit/test_moto.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,3 +844,31 @@ def fake_start(*, sql: str, **_) -> str:
# The intended LOCATION (un-doubled quotes) is the only top-level clause.
assert "LOCATION 's3://intended/output/'" in sql
assert "LOCATION 's3://other/'" not in sql


def test_dynamodb_read_items_max_items_evaluated_zero(moto_dynamodb_client, moto_dynamodb_table) -> None:
items = [{"key": 1, "value": "A"}, {"key": 2, "value": "B"}]
wr.dynamodb.put_items(items=items, table_name=moto_dynamodb_table)

# 1. max_items_evaluated=0 without allow_full_scan
df0 = wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0)
assert isinstance(df0, pd.DataFrame)
assert len(df0) == 0

# 2. max_items_evaluated=0 with allow_full_scan=True
df0_scan = wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0, allow_full_scan=True)
assert isinstance(df0_scan, pd.DataFrame)
assert len(df0_scan) == 0

# 3. max_items_evaluated=0 as_dataframe=False
items0 = wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0, as_dataframe=False)
assert items0 == []

# 4. max_items_evaluated=0 chunked=True
chunks = list(wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=0, chunked=True))
assert len(chunks) == 1
assert len(chunks[0]) == 0

# 5. max_items_evaluated=-1 raises InvalidArgumentValue
with pytest.raises(wr.exceptions.InvalidArgumentValue):
wr.dynamodb.read_items(table_name=moto_dynamodb_table, max_items_evaluated=-1)