From f240475cb3a1ea1dd6479e4c4c1e9f6acf6787c9 Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Wed, 9 Sep 2026 19:49:51 +0530 Subject: [PATCH 1/4] sorts: type bubble sort for any comparable items Bound bubble_sort_iterative and bubble_sort_recursive to a Comparable protocol instead of Any, add TypeError doctests, and cover the mixed-type failure in tests/test_sorts.py. Refs #15234 --- sorts/bubble_sort.py | 21 ++++++++++++++++++--- tests/test_sorts.py | 12 +++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) 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..72e111fac0be 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 @@ -92,3 +92,13 @@ def test_sort_matches_builtin(sort, case): def test_binary_insertion_sort_rejects_non_comparable_items(): with pytest.raises(TypeError): binary_insertion_sort([1, "a"]) + + +@pytest.mark.parametrize( + "sort", + (bubble_sort_iterative, bubble_sort_recursive), + ids=lambda f: f.__name__, +) +def test_bubble_sort_rejects_non_comparable_items(sort): + with pytest.raises(TypeError): + sort([1, "a"]) From 7e04048fff3e4a1a10d5b4aea9e89f5343a7e3d7 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 9 Sep 2026 16:50:03 +0200 Subject: [PATCH 2/4] Update tests/test_sorts.py --- tests/test_sorts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sorts.py b/tests/test_sorts.py index 72e111fac0be..ab717df656b5 100644 --- a/tests/test_sorts.py +++ b/tests/test_sorts.py @@ -96,7 +96,7 @@ def test_binary_insertion_sort_rejects_non_comparable_items(): @pytest.mark.parametrize( "sort", - (bubble_sort_iterative, bubble_sort_recursive), + [bubble_sort_iterative, bubble_sort_recursive], ids=lambda f: f.__name__, ) def test_bubble_sort_rejects_non_comparable_items(sort): From a9bc6688ada2129ec4b2db6a4c867de9341e6b8c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 9 Sep 2026 16:52:24 +0200 Subject: [PATCH 3/4] Add binary insertion sort to tests and rename function Updated tests to include binary insertion sort and renamed test function. --- tests/test_sorts.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_sorts.py b/tests/test_sorts.py index ab717df656b5..a85ae92f625f 100644 --- a/tests/test_sorts.py +++ b/tests/test_sorts.py @@ -89,16 +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(): - with pytest.raises(TypeError): - binary_insertion_sort([1, "a"]) - - @pytest.mark.parametrize( "sort", - [bubble_sort_iterative, bubble_sort_recursive], + [ + binary_insertion_sort, + bubble_sort_iterative, + bubble_sort_recursive, + insertion_sort + ], ids=lambda f: f.__name__, ) -def test_bubble_sort_rejects_non_comparable_items(sort): +def test_sort_rejects_non_comparable_items(sort): with pytest.raises(TypeError): sort([1, "a"]) From 55b05fefe9003676e979139dd5941cc139450db4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:52:37 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_sorts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sorts.py b/tests/test_sorts.py index a85ae92f625f..caa4b31cac81 100644 --- a/tests/test_sorts.py +++ b/tests/test_sorts.py @@ -95,7 +95,7 @@ def test_sort_matches_builtin(sort, case): binary_insertion_sort, bubble_sort_iterative, bubble_sort_recursive, - insertion_sort + insertion_sort, ], ids=lambda f: f.__name__, )