From e424dee1c339cd1d6ad79810b01a061ce243dcf3 Mon Sep 17 00:00:00 2001 From: AntoineGautier Date: Mon, 7 Sep 2026 11:28:26 +0200 Subject: [PATCH 1/2] Fix common_member to handle one-shot iterables --- server/scripts/sequence-doc/src/utils.py | 5 ++ .../sequence-doc/tests/test_mogrifier.py | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 server/scripts/sequence-doc/tests/test_mogrifier.py diff --git a/server/scripts/sequence-doc/src/utils.py b/server/scripts/sequence-doc/src/utils.py index f70ba18c..179071b2 100644 --- a/server/scripts/sequence-doc/src/utils.py +++ b/server/scripts/sequence-doc/src/utils.py @@ -5,7 +5,12 @@ def reduce_to_boolean(boolList: list[bool]) -> bool: def common_member(l1, l2) -> bool: '''Is any member of l1 in l2 + + `l2` is materialized first so that one-shot iterables (e.g. `map`, + generators) can be passed safely: membership is tested once per element + of `l1`, which would otherwise exhaust the iterator after the first check. ''' + l2 = list(l2) return [i for i in l1 if i in l2] def remove_empty_strings(string_list: list[str]) -> list[str]: diff --git a/server/scripts/sequence-doc/tests/test_mogrifier.py b/server/scripts/sequence-doc/tests/test_mogrifier.py new file mode 100644 index 00000000..697e3f86 --- /dev/null +++ b/server/scripts/sequence-doc/tests/test_mogrifier.py @@ -0,0 +1,53 @@ +''' +Regression tests for issue #619: +`[ANY ...]` toggle dropped its section when the resolved selection list had +more than one entry and a non-matching entry was iterated before a matching one, +because `common_member` was handed a one-shot `map` iterator. +''' +import utils +from mogrifier import evaluate_annotation + + +def test_common_member_accepts_one_shot_iterable(): + ''' A `map`/generator must be usable even when the first few probes miss. + ''' + haystack = map(str.upper, ['other', 'match']) + assert utils.common_member(['NOPE', 'MATCH'], haystack) == ['MATCH'] + + +def test_any_toggle_kept_when_match_is_not_first_selection(): + ''' [ANY ...] keeps the section (returns False) when any compare value is + selected, regardless of ordering / list length. + ''' + name_map = { + 'buiPreCon': 'path.buiPreCon', + 'ReturnFanMeasuredAir': 'ReturnFanMeasuredAir', + 'ReturnFanCalculatedAir': 'ReturnFanCalculatedAir', + } + selections = { + # non-matching entry first, matching entry second + 'path.buiPreCon': ['ReliefFan', 'ReturnFanCalculatedAir'], + } + op = { + 'op': 'ANY', + 'text': '[ANY buiPreCon ReturnFanMeasuredAir ReturnFanCalculatedAir]', + } + + assert evaluate_annotation(op, name_map, selections) is False + + +def test_any_toggle_deleted_when_no_compare_value_selected(): + ''' [ANY ...] still deletes (returns True) when nothing matches. + ''' + name_map = { + 'buiPreCon': 'path.buiPreCon', + 'ReturnFanMeasuredAir': 'ReturnFanMeasuredAir', + 'ReturnFanCalculatedAir': 'ReturnFanCalculatedAir', + } + selections = {'path.buiPreCon': ['ReliefFan', 'ReliefDamper']} + op = { + 'op': 'ANY', + 'text': '[ANY buiPreCon ReturnFanMeasuredAir ReturnFanCalculatedAir]', + } + + assert evaluate_annotation(op, name_map, selections) is True From fca7286fbec3fadd957d68f09de32b7b7f4e33da Mon Sep 17 00:00:00 2001 From: AntoineGautier Date: Mon, 7 Sep 2026 11:30:50 +0200 Subject: [PATCH 2/2] Add sequence-doc Python tests to CI workflow --- .github/workflows/server-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 4586d594..3fd14836 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -40,6 +40,9 @@ jobs: run: npm run install-python-deps - name: Install NPM packages run: npm ci + - name: Run sequence-doc Python tests + working-directory: server/scripts/sequence-doc + run: python3 -m pytest -c pytest.toml - name: Run tests run: | npm run start &