fix: replace list.remove() during iteration with comprehension filtering#443
fix: replace list.remove() during iteration with comprehension filtering#443lil-aditya wants to merge 1 commit intoEAPD-DRB:mainfrom
Conversation
Both deleteScenarioCaseRuns and deleteCaseRun used the anti-pattern of calling list.remove(item) inside a for-loop over the same list. When an element is removed, the iterator skips the next element because the internal index advances past the shifted items. Impact: - deleteScenarioCaseRuns: if a scenario ID appeared in consecutive positions within a case run's Scenarios list, the second occurrence was silently retained, leaving orphaned scenario data in resData.json that could not be deleted through the UI. - deleteCaseRun: same pattern, though less likely to trigger in practice since case names are typically unique. Fix: replace the mutation-during-iteration pattern with list-comprehension filtering, which builds a new list and is both safe and idiomatic Python. Includes 6 new unit tests covering: - Single scenario removal - Consecutive duplicate removal (the regression test) - Cross-case-run removal - No-match noop - resultsOnly flag behavior
There was a problem hiding this comment.
Pull request overview
Fixes a silent Python list-mutation bug in case/scenario deletion logic so that all matching entries are removed reliably (including consecutive duplicates), and adds regression/unit tests to prevent reintroduction.
Changes:
- Replace
list.remove()-during-iteration indeleteScenarioCaseRunswith comprehension-based filtering. - Replace
list.remove()-during-iteration indeleteCaseRunwith comprehension-based filtering. - Add unit tests covering single removal, consecutive-duplicate regression, cross-case-run removal, noop, and
resultsOnlybehavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| API/Classes/Case/DataFileClass.py | Replaces in-loop list mutation with safe list filtering in scenario and case-run deletion paths. |
| tests/test_list_mutation_fix.py | Adds targeted tests validating the deletion behavior and the regression scenario. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import sys | ||
| from pathlib import Path | ||
| from unittest.mock import patch, MagicMock | ||
|
|
||
| import pytest | ||
|
|
||
| # Ensure the API directory is on sys.path so we can import the classes | ||
| API_DIR = str(Path(__file__).resolve().parent.parent / "API") | ||
| if API_DIR not in sys.path: | ||
| sys.path.insert(0, API_DIR) | ||
|
|
||
|
|
There was a problem hiding this comment.
This test file manually inserts API/ into sys.path, but the repo already sets pythonpath = ["API"] in pyproject.toml and tests/conftest.py explicitly documents that imports should work without sys.path hacks. Keeping this can cause duplicate-import edge cases and makes the test suite less consistent; please remove the sys.path modification and rely on the configured pytest pythonpath instead.
| import sys | |
| from pathlib import Path | |
| from unittest.mock import patch, MagicMock | |
| import pytest | |
| # Ensure the API directory is on sys.path so we can import the classes | |
| API_DIR = str(Path(__file__).resolve().parent.parent / "API") | |
| if API_DIR not in sys.path: | |
| sys.path.insert(0, API_DIR) | |
| from pathlib import Path | |
| from unittest.mock import patch, MagicMock | |
| import pytest |
| import json | ||
| import sys | ||
| from pathlib import Path | ||
| from unittest.mock import patch, MagicMock |
There was a problem hiding this comment.
MagicMock is imported here but never used in this test module. Please drop the unused import to keep the test code minimal and avoid confusion about intended mocking.
| from unittest.mock import patch, MagicMock | |
| from unittest.mock import patch |
Both
deleteScenarioCaseRunsanddeleteCaseRunused the anti-pattern of callinglist.remove(item)inside a for-loop over the same list. When an element is removed, the iterator skips the next element because the internal index advances past the shifted items.Impact:
deleteScenarioCaseRuns: if a scenario ID appeared in consecutive positions within a case run's Scenarios list, the second occurrence was silently retained, leaving orphaned scenario data in resData.json that could not be deleted through the UI.deleteCaseRun: same pattern, though less likely to trigger in practice since case names are typically unique.Fix: replace the mutation-during-iteration pattern with list-comprehension filtering, which builds a new list and is both safe and idiomatic Python.
Includes 6 new unit tests covering:
Linked Issue
Existing related work reviewed
Overlap assessment
deleteScenarioCaseRunsordeleteCaseRunlogicWhy this PR should proceed
This is a silent data-corruption bug that leaves orphaned scenario entries in
resData.json, which users cannot remove through the UI.Summary
list.remove()insideforloops with list-comprehension filtering indeleteScenarioCaseRunsanddeleteCaseRunValidation
All 55 tests pass (6 new + 49 existing):
Scope check