conftest.py: support importorskip at import, make every other outcome exception a usage error
Maintainer thường phản hồi trong vòng 1 ngày
@RonnyPfannschmidt đang làm issue này rồi.
Từ ngày 6/10/2026.
- #15143 của @RonnyPfannschmidt — đang mở
Đánh giá
Issue này chưa được đánh giá.
Mô tả
🤖 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._importconftestwrapsexcept ExceptionintoConftestImportFailure.OutcomeExceptionderives fromBaseException, soSkipped/Failed/XFailedslip past, whileunittest.SkipTest(anException) is reported as an error.- During collection the conftest happens to be imported inside the
Dircollector'sCallInfo(pytest_make_collect_reportinrunner.py), so an escapedSkippedbecomes 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_levelcheck exists only inpython.importtestmodule, so a plainpytest.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-levelpytest.skip/pytest.fail/raise SkipTestin any conftest. Typical:pa = pytest.importorskip("pyarrow")inpandas/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 frompytest_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
- Support
pytest.importorskipat 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 ofERROR: found no collectors. - Every other outcome exception at conftest import is a usage error naming the conftest:
pytest.skip()(with or withoutallow_module_level),pytest.fail(),pytest.xfail(). This resolves #12371.pytest.skip()currently "works" during collection, so it gets aPytestRemovedIn10Warning(keeping today's directory skip) in 9.x and becomes the usage error in 10.fail/xfailalready error during collection and crash on initial conftests, so they become the usage error right away.
--import-mode=importlib: remove the conftest fromsys.moduleswhen 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.
- Ngôn ngữ chính
- Python
- Star
- 14.6k
- Fork
- 3.5k
- Merge trung bình
- 2 ngày 6 giờ
- Pull request đã merge (30 ngày)
- 31
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của pytest-dev/pytest
-
Logging capture crashes when another thread registers a loggerCó thể đã có người làm @Spikhalskiy đã nhận 6 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
pytest-dev/pytest#15237 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Subtest durations become negative when `time` is mocked (subtests.py bypasses `_pytest.timing`)Có thể đã có người làm @RonnyPfannschmidt đã nhận 2 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
pytest-dev/pytest#15201 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
`faulthandler_timeout` stops covering a test once setup, call or a subtest fails (`pytest_exception_interact` cancels the timer)Có thể đã có người làm @mayur-dhavan đã nhận 2 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
pytest-dev/pytest#15180 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
monkeypatch.setattr fails to undo on objects with a custom __setattr__ (regression from #14969)Có thể đã có người làm @hardikkaurani đã nhận 33 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
pytest-dev/pytest#15099 · 6 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Allow dotted test filenames (`*.test.py`) via one-line change to `compute_module_name`Có thể làm lại được @siddy-stack đã nhận 70 ngày trước và không có pull request nào đang mở. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
pytest-dev/pytest#14514 · 6 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của pytest-dev/pytest
Issue tương tự
-
bug P1
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Toloka/tolokaforge#1947 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
SageMaker provider: streaming fails with NoStreamDataError on DJL Serving (LMI) endpointsCó thể đã có người làm @balajiaru đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
UKGovernmentBEIS/inspect_ai#6127 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
pydot/pydot#601 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
letsencrypt/cp-cps#361 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100