from dataclasses import replace from typing import List, Sequence, Set from .todo_item import Todo def _in_manual_order(todos: Sequence[Todo], which: str) -> List[Todo]: """Manual order: order ascending, ties by position (sorted is stable).""" seen: Set[str] = set() for todo in todos: if todo.id in seen: raise ValueError(f'duplicate id "{todo.id}" in the {which} list') seen.add(todo.id) return sorted(todos, key=lambda todo: todo.order) def merge_todos(current: Sequence[Todo], incoming: Sequence[Todo]) -> List[Todo]: """Merge by id: incoming wins in the current todo's place, new ids follow; manual order, renumbered.""" mine = _in_manual_order(current, "current") theirs = _in_manual_order(incoming, "incoming") by_id = {todo.id: todo for todo in theirs} kept = {todo.id for todo in mine} merged = [by_id.get(todo.id, todo) for todo in mine] + [todo for todo in theirs if todo.id not in kept] return [replace(todo, order=order) for order, todo in enumerate(merged)]