Skip to content

chore: iterate dict directly instead of via .keys() (ruff SIM118)#155

Open
alexzhu0 wants to merge 1 commit intoFlowElement-ai:mainfrom
alexzhu0:chore/ruff-sim118-drop-dict-keys
Open

chore: iterate dict directly instead of via .keys() (ruff SIM118)#155
alexzhu0 wants to merge 1 commit intoFlowElement-ai:mainfrom
alexzhu0:chore/ruff-sim118-drop-dict-keys

Conversation

@alexzhu0
Copy link
Copy Markdown
Contributor

@alexzhu0 alexzhu0 commented May 2, 2026

Summary

Ruff rule SIM118 flags x in dict.keys() / for x in dict.keys(). Iterating a dict directly is the idiomatic form and is measurably faster:

  • .keys() constructs a fresh dict_keys view object on every call
  • for x in d / x in d skips the view and goes straight to the dict's internal __iter__ / __contains__

5 sites, 4 files.

 # Step 2: Expand neighbors
 ids_1_set = set(relevant_ids)
-neighbor_ids = [nid for nid in fragment_1.nodes.keys() if nid not in ids_1_set]
+neighbor_ids = [nid for nid in fragment_1.nodes if nid not in ids_1_set]

Semantic equivalence

Every site either iterates the dict or checks membership — none captures, returns, or type-annotates the .keys() view. 4 of the 5 fixes were gated as "hidden" by ruff's conservative default because .keys() returns a distinct view type; I inspected each site manually and applied them via --unsafe-fixes after confirming no view is ever retained.

Files

File Context
m_flow/retrieval/episodic/bundle_search.py 2 sites in _two_phase_projection / _two_phase_projection_with_stats — hot path for neighbor expansion
m_flow/retrieval/utils/procedural_bundle_search.py same neighbor-expansion pattern in the procedural search variant
m_flow/adapters/vector/chromadb/ChromaDBAdapter.py ChromaDB deserialization loop
m_flow/tests/test_multi_tenancy.py a tiny _get_first_dataset_id test helper

4 files, +5 / −5.

Verification

$ ruff check . --exclude 'm_flow/baml_client' --exclude 'm_flow-frontend' --select SIM118
All checks passed!

$ for f in <each touched file>; do uv run python -c "import ast; ast.parse(open('$f').read())"; done
# clean across all 4 files

No behavior change. Generated code under m_flow/baml_client/ is untouched.

I affirm that all code in every commit of this pull request conforms to the terms of the M-flow Developer Certificate of Origin

Ruff rule SIM118 flags `x in dict.keys()` / `for x in dict.keys()`.
Iterating a dict directly is the idiomatic form and is measurably faster:
`.keys()` constructs a view object on every call; `for x in d` or
`x in d` skips the view and goes straight to the dict's internal
`__contains__` / `__iter__`.

Scope: 5 sites across 4 files — 2 in bundle_search neighbor expansion
(hot path inside `_two_phase_projection`), 1 in procedural_bundle_search
(same pattern), 1 in a ChromaDB deserialization loop, 1 in a test helper.

Semantic equivalence: every site iterates the dict / checks membership;
none captures or returns the `.keys()` view. 4 fixes were gated as
"hidden" by ruff's conservative default because `.keys()` returns a
distinct view type — inspected each site manually and applied the
`--unsafe-fixes` class after confirming no view is ever retained.

Verification:
- `ruff check . --exclude 'm_flow/baml_client' --select SIM118` is now clean
- `ast.parse` on every touched file: clean

No behavior change.
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.

1 participant