Repository navigation
Положить порог покрытия туда, где codecov.yml говорит, что он лежит - #16
Merged
Merged
Conversation
codecov.yml explains why both Codecov statuses are informational:
The real floor lives in pyproject.toml, where `pytest --cov` enforces it
identically on a laptop and in CI.
Neither half was true. pyproject.toml had no coverage configuration at all, and
the floor was a `--cov-fail-under=90` flag on one CI command line, so
`pytest --cov=glia` on a laptop gated at nothing. The one sentence that explains
why the remote gate is switched off was the sentence that was wrong.
The floor is now `[tool.coverage.report] fail_under = 90`, which is what the
sentence claims, and the flag is gone from CI so the number lives in one place.
Checked in both directions: at 99 the same command exits 1 with "Required test
coverage of 99.0% not reached", at 90 it exits 0. `--cov` stays out of addopts
on purpose -- the second test job runs the suite without coverage deliberately,
and forcing it on would take that away.
Both READMEs said "167 offline tests, ~95% coverage". The count is right today;
the coverage is 94.39%, and more to the point it is a figure that moves on
almost every commit, which is not something prose can carry honestly. This
organisation's own rule is that a published number is measured on the run it
describes -- so the README now states the floor, which is a guarantee and does
not move, and the measured figure stays on the badge, where it is recomputed per
run. (That badge currently reads "unknown", for a reason that is not this
repository's: `secrets.CODECOV_TOKEN` is empty, `fail_ci_if_error` is correctly
conditional on it, and the upload is rejected quietly. Reported separately.)
scripts/check_claims.py holds both numbers to the suite. The count comes from
pytest's own collection, not from counting `def test_`: one parametrized
function here is four collected tests, so counting functions would report 164
and be confidently wrong. The floor comes from pyproject.toml, read with a
section-scoped regular expression rather than tomllib, which arrived in 3.11 and
would crash the script on the 3.10 this project still promises.
A claim that has gone missing is reported like a wrong number. Rewriting the
sentence is what makes a check like this stop checking, silently, and that is
the failure worth catching.
Seven ways of drifting were tried against a copy: a test added with the prose
unchanged, each README's count moved on its own, the floor raised in pyproject,
the gate deleted outright, and each sentence rewritten away. All seven reported.
The floor regex was driven through six pyproject shapes, including one with a
`fail_under` in a different section before and after the right one.
…ction
It went red on its first run with
could not ask pytest how many tests there are
which is true, useless, and my fault twice over.
The cause: CI sets FORCE_COLOR=1 for every step, so pytest's summary arrives as
"\x1b[32m\x1b[32m167 tests collected\x1b[0m…" and a pattern anchored at the
start of the line never reaches the digits. It passes on a laptop, where
nothing forces colour. `--color=no` settles it, and the escapes are stripped
as well -- the next thing to colourise pytest's output will not announce itself
either.
The second fault was the message. Returning a bare None and printing one
sentence that names no cause meant the only way to find a single escape
sequence was another round trip through CI. It now prints pytest's return code
and the last six lines of what it said.
Writing that turned up a worse bug than the one it was written for. A test file
that fails to import makes pytest print "167 tests collected, 1 error" and exit
2 -- and reading the count before the return code found the 167 and passed,
reporting that the READMEs accurately describe a suite that cannot be
collected. The return code is now checked first.
Driven through: a healthy tree with and without FORCE_COLOR, and under NO_COLOR,
TERM=dumb, FORCE_COLOR=3 and PY_COLORS=1; an unimportable test file, which now
exits 2 naming the module; pytest missing entirely; and a healthy added test,
which still reports 167 against 168 in both READMEs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
codecov.ymlобъясняет, почему оба статуса Codecov informational:Обе половины неправда. В
pyproject.tomlне было никакой конфигурации покрытия, а порог сидел флагом--cov-fail-under=90в одной команде CI. То естьpytest --cov=gliaна ноутбуке не гейтил ничего. Единственная фраза, объясняющая, почему удалённый гейт выключен, — и была той фразой, которая неверна.Порог
Теперь
[tool.coverage.report] fail_under = 90— ровно там, где сказано. Флаг из CI убран, чтобы число жило в одном месте.Проверено в обе стороны: при 99 та же команда выходит с 1 и
Required test coverage of 99.0% not reached, при 90 — с 0.--covнамеренно не вaddopts: второй тестовый job гоняет набор без покрытия специально, и включение отняло бы это.Числа в README
Оба README говорили «167 offline tests, ~95% coverage». Счёт сегодня верен; покрытие — 94.39%, и главное, что это цифра, которая двигается почти на каждом коммите. Такое проза нести честно не может.
Правило самой организации: опубликованное число измеряется на том прогоне, который оно описывает. Поэтому README теперь называет порог — это гарантия, и она не двигается, — а измеренная цифра остаётся на бейдже, где пересчитывается каждый прогон.
scripts/check_claims.pyДержит оба числа при наборе.
Счёт берётся из собственной коллекции pytest, а не из подсчёта
def test_: одна параметризованная функция здесь — четыре собранных теста, так что подсчёт функций дал бы 164 и был бы уверенно неправ.Порог читается из
pyproject.tomlрегуляркой, привязанной к секции, а не черезtomllib: он появился в 3.11, а проект обещает 3.10, и импорт уронил бы скрипт у того, кто пришёл на самом старом обещанном Python.Пропавшее утверждение сообщается как неверное число. Переписать фразу — это и есть то, от чего такая проверка перестаёт проверять, молча.
Проверено
Семь способов разойтись на копии:
says 167 tests, pytest collects 168says a 90% floor, pyproject enforces 95%no [tool.coverage.report] fail_under, so pytest --cov gates at nothingthe sentence was rewritten, so the test count is now uncheckedРегулярка порога прогнана через шесть форм
pyproject, включаяfail_underв другой секции до и после нужной.Локально:
ruff checkчисто,mypy— 28 файлов без замечаний, 167 тестов, покрытие 94.39% против порога 90%.Первый прогон был красный — и это оказалось полезно
Проверка упала с
Причина: CI ставит
FORCE_COLOR=1на каждый шаг, и сводка pytest приходит как\x1b[32m\x1b[32m167 tests collected\x1b[0m…. Шаблон, привязанный к началу строки, до цифр не доходит. На ноутбуке, где цвет никто не форсит, всё сходилось. Лечится--color=no, плюс escape-последовательности теперь снимаются на всякий случай — следующее, что раскрасит вывод pytest, тоже не предупредит.Вторая ошибка была в сообщении. Вернуть голый
Noneи напечатать одну фразу, не называющую причину, — значит заставить искать одну escape-последовательность ещё одним кругом через CI. Теперь печатается код возврата pytest и последние шесть строк того, что он сказал.И при написании этого нашлась ошибка хуже той, ради которой писалось. Тестовый файл, который не импортируется, заставляет pytest напечатать
167 tests collected, 1 errorи выйти с 2 — а чтение счёта до кода возврата находило 167 и проходило, сообщая, что README точно описывают набор, который невозможно собрать. Код возврата теперь проверяется первым:Прогнано: здоровое дерево с
FORCE_COLORи без, плюсNO_COLOR,TERM=dumb,FORCE_COLOR=3,PY_COLORS=1; неимпортируемый тест; отсутствующий pytest; и добавленный здоровый тест — он по-прежнему даёт 167 против 168 в обоих README.