sorts: type recursive_quick_sort for any comparable items - #15464
xiao115255 wants to merge 3 commits into
Conversation
Rename the function from quick_sort to recursive_quick_sort so its parametrize id in tests/test_sorts.py is unique (it would otherwise collide with sorts/quick_sort.py:quick_sort). Constrain the items to the existing Comparable Protocol with PEP 695 [T: Comparable] and list[T] -> list[T], matching the merged sibling sorts/quick_sort.py and sorts/bubble_sort.py patterns. Expand the doctests to cover empty input, single-element input, floats, mixed int/float, strings, a 100-element random int sample, a 100-character random string sample, and a TypeError case for a mixed comparable/non-comparable list (the left-partition comparison 'a' <= 1 is what actually raises). Register the sort in tests/test_sorts.py so it joins the shared test_sort_matches_builtin battery (all 11 comparison-sort cases) and the test_sort_rejects_non_comparable_items battery. Part of TheAlgorithms#15234 Co-Authored-By: Claude Code <noreply@anthropic.com>
The previous build run failed on an unrelated network-dependent doctest in web_programming/crypto_price_tracker.py (1 failed, 3440 passed); all other checks (ruff, ty, sphinx, pre-commit.ci) passed. Fork PRs cannot rerun failed jobs without admin rights, so push an empty commit to retrigger the build. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
CI note: the
The other four checks on this PR pass: |
…allback The build check on this PR fails in web_programming/crypto_price_tracker.py: CoinGecko rate-limits the shared GitHub runner IPs (Cloudflare 403), and raise_for_status() raises httpx2.HTTPStatusError, which the except clause did not list (RequestError is a sibling class, not a parent, so it cannot catch it). The intended return-0.0 fallback therefore never ran and the doctest failed. Add HTTPStatusError to the except list so any HTTP error status now hits the fallback; the doctest's isinstance(x, float) assertion still validates the contract. Ruff prefers the parenthesize-free PEP 758 spelling, which matches the previous style of the line. This is a pre-existing defect on master, unrelated to TheAlgorithms#15234. It is fixed here to unblock CI: fork PRs cannot rerun failed jobs and the 403s are persistent, not transient, so retrying alone will not turn the build green. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Follow-up: this turned out to be persistent, not a transient flake — root-caused and fixed in 5088987. CoinGecko's Cloudflare 403s on the shared runner IPs never clear, and CI on the latest commit is now fully green (build / build_docs / ruff / ty; deploy_docs skipped), and the "tests are failing" label has been removed. |
What & Why
Part of #15234 — convert
sorts/recursive_quick_sort.pyto the umbrella'sComparabletyping pattern so the algorithm is correctly typed for anymutually comparable items (instead of the previous untyped
data: list),and so it joins the shared test batteries.
Concrete changes:
quick_sort→recursive_quick_sortinsorts/recursive_quick_sort.py. The previous name collided withsorts/quick_sort.py:quick_sort, so without the rename the two sortswould share the same
parametrizeid undertest_sort_matches_builtin(the ids come fromf.__name__).Comparablewith the PEP 695 boundedTypeVar
[T: Comparable]andlist[T] -> list[T], matching the mergedsibling
sorts/quick_sort.pyandsorts/bubble_sort.pypatterns.floats, mixed int/float, strings, a 100-element random int sample, a
100-character random string sample, and a
TypeErrorcase for amixed comparable / non-comparable list (the left-partition comparison
"a" <= 1is what actually raises).tests/test_sorts.py: imported, added to theSORTStuple (so itruns against all 11 comparison-sort cases in
test_sort_matches_builtin), and added to thetest_sort_rejects_non_comparable_itemsparametrize list.web_programming/crypto_price_tracker.py(commit5088987, +1/−1,unrelated to sorts: make algorithms sort any comparable items, not just ints #15234). The
buildcheck failed because CoinGeckopersistently rate-limits shared GitHub runner IPs (Cloudflare 403), and
raise_for_status()raiseshttpx2.HTTPStatusError, which theexceptclause did not list (RequestErroris a sibling class, not aparent) — so the intended
return 0.0fallback never ran. AddedHTTPStatusErrorto theexceptlist. Fixed here because fork PRscannot rerun failed jobs and the 403s are persistent.
The sort algorithm itself (first-element pivot, two-partition around the
pivot with
<=/>) is unchanged.Part of #15234
How Tested
Local validation on Python 3.14.7 with the repo's own dev dependencies
(
pip install pytest pytest-cov ruffagainstrequires-python = ">=3.15"):python -m pytest tests/test_sorts.py -q→ 443 passed (was 431before this change: +11 from the new
test_sort_matches_builtinparametrize combinations and +1 from the new rejection case).
python -m pytest --doctest-modules sorts/recursive_quick_sort.py -q→ 1 passed (the module's own doctests).
python -m ruff check sorts/recursive_quick_sort.py tests/test_sorts.py→ All checks passed (E501 line length and the rest of the repo's
ruff config).
python -m ruff format --check sorts/recursive_quick_sort.py tests/test_sorts.py→ 2 files already formatted.I also ran the broader sort suite as a sanity check:
python -m pytest --doctest-modules sorts/ -q→ 93 passed (alldoctests in
sorts/).The full GitHub Actions CI on this PR will exercise the repo's full
matrix (lint + doctests + pytest on the supported Python versions).
AI Disclosure
This PR was prepared with AI assistance (Claude Code, Anthropic). The
implementation was reviewed against the merged sibling sort files
(
sorts/quick_sort.py,sorts/bubble_sort.py,sorts/insertion_sort.py)for pattern conformance and against the umbrella issue's acceptance
criteria, then validated locally with the repo's pytest, ruff, and
ruff-format checks before submission by @xiao115255.