Skip to content

Proposals: import roots and packaged suites - #10824

Draft
RonnyPfannschmidt wants to merge 5 commits into
pytest-dev:mainfrom
RonnyPfannschmidt:draft-importmode-rootspec
Draft

RonnyPfannschmidt wants to merge 5 commits into
pytest-dev:mainfrom
RonnyPfannschmidt:draft-importmode-rootspec

Conversation

@RonnyPfannschmidt

@RonnyPfannschmidt RonnyPfannschmidt commented Mar 19, 2023 •

Copy link
Copy Markdown
Member

Requested by Ronny · project thread

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

This PR adds two design proposals under doc/en/proposals/. It contains no code. The goal is to agree on direction before any implementation PRs.

import_roots.rst: import roots. This is an opt-in, declarative alternative to --import-mode, configured in TOML. Each root states how part of the world maps onto the import system:

  • local: tests that aren't shipped. The convention is a top-level testing/ folder. Modules import under the root's required name, without any sys.path mutation.
  • mirrored: worktree source of an installed distribution, imported under its real name. Editable installs need no check, and a stale non-editable install fails collection.
  • installed: an installed distribution with no worktree involved, for example a test suite shipped inside a package.

Without roots configured, behaviour is unchanged. With roots configured, they replace --import-mode and pythonpath, and --pyargs resolves through them. Name collisions are hard errors, and there are no shims, aliases or implicit subprocess support.

packaged_suites.rst: packaged suites. A package can ship a test suite, for example a conformance suite for an interface, and declare its parameters in Python (SuiteSpec). A consuming project binds it from an initial conftest through a hook (pytest_bind_suites). Each binding becomes its own collector with scoped fixtures, so one suite can run against several implementations in one session. This replaces today's per-project workarounds: pandas and fsspec subclassing, SQLAlchemy's star-import plus setup.cfg sections, and array-api-tests' environment variable. A prototype plugin against main confirmed the collection, fixture scoping, parametrization and early validation behaviour. Packaged suites are independent of import roots and could land first.

Names in both documents are provisional. The packaged-suites naming deliberately avoids Test* names, which collection picks up, as well as unittest.TestSuite and junit-xml's "testsuite". It aligns with the *Spec vocabulary of the ensemble PoC (#14809).

Feedback wanted on:

  • the three root kinds and the TOML shape,
  • Python declaration plus hook binding for suites, versus alternatives such as fixture slots or TOML parameters,
  • names.

Related: #15022 (assertion rewriting of __init__.py under importlib mode, which a new finder would also hit), #14709 and #13257 (namespace shadowing that import roots aims to remove), #14809 (ensembles).

@RonnyPfannschmidt
RonnyPfannschmidt force-pushed the draft-importmode-rootspec branch from a03a8fa to c37f550 Compare March 20, 2023 15:27
@RonnyPfannschmidt

Copy link
Copy Markdown
Member Author

Note on implementation,

This will require py3.9+ importlib_metadata apis for the details on resource

An accompanying note to migrate to their apis seems necessary (so that pytest can warn on stale resources as well

The best way to register test root namespaces is still unclear

@RonnyPfannschmidt

Copy link
Copy Markdown
Member Author

@bluetech i wonder if this proposal/idea could integrate with directory/package collection enhancements/changes in a way that allows migration

:orphan:

===================================
PROPOSAL: Parametrize with fixtures

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to adjust this

Comment on lines +16 to +17
test module discovery in pytest currently is is pre-pep40 and create pains for users
by adding anything things to sys.path and creating easy conflicts in sys.modules

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
test module discovery in pytest currently is is pre-pep40 and create pains for users
by adding anything things to sys.path and creating easy conflicts in sys.modules
Test module discovery in pytest currently is is pre-PEP420 and creates pain for users
by adding things to ``sys.path`` and creating easy conflicts in ``sys.modules``.

A new import mode take a definition of import roots.

a import root is either a folder in the worktree that will no be installed,
or a folder that will be installed either normally or editable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is installation done? Like pytest will install to the venv with pip?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users Will have to manage install, pytest should never do that part


In any case pytest will collect the file tree in the working directory.

If normal install us used and the content of the imported file differs from the working directory,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If normal install us used and the content of the imported file differs from the working directory,
If normal install is used and the content of the imported file differs from the working directory,

@gpshead

gpshead commented Apr 4, 2025

Copy link
Copy Markdown

... any chance this proposal might happen? (I realize that's probably just asking if anyone is going to take on the work and I"m not here volunteering so... mostly just poking it to see if there is interest)

@RonnyPfannschmidt

Copy link
Copy Markdown
Member Author

I have 2 refactoring of horror higher on my priority Lust ans im currently very thin stretched for time on that

@nicoddemus

Copy link
Copy Markdown
Member

Read it and leaving a comment that this sounds like a step in the right direction. 👍

@RonnyPfannschmidt
RonnyPfannschmidt force-pushed the draft-importmode-rootspec branch from 4523cda to ae35c6f Compare October 4, 2026 13:06
@RonnyPfannschmidt RonnyPfannschmidt changed the title Proposal: root spec import mode to replace legacy importing and importmode Proposals: import roots and packaged suites Oct 6, 2026
@RonnyPfannschmidt
RonnyPfannschmidt force-pushed the draft-importmode-rootspec branch from 20a48c5 to 238de34 Compare October 11, 2026 07:26
RonnyPfannschmidt and others added 5 commits October 14, 2026 22:10
Rename the proposal from importmode_root_spec to import_roots and
reposition it as a declarative alternative that replaces --import-mode
instead of adding a fourth mode:

* update the problem statement for the pytest 8 importlib rework
  (real module names, sys.modules insertion) and ground it in the
  modern import system (PEP 420/451/610/660, importlib.metadata)
* specify implied roots for simple layouts with a hard failure on
  ambiguity instead of guessing
* specify minimal editable vs real vs stale install classification
  via PEP 610 direct_url.json, with StaleInstallError on divergence
* fix the copy-pasted title and turn the todo notes into a proper
  test case matrix

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collection targets must map to exactly one root, testpaths entries act
as an inference signal for local roots, and conftest files above every
root are recorded as an open naming question.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Suites shipped inside installed packages declare their parameters in
Python (SuiteSpec) and are bound by the consuming project's initial
conftests via a hook (pytest_bind_suites). Names are provisional and
chosen to avoid the Test* collection trap, unittest.TestSuite and the
junit-xml testsuite meaning.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ae6NTCLoJgE5chCkbn19HX
Roots are opt-in (no behaviour change without them), TOML-only, with
three kinds (local, mirrored, installed) and a required name. Local
roots use declared names with a collision check and no sys.path,
aliases or subprocess support. --pyargs resolves through roots;
pythonpath is superseded. Implied roots are dropped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ae6NTCLoJgE5chCkbn19HX
@RonnyPfannschmidt
RonnyPfannschmidt force-pushed the draft-importmode-rootspec branch from 238de34 to dddf9e7 Compare October 14, 2026 20:28

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip news used on prs to opt out of the changelog requirement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants