diff --git a/sorts/bubble_sort.py b/sorts/bubble_sort.py index c66d5d59dd93..fb509aa8237d 100644 --- a/sorts/bubble_sort.py +++ b/sorts/bubble_sort.py @@ -1,7 +1,14 @@ -from typing import Any +from typing import Any, Protocol, TypeVar -def bubble_sort_iterative(collection: list[Any]) -> list[Any]: +class Comparable(Protocol): + def __lt__(self, other: Any, /) -> bool: ... + + +T = TypeVar("T", bound=Comparable) + + +def bubble_sort_iterative[T: Comparable](collection: list[T]) -> list[T]: """Pure implementation of the bubble sort algorithm in Python (iterative). Bubble sort works by repeatedly stepping through the collection, @@ -58,6 +65,10 @@ def bubble_sort_iterative(collection: list[Any]) -> list[Any]: >>> collection_arg = random.choices(string.ascii_letters + string.digits, k=100) >>> bubble_sort_iterative(collection_arg) == sorted(collection_arg) True + >>> bubble_sort_iterative([1, "a"]) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' """ length = len(collection) for i in reversed(range(length)): @@ -71,7 +82,7 @@ def bubble_sort_iterative(collection: list[Any]) -> list[Any]: return collection -def bubble_sort_recursive(collection: list[Any]) -> list[Any]: +def bubble_sort_recursive[T: Comparable](collection: list[T]) -> list[T]: """Pure implementation of the bubble sort algorithm in Python (recursive). Functionally identical to the iterative version: each call makes a @@ -124,6 +135,10 @@ def bubble_sort_recursive(collection: list[Any]) -> list[Any]: >>> collection_arg = random.choices(string.ascii_letters + string.digits, k=100) >>> bubble_sort_recursive(collection_arg) == sorted(collection_arg) True + >>> bubble_sort_recursive([1, "a"]) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' """ length = len(collection) swapped = False diff --git a/tests/test_sorts.py b/tests/test_sorts.py index 6de12789dd0a..caa4b31cac81 100644 --- a/tests/test_sorts.py +++ b/tests/test_sorts.py @@ -17,7 +17,7 @@ import pytest from sorts.binary_insertion_sort import binary_insertion_sort -from sorts.bubble_sort import bubble_sort_iterative +from sorts.bubble_sort import bubble_sort_iterative, bubble_sort_recursive from sorts.circle_sort import circle_sort from sorts.cocktail_shaker_sort import cocktail_shaker_sort from sorts.comb_sort import comb_sort @@ -89,6 +89,16 @@ def test_sort_matches_builtin(sort, case): assert list(sort(list(case))) == sorted(case) -def test_binary_insertion_sort_rejects_non_comparable_items(): +@pytest.mark.parametrize( + "sort", + [ + binary_insertion_sort, + bubble_sort_iterative, + bubble_sort_recursive, + insertion_sort, + ], + ids=lambda f: f.__name__, +) +def test_sort_rejects_non_comparable_items(sort): with pytest.raises(TypeError): - binary_insertion_sort([1, "a"]) + sort([1, "a"])