Pytest 8 migration check — check pytest changes free

Flags pytest APIs removed in pytest 8 and pytest config keys that are silently ignored, with the replacement line and the version that removed each one. Runs entirely in your browser — nothing is uploaded.

Same engine as the VS Code extension, byte for byte.

Install free

Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.

VS Code MarketplaceOpen VSX (Cursor, VSCodium)npmMCP server (npx)Docker Hub
ext install ReadyStack.pytest-deprecation-lint
npx @readystack/pytest-deprecation-lint <file>
npx @readystack/pytest-deprecation-lint --mcp

Team? One key for every ReadyStack linter, 5 seats, $149 once

Get the full rule table as a PDF
All 19 rules Pytest Deprecation Lint (pytest 8 removals) checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.

Get the full version $29

Sweep every test file, conftest.py and config file in the workspace in one pass and export the dated findings as Markdown or JSON you keep and paste into a CI job or a migration ticket.

One payment, one licence key for this tool. The key is shown right after payment.

A contract Python engineer reviewing the same suite for pytest 8 breakage by hand bills roughly $80-$120 an hour in the US market.

Buy the full version — $29
ENDEJAESPT

Find a tool

· ReadyStack

Worked example

Real numbers from this tool, line by line.

Pytest Deprecation Lint (pytest 8 removals)

Twelve findings, seven of them fatal, in a 75-line pytest file: that is what a Python team running an unpinned pytest in CI is carrying without seeing it. The file is the checkout suite shipped as _fixtures/dirty.py with Pytest Deprecation Lint. It was written against pytest 6, it reads fine, and it passed for years.

Then the runner installs pytest 8.

Seven of those lines pytest 8 will not run as written:

@pytest.yield_fixture -> @pytest.fixture pytest.config.getoption(...) -> the pytestconfig fixture pytest.warns(None) -> pytest.warns(DeprecationWarning) pytest.raises(Err, message=) -> pytest.raises(Err, match="...") def event_loop(): -> def event_loop_policy(): @parametrize on TestCase -> drop the unittest.TestCase base item.get_marker("slow") -> item.get_closest_marker("slow")

pytest.warns(None) went away in pytest 8.0, yield_fixture in 6.2, the message= keyword and the global pytest.config object in 5.0, get_marker() in 4.0. Redefining the event_loop fixture was removed in pytest-asyncio 1.0.

The loud ones are the cheap ones: a TypeError in CI is visible, and somebody fixes it within the hour.

The expensive half is quiet.

@pytest.mark.parametrize on a unittest.TestCase subclass does not error in the obvious place - pytest simply will not inject the arguments, so the case you think covers two amounts covers neither. A mark stacked above @pytest.fixture is ignored outright, so the skipif guarding your slow fixture is decoration. An async def test_ with no asyncio marker and no asyncio_mode = "auto" is skipped with a warning, and a skipped test is a green test. Nose-style setup(self) methods stopped being called in pytest 8.0: the body never runs, and the assertions below it run against an unprepared object.

And the quietest one is not code at all. pytest reads [tool.pytest.ini_options] in pyproject.toml. It does not read [tool.pytest]. Put your addopts, markers, filterwarnings and testpaths under the shorter table and pytest ignores all of it without printing a word - the coverage gate you think is enforcing 80% is not running, and the suite still exits 0.

This is where generated test code lands hardest. An assistant trained on years of pytest 6 and 7 examples writes yield_fixture, pytest.warns(None) and message=, because that is what most of the code it read looks like. The test it produces is plausible, reviewable and stale.

Pytest Deprecation Lint is a VS Code extension and a browser page sharing one rule table of 19 rules. Open a test file, conftest.py, pytest.ini, pyproject.toml, setup.cfg or tox.ini, run "Check this file", and each affected line shows up in the Problems panel with the version that removed it and the replacement line. On the migrated copy of that same suite, _fixtures/clean.py, it reports 0.

Ruff, flake8 and pylint will not tell you any of this. They model Python, not pytest's removal history and not its config tables, and pytest itself only reports a removal on the machine that has already upgraded - usually CI, after the merge.

Linting the file you have open is free, all 19 rules, no key and no account: https://getreadystack.com/tools/pytest-deprecation-lint

The paid tier is a different job rather than a bigger one - sweeping every test file, conftest.py and config file in the workspace in one pass and exporting the dated findings as Markdown or JSON you keep for the CI job or the migration ticket. A contract Python engineer doing that reading by hand bills roughly $80 to $120 an hour in the US market.

15 seconds — what it actually does

Questions people ask

What does Pytest Deprecation Lint actually do?

It reads a test file, conftest.py, pytest.ini, pyproject.toml, setup.cfg or tox.ini and flags each line that current pytest handles differently than it reads: APIs removed in pytest 4.0 through 8.0, and config tables pytest ignores. Every finding names the removal version and prints the replacement line.

Who is it for?

Python developers and QA engineers holding a pytest suite that predates the pytest 8 bump, and anyone reviewing test code an assistant generated. Assistants were trained on years of pytest 6 and 7 examples, so yield_fixture, pytest.warns(None) and message= keep reappearing in new files.

Why is a free linter not enough?

Ruff, flake8 and pylint check Python, not pytest's own removal history or its config tables. None of them tells you that a [tool.pytest] table in pyproject.toml is being ignored, that a mark above a fixture does nothing, or that parametrize on a TestCase subclass never injects its arguments.

What is free and what costs money?

Linting the file you have open is free and complete: all 19 rules, every finding, every replacement line, no key and no account. The paid tier adds a different job, not a bigger one: sweeping the whole workspace in one pass and exporting dated findings as Markdown or JSON you keep.

What would this cost done by hand?

Reading a mid-sized suite line by line against the pytest changelog is an afternoon for someone who knows pytest, and a contract Python engineer in the US market bills roughly $80 to $120 an hour for it. The extension is $29 once,.

Why not just ask ChatGPT or another AI chat?

A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Pytest Lint - pytest 8 deprecations and removals checks the file you open against 19 rules from a rule set dated 2026-09-20, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.

Ask about this tool

One question, answered by the person who built it. Your email only if you want the answer sent.

Embed this tool on your site (free)

Paste this code into your page. It runs in your visitor’s browser and stays up to date. Nothing your visitors type is stored.

 All embeddable tools

For businesses: your name and logo instead of ours, and each visitor’s result + e-mail in your inbox (only when they tick consent) — Pro from $19/month. See Pro →