Skip to content

Preserve strict comparison and stable source order in descending merge - #230

Open
Apeksha9389 wants to merge 2 commits into
maxfischer2781:masterfrom
Apeksha9389:fix/descending-merge-stability
Open

Apeksha9389 wants to merge 2 commits into
maxfischer2781:masterfrom
Apeksha9389:fix/descending-merge-stability

Conversation

@Apeksha9389

@Apeksha9389 Apeksha9389 commented Oct 18, 2026 •

Copy link
Copy Markdown

Descending merge() reverses equal-key source order and its XOR-based comparison treats equal or unordered keys as less than one another. Reverse the comparison operands instead of negating its result, and keep the source-order index ascending because the key iterator already accounts for descending order.

Regression coverage compares equal-key source order with heapq.merge using synchronous and asynchronous keys, and directly checks that equal and unordered keys are not strictly ordered in either direction.

Closes #234.

Validation on Python 3.12: all 412 tests pass, along with Black, Flake8, MyPy and PyRight. Other Python versions were not run locally. Prepared with OpenAI Codex assistance; all reported local checks were executed.

@Apeksha9389

Copy link
Copy Markdown
Author

Could a maintainer approve the pending CI runs and review this PR for merging? Local tests, Flake8, Black, MyPy, and PyRight all pass. Thank you.

@maxfischer2781

Copy link
Copy Markdown
Owner

I am somewhat surprised by the approach here. This looks like the same bug as in #231/#235, which implies it has the same failure modes (namely also the issue of unsorted items). Why take a different approach here?

@Apeksha9389

Copy link
Copy Markdown
Author

You're right: the XOR comparator has the same problem as #231. Updated in 0882b33 to reverse the comparison operands instead, with six regression cases covering equal and unordered keys in both directions. The input-order index fix is retained because the key iterator already accounts for descending order, so reversing the tie index reverses equal-key sources a second time. All 412 tests, Flake8, Black, MyPy and PyRight pass locally.

@Apeksha9389 Apeksha9389 changed the title Preserve equal-key source order in descending merge Preserve strict comparison and stable source order in descending merge Oct 19, 2026
Comment thread unittests/test_heapq.py
Comment on lines +24 to +30
@pytest.mark.parametrize("reverse", [False, True])
@pytest.mark.parametrize("keys", [(1, 1), (float("nan"), 1), (1, float("nan"))])
def test_merge_key_iter_does_not_order_equal_or_unordered_keys(reverse, keys):
first = _KeyIter(keys[0], asyncify(()), reverse, keys[0], None)
second = _KeyIter(keys[1], asyncify(()), reverse, keys[1], None)
assert not first < second
assert not second < first

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the point of this test. This just seems to target a private implementation detail by filling it with doctored data to verify something that is only meaningful as an implementation detail of another algorithm. What is the goal here? Did I miss something?

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.

[Bug]: Descending merge reverses equal-key source order

2 participants