# What changed in pytest

> 79 changes in pytest 9 from its official release notes, upgrade guides and advisories: 10 breaking, 11 deprecations, 1 security, 17 new APIs and options. Each one cited. Sources checked 2026-10-18. HTML: https://unstale.sh/pypi/pytest/

To see which of these apply to a repository, run `npx @unstale/cli init` in it.

## pytest 9

### Breaking changes

- Autouse fixtures with module, package, or session scope defined inline in Python test modules may execute twice when doctest modules are enabled. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Fixture overrides are resolved first by visibility in the collection tree, so a more specific node takes precedence over a more general node regardless of registration order. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Unraisable exceptions from finalizers are collected during `pytest_unconfigure` before session warning filters are torn down, so matching error filters promote them to failures regardless of plugin cleanup order. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- It is no longer considered an interactive exception, so `pytest_exception_interact` is no longer called for it. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Disallows blocking a `conftest.py` file and raises a clear `UsageError` explaining that conftest files are not plugins and cannot be disabled via `-p`. (9.0.3) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.3)
- CI mode is activated only when `CI` or `BUILD_NUMBER` is defined and has a non-empty value. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- A file argument with parametrization syntax is now reported as a usage error instead of silently being treated as the file path. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Warnings of this type now raise errors by default; affected features are slated for removal in pytest 9.1. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- pytest no longer supports Python 3.9. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- A single `--version` no longer loads the plugin infrastructure; passing it twice retains the behavior of showing pytest and plugin information. It only works when passed directly on the command line. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)

### Security

- Fixes the use of an insecure temporary directory. (9.0.3) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.3), [security advisory](https://github.com/advisories/GHSA-6W46-J5RX-G56G)

### Deprecations

- Class-scoped fixtures defined as instance methods without `@classmethod` now emit a deprecation warning; use `@classmethod` instead. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The private `config.inicfg` attribute is deprecated; use `config.getini()` to access configuration values. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Passing `nodeid` strings to fixture registration APIs is deprecated; use the `node` parameter for fixture scoping. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Passing `baseid` to `FixtureDef` is deprecated; use the `node` parameter for fixture scoping. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The private `FixtureDef.has_location` attribute is deprecated and will be removed in pytest 10. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Configuring hooks using markers, deprecated since pytest 7.2, is now scheduled for removal in pytest 10. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The option is deprecated; the same functionality is available in the external `pytest-pastebin` plugin. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- This function is deprecated and will be removed in pytest 10; use `pytest.main` instead. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Type checkers now recognize `yield_fixture` as deprecated through the `deprecated` decorator. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The attribute will be deprecated in pytest 9.1 and removed in pytest 10. (9.0.2) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.2)
- Prints a warning when configuration is spread over more than one file, clarifying that only one is used. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)

### New APIs and options

- Adds a setting to render string equality failures as separate `Left:` and `Right:` blocks instead of `ndiff` output. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Adds a command-line threshold that fails the test run when the number of warnings exceeds the given value. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Adds a configuration threshold that fails the test run when the number of warnings exceeds the given value. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Supports comparisons with `datetime` and `timedelta`; datetime comparisons require an explicit absolute or relative tolerance as a `timedelta`, and relative tolerance is unsupported. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The callable overload uses `ParamSpec` instead of `Any` for type hints, and `func` can now be passed as a keyword argument. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Adds an imperative interface for registering fixtures, intended for plugins where declarative registration is cumbersome or unviable. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The callable overload uses `ParamSpec` instead of `Any` for type hints, and `func` can now be passed as a keyword argument. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Adds `pytest.toml` as a separate native TOML configuration file. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds `.pytest.toml` as a separate native TOML configuration file. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds a configuration option that enables `strict_config`, `strict_markers`, `strict_parametrization_ids`, and `strict_xfail`; individual options can override it. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds `strict_config` as a configuration option alias for the `--strict-config` flag. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds `strict_markers` as a configuration option alias for the `--strict-markers` flag. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- When enabled, emits an error for non-unique parameter set IDs instead of automatically making them unique. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds `strict_xfail` as an alias to `xfail_strict`. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds subtests as an alternative to parametrization when values are not all known at collection time; failures are reported individually. The feature is experimental. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Adds native TOML configuration in the `[tool.pytest]` table of `pyproject.toml`; it cannot be used alongside `[tool.pytest.ini_options]`. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- pytest now supports unittest subTest. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)

### Performance

- Quadratic-time behavior when handling unittest subtests in Python 3.10 was fixed. (9.0.2) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.2)

### Behavior and default changes

- Help and error messages identify `pytest`, `python -m pytest`, or `pytest.main()` according to how pytest was invoked. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Output excludes internal-implementation fixtures generated by `@pytest.mark.parametrize` and similar. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- When warnings were emitted but the match pattern did not match, the message now says “Regex pattern did not match” instead of “DID NOT WARN”. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- A `PytestCollectionWarning` is emitted when module-level `__getattr__` returns `None` for `pytestmark`; collection then continues normally. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Output now prints a space after the test name and any listed fixtures to separate them from the test result. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The default number of `gc.collect()` passes is reduced from five to one on CPython; PyPy retains five passes. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Terminal progress is disabled by default except on Windows; enable it with -p terminalprogress. (9.0.2) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.2)
- The previously-deprecated flag now enables strict mode. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)

### Fixes and other changes

- Restored loading files under `<invocation dir>/test*` as initial conftests when pytest is invoked without arguments, so hooks in those files can run. (9.1.1) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.1)
- Fixed mypy list-item typing errors for the argvalues parameter. (9.1.1) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.1)
- Fixed incorrect match messages that could pair an exception with the wrong error. (9.1.1) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.1)
- Logging capture now works for non-propagating loggers, not only logs that reach the root logger. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Fixes doubled output when `capteesys` is used with `--capture=no` (`-s`). (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Fixes duplicated `-W` option values in `Config.known_args_namespace`. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Fixture values are released more promptly when a test is interrupted by `KeyboardInterrupt` or early exit. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- High Unicode supplementary-plane characters, such as emoji, are no longer incorrectly escaped in test failure messages. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- An exception from this hook no longer prevents fixtures from being torn down, avoiding additional errors in following tests. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Recognizes types with `__array_interface__` as numpy-like arrays. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- A trailing-comma single argument name such as `"arg,"` now unpacks single-element tuple values like `("arg",)`. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The callable overload uses `ParamSpec` instead of `Any` for type hints, and `func` can now be passed as a keyword argument. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Assertion verbosity is propagated so the `-v` hint in match-diff output works. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Adds official support for Python 3.15. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Fixes a regression where `--strict-config` specified through `addopts` was silently ignored. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Fixes a regression where `--strict-markers` specified through `addopts` was silently ignored. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Autouse fixtures defined inside a skipped or `skipIf`-decorated test case no longer run. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- The short form of `--version` now displays the current version correctly. (9.1.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.1.0)
- Correctly takes mapping key order into account when comparing mappings. (9.0.3) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.3)
- Fixes a crash when a test raises an exception group with `__tracebackhide__ = True`. (9.0.3) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.3)
- Non-string messages passed to `subTest()` are now printed. (9.0.3) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.3)
- The private attribute is restored to working order with a compatibility shim after a breaking change in pytest 9.0.0. (9.0.2) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.2)
- When TERM is dumb, pytest no longer emits escape codes, even if the terminal progress plugin is enabled. (9.0.2) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.2)
- Fixes a UserWarning on some earlier Python 3.12 and 3.13 point versions. (9.0.1) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.1)
- The plugin is automatically disabled when iTerm2 is detected because it generated desktop notifications instead of the desired functionality. (9.0.1) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.1)
- Raising unittest.SkipTest once again skips tests. (9.0.1) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.1)
- Fixes teardown handling for an `ExceptionGroup` containing only skipped exceptions, which previously appeared as an error. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Improves assertion and error messages when comparing mappings with differing lengths or keys. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Hidden `.pytest.ini` files are now selected as the configuration file even when empty. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- Type annotations for `pytest.skip` and related functions are more spec-compliant to work across more type checkers. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
- A filter referencing a class that cannot be imported now produces a message instead of failing. (9.0.0) — [release notes](https://github.com/pytest-dev/pytest/releases/tag/9.0.0)
