Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

conftest.py: support importorskip at import, make every other outcome exception a usage error

Abierto
#15,142 0 comentarios 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 1 día

@RonnyPfannschmidt ya está trabajando en esto.

Desde el 6/10/2026.

  • #15143 de @RonnyPfannschmidt — abierto

Evaluación

Este issue todavía no se ha evaluado.

Descripción

topic: collection

🤖 Written by Claude Opus 5.5 via Claude Code for the pytest maintainers; I prompted it, it did the work, I read it.

Problem

A conftest.py is plugin code, not a collected module. Today an outcome exception raised while importing it does something different depending on how pytest was invoked:

conftest top level pytest tests pytest tests/sub or a node id
pytest.importorskip("missing") directory skipped, exit 0 raw Skipped traceback, exit 1 (#15141)
pytest.skip("x") (no allow_module_level) whole directory skipped, exit 0 (#12371) raw Skipped traceback, exit 1
pytest.fail("x") collection error, exit 2 raw traceback, exit 1
raise unittest.SkipTest("x") collection error, exit 2 collection error

(checked on main @ e84e063)

Why:

  • PytestPluginManager._importconftest wraps except Exception into ConftestImportFailure. OutcomeException derives from BaseException, so Skipped/Failed/XFailed slip past, while unittest.SkipTest (an Exception) is reported as an error.
  • During collection the conftest happens to be imported inside the Dir collector's CallInfo (pytest_make_collect_report in runner.py), so an escaped Skipped becomes a skip of the directory.
  • Initial conftests (_set_initial_conftests, for command-line args) have no collector around them, so the same exception crashes pytest.
  • The allow_module_level check exists only in python.importtestmodule, so a plain pytest.skip("x") in a conftest silently skips a whole package.

Real-world usage

Scan of 1648 conftest.py files in 177 popular repos:

  • Import-time outcome exceptions in conftests: 10 files in 6 repos (pandas, fsspec, kombu, ibis, salt, gunicorn). All of them are pytest.importorskip; there was no top-level pytest.skip/pytest.fail/raise SkipTest in any conftest. Typical: pa = pytest.importorskip("pyarrow") in pandas/tests/arrays/arrow/conftest.py, gating the directory and binding the module for the fixtures below in one line.
  • Alternatives in use are all worse for this job: conditional collect_ignore/collect_ignore_glob (14 repos, silent, a try/except per dependency, does not bind the module), pytest_ignore_collect (7 repos, silent), skip markers added from pytest_collection_modifyitems/pytest_runtest_setup (~12 repos, verbose, does not protect the conftest's own imports).

So importorskip in a conftest is a legitimate, useful idiom; everything else is an accident.

Proposal

  1. Support pytest.importorskip at conftest import. It skips the conftest's directory, consistently: also when the conftest is an initial conftest (command-line path or node id), which fixes #15141. A node id below the skipped directory reports the skip instead of ERROR: found no collectors.
  2. Every other outcome exception at conftest import is a usage error naming the conftest: pytest.skip() (with or without allow_module_level), pytest.fail(), pytest.xfail(). This resolves #12371.
    • pytest.skip() currently "works" during collection, so it gets a PytestRemovedIn10Warning (keeping today's directory skip) in 9.x and becomes the usage error in 10. fail/xfail already error during collection and crash on initial conftests, so they become the usage error right away.
  3. --import-mode=importlib: remove the conftest from sys.modules when its import raises, so a retry never sees a half-executed module (#15141, point 3).

Implementation note: importorskip raises a plain Skipped today, so it needs to be told apart, e.g. a private Skipped subclass or flag set only by importorskip (including its minversion skip).

Not affected: pytest.exit() (Exit is not an OutcomeException), outcome exceptions raised from conftest hooks or fixtures at runtime (node-scoped, already well-defined, see test_skip_file_by_conftest), and skips in a package __init__.py (a collected module, governed by allow_module_level).

Docs

Document importorskip in conftest.py as the supported way to gate a directory on an optional dependency, and state that no other skip/fail is allowed there.

Supersedes #12371 and #15141 (both closed in favour of this). Background: #4479.

Lenguaje dominante
Python
Estrellas
14.6k
Forks
3.5k
Merge medio
2 d 5 h
PR fusionados (30 d)
27

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de pytest-dev/pytest

Todos los issues de pytest-dev/pytest

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.