litellm/tests/test_litellm/test_ruff_strict_gate.py
Mateo Wang cf6fdac304
perf(lint): skip and cache base gate passes, parallelize make lint, skip redundant prisma generate (#32000)
* perf(lint): skip and cache base gate passes, parallelize make lint, skip redundant prisma generate

make pre-commit paid for a full second basedpyright pass over a merge-base
worktree on every run even when no rule was over its ceiling, re-generated an
unchanged Prisma client, and ran seven independent checks sequentially. The
basedpyright and ruff strict gates now skip the base pass when head is within
every limit (the same early-out type_discipline_gate already had), the
basedpyright base counts are cached under the git common dir keyed by
merge-base commit, pyrightconfig.json, and uv.lock, prisma generate only runs
when the schema or prisma version changed, and make lint fans its checks out
through a parallel sub-make after a single setup phase

* fix(lint): keep the base-cache scratch file out of the prune glob

The tmp+rename scratch in store_counts was named basedpyright-base-<hash>.json.tmp,
which the stale-entry prune glob (basedpyright-base-*) also matches, so a concurrent
lint run from another worktree sharing the same git common dir could unlink it between
write_text and replace and crash the gate with FileNotFoundError. The scratch is now
dot-prefixed so the glob can never see it, pid-suffixed so concurrent writers of the
same entry never share a scratch, and the prune glob is restricted to committed
*.json entries
2026-07-02 19:24:00 -07:00

112 lines
3.8 KiB
Python

import importlib.util
from pathlib import Path
import pytest
_MODULE_PATH = Path(__file__).resolve().parents[2] / "scripts" / "ruff_strict_gate.py"
_spec = importlib.util.spec_from_file_location("ruff_strict_gate", _MODULE_PATH)
gate = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(gate)
Violation = gate.Violation
def rule(name, limit):
return {name: {"limit": limit}}
def test_under_ceiling_passes():
assert gate.evaluate({"ANN001": 100}, {"ANN001": 100}, rule("ANN001", 110)) == []
def test_ceiling_is_the_limit_boundary():
budget = rule("ANN001", 110)
at = gate.evaluate({"ANN001": 110}, {"ANN001": 90}, budget)
over = gate.evaluate({"ANN001": 111}, {"ANN001": 90}, budget)
assert at == []
assert [b.rule for b in over] == ["ANN001"]
assert over[0].cap == 110
assert over[0].added == 21
def test_over_ceiling_and_change_added_fails():
breaches = gate.evaluate({"C901": 11}, {"C901": 9}, rule("C901", 10))
assert [b.rule for b in breaches] == ["C901"]
assert breaches[0].added == 2
def test_base_already_over_ceiling_change_added_nothing_is_not_blamed():
# drift safety: base is over limit, this change leaves the count where it is
assert gate.evaluate({"C901": 15}, {"C901": 15}, rule("C901", 10)) == []
def test_change_that_reduces_an_over_ceiling_rule_is_not_blamed():
# still over limit, but moving the right direction
assert gate.evaluate({"C901": 14}, {"C901": 16}, rule("C901", 10)) == []
def test_rules_are_independent():
budget = {**rule("ANN001", 150), **rule("C901", 10)}
breaches = gate.evaluate(
{"ANN001": 130, "C901": 11}, {"ANN001": 100, "C901": 10}, budget
)
assert [b.rule for b in breaches] == ["C901"] # ANN001 130 <= 150, C901 11 > 10
def test_missing_rule_counts_as_zero():
assert gate.evaluate({}, {}, rule("C901", 0)) == []
def test_update_ratchets_limit_down_by_what_the_branch_fixed_never_up():
budget = {**rule("ANN001", 150), **rule("C901", 10)}
# ANN001 fixed 20 (100 -> 80) so its limit falls 150 -> 130; C901 grew, so its
# limit holds flat at 10 (a fix must never loosen a ceiling).
current = {"ANN001": 80, "C901": 12}
base = {"ANN001": 100, "C901": 9}
assert gate.ratcheted_budget(budget, current, base) == {
"ANN001": {"limit": 130},
"C901": {"limit": 10},
}
def test_parse_changed_lines_maps_added_lines_per_file():
diff = (
"+++ b/litellm/a.py\n"
"@@ -10 +10,3 @@\n+x\n+y\n+z\n"
"+++ b/litellm/b.py\n"
"@@ -5,2 +7 @@\n+q\n"
)
changed = gate.parse_changed_lines(diff)
assert changed["litellm/a.py"] == {10, 11, 12}
assert changed["litellm/b.py"] == {7}
def test_introduced_keeps_only_violations_on_changed_lines():
violations = [
Violation("litellm/a.py", 10, "ANN001"),
Violation("litellm/a.py", 99, "C901"),
]
assert gate.introduced(violations, {"litellm/a.py": {10}}) == [
Violation("litellm/a.py", 10, "ANN001")
]
@pytest.mark.parametrize("hunk", ["@@ -1 +1 @@", "@@ -1,0 +1,2 @@"])
def test_parse_changed_lines_handles_single_and_ranged_hunks(hunk):
assert gate.parse_changed_lines(f"+++ b/litellm/a.py\n{hunk}\n")["litellm/a.py"]
def test_over_ceiling_flags_only_counts_above_the_limit():
budget = rule("C901", 10)
assert gate.over_ceiling({"C901": 10}, budget) == frozenset()
assert gate.over_ceiling({"C901": 11}, budget) == frozenset({"C901"})
assert gate.over_ceiling({}, budget) == frozenset()
def test_over_ceiling_ignores_rules_missing_from_the_budget():
assert gate.over_ceiling({"NEW99": 100}, rule("C901", 10)) == frozenset()
def test_over_ceiling_is_independent_across_rules():
budget = {**rule("ANN001", 150), **rule("C901", 10)}
assert gate.over_ceiling({"ANN001": 130, "C901": 11}, budget) == frozenset({"C901"})