|
oct
|
Classes | |
| class | FileEntry |
| class | ParallelManifest |
| class | ModuleAnalysis |
| class | _StaticDetector |
| class | _Tracer |
Functions | |
| str | keyed (str family, str key) |
| str | resource_family (str resource) |
| str|None | resource_key (str resource) |
| bool | conflicts_with (str left, str right) |
| bool | is_conflicting (str resource) |
| bool | is_known_resource (str resource) |
| str | unknown (str detail) |
| str | resource_for_path_hint (str hint) |
| str|None | path_key (str hint) |
| str | write_resource (str hint, str|None key) |
| str|None | launch_family (Any argv) |
| frozenset[str] | launch_resources (Any argv) |
| set[str] | _target_names (ast.AST node) |
| bool | _is_tmp_expr (ast.AST|None node, frozenset[str] tainted) |
| tuple[bool, bool] | _fixture_decorated (ast.AST node) |
| bool | _returns_tmp (ast.AST node, frozenset[str] tainted) |
| frozenset[str] | _collect_taint (ast.AST tree, Iterable[str] seeds) |
| Iterable[ast.AST] | _scope_nodes (ast.AST tree) |
| bool | _proven_tmp_expr (ast.AST|None node, frozenset[str] tainted) |
| frozenset[str] | _scope_proofs (ast.AST tree, Iterable[str] seeds, *, Iterable[str] parameters=()) |
| set[str] | _parameter_names (ast.FunctionDef|ast.AsyncFunctionDef node) |
| dict[ast.AST, frozenset[str]] | _helper_parameter_taints (ast.Module tree, frozenset[str] base, Iterable[str] seeds=()) |
| list[ast.Call] | _closed_helper_calls (ast.Module tree, ast.FunctionDef|ast.AsyncFunctionDef helper, Mapping[ast.AST, ast.AST] parents) |
| ast.AST|None | _helper_actual (ast.FunctionDef|ast.AsyncFunctionDef helper, ast.Call call, str name) |
| set[str] | _rebound_parameters (ast.AST tree, set[str] names) |
| dict[str, str] | _import_hints (ast.AST tree) |
| str|None | _hint_for_dotted (str dotted) |
| str | _string_hint (ast.AST|None node) |
| bool | _is_absolute_literal (str text) |
| str | _join_literal (str left, str right) |
| str|None | _parent_literal (str text) |
| bool | _is_pid_expr (ast.AST|None node) |
| str|None | _literal_fstring (ast.JoinedStr node) |
| bool | _is_os_path_join (ast.AST func) |
| str|None | _literal_parents_index (ast.Subscript node, Mapping[str, str] constants) |
| str|None | _literal_path (ast.AST|None node, Mapping[str, str]|None constants=None) |
| str|None | _literal_sequence (ast.Call node, Mapping[str, str] constants, *, Callable[[str, str], str] joiner) |
| dict[str, int] | _binding_counts (ast.AST tree) |
| dict[str, str] | _module_constants (ast.Module tree, str|None module_path) |
| str|None | _argv_element (ast.AST node) |
| list[str|None]|None | _literal_argv (ast.Call node, str attr) |
| bool | _write_mode (ast.Call node) |
| bool | _is_path_replace (ast.Call node) |
| bool | _is_environ (ast.AST|None node) |
| frozenset[str] | _requested_names (ast.AST tree) |
| ModuleAnalysis | analyse_source (str source, *, str filename="<test>", Iterable[str] tmp_seeds=()) |
| frozenset[str] | classify_source (str source, *, str filename="<test>", Sequence[ModuleAnalysis] conftests=()) |
| str | _read (Path path) |
| list[ModuleAnalysis] | _conftest_chain (Path root, Path path, dict[Path, ModuleAnalysis] cache) |
| dict[str, frozenset[str]] | classify_tree (Path root, Sequence[str] test_roots, *, str pattern="test_*.py") |
| str | _find (dict[str, str] parent, str path) |
| None | _union (dict[str, str] parent, str left, str right) |
| str | _slug (str resource) |
| list[tuple[str, list[str]]] | _named_components (Mapping[str, list[str]] components, Mapping[str, frozenset[str]] sets) |
| dict[str, str] | build_groups (Mapping[str, Iterable[str]] classified, *, Mapping[str, str]|None pins=None) |
| dict[str, Any] | build_manifest (Mapping[str, Iterable[str]] classified, *, str tool_version, Mapping[str, str]|None pins=None, str|None generated_at=None) |
| None | write_manifest (Path path, Mapping[str, Any] document) |
| ParallelManifest | load_manifest (Path path) |
| tuple[dict[str, str], tuple[str,...]] | resolve_groups (ParallelManifest manifest, Iterable[str] relpaths) |
| int | _raw_max_workers (Path workspace_root, str package) |
| int | resolve_max_workers (Path workspace_root, str package) |
| int | available_cpu_count () |
| int | resolve_worker_count (Path workspace_root, str package, *, int|None cpu_count=None) |
| str | free_group_name (str nodeid, *, bool whole_file=False) |
| tuple[tuple[str,...], str|None] | apply_group_marks (Any config, Iterable[Any] items, Path manifest_path) |
| bool | is_xdist_worker (Any config) |
| None | _adopt_group_dist_in_worker (Any config, Any option, str dist) |
| int|None | configure_parallel_defaults (Any config, *, Path workspace_root, str package, str dist="loadgroup") |
| bool | _from_pytest_internals (int depth=4) |
| bool | _is_pid_stamped (str basename, str pid) |
| None | pytest_addoption (Any parser) |
| None | pytest_configure (Any config) |
| None | pytest_runtest_logstart (str nodeid, Any location) |
| None | pytest_runtest_logfinish (str nodeid, Any location) |
| None | pytest_sessionfinish (Any session, Any exitstatus) |
| dict[str, set[str]] | load_traces (Sequence[Path] sources) |
| tuple[Path, str, tuple[str,...]] | _package_for_root (Path root) |
| Path | default_manifest_path (Path root, Sequence[str] test_roots) |
| dict[str, str] | _parse_pins (Sequence[str] values) |
| str | _tool_version () |
| None | _print_summary (Mapping[str, Any] document, Path out, Path workspace_root, str package) |
| list[str] | diff_manifests (Mapping[str, Any] committed, Mapping[str, Any] fresh) |
| int | run_classify (Sequence[str] argv) |
| int | _run_check (Path out, Mapping[str, Any] document) |
| int | main (Sequence[str]|None argv=None) |
Variables | |
| int | DEFAULT_MAX_WORKERS = 24 |
| str | RES_REGISTRY_SQLITE = "registry_sqlite" |
| str | RES_COMMS_ROOT = "comms_root" |
| str | RES_SETTINGS_FILE = "settings_file" |
| str | RES_OCTRC = "octrc" |
| str | RES_WORKTREE_DIR = "worktree_dir" |
| str | RES_MAIN_TREE_WRITE = "main_tree_write" |
| str | RES_ENV_SUBPROCESS = "env_subprocess" |
| str | RES_ENV_MUTATION = "env_mutation" |
| str | RES_NETWORK = "network" |
| str | RES_CWD_CHANGE = "cwd_change" |
| str | RES_GLOBAL_SINGLETON_RESET = "global_singleton_reset" |
| str | PORT_PREFIX = "port:" |
| str | UNKNOWN_PREFIX = "unknown:" |
| tuple | RESOURCE_VOCABULARY |
| frozenset | PROCESS_LOCAL_RESOURCES |
| str | KEY_SEPARATOR = ":" |
| frozenset | KEYED_FAMILIES |
| str | OUTSIDE_KEY = "<outside>" |
| str | SCHEMA_VERSION = "1.0" |
| str | MANIFEST_FILENAME = "parallel_manifest.json" |
| str | GROUP_FREE = "free" |
| str | GROUP_UNCLASSIFIED = "unclassified-serial" |
| str | FREE_GROUP_PREFIX = f"{GROUP_FREE}:" |
| str | WHOLE_FILE_MARKER = "whole_file" |
| str | PYTHON_ARGV0 = "<python>" |
| _PYTHON_PROGRAM = re.compile(r"^python[0-9tw.]*$", re.IGNORECASE) | |
| frozenset | _PYTHON_FLAGS |
| dict | LAUNCH_FAMILIES |
| frozenset | _TMP_SEEDS |
| frozenset | _TMP_CALLS |
| frozenset | _PATH_WRITES |
| frozenset | _OS_WRITES |
| dict | _SHUTIL_WRITES |
| frozenset | _SUBPROCESS_ATTRS |
| frozenset | _SUBPROCESS_MODULES |
| frozenset | _SUBPROCESS_NAMES |
| frozenset | _NETWORK_ATTRS |
| frozenset | _NETWORK_MODULES |
| frozenset | _RESET_NAMES |
| dict | _MODULE_HINTS |
| frozenset | _PATH_CONSTRUCTORS |
| frozenset | _PATH_IDENTITY_CALLS = frozenset({"resolve", "absolute"}) |
| str | _PID_PLACEHOLDER = "0" |
| int | _MAX_PARENTS_INDEX = 64 |
| str | TRACE_OPTION = "--oct-trace" |
| tuple | _TRACE_IGNORED |
| int | EXIT_MANIFEST_DRIFT = 4 |
Purpose
-------
Resource-keyed test parallelism (Plan 239 / TEST-01). A pytest worker
is a separate PROCESS, so in-process state is per-worker and safe;
what collides across workers is shared EXTERNAL state (a registry
database, a comms root, a tracked settings file, a bound port, writes
outside ``tmp_path``). This module classifies every test file by the
shared resources it touches, groups the conflicting files into the
connected components of that conflict graph, and hands the grouping to
pytest through xdist's ``--dist loadgroup``.
Responsibilities
----------------
- Pin the CLOSED resource vocabulary (Plan 239 P2), its KEYED
refinement (Plan 247 P1: ``main_tree_write:<top>`` and
``env_subprocess:<family>``) and the ``unknown:<detail>``
fail-closed escape hatch.
- STATIC detector: an :mod:`ast` pass over each test file plus the
conftest fixtures it actually requests (:func:`analyse_source`,
:func:`classify_source`, :func:`classify_tree`).
- DYNAMIC detector: the ``--oct-trace`` pytest plugin, which wraps
``open`` / ``os.environ`` / ``socket.bind`` / ``subprocess`` /
``os.chdir`` for the duration of each test and writes a per-process
trace (:func:`load_traces`).
- Grouping and the committed manifest (:func:`build_groups`,
:func:`build_manifest`, :func:`load_manifest`,
:func:`resolve_groups`).
- The pytest-side seams a root conftest calls
(:func:`resolve_worker_count`, :func:`configure_parallel_defaults`).
- The regeneration CLI: ``python -m oct.testing.parallel classify
--root <subproject root>``.
Diagnostics
-----------
Domain: OCT-TESTING
Levels:
L2: lifecycle (classification start/end, tracer install/remove)
L3: semantic details (resolved cap, group counts)
L4: deep tracing (per-file resource sets)
Contracts
---------
- A file's classification is the UNION of both detectors (P3):
neither alone is authoritative. The union is why BOTH detectors
must key what they can - one bare verdict re-widens a file the
other had already narrowed.
- The vocabulary is CLOSED. A signature the detectors cannot map into
it is recorded as ``unknown:<detail>``, which conflicts with every
file that carries any resource at all (fail closed, P2/P4).
- A KEY only ever NARROWS (Plan 247 P1). Two keyed tokens of one
family conflict when their keys are equal; a BARE family token
conflicts with every member of its family, so anything a detector
cannot attribute keeps precisely its pre-247 behaviour. Only
``unknown:*`` is a GLOBAL wildcard; a bare family token is not.
- The ENVIRONMENT is process-local for grouping (Plan 276 P1/P2). An
``os.environ`` write is recorded as ``env_mutation`` and connects
the file to nothing: a worker is a separate PROCESS, so a write in
one can never reach a child another one spawns. ``env_subprocess``
is therefore recorded for a CHILD LAUNCH only, and a BARE launch is
the one family wildcard that holds just the other bare launches -
what a child does to genuinely shared state is what its
:data:`LAUNCH_FAMILIES` entry declares (``main_tree_write:*``), and
``unknown:*`` still fails closed on everything else.
- Manifest keys are ROOT-RELATIVE POSIX paths, identical to the path
part of a pytest nodeid. Every recorded value is machine
independent: the manifest is committed, so no absolute path, user
name or temp directory may ever reach it.
- A conftest contributes its AUTOUSE fixtures' resources to every file
beneath it and its other fixtures' resources to the files that
request them by name. Module-level conftest code and conftest hook
functions are session-level uses that per-file grouping cannot
separate, so they are deliberately not attributed to files.
- ``pytest`` is NEVER imported at module scope: it is an optional
(``[test]`` extra) dependency of oct, so the plugin hooks below are
plain functions that pytest discovers by name.
- No ``sys.exit`` outside the ``__main__`` CLI block.
Dependencies
------------
- oct.core.diagnostics (_dbg)
- oct.testing.errors (the spec-10 §12.4 taxonomy as data)
- oct.testing.manifest (the §9 workspace test blocks; ``max_workers``)
- oct.tools.atomic_write (atomic_write_text for writing the committed manifest)
- oct.core.workspace (lazy; find_workspace_root for the classify CLI)
- oct (lazy; the oct version recorded in the manifest)
- pytest (lazy; the xdist_group marker and UsageError in the plugin hooks)
- xdist (not imported; the pytest-xdist plugin whose worker count and loadgroup scheduling this module configures)
|
protected |
Re-assert ``loadgroup`` inside an xdist worker process. xdist ships the CONTROLLER's ORIGINAL command line to each worker (``workermanage.WorkerController.setup`` sends ``config.invocation_params.args``), so an in-memory ``--dist`` chosen by :func:`configure_parallel_defaults` is invisible there. The worker's ``remote.setup_config`` derives its private ``option.loadgroup`` flag from the dist it can see and then forces ``dist='no'``; that flag is what makes the worker append the ``@<group>`` nodeid suffix the ``loadgroup`` scheduler reads, so without this the marks are collected and then ignored, and a group silently spreads across workers (measured, 2026-09-06). An explicit ``--dist`` on the command line is left alone: there the worker already computed the flag from the operator's choice.
Definition at line 2490 of file parallel.py.
|
protected |
One argv element as a literal string, or None when unreadable.
Definition at line 1472 of file parallel.py.
|
protected |
How many times each name is BOUND anywhere in a module (P1). A module constant is only readable while it is a constant, so the resolver admits a name bound exactly once - by the module-level assignment it read. Everything that can put a different value behind a name counts here: a second assignment, a parameter, a ``def``/``class``, an import alias, an ``except`` or ``match`` capture. A ``global``/``nonlocal`` declaration counts twice, which disqualifies the name outright: it can rewrite the constant from a scope this walk cannot order.
Definition at line 1388 of file parallel.py.
|
protected |
Return every direct call, or no proof when the helper can escape.
Definition at line 1043 of file parallel.py.
|
protected |
Fixpoint over the names bound to a temporary-path value.
Parameters
----------
tree
The parsed module.
seeds
Extra names to seed with: the temp-returning fixtures of the
conftests above this module.
Returns
-------
frozenset[str]
Every name a write target may safely be derived from.
Definition at line 806 of file parallel.py.
|
protected |
Analyse every ``conftest.py`` from *root* down to *path*.
Definition at line 1881 of file parallel.py.
|
protected |
Union-find root of *path*, with path compression.
Definition at line 1959 of file parallel.py.
|
protected |
Return ``(is_fixture, is_autouse)`` for a function definition.
Definition at line 774 of file parallel.py.
|
protected |
True when the calling code is pytest's own machinery. ``monkeypatch.setenv`` writes through ``os.environ`` like any other caller, but it records an undo, so it is not a leak and must not be recorded as one. Neither is pytest's own ``PYTEST_CURRENT_TEST`` bookkeeping - which reaches ``__delitem__`` through ``MutableMapping.pop`` in ``<frozen _collections_abc>``, so the search skips FROZEN frames and judges the first real one. Without that skip every file in a suite reads as an environment writer (measured on all 324 oc_chat files, 2026-09-06).
Definition at line 2575 of file parallel.py.
|
protected |
Read a parameter's actual argument; omissions stay unresolved.
Definition at line 1083 of file parallel.py.
|
protected |
Prove helper parameters from every visible call, without name leakage. Only direct references to uniquely named module functions qualify. An escaping reference, reflection, rebinding or starred call keeps the helper opaque. Inferred names belong to that function's scope only.
Definition at line 949 of file parallel.py.
|
protected |
The hinted resource of a dotted module path, if any.
Definition at line 1129 of file parallel.py.
|
protected |
Map names imported from a hinted module to their resource.
Definition at line 1109 of file parallel.py.
|
protected |
True when a literal path fragment is not root-relative. The same three shapes :func:`path_key` refuses - a leading slash, a drive letter, and anything else carrying the key separator in its first component - because a fragment that is absolute swallows everything joined BEFORE it.
Definition at line 1177 of file parallel.py.
|
protected |
True when *node* is ``os.environ`` or a subscript of it.
Definition at line 1561 of file parallel.py.
|
protected |
True for the fully spelled ``os.path.join`` attribute chain.
Definition at line 1266 of file parallel.py.
|
protected |
True only for the one-argument ``pathlib.Path.replace`` (P1). ``replace`` is the one name in :data:`_PATH_WRITES` that several unrelated types also carry, and the ARITY separates them exactly. ``Path.replace(target)`` takes one argument, positionally or by that keyword name; ``str.replace(old, new)`` needs at least two; ``datetime.replace`` names a field, never ``target``; and ``dataclasses.replace(record, **changes)`` passes the record plus its changes. Measured on the oc_chat suite (Plan 284 P0): fifteen of the thirty-eight files carrying the BARE ``main_tree_write`` carried it for a write that does not exist, and a bare token welds every keyed writer of its family into one group. This narrows how the CALL is read, never the vocabulary. A real ``Path.replace`` still records its write, and ``os.replace`` / ``shutil`` are matched by their own earlier arms and never reach here.
Definition at line 1535 of file parallel.py.
|
protected |
True when *node* is ``os.getpid()``, or a ``str()`` of one.
Definition at line 1228 of file parallel.py.
|
protected |
True when *basename* carries *pid* as a whole token. A pid-stamped artefact - oc_diagnostics writes ``logs/unified_debug_logs_<stamp>_p<pid>.txt`` - is per-process by construction, so it can never collide across workers, and it is written lazily by whichever test happens to initialise diagnostics first, so attributing it would make the classification depend on run order. The match is on WHOLE tokens, never a substring. A bare ``str(pid) in basename`` silently swallowed a GENUINE ``main_tree_write``: with pid 648, the artefact filename ``..._1788651058142648000_6d28ee.txt`` (a nanosecond stamp) matched by coincidence, which dropped ``tests/unit/test_203_event_payload_completeness.py`` out of its conflict group and made the classification differ between two runs of the same tree (gate finding R1, measured 2026-09-06).
Definition at line 2600 of file parallel.py.
|
protected |
True when *node* is derived from a temporary directory.
Definition at line 759 of file parallel.py.
|
protected |
Join two literal fragments the way ``pathlib`` joins them.
An absolute right operand DISCARDS the left one - ``Path('docs') /
'/var/lib'`` is ``/var/lib`` - so reading the left as the key would
invent a directory the write never touches. Returning the right
operand whole hands :func:`path_key` an absolute path, which it
already refuses.
Definition at line 1189 of file parallel.py.
|
protected |
The argv of a launch call, as far as the literals allow (P3). ``create_subprocess_exec`` takes the program and its arguments as separate positional parameters; every other seam takes one sequence. A STARRED element hides the length and the position of everything AFTER it, so the argv is truncated there and only the readable PREFIX comes back (Plan 276 P3). The prefix decides the family and nothing else: the family is the PROGRAM - ``argv[0]``, plus the ``-m <module>`` pair when ``argv[0]`` is an interpreter - and a starred tail cannot change what the program is. A prefix too short to name a module still reads as the bare interpreter, which the table deliberately does not vouch for, and an argv whose FIRST element is starred has no readable program at all and stays bare. Measured on the oc_chat suite (2026-09-15): nine ``['git', *args]`` helpers and one ``[sys.executable, '-m', 'oc_chat.scripts.replay', *args]`` helper were bare for this reason alone.
Definition at line 1485 of file parallel.py.
|
protected |
An f-string read as a path when its placeholders cannot move the key.
The key is the FIRST component, so a placeholder is harmless
exactly while every separator in the string comes BEFORE it: a pid
stamped into the basename leaves the directory literal, and
``f'{os.getpid()}/run.txt'`` does not. Only the pid qualifies as a
placeholder at all - a temp-derived one never reaches here, because
:meth:`_StaticDetector._write` drops the write before it asks for a
key, and anything else is a value this pass cannot read.
Definition at line 1238 of file parallel.py.
|
protected |
``<literal>.parents[N]`` for a constant, non-negative literal N.
Definition at line 1277 of file parallel.py.
|
protected |
The path *node* names when this pass can read it in full (P2).
``_string_hint`` deliberately mashes names and attributes together
so a MARKER can be spotted anywhere in an expression; that mash is
useless as a key, because ``Path('docs/x')`` would key on ``Path``
and land in a different group from ``open('docs/y', 'w')`` - two
writes into the same directory, separated. So keying reads the
expression strictly instead: a constant, a ``Path(...)`` of
constants, or a ``/`` join of those.
Plan 284 P1 widens WHAT counts as readable without widening how
loosely it is read. *constants* carries the module's own
unambiguous names - ``__file__`` among them, bound to the module's
ROOT-RELATIVE path - so ``Path(__file__).resolve().parent /
'golden'`` names a real directory instead of an opaque one. Each
added shape either resolves completely or yields None; none of them
guesses at a component it could not read.
Parameters
----------
node
The expression naming a write target.
constants
Module-level names this pass proved to be literal paths, as
:func:`_module_constants` builds them. Absent, the function
reads exactly what it read before Plan 284.
Returns
-------
str | None
A path in :func:`path_key`'s space - root-relative unless the
expression itself was absolute or escaped upward - or None when
any part of the expression is unreadable.
Definition at line 1300 of file parallel.py.
|
protected |
Fold a call's positional arguments through *joiner*, or None.
Definition at line 1370 of file parallel.py.
|
protected |
The module-level names that unambiguously name a literal path (P1).
Read in SOURCE ORDER, so a constant may be built from one declared
above it - the shape the suite writes as ``ROOT = ...`` then
``SEED = ROOT / 'seed'`` - and never from one declared below, which
does not exist yet at that point in the module either.
Parameters
----------
tree
The parsed module.
module_path
The module's ROOT-RELATIVE POSIX path, or None when the caller
analysed a source string with no place in the tree. It is what
``__file__`` resolves to; without it the anchor stays opaque
and every shape built on it stays bare.
Returns
-------
dict[str, str]
Name -> literal path, for names bound exactly once.
Definition at line 1428 of file parallel.py.
|
protected |
Assign deterministic names to the conflict components.
Definition at line 1979 of file parallel.py.
|
protected |
Resolve *root* to its workspace, package name and test roots.
Definition at line 2957 of file parallel.py.
|
protected |
All names bound by one function's argument specification.
Definition at line 941 of file parallel.py.
|
protected |
The parent of a root-relative literal fragment, or None (P1). Climbing past the package root yields a ``..`` prefix rather than an empty string, because the two mean different things and only the first is an escape: the root itself is a legitimate location with no top-level component, while ``..`` is outside the tree the manifest describes. :func:`path_key` refuses both, which is the fail-closed answer for each.
Definition at line 1207 of file parallel.py.
|
protected |
Parse repeated ``--pin <path>=<group>`` arguments.
Definition at line 2989 of file parallel.py.
|
protected |
Print an ASCII-only summary of a regeneration.
Definition at line 3012 of file parallel.py.
|
protected |
Read a helper actual without assuming an opaque call returns its input.
Definition at line 864 of file parallel.py.
|
protected |
Read ``max_workers`` straight from the manifest JSON. The compatibility path for an INSTALLED ``oct.testing.manifest`` that predates the P1 key; it applies the same validation the parser does, so an invalid value still refuses rather than degrading to the default.
Definition at line 2239 of file parallel.py.
|
protected |
Read *path* as UTF-8, tolerating a stray decoding error.
Definition at line 1876 of file parallel.py.
|
protected |
Reject new parameter proofs when the body assigns their names.
Definition at line 1102 of file parallel.py.
|
protected |
Every parameter name any function in *tree* requests.
Definition at line 1759 of file parallel.py.
|
protected |
True when every value a fixture body returns/yields is temp.
Definition at line 793 of file parallel.py.
|
protected |
The ``--check`` half of :func:`run_classify`.
Definition at line 3144 of file parallel.py.
|
protected |
Walk one lexical body without importing names from nested bodies.
Definition at line 851 of file parallel.py.
|
protected |
Prove local aliases only when every binding has a temporary origin.
Definition at line 888 of file parallel.py.
|
protected |
Group-name form of a resource token.
Definition at line 1974 of file parallel.py.
|
protected |
Join every string constant, attribute and name inside *node*.
Definition at line 1137 of file parallel.py.
|
protected |
Every plain name bound by an assignment target *node*.
Definition at line 752 of file parallel.py.
|
protected |
The oct version string recorded in the manifest.
Definition at line 3003 of file parallel.py.
|
protected |
Merge the components of *left* and *right*.
Definition at line 1967 of file parallel.py.
|
protected |
True when an ``open``-like call requests a writing mode.
Definition at line 1520 of file parallel.py.
| ModuleAnalysis oct.testing.parallel.analyse_source | ( | str | source, |
| * | , | ||
| str | filename = "<test>", | ||
| Iterable[str] | tmp_seeds = () ) |
Statically analyse one module.
Parameters
----------
source
Module source text.
filename
Reported in diagnostics only.
tmp_seeds
Fixture names from an enclosing conftest whose value is a
temporary path; requesting one taints the parameter.
Returns
-------
:class:`ModuleAnalysis`
Notes
-----
A file that does not parse is not silently clean: it comes back
carrying ``unknown:parse-error``, which conflicts with everything.
Definition at line 1770 of file parallel.py.
| tuple[tuple[str, ...], str | None] oct.testing.parallel.apply_group_marks | ( | Any | config, |
| Iterable[Any] | items, | ||
| Path | manifest_path ) |
Stamp every collected item with its scheduling group (P4/P5).
Call from a root conftest's ``pytest_collection_modifyitems``
under ``@pytest.hookimpl(tryfirst=True)``: xdist's worker-side
hook is what turns the mark into the ``@<group>`` nodeid suffix
its scheduler reads, and it runs FIRST otherwise, so a later mark
is collected and then ignored.
A file in a real conflict group, and a file the manifest does not
classify, are stamped with that group's ONE name, exactly as
before: both mean "these tests must not run beside each other".
A ``free`` file's items each carry their own name through
:func:`free_group_name` (Plan 286 P1), because a free file shares
nothing and one name is one worker.
Parameters
----------
config
The pytest ``Config``.
items
The collected items, modified in place.
manifest_path
The committed ``parallel_manifest.json``.
Returns
-------
tuple
``(missing, manifest_error)``: the collected files with no
manifest entry, and the load failure when the manifest itself
could not be read. Both are fail-closed states - every
affected item is stamped :data:`GROUP_UNCLASSIFIED`, so it
runs serially with respect to the other unclassified files
and a completeness check can fail the run by name.
Definition at line 2402 of file parallel.py.
| int oct.testing.parallel.available_cpu_count | ( | ) |
The affinity-aware CPU count (ADR-T-11's v0.4 amendment).
The ONE normative resolution every worker-count formula reads::
os.process_cpu_count() # Python >= 3.13
else len(os.sched_getaffinity(0)) # where the OS exposes it
else (os.cpu_count() or 1)
A bare ``os.cpu_count()`` overcounts inside a container and under
CPU affinity (OI-027) - exactly where over-spawning hurts most.
Definition at line 2322 of file parallel.py.
| dict[str, str] oct.testing.parallel.build_groups | ( | Mapping[str, Iterable[str]] | classified, |
| * | , | ||
| Mapping[str, str] | None | pins = None ) |
Group files into the connected components of the conflict graph.
Files sharing any CONFLICTING resource are connected, where
"sharing" follows :func:`conflicts_with`: two KEYED tokens share
only when their keys are equal, and a BARE family token shares
with every keyed member of its own family (Plan 247 P1). A file
carrying an ``unknown:*`` token connects to every file that
carries any conflicting resource (fail closed, P2); a file left
with none - no resources at all, or only
:data:`PROCESS_LOCAL_RESOURCES` - is :data:`GROUP_FREE` and
connects to nothing. Names derive from each component's own
sorted resources, so the same input always produces the same
names.
``env_subprocess`` is the one family whose BARE token does not
reach its keyed members (Plan 276 P2). A worker is a separate
PROCESS, so the environment a child inherits never crosses one,
and an unattributable launch therefore holds only the other
unattributable launches. Measured on the oc_chat suite
(2026-09-15): the removed weld alone put 100 files carrying a
quarter of the suite's tests into a single group, of which 46
held the bare token.
Parameters
----------
classified
Root-relative path -> resource set.
pins
Operator-pinned ``path -> group`` overrides (P7). A pinned
file leaves the graph entirely and keeps its own group name.
Returns
-------
dict[str, str]
Root-relative path -> group name.
Definition at line 2002 of file parallel.py.
| dict[str, Any] oct.testing.parallel.build_manifest | ( | Mapping[str, Iterable[str]] | classified, |
| * | , | ||
| str | tool_version, | ||
| Mapping[str, str] | None | pins = None, | ||
| str | None | generated_at = None ) |
Build the committed manifest document (the P4 shape).
Definition at line 2120 of file parallel.py.
| frozenset[str] oct.testing.parallel.classify_source | ( | str | source, |
| * | , | ||
| str | filename = "<test>", | ||
| Sequence[ModuleAnalysis] | conftests = () ) |
Classify one test module, folding in the conftests above it. A file inherits the resources of every AUTOUSE conftest fixture on its path, plus those of the conftest fixtures it requests by name (P3a).
Definition at line 1848 of file parallel.py.
| dict[str, frozenset[str]] oct.testing.parallel.classify_tree | ( | Path | root, |
| Sequence[str] | test_roots, | ||
| * | , | ||
| str | pattern = "test_*.py" ) |
Statically classify every test file under *test_roots*.
Parameters
----------
root
Subproject root; manifest keys are relative to it.
test_roots
Root-relative test directories (the workspace manifest's
``test.test_roots``).
pattern
Test-file glob, matching pytest's ``python_files``.
Returns
-------
dict[str, frozenset[str]]
Root-relative POSIX path -> resource set.
Definition at line 1909 of file parallel.py.
| int | None oct.testing.parallel.configure_parallel_defaults | ( | Any | config, |
| * | , | ||
| Path | workspace_root, | ||
| str | package, | ||
| str | dist = "loadgroup" ) |
Turn parallelism on by default for a run (P5).
Call this from a root conftest's ``pytest_cmdline_main`` under
``@pytest.hookimpl(tryfirst=True)``: xdist's own ``tryfirst`` hook
is what turns ``numprocesses`` into ``tx`` endpoints, so a later
assignment engages nothing.
Returns
-------
int | None
The resolved worker count, or ``None`` when the run was left
alone: an xdist worker process, a nested run inside one,
``-p no:xdist``, or an explicit ``-n`` on the command line.
Definition at line 2515 of file parallel.py.
| bool oct.testing.parallel.conflicts_with | ( | str | left, |
| str | right ) |
True when two resource tokens can collide (the P1 rule).
Equal keyed tokens conflict unless their launch family is known
to share nothing (Plan 251 P4). A BARE token still conflicts with
every member of its family, keyed or not - with ONE exception,
:data:`RES_ENV_SUBPROCESS` (Plan 276 P2): a bare launch conflicts
with other bare launches only.
That exception is not a relaxation of the fail-closed rule; it is
the rule applied to what an xdist worker actually is. A bare
``main_tree_write`` means "a write to a directory this pass could
not read", and the directory it could not read may be any of the
keyed ones, so it must conflict with all of them. A bare
``env_subprocess`` means "a child this pass could not name", and
the one thing a keyed sibling would share with it - the inherited
environment - is per PROCESS: a worker is a process, so that
inheritance never crosses one. What a child does to state that IS
shared is what its family declares through its own resources
(``main_tree_write:*``), and what ``unknown:*`` fails closed on.
Parameters
----------
left, right
Resource tokens as the detectors record them.
Returns
-------
bool
Whether a file carrying *left* may run beside one carrying
*right*.
Definition at line 285 of file parallel.py.
| Path oct.testing.parallel.default_manifest_path | ( | Path | root, |
| Sequence[str] | test_roots ) |
The manifest path implied by *test_roots* (their common parent).
Definition at line 2977 of file parallel.py.
| list[str] oct.testing.parallel.diff_manifests | ( | Mapping[str, Any] | committed, |
| Mapping[str, Any] | fresh ) |
Compare two manifest documents by CONTENT, file by file.
Only ``files`` is compared: ``generated_at`` and ``tool_version``
differ on every regeneration by design.
Returns
-------
list[str]
One line per disagreeing file, each naming the file and the
reason. Empty when the two documents classify identically.
Definition at line 3040 of file parallel.py.
| str oct.testing.parallel.free_group_name | ( | str | nodeid, |
| * | , | ||
| bool | whole_file = False ) |
The per-test group name a ``free`` item carries (Plan 286 P1).
A free file shares no resource with anything, so its tests may run
anywhere - including in different workers. The name is therefore
the item's own nodeid, not the group ``free`` every free file used
to share: ``--dist loadgroup`` keeps ONE group on ONE worker, so
the shared name pinned the whole free set to a single worker
(measured on the oc_chat suite from this worktree, BASE
``3297fae7``: of twenty workers, gw0 ran all 3877 tests of all 283
free files and only three other workers ran anything at all).
*whole_file* is the P2 opt-out: the name is then the FILE's path,
so that one file's tests stay together while every other free file
still spreads.
Parameters
----------
nodeid
The collected item's nodeid, ``<relpath>::<test>``.
whole_file
True when the item carries :data:`WHOLE_FILE_MARKER`.
Definition at line 2375 of file parallel.py.
| bool oct.testing.parallel.is_conflicting | ( | str | resource | ) |
True when *resource* can collide ACROSS worker processes. Every ``unknown:<detail>`` conflicts by construction. An empty launch-family entry has no self-conflict (Plan 251 P4), but its token remains visible to the GLOBAL ``unknown:*`` wildcard in :func:`build_groups` - no longer to a bare launch, which since Plan 276 P2 holds only the other bare launches. Other keyed resources remain shared.
Definition at line 327 of file parallel.py.
| bool oct.testing.parallel.is_known_resource | ( | str | resource | ) |
True when *resource* is inside the closed P2 vocabulary.
Parameters
----------
resource
A resource token as the detectors record it.
Returns
-------
bool
True for a vocabulary member, a keyed token of a
:data:`KEYED_FAMILIES` member, or a well-formed ``port:<n>``;
False for ``unknown:<detail>`` and anything unrecognised.
Definition at line 343 of file parallel.py.
| bool oct.testing.parallel.is_xdist_worker | ( | Any | config | ) |
True when *config* belongs to an xdist worker process. The guard that stops a worker re-injecting ``-n`` and spawning its own workers: xdist resets ``numprocesses`` to ``None`` in the worker's config, which otherwise looks exactly like "no ``-n`` was given" to :func:`configure_parallel_defaults`. The environment half also catches a NESTED pytest run launched from inside a worker, which inherits ``PYTEST_XDIST_WORKER`` and must stay serial.
Definition at line 2474 of file parallel.py.
| str oct.testing.parallel.keyed | ( | str | family, |
| str | key ) |
Build the keyed token ``<family>:<key>`` (P1). An empty *key* yields the BARE family token: a caller that could not attribute the use says so by producing the wildcard, never by inventing a key.
Definition at line 257 of file parallel.py.
| str | None oct.testing.parallel.launch_family | ( | Any | argv | ) |
The program family of a child launch, or None when opaque (P3).
``python -m <module>`` names the MODULE, because that is what the
child actually IS - ``oc_chat.testing``, ``oct.cli`` and
``oc_chat.registry`` are three families, not one interpreter. Any
other program names its own basename without extension. A bare
interpreter (``python -c``, ``python script.py``) names only
``python``, which the table deliberately does not vouch for.
Parameters
----------
argv
The argv as the caller passed it: a sequence whose unreadable
elements are None, a shell string, or anything else.
Returns
-------
str | None
The family name, or None when the argv has no readable head.
Definition at line 586 of file parallel.py.
| frozenset[str] oct.testing.parallel.launch_resources | ( | Any | argv | ) |
The resources one child launch contributes (P3). A family named in :data:`LAUNCH_FAMILIES` contributes its own keyed token plus everything the table vouches for. A family the table does not name - and an argv with no readable family at all - contributes the BARE token, which conflicts with every launcher.
Definition at line 631 of file parallel.py.
| ParallelManifest oct.testing.parallel.load_manifest | ( | Path | path | ) |
Load and validate a committed ``parallel_manifest.json``.
Raises
------
OctTestError
``9102`` when the file is unreadable, is not JSON, or does not
carry the P4 shape. A malformed manifest never degrades to an
empty one: that would silently widen parallelism.
Definition at line 2158 of file parallel.py.
| dict[str, set[str]] oct.testing.parallel.load_traces | ( | Sequence[Path] | sources | ) |
Merge trace documents from files and/or directories.
Definition at line 2939 of file parallel.py.
| int oct.testing.parallel.main | ( | Sequence[str] | None | argv = None | ) |
CLI entry point; ``classify`` is the only subcommand.
Definition at line 3166 of file parallel.py.
| str | None oct.testing.parallel.path_key | ( | str | hint | ) |
The top-level component of a ROOT-RELATIVE path *hint* (P2).
Parameters
----------
hint
A path relative to the package root, in either slash style.
Returns
-------
str | None
The first component - the directory the write lands in - or
None for an absolute path, a drive-qualified path, or an
upward escape. None means "no key", which produces the bare
wildcard: a key that is not a real top inside the root would
separate two writes that really can collide.
Definition at line 475 of file parallel.py.
| None oct.testing.parallel.pytest_addoption | ( | Any | parser | ) |
Register ``--oct-trace`` (pytest plugin hook, P3b).
Definition at line 2854 of file parallel.py.
| None oct.testing.parallel.pytest_configure | ( | Any | config | ) |
Install the tracer when ``--oct-trace`` was given. Refuses a PARALLEL traced run outright (R3). Measured on the oc_chat suite 2026-09-06: with workers, only the controller wrote a trace file, so the classification would have been rebuilt from collection-time activity alone. Refusing at configure time, before any worker starts, is the fail-closed choice; a partial trace that looks complete is the failure mode this whole mechanism exists to prevent.
Definition at line 2869 of file parallel.py.
| None oct.testing.parallel.pytest_runtest_logfinish | ( | str | nodeid, |
| Any | location ) |
Stop attributing observations to a test.
Definition at line 2903 of file parallel.py.
| None oct.testing.parallel.pytest_runtest_logstart | ( | str | nodeid, |
| Any | location ) |
Attribute the next observations to *nodeid*'s file.
Definition at line 2897 of file parallel.py.
| None oct.testing.parallel.pytest_sessionfinish | ( | Any | session, |
| Any | exitstatus ) |
Write this process's trace and restore the wrapped seams.
Definition at line 2909 of file parallel.py.
| tuple[dict[str, str], tuple[str, ...]] oct.testing.parallel.resolve_groups | ( | ParallelManifest | manifest, |
| Iterable[str] | relpaths ) |
Map collected file paths to groups, failing closed on absence.
Returns
-------
tuple
``(path -> group, missing)``. A collected file with no
manifest entry maps to :data:`GROUP_UNCLASSIFIED` and is
listed in *missing*, so a stale manifest can never silently
widen parallelism.
Definition at line 2203 of file parallel.py.
| int oct.testing.parallel.resolve_max_workers | ( | Path | workspace_root, |
| str | package ) |
Read ``subprojects[].test.max_workers`` for *package* (P1/P5).
REFUSES a manifest-level failure instead of degrading to the
shipped default (Plan 247 P5): a workspace manifest that EXISTS
and cannot be loaded, and a package that manifest does not
declare, are both configuration errors, and the only caller is a
root conftest deciding how many workers to inject - degrading
there ran two dozen workers against a workspace nobody could
parse, silently.
A manifest that is ABSENT ENTIRELY is not a misconfiguration and
still resolves the shipped default (operator ruling 2026-09-08):
there is no configuration to be wrong about, and the §20 stand-in
is asked to run over standalone fixture trees that carry no
workspace manifest by design - refusing there declined to
parallelise fourteen witnesses that had nothing wrong with them.
An ABSENT ``max_workers`` key on a DECLARED package likewise still
defaults, as does an installed manifest parser that predates the
key, through :func:`_raw_max_workers`.
Raises
------
OctTestError
Whatever :func:`load_test_manifest` raises for a workspace
manifest that exists but is unusable, and ``9102`` when
*package* is not declared in one that loaded.
Definition at line 2271 of file parallel.py.
| int oct.testing.parallel.resolve_worker_count | ( | Path | workspace_root, |
| str | package, | ||
| * | , | ||
| int | None | cpu_count = None ) |
Resolve ``auto`` to ``min(max_workers, available_cpu_count())``. P1 for the cap, ADR-T-11's v0.4 amendment for the CPU count (P5).
Definition at line 2354 of file parallel.py.
| str oct.testing.parallel.resource_family | ( | str | resource | ) |
The family of *resource*, or the token itself when not keyed.
Definition at line 269 of file parallel.py.
| str oct.testing.parallel.resource_for_path_hint | ( | str | hint | ) |
Map a path-ish *hint* to its shared resource.
Parameters
----------
hint
Any path fragment: string constants lifted out of the source,
or a concrete path the dynamic tracer observed.
Returns
-------
str
The matching vocabulary member, or
:data:`RES_MAIN_TREE_WRITE` when the hint names no known
shared file - an unrecognised write is still a write, and
still shared.
Definition at line 451 of file parallel.py.
| str | None oct.testing.parallel.resource_key | ( | str | resource | ) |
The key *resource* carries, or None when it is BARE.
Definition at line 277 of file parallel.py.
| int oct.testing.parallel.run_classify | ( | Sequence[str] | argv | ) |
Regenerate (or CHECK) a subproject's parallel manifest. ``--check`` classifies in memory from the same inputs and diffs the result against the committed manifest instead of overwriting it: exit 0 on identity, :data:`EXIT_MANIFEST_DRIFT` listing every file whose resources or group differ. The completeness check inside the suite only proves a file is PRESENT; this is what proves the entries are still TRUE (gate finding R1). A trace passed with ``--trace`` must come from a SERIAL traced run (``pytest -n 0 -p oct.testing.parallel --oct-trace=<path>``); the plugin refuses to trace a parallel run, because a partial trace would quietly reclassify every file it did not observe.
Definition at line 3082 of file parallel.py.
| str oct.testing.parallel.unknown | ( | str | detail | ) |
Build the fail-closed ``unknown:<detail>`` token. *detail* must be machine independent (no absolute paths, no user names): the manifest that carries it is committed.
Definition at line 365 of file parallel.py.
| None oct.testing.parallel.write_manifest | ( | Path | path, |
| Mapping[str, Any] | document ) |
Write *document* to *path* as stable, newline-terminated JSON.
Definition at line 2149 of file parallel.py.
| str oct.testing.parallel.write_resource | ( | str | hint, |
| str | None | key ) |
The resource of a write to *hint*, keyed where P2 allows.
Keying only ever refines the UNATTRIBUTED write: a hint the
vocabulary already names something specific - the comms root, the
registry database, an ``octrc.json`` - keeps that token, because
two writes to the same shared FILE collide whichever directory
they were reached through.
Parameters
----------
hint
Any path fragment, as :func:`resource_for_path_hint` takes it.
key
The top-level directory the write landed in, or None when the
caller could not read one.
Returns
-------
str
A specific vocabulary member, ``main_tree_write:<key>``, or
the bare :data:`RES_MAIN_TREE_WRITE`.
Definition at line 501 of file parallel.py.
|
protected |
Definition at line 1174 of file parallel.py.
|
protected |
Definition at line 719 of file parallel.py.
|
protected |
Definition at line 701 of file parallel.py.
|
protected |
Definition at line 706 of file parallel.py.
|
protected |
Definition at line 671 of file parallel.py.
|
protected |
Definition at line 1153 of file parallel.py.
|
protected |
Definition at line 1162 of file parallel.py.
|
protected |
Definition at line 665 of file parallel.py.
|
protected |
Definition at line 1169 of file parallel.py.
|
protected |
Definition at line 549 of file parallel.py.
|
protected |
Definition at line 543 of file parallel.py.
|
protected |
Definition at line 711 of file parallel.py.
|
protected |
Definition at line 679 of file parallel.py.
|
protected |
Definition at line 685 of file parallel.py.
|
protected |
Definition at line 691 of file parallel.py.
|
protected |
Definition at line 696 of file parallel.py.
|
protected |
Definition at line 659 of file parallel.py.
|
protected |
Definition at line 654 of file parallel.py.
|
protected |
Definition at line 2569 of file parallel.py.
| int oct.testing.parallel.DEFAULT_MAX_WORKERS = 24 |
Definition at line 127 of file parallel.py.
| int oct.testing.parallel.EXIT_MANIFEST_DRIFT = 4 |
Definition at line 3037 of file parallel.py.
| str oct.testing.parallel.FREE_GROUP_PREFIX = f"{GROUP_FREE}:" |
Definition at line 393 of file parallel.py.
| str oct.testing.parallel.GROUP_FREE = "free" |
Definition at line 385 of file parallel.py.
| str oct.testing.parallel.GROUP_UNCLASSIFIED = "unclassified-serial" |
Definition at line 388 of file parallel.py.
| str oct.testing.parallel.KEY_SEPARATOR = ":" |
Definition at line 231 of file parallel.py.
| frozenset oct.testing.parallel.KEYED_FAMILIES |
Definition at line 243 of file parallel.py.
| dict oct.testing.parallel.LAUNCH_FAMILIES |
Definition at line 573 of file parallel.py.
| str oct.testing.parallel.MANIFEST_FILENAME = "parallel_manifest.json" |
Definition at line 382 of file parallel.py.
| str oct.testing.parallel.OUTSIDE_KEY = "<outside>" |
Definition at line 254 of file parallel.py.
| str oct.testing.parallel.PORT_PREFIX = "port:" |
Definition at line 182 of file parallel.py.
| frozenset oct.testing.parallel.PROCESS_LOCAL_RESOURCES |
Definition at line 223 of file parallel.py.
| str oct.testing.parallel.PYTHON_ARGV0 = "<python>" |
Definition at line 540 of file parallel.py.
| str oct.testing.parallel.RES_COMMS_ROOT = "comms_root" |
Definition at line 138 of file parallel.py.
| str oct.testing.parallel.RES_CWD_CHANGE = "cwd_change" |
Definition at line 175 of file parallel.py.
| str oct.testing.parallel.RES_ENV_MUTATION = "env_mutation" |
Definition at line 169 of file parallel.py.
| str oct.testing.parallel.RES_ENV_SUBPROCESS = "env_subprocess" |
Definition at line 160 of file parallel.py.
| str oct.testing.parallel.RES_GLOBAL_SINGLETON_RESET = "global_singleton_reset" |
Definition at line 179 of file parallel.py.
| str oct.testing.parallel.RES_MAIN_TREE_WRITE = "main_tree_write" |
Definition at line 153 of file parallel.py.
| str oct.testing.parallel.RES_NETWORK = "network" |
Definition at line 172 of file parallel.py.
| str oct.testing.parallel.RES_OCTRC = "octrc" |
Definition at line 144 of file parallel.py.
| str oct.testing.parallel.RES_REGISTRY_SQLITE = "registry_sqlite" |
Definition at line 135 of file parallel.py.
| str oct.testing.parallel.RES_SETTINGS_FILE = "settings_file" |
Definition at line 141 of file parallel.py.
| str oct.testing.parallel.RES_WORKTREE_DIR = "worktree_dir" |
Definition at line 147 of file parallel.py.
| tuple oct.testing.parallel.RESOURCE_VOCABULARY |
Definition at line 188 of file parallel.py.
| str oct.testing.parallel.SCHEMA_VERSION = "1.0" |
Definition at line 379 of file parallel.py.
| str oct.testing.parallel.TRACE_OPTION = "--oct-trace" |
Definition at line 2566 of file parallel.py.
| str oct.testing.parallel.UNKNOWN_PREFIX = "unknown:" |
Definition at line 185 of file parallel.py.
| str oct.testing.parallel.WHOLE_FILE_MARKER = "whole_file" |
Definition at line 399 of file parallel.py.