oct
Loading...
Searching...
No Matches
oct.testing.cache Namespace Reference

Classes

class  CacheStore
class  _ModuleIndex
class  CacheKeyBuilder
class  CacheDecision
class  _CacheRun

Functions

Path store_path (Path root)
datetime _now ()
str _stamp (datetime moment)
datetime|None _parse_stamp (object text)
None clear_store (Path root)
dict[str, Any] read_last_run (Path root)
bytes|None _read_bytes (Path path)
bool _is_namespace_package (Path path)
tuple[Path,...] _conftest_paths (Path root, Path path)
None _feed (Any digest, bytes label, bytes payload)
str _interpreter_identity ()
str _oct_version ()
bool is_security_file (str relpath)
ast.Module|None _source_tree (Path path)
str|None _dotted_name (ast.AST node)
bool _imports_hypothesis (ast.Module tree)
bool _pins_derandomize (ast.Module tree)
bool is_unpinned_property_file (Path path, *, Path|None root=None)
tuple[str,...] _unpinned_property_files (ParallelManifest manifest, Path root)
tuple[str,...] eligible_files (ParallelManifest manifest, *, Path|None root=None)
CacheDecision decide (Iterable[str] candidates, CacheKeyBuilder keyer, CacheStore store)
list[str] report_lines (CacheDecision decision, *, bool verbose=False)
None add_cache_options (Any parser)
None install (Any config, *, Path|None manifest_path=None)
bool _is_intentional_skip (Any report)
tuple[set[str], set[str]] _file_outcomes (Any terminalreporter)
None pytest_addoption (Any parser)
None pytest_configure (Any config)
None pytest_sessionstart (Any session)
None pytest_collection_modifyitems (Any config, list items)
None pytest_terminal_summary (Any terminalreporter, Any exitstatus, Any config)

Variables

str CACHE_OPTION = "--oct-cache"
str CACHE_CLEAR_OPTION = "--oct-cache-clear"
str CACHE_ENV = "OCT_TEST_CACHE"
str PLUGIN_NAME = "oct.testing.cache"
str STORE_SCHEMA_VERSION = "1.0"
tuple STORE_RELPATH = (".option_c", "cache", "test-cache.json")
int PRUNE_DAYS = 30
str TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
str SECURITY_FRAGMENT = "/tests/security/"
str KIND_WORKSPACE = "workspace"
str KIND_EXTERNAL = "external"
str KIND_ABSENT = "absent"
str KIND_MISSING = "missing"
bytes NO_PYTEST_INI = b"<no pytest.ini>"
str _OPTIONS_MARK = "_oct_cache_options_registered"
str _MANIFEST_ATTR = "_oct_cache_manifest_path"
str _RUN_ATTR = "_oct_cache_run"
frozenset _BAD_CATEGORIES

Detailed Description

Purpose
-------
The content-hashed test cache (Plan 249 / TEST-03). uv's principle -
rebuild only when the inputs change - applied to a test suite: a test
FILE whose every input hashes to a value that was already green is not
run again. The cache may only ever skip a file it can PROVE unchanged;
every doubt runs the file.

Responsibilities
----------------
- Pin the key (P1): SHA-256 over the test file's bytes, the bytes of
  every workspace module reachable from its imports, the bytes of
  every ``conftest.py`` on its path, its plan-239 manifest entry, the
  manifest ``schema_version``, the interpreter, the oct version and
  the ``pytest.ini`` bytes. An input it cannot resolve yields ``None``,
  and a file without a key is never skipped
  (:class:`CacheKeyBuilder`).
- Own the store (P2): ``<root>/.option_c/cache/test-cache.json``,
  key -> the UTC time of the last run in which every test of that file
  passed under that key, emptied on a manifest regeneration and pruned
  at :data:`PRUNE_DAYS` (:class:`CacheStore`).
- Pin the skip policy (P3): only a ``free``, keyed, green,
  non-``tests/security/`` file whose outcome is deterministic;
  a Hypothesis import without ``derandomize=True`` never enters the
  candidate set (:func:`eligible_files`, :func:`decide`).
- Be the pytest plugin that applies it (P4), off unless
  :data:`CACHE_OPTION` or :data:`CACHE_ENV` says otherwise, and the
  seams a root conftest calls (:func:`add_cache_options`,
  :func:`install`).
- Record what a run did so ``oct test --cached`` can put it in the
  plan-245 ledger (P5, :func:`read_last_run`).

Diagnostics
-----------
Domain: OCT-TESTING
Levels:
    L2: lifecycle (store load/save, decision taken)
    L3: semantic details (skip counts, unresolved imports)
    L4: deep tracing (per-file keys and closures)

Contracts
---------
- FAIL CLOSED everywhere. A missing manifest entry, an unreadable
  file, an import that resolves to nothing, a manifest that has been
  regenerated since the store was written, a syntax error: each of
  them means RUN THE FILE, never "assume unchanged".
- The cache is NEVER on by default and never at a gate: the plugin
  does nothing unless the command line carries :data:`CACHE_OPTION` or
  the environment carries ``OCT_TEST_CACHE=1``.
- ``tests/security/`` is excluded unconditionally: the M8 witnesses
  always run.
- A file importing Hypothesis is never eligible unless that file or a
  ``conftest.py`` on its path contains an explicit
  ``derandomize=True`` settings keyword.
- A module OUTSIDE the workspace (standard library, site-packages) is
  identified and EXCLUDED from the closure, exactly as P1 requires.
  A name that resolves NOWHERE - an optional third-party import behind
  a ``try``/``except``, of which the oc_chat closure holds five - is
  not a first-party input either, so it cannot fail the key closed
  without disabling the cache entirely (measured 2026-09-08: treating
  it as a doubt left 0 of 221 eligible oc_chat files keyable). Its
  ABSENCE is recorded in the key instead, so installing the package
  invalidates every file that reaches it. A FIRST-PARTY input the
  resolver cannot follow - an unparsable module, a workspace file it
  cannot read, a relative import escaping the workspace - still makes
  the key ``None``.
- ``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`` anywhere in this module.

Dependencies
------------
- oct.core.diagnostics (_dbg)
- oct.core.workspace (lazy; read-only: the subproject roots the resolver treats as workspace package roots)
- oct.testing.errors (the spec-10 ยง12.4 taxonomy as data)
- oct.testing.parallel (the committed classification and its groups)
- oct.tools.atomic_write (atomic_write_text for saving the test-cache store)
- oct (lazy; the installed oct version recorded in the cache key)

Function Documentation

◆ _conftest_paths()

tuple[Path, ...] oct.testing.cache._conftest_paths ( Path root,
Path path )
protected
Every ``conftest.py`` from *root* down to *path*.

Definition at line 712 of file cache.py.

Here is the caller graph for this function:

◆ _dotted_name()

str | None oct.testing.cache._dotted_name ( ast.AST node)
protected
Return a simple dotted expression name, when statically known.

Definition at line 932 of file cache.py.

Here is the caller graph for this function:

◆ _feed()

None oct.testing.cache._feed ( Any digest,
bytes label,
bytes payload )
protected
Feed one length-prefixed field into *digest*.

The length prefix is what makes the concatenation unambiguous: two
different input sequences can never produce the same byte stream.

Definition at line 884 of file cache.py.

Here is the caller graph for this function:

◆ _file_outcomes()

tuple[set[str], set[str]] oct.testing.cache._file_outcomes ( Any terminalreporter)
protected
Split the run's reports into green and not-green FILES.

Returns
-------
tuple
    ``(green, bad)`` sets of nodeid path parts. A file in *bad* is
    never in *green*: one failure is enough.

Definition at line 1364 of file cache.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _imports_hypothesis()

bool oct.testing.cache._imports_hypothesis ( ast.Module tree)
protected
True when *tree* imports the top-level ``hypothesis`` package.

Definition at line 945 of file cache.py.

Here is the caller graph for this function:

◆ _interpreter_identity()

str oct.testing.cache._interpreter_identity ( )
protected
The running interpreter, as the key records it.

Definition at line 897 of file cache.py.

◆ _is_intentional_skip()

bool oct.testing.cache._is_intentional_skip ( Any report)
protected
True when pytest recorded a REASON for a skip.

``skip``/``skipif``/``pytest.skip`` all produce the standard
``(path, lineno, reason)`` triple. A skip with no readable reason
is not evidence that the file passed, so it is not treated as one.

Definition at line 1348 of file cache.py.

Here is the caller graph for this function:

◆ _is_namespace_package()

bool oct.testing.cache._is_namespace_package ( Path path)
protected
True when *path* is an importable directory with no ``__init__``.

``oc_chat/tools/`` is the live example: a directory of modules that
six test files import as ``tools.<name>``. The ``.py`` requirement
is what keeps ``docs/`` and ``plans/`` from being read as packages
merely because they are directories beside one.

Definition at line 362 of file cache.py.

Here is the caller graph for this function:

◆ _now()

datetime oct.testing.cache._now ( )
protected
The current UTC time, to whole seconds.

Definition at line 153 of file cache.py.

Here is the caller graph for this function:

◆ _oct_version()

str oct.testing.cache._oct_version ( )
protected
The oct version string, as the key records it.

Definition at line 902 of file cache.py.

◆ _parse_stamp()

datetime | None oct.testing.cache._parse_stamp ( object text)
protected
Read a stored timestamp, or None when it is unreadable.

Definition at line 163 of file cache.py.

Here is the caller graph for this function:

◆ _pins_derandomize()

bool oct.testing.cache._pins_derandomize ( ast.Module tree)
protected
True when a Hypothesis settings call pins ``derandomize=True``.

Definition at line 962 of file cache.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _read_bytes()

bytes | None oct.testing.cache._read_bytes ( Path path)
protected
Read *path*, or None when it cannot be read.

Definition at line 354 of file cache.py.

Here is the caller graph for this function:

◆ _source_tree()

ast.Module | None oct.testing.cache._source_tree ( Path path)
protected
Parse *path*, or return None when its source is unusable.

Definition at line 920 of file cache.py.

Here is the caller graph for this function:

◆ _stamp()

str oct.testing.cache._stamp ( datetime moment)
protected
Format *moment* the way the store records it.

Definition at line 158 of file cache.py.

Here is the caller graph for this function:

◆ _unpinned_property_files()

tuple[str, ...] oct.testing.cache._unpinned_property_files ( ParallelManifest manifest,
Path root )
protected
Free non-security manifest files refused by the property guard.

Definition at line 1008 of file cache.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_cache_options()

None oct.testing.cache.add_cache_options ( Any parser)
Register the cache options, at most once per run (P4).

Safe to call from BOTH a root conftest's ``pytest_addoption`` and
this module's own, because pytest hands every implementation the
same :class:`~_pytest.config.argparsing.Parser`.

Definition at line 1150 of file cache.py.

Here is the caller graph for this function:

◆ clear_store()

None oct.testing.cache.clear_store ( Path root)
Remove the store under *root* entirely (P4).

Definition at line 293 of file cache.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ decide()

CacheDecision oct.testing.cache.decide ( Iterable[str] candidates,
CacheKeyBuilder keyer,
CacheStore store )
Decide which of *candidates* provably did not change (P3).

A candidate is skipped only when it has a key AND that key has a
green entry in *store*. Everything else runs.

Definition at line 1069 of file cache.py.

Here is the caller graph for this function:

◆ eligible_files()

tuple[str, ...] oct.testing.cache.eligible_files ( ParallelManifest manifest,
* ,
Path | None root = None )
Every manifest file a cache may EVER skip (P3).

A non-free file can vary with shared state, a security witness must
always run, and a Hypothesis file without ``derandomize=True`` can
vary with an unkeyed seed. Each is excluded when *root* makes source
inspection available; omitting *root* preserves the manifest-only
compatibility seam.

Definition at line 1020 of file cache.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ install()

None oct.testing.cache.install ( Any config,
* ,
Path | None manifest_path = None )
Attach this plugin to *config* (the root-conftest seam).

Pins the classification the cache reads and registers the module
as a plugin when ``-p oct.testing.cache`` did not already. The
manifest path is read LAZILY, so it does not matter whether this
call happens before or after the plugin's own ``pytest_configure``.

Definition at line 1178 of file cache.py.

◆ is_security_file()

bool oct.testing.cache.is_security_file ( str relpath)
True when *relpath* is an M8 witness, which always runs (P3).

Definition at line 915 of file cache.py.

Here is the caller graph for this function:

◆ is_unpinned_property_file()

bool oct.testing.cache.is_unpinned_property_file ( Path path,
* ,
Path | None root = None )
True when *path* imports Hypothesis without a deterministic profile.

Definition at line 985 of file cache.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pytest_addoption()

None oct.testing.cache.pytest_addoption ( Any parser)
Register the cache options (pytest plugin hook, P4).

Definition at line 1399 of file cache.py.

Here is the call graph for this function:

◆ pytest_collection_modifyitems()

None oct.testing.cache.pytest_collection_modifyitems ( Any config,
list items )
Deselect the items of every provably unchanged file (P3).

Definition at line 1439 of file cache.py.

◆ pytest_configure()

None oct.testing.cache.pytest_configure ( Any config)
Build this run's state and honour ``--oct-cache-clear`` (P4).

Definition at line 1404 of file cache.py.

Here is the call graph for this function:

◆ pytest_sessionstart()

None oct.testing.cache.pytest_sessionstart ( Any session)
Report the decision once, on the process the operator watches.

Under xdist the controller does not collect, so the deselection
below happens in the workers and their output is never shown; the
decision is deterministic, so the controller reports exactly what
the workers then apply.

Definition at line 1419 of file cache.py.

Here is the call graph for this function:

◆ pytest_terminal_summary()

None oct.testing.cache.pytest_terminal_summary ( Any terminalreporter,
Any exitstatus,
Any config )
Write the store from this run's outcomes (P2/P5).

Definition at line 1466 of file cache.py.

◆ read_last_run()

dict[str, Any] oct.testing.cache.read_last_run ( Path root)
What the last cached run under *root* did (P5).

Returns
-------
dict
    ``{"at": ..., "ran": N, "cached": M}``, or an empty dict when
    no store exists or it carries no record. The caller treats an
    empty dict as "no measurement", never as zero.

Definition at line 307 of file cache.py.

Here is the call graph for this function:

◆ report_lines()

list[str] oct.testing.cache.report_lines ( CacheDecision decision,
* ,
bool verbose = False )
The cache and deterministic-property reports for one run (P3).

Cached files are reported once by count and, under ``-v``, by name.
Every unpinned Hypothesis file is always named once so the refusal is
actionable even when no file is skipped.

Definition at line 1102 of file cache.py.

Here is the caller graph for this function:

◆ store_path()

Path oct.testing.cache.store_path ( Path root)
The store's path under the package *root* (P2).

Definition at line 148 of file cache.py.

Here is the caller graph for this function:

Variable Documentation

◆ _BAD_CATEGORIES

frozenset oct.testing.cache._BAD_CATEGORIES
protected
Initial value:
1= frozenset({
2 "failed", "error", "xfailed", "xpassed",
3})

Definition at line 1145 of file cache.py.

◆ _MANIFEST_ATTR

str oct.testing.cache._MANIFEST_ATTR = "_oct_cache_manifest_path"
protected

Definition at line 1137 of file cache.py.

◆ _OPTIONS_MARK

str oct.testing.cache._OPTIONS_MARK = "_oct_cache_options_registered"
protected

Definition at line 1134 of file cache.py.

◆ _RUN_ATTR

str oct.testing.cache._RUN_ATTR = "_oct_cache_run"
protected

Definition at line 1140 of file cache.py.

◆ CACHE_CLEAR_OPTION

str oct.testing.cache.CACHE_CLEAR_OPTION = "--oct-cache-clear"

Definition at line 118 of file cache.py.

◆ CACHE_ENV

str oct.testing.cache.CACHE_ENV = "OCT_TEST_CACHE"

Definition at line 121 of file cache.py.

◆ CACHE_OPTION

str oct.testing.cache.CACHE_OPTION = "--oct-cache"

Definition at line 115 of file cache.py.

◆ KIND_ABSENT

str oct.testing.cache.KIND_ABSENT = "absent"

Definition at line 343 of file cache.py.

◆ KIND_EXTERNAL

str oct.testing.cache.KIND_EXTERNAL = "external"

Definition at line 335 of file cache.py.

◆ KIND_MISSING

str oct.testing.cache.KIND_MISSING = "missing"

Definition at line 347 of file cache.py.

◆ KIND_WORKSPACE

str oct.testing.cache.KIND_WORKSPACE = "workspace"

Definition at line 332 of file cache.py.

◆ NO_PYTEST_INI

bytes oct.testing.cache.NO_PYTEST_INI = b"<no pytest.ini>"

Definition at line 351 of file cache.py.

◆ PLUGIN_NAME

str oct.testing.cache.PLUGIN_NAME = "oct.testing.cache"

Definition at line 125 of file cache.py.

◆ PRUNE_DAYS

int oct.testing.cache.PRUNE_DAYS = 30

Definition at line 139 of file cache.py.

◆ SECURITY_FRAGMENT

str oct.testing.cache.SECURITY_FRAGMENT = "/tests/security/"

Definition at line 145 of file cache.py.

◆ STORE_RELPATH

tuple oct.testing.cache.STORE_RELPATH = (".option_c", "cache", "test-cache.json")

Definition at line 136 of file cache.py.

◆ STORE_SCHEMA_VERSION

str oct.testing.cache.STORE_SCHEMA_VERSION = "1.0"

Definition at line 133 of file cache.py.

◆ TIME_FORMAT

str oct.testing.cache.TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"

Definition at line 142 of file cache.py.