MutaFix run: more-itertools-010

ranker nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B · patcher nvidia/nemotron-3-super-120b-a12b · via Nebius Token Factory

fixedoutcome
50swall time
3model calls
$0.0031API cost
Benchmark ground truth (hidden from the agent)
more_itertools/recipes.py:520 · operator NEGCOND · function more_itertools/recipes.py::unique_justseen
- if not (key is None):   (injected bug)+ if key is None:   (original)
retriever rank 1 of 20 · ranker position 1 · patched the right function yes · exact restore no

Trace

reproduce
+11.61s
2 failing test(s) · 2 failed, 766 passed · 11.61s
failing tests and errors
tests/test_more.py::ClassifyUniqueTests::test_vs_unique_justseen_key
tests/test_recipes.py::UniqueJustseenTests::test_custom_key
tests/test_more.py::ClassifyUniqueTests::test_vs_unique_justseen_key
E   AssertionError: Lists differ: ['A', 'B', 'C', 'c', 'A', 'D'] != ['A', 'B', 'C', 'A', 'D']
E   
E   First differing element 3:
E   'c'
E   'A'
E   
E   First list contains 1 additional elements.
E   First extra element 5:
E   'D'
E   
E   - ['A', 'B', 'C', 'c', 'A', 'D']
E   ?                 -----
E   
E   + ['A', 'B', 'C', 'A', 'D']
tests/test_recipes.py::UniqueJustseenTests::test_custom_key
E   AssertionError: Lists differ: ['A', 'B', 'C', 'A', 'D'] != ['A', 'B', 'C', 'c', 'A', 'D']
E   
E   First differing element 3:
E   'A'
E   'c'
E   
E   Second list contains 1 additional elements.
E   First extra element 5:
E   'D'
E   
E   - ['A', 'B', 'C', 'A', 'D']
E   + ['A', 'B', 'C', 'c', 'A', 'D']
E   ?                 +++++
trace
+24.49s
re-ran 2 test file(s) with the trace plugin: 2 failing and 766 passing tests, 2 library functions ran in a failing test · 12.8s
tests/test_more.py, tests/test_recipes.py
retrieve
+24.49s
280 functions indexed, 2 reachable from tests/test_more.py::ClassifyUniqueTests::test_vs_unique_justseen_key in the static call graph. Kept 20 candidates, ranked by spectrum score (Ochiai), call graph and BM25 break ties.
candidates in retriever order
  1. more_itertools/recipes.py::unique_justseen call depth 1 · Ochiai 0.50 (failing 2, passing 6)
  2. more_itertools/more.py::classify_unique call depth 1 · Ochiai 0.19 (failing 1, passing 13)
  3. more_itertools/recipes.py::unique_everseen call depth - · Ochiai 0.00 (failing 0, passing 10)
  4. more_itertools/more.py::duplicates_justseen call depth - · Ochiai 0.00 (failing 0, passing 9)
  5. more_itertools/more.py::all_unique call depth - · Ochiai 0.00 (failing 0, passing 5)
  6. more_itertools/more.py::duplicates_everseen call depth - · Ochiai 0.00 (failing 0, passing 8)
  7. more_itertools/recipes.py::unique call depth - · Ochiai 0.00 (failing 0, passing 3)
  8. more_itertools/recipes.py::all_equal call depth - · Ochiai 0.00 (failing 0, passing 19)
  9. more_itertools/more.py::unique_to_each call depth - · Ochiai 0.00 (failing 0, passing 3)
  10. more_itertools/more.py::unique_in_window call depth - · Ochiai 0.00 (failing 0, passing 3)
  11. more_itertools/more.py::is_sorted call depth - · Ochiai 0.00 (failing 0, passing 1)
  12. more_itertools/more.py::distinct_combinations call depth - · Ochiai 0.00 (failing 0, passing 3)
  13. more_itertools/more.py::minmax call depth - · Ochiai 0.00 (failing 0, passing 6)
  14. more_itertools/more.py::sort_together call depth - · Ochiai 0.00 (failing 0, passing 6)
  15. more_itertools/more.py::groupby_transform call depth - · Ochiai 0.00 (failing 0, passing 5)
  16. more_itertools/more.py::takewhile_inclusive call depth - · Ochiai 0.00 (failing 0, passing 3)
  17. more_itertools/more.py::distinct_permutations call depth - · Ochiai 0.00 (failing 0, passing 8)
  18. more_itertools/more.py::unzip call depth - · Ochiai 0.00 (failing 0, passing 5)
  19. more_itertools/more.py::_sample_weighted call depth - · Ochiai 0.00 (failing 0, passing 5)
  20. more_itertools/more.py::make_decorator call depth - · Ochiai 0.00 (failing 0, passing 3)
rank
+24.49s
spectrum order kept (no model call)
  1. more_itertools/recipes.py::unique_justseen
  2. more_itertools/more.py::classify_unique
  3. more_itertools/recipes.py::unique_everseen
  4. more_itertools/more.py::duplicates_justseen
  5. more_itertools/more.py::all_unique
read
+27.54s
turn 1 · NVIDIA-Nemotron-3-Nano-30B-A3B · 3328 in / 158 out · 3.04s · $0.00024

read more_itertools/recipes.py::unique_justseen

The failing tests show that `unique_justseen` with a key function is producing incorrect ordering and missing elements. The current implementation uses `map(itemgetter(0), groupby(iterable))` when a key is provided, which only yields the key values, not the original elements. This explains why the test expects `['A', 'B', 'C', 'A', 'D']` but gets `['A', 'B', 'C', 'c', 'A', 'D']` – the key function is applied to groups but the original elements are not preserved. The fix should yield the original elements while using the key for grouping comparison.

patch
+30.87s
turn 2 · NVIDIA-Nemotron-3-Nano-30B-A3B · 3750 in / 178 out · 2.91s · $0.00027

The current code incorrectly returns the key values (itemgetter(0)) instead of the original elements when a key is provided. The test expects the original elements in order, but the current implementation yields the key values ('c' instead of 'A' in position 3). The fix uses groupby with the key function and then maps each group to its first element using next() to preserve the original elements while still using the key for duplicate detection.

--- a/more_itertools/recipes.py+++ b/more_itertools/recipes.py@@ -519,5 +519,5 @@     """     if not (key is None):-        return map(itemgetter(0), groupby(iterable))+        return map(lambda x: next(x), groupby(iterable, key))      return map(next, map(itemgetter(1), groupby(iterable, key)))

tests: 2 failing (target tests) 2 failed

tests/test_more.py::ClassifyUniqueTests::test_vs_unique_justseen_key
tests/test_recipes.py::UniqueJustseenTests::test_custom_key
patch
+49.87s
turn 3 · nemotron-3-super-120b-a12b · 4044 in / 1489 out · 6.66s · $0.00255

The conditional branch for key!=None was incorrect: it used groupby without the key function and returned the group keys instead of the first element of each group. The correct behavior for both key=None and key!=None is to group by the key (or identity) and yield the first element of each group, which is achieved by map(next, map(itemgetter(1), groupby(iterable, key))).

--- a/more_itertools/recipes.py+++ b/more_itertools/recipes.py@@ -518,7 +518,4 @@      """-    if not (key is None):-        return map(itemgetter(0), groupby(iterable))-     return map(next, map(itemgetter(1), groupby(iterable, key))) 

tests: all tests pass 768 passed

model reasoning (excerpt)
We need to understand what's happening. The error says "'tuple' object is not an iterator". That suggests we tried to call next on something that is not an iterator? Actually our new code:

return map(lambda x: next(x), groupby(iterable, key))

But note: groupby returns an iterator of tuples (key, group_iterator). So x is a tuple (k, g). Then we do next(x) -> trying to get the first item of the tuple? No, next(x) tries to iterate over the tuple as an iterator, yielding its items. But we want the first element of the group, not the key. Actually we want the first element of the group iterator g. In standard recipes, unique_justseen with key is implemented as:

def unique_justseen(iterable, key=None):
    return map(next, map(itemgetter(1), groupby(iterable, key)))

Wait look at the original code: there were two branches. When key is None, they did: return map(next, map(itemgetter(1), groupby(iterable, key))) ??? Let's re-examine original:

Original lines 520-523:

    if not (key is None):
        return map(itemgetter(0), groupby(iterable))

    return map(next, map(itemgetter(1), groupby(iterable, key)))

So when key is None, they do: groupby(iterable) -> returns (key, group) where key is the element itself (since no key function). Then map(itemgetter(1)) gets the group iterator, then map(next) gets the first element of each group. That yields the original elements.

When key is not None, they incorrectly did: map(itemgetter(0), groupby(iterable)) -> they forgot to use the k

Final patch

--- a/more_itertools/recipes.py+++ b/more_itertools/recipes.py@@ -518,7 +518,4 @@      """-    if not (key is None):-        return map(itemgetter(0), groupby(iterable))-     return map(next, map(itemgetter(1), groupby(iterable, key)))