Skip to content

Commit f72e6f1

Browse files
chrisguidryclaude
andauthored
Fix event filter empty label value arrays to return no results (#18810)
Co-authored-by: Claude <[email protected]>
1 parent 2874f03 commit f72e6f1

File tree

4 files changed

+85
-13
lines changed

4 files changed

+85
-13
lines changed

AGENTS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,6 @@ prefect config view # Inspect configuration
6868

6969
- GitHub issues are used for tracking issues (use the `gh` cli)
7070
- Pre-commit hooks required (never use `--no-verify`)
71+
- There are some slower pre-push hooks that may modify files on `git push`; when that happens, run `git commit --amend` to bring those into the prior commit (never use `--amend` in any other situation unless asked)
7172
- Dependencies: updates to client-side deps in `@pyproject.toml` require parallel changes ing `@client/pyproject.toml`
72-
- AGENTS.md always symlinked to CLAUDE.md
73+
- AGENTS.md always symlinked to CLAUDE.md

docs/v3/api-ref/python/prefect-server-events-filters.mdx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,11 @@ includes(self, event: Event) -> bool
257257
Does the given event match the criteria of this filter?
258258

259259

260-
### `EventRelatedFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L387" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
260+
### `EventRelatedFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L392" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
261261

262262
**Methods:**
263263

264-
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L405" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
264+
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L410" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
265265

266266
```python
267267
build_where_clauses(self, db: PrefectDBInterface) -> Sequence['ColumnExpressionArgument[bool]']
@@ -291,11 +291,11 @@ includes(self, event: Event) -> bool
291291
Does the given event match the criteria of this filter?
292292

293293

294-
### `EventAnyResourceFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L486" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
294+
### `EventAnyResourceFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L496" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
295295

296296
**Methods:**
297297

298-
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L523" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
298+
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L533" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
299299

300300
```python
301301
build_where_clauses(self, db: PrefectDBInterface) -> Sequence['ColumnExpressionArgument[bool]']
@@ -316,7 +316,7 @@ Would the given filter exclude this event?
316316
get_filters(self) -> list['EventDataFilter']
317317
```
318318

319-
#### `includes` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L501" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
319+
#### `includes` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L511" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
320320

321321
```python
322322
includes(self, event: Event) -> bool
@@ -331,11 +331,11 @@ includes(self, event: Event) -> bool
331331
Does the given event match the criteria of this filter?
332332

333333

334-
### `EventIDFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L591" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
334+
### `EventIDFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L606" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
335335

336336
**Methods:**
337337

338-
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L604" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
338+
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L619" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
339339

340340
```python
341341
build_where_clauses(self, db: PrefectDBInterface) -> Sequence['ColumnExpressionArgument[bool]']
@@ -356,7 +356,7 @@ Would the given filter exclude this event?
356356
get_filters(self) -> list['EventDataFilter']
357357
```
358358

359-
#### `includes` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L596" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
359+
#### `includes` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L611" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
360360

361361
```python
362362
includes(self, event: Event) -> bool
@@ -371,7 +371,7 @@ includes(self, event: Event) -> bool
371371
Does the given event match the criteria of this filter?
372372

373373

374-
### `EventOrder` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L615" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
374+
### `EventOrder` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L630" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
375375

376376
**Methods:**
377377

@@ -384,11 +384,11 @@ auto() -> str
384384
Exposes `enum.auto()` to avoid requiring a second import to use `AutoEnum`
385385

386386

387-
### `EventFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L620" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
387+
### `EventFilter` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L635" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
388388

389389
**Methods:**
390390

391-
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L653" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
391+
#### `build_where_clauses` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L668" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
392392

393393
```python
394394
build_where_clauses(self, db: PrefectDBInterface) -> Sequence['ColumnExpressionArgument[bool]']
@@ -418,7 +418,7 @@ includes(self, event: Event) -> bool
418418
Does the given event match the criteria of this filter?
419419

420420

421-
#### `logical_limit` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L670" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
421+
#### `logical_limit` <sup><a href="https://github.com/PrefectHQ/prefect/blob/main/src/prefect/server/events/filters.py#L685" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
422422

423423
```python
424424
logical_limit(self) -> int

src/prefect/server/events/filters.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,11 @@ def build_where_clauses(
359359

360360
if labels:
361361
for _, (label, values) in enumerate(labels.items()):
362+
# Empty label value arrays should match nothing
363+
if not values:
364+
label_filters.append(sa.false())
365+
continue
366+
362367
label_ops = LabelOperations(values)
363368

364369
label_column = db.EventResource.resource[label].astext
@@ -451,6 +456,11 @@ def build_where_clauses(
451456

452457
if labels:
453458
for _, (label, values) in enumerate(labels.items()):
459+
# Empty label value arrays should match nothing
460+
if not values:
461+
label_filters.append(sa.false())
462+
continue
463+
454464
label_ops = LabelOperations(values)
455465

456466
label_column = db.EventResource.resource[label].astext
@@ -563,6 +573,11 @@ def build_where_clauses(
563573

564574
if labels:
565575
for _, (label, values) in enumerate(labels.items()):
576+
# Empty label value arrays should match nothing
577+
if not values:
578+
label_filters.append(sa.false())
579+
continue
580+
566581
label_ops = LabelOperations(values)
567582

568583
label_column = db.EventResource.resource[label].astext

tests/events/server/test_events_queries.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,3 +1502,59 @@ async def test_event_dates_always_have_timezones(
15021502
async def test_corrupted_page_tokens_are_treated_as_noops(busted_token: str):
15031503
with pytest.raises(ValueError):
15041504
from_page_token(busted_token)
1505+
1506+
1507+
async def test_resource_filter_empty_label_values(
1508+
events_query_session: AsyncSession,
1509+
full_occurred_range: EventOccurredFilter,
1510+
) -> None:
1511+
"""Test that resource labels with empty values array return no results."""
1512+
1513+
filter = EventFilter(
1514+
occurred=full_occurred_range,
1515+
resource=EventResourceFilter(labels={"hello": []}), # Empty values = no matches
1516+
)
1517+
1518+
events, count, _ = await query_events(session=events_query_session, filter=filter)
1519+
1520+
# Empty label values should match nothing
1521+
assert count == 0
1522+
assert events == []
1523+
1524+
1525+
async def test_related_filter_empty_label_values(
1526+
events_query_session: AsyncSession,
1527+
full_occurred_range: EventOccurredFilter,
1528+
) -> None:
1529+
"""Test that related resource labels with empty values array return no results."""
1530+
1531+
filter = EventFilter(
1532+
occurred=full_occurred_range,
1533+
related=EventRelatedFilter(labels={"hello": []}), # Empty values = no matches
1534+
)
1535+
1536+
events, count, _ = await query_events(session=events_query_session, filter=filter)
1537+
1538+
# Empty label values should match nothing
1539+
assert count == 0
1540+
assert events == []
1541+
1542+
1543+
async def test_any_resource_filter_empty_label_values(
1544+
events_query_session: AsyncSession,
1545+
full_occurred_range: EventOccurredFilter,
1546+
) -> None:
1547+
"""Test that any resource labels with empty values array return no results."""
1548+
1549+
filter = EventFilter(
1550+
occurred=full_occurred_range,
1551+
any_resource=EventAnyResourceFilter(
1552+
labels={"hello": []}
1553+
), # Empty values = no matches
1554+
)
1555+
1556+
events, count, _ = await query_events(session=events_query_session, filter=filter)
1557+
1558+
# Empty label values should match nothing
1559+
assert count == 0
1560+
assert events == []

0 commit comments

Comments
 (0)