diff --git a/asyncstdlib/builtins.py b/asyncstdlib/builtins.py index 5c8f54c..fa0690d 100644 --- a/asyncstdlib/builtins.py +++ b/asyncstdlib/builtins.py @@ -11,6 +11,7 @@ Optional, Dict, Any, + cast, ) import builtins as _sync_builtins @@ -446,13 +447,11 @@ async def sorted( It is guaranteed to be worst-case O(n log n) runtime. """ if key is None: - # TODO: is this a worthwhile optimisation? - try: - return _sync_builtins.sorted(iterable, reverse=reverse) # type: ignore - except TypeError: - items: _sync_builtins.list[Any] = [item async for item in aiter(iterable)] - items.sort(reverse=reverse) - return items + if isinstance(iterable, Iterable): + return _sync_builtins.sorted(cast(Iterable[Any], iterable), reverse=reverse) + items: _sync_builtins.list[Any] = [item async for item in aiter(iterable)] + items.sort(reverse=reverse) + return items else: async_key = _awaitify(key) keyed_items = [(await async_key(item), item) async for item in aiter(iterable)] diff --git a/unittests/test_builtins.py b/unittests/test_builtins.py index 382fddd..55b0716 100644 --- a/unittests/test_builtins.py +++ b/unittests/test_builtins.py @@ -343,3 +343,29 @@ def collision_key(x: int) -> int: assert await a.sorted(values, key=awaitify(collision_key)) == sorted( values, key=collision_key ) + + +@pytest.mark.parametrize("reverse", [False, True]) +@sync +async def test_sorted_preserves_comparison_errors(reverse): + with pytest.raises(TypeError): + await a.sorted(iter([1, "two"]), reverse=reverse) + + +@sync +async def test_sorted_preserves_iteration_errors(): + def records(): + yield 1 + raise TypeError("source failure") + + with pytest.raises(TypeError, match="source failure"): + await a.sorted(records()) + + +@sync +async def test_sorted_supports_indexed_sequences(): + class Indexed: + def __getitem__(self, index): + return [3, 1, 2][index] + + assert await a.sorted(Indexed()) == [1, 2, 3]