Skip to content

fix: honor boolean operators in -k snapshot selection - #1127

Merged
noahnu merged 1 commit into
syrupy-project:mainfrom
frenck:frenck/fix-770-keyword-expression
Jun 26, 2026
Merged

fix: honor boolean operators in -k snapshot selection#1127
noahnu merged 1 commit into
syrupy-project:mainfrom
frenck:frenck/fix-770-keyword-expression

Conversation

@frenck

@frenck frenck commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

syrupy reimplemented the pytest -k keyword expression with a hand rolled matcher (report.Expression) that flattened the expression into a set of tokens and returned true if any token was a substring of the snapshot name. This ignored the and/or/not and parenthesis operators entirely.

As a result, a negated expression like -k 'not one' treated one as a positive match, so the deselected test_parametrized[one] snapshot was considered unused. On a normal run that reports a spurious unused snapshot (and fails the suite), and with --snapshot-update the snapshot is then deleted, which is data loss.

Minimal reproduction (from #770), no pytest-bdd required:

import pytest

@pytest.mark.parametrize("param", ["one", "two", "three"])
def test_parametrized(param, snapshot):
    assert param == snapshot
pytest --snapshot-update          # writes 3 snapshots
pytest -k 'not one'               # before: "1 snapshot unused"; after: clean
pytest --snapshot-update -k 'not one'   # before: deletes test_parametrized[one]

This delegates parsing and evaluation to pytest's own _pytest.mark.expression.Expression, so selection matches -k exactly, including boolean operators and parentheses. syrupy already requires pytest >= 8, and report.py already imports from _pytest (_pytest.skipping), so this does not introduce a new kind of dependency. Compiled expressions are cached.

Related Issues

Checklist

  • This PR has sufficient documentation.
  • This PR has sufficient test coverage.
  • This PR title satisfies semantic convention.

Additional Comments

Added regression tests in tests/integration/test_snapshot_option_filter_keyword.py covering a positive filter, a negated filter, and a negated filter under --snapshot-update (asserting the deselected snapshot is kept). The two negated cases fail on main and pass with this change. Bracket and dash keyword forms that the existing tests rely on (for example -k 'test_used[') keep working, since pytest's parser accepts them as substring matchers. One # type: ignore[arg-type] is needed where syrupy's Callable[[str], bool] matcher meets pytest's keyword-argument-tolerant matcher protocol; keyword matching only ever passes the positional name.

@frenck
frenck marked this pull request as draft June 26, 2026 11:46
@frenck

frenck commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Aah messed up my branches. Sorry, let me quickly fix that.

../Frenck

                       

Blogging my personal ramblings at frenck.dev

@frenck
frenck force-pushed the frenck/fix-770-keyword-expression branch from 32ff7b3 to 1c8e65e Compare June 26, 2026 11:47
@frenck
frenck marked this pull request as ready for review June 26, 2026 11:48
@frenck

frenck commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Done.

../Frenck

                       

Blogging my personal ramblings at frenck.dev

syrupy reimplemented the pytest -k keyword expression with a hand rolled
matcher that flattened the expression into tokens and returned true if any
token was a substring of the snapshot name. This ignored the and/or/not and
parenthesis operators, so a negated expression like -k 'not one' treated
'one' as a positive match and considered the deselected test_parametrized[one]
snapshot unused. With --snapshot-update that unused snapshot was then deleted.

Delegate parsing and evaluation to pytest's own _pytest.mark.expression so
selection matches -k exactly. syrupy already requires pytest >= 8 and
report.py already imports from _pytest, and compiled expressions are cached.

Closes syrupy-project#770
@frenck
frenck force-pushed the frenck/fix-770-keyword-expression branch from 8d0387c to cc3b7c7 Compare June 26, 2026 11:49
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1127   +/-   ##
=======================================
  Coverage   97.44%   97.44%           
=======================================
  Files          24       24           
  Lines        1758     1758           
=======================================
  Hits         1713     1713           
  Misses         45       45           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@noahnu
noahnu merged commit cd3c81a into syrupy-project:main Jun 26, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrectly delete unused snapshot in pytest bdd when target run using -k filter

2 participants