|
| tuple[list[Entry], list[str], bool] | parse_entries (str docstring) |
| tuple[Path,...] | _workspace_roots (Path project_root, _Probe probe) |
| tuple[Path, bool] | _naming_root (Path py_file, tuple[Path,...] roots, _Probe probe) |
| _Resolver | _resolver_for (tuple[Path,...] roots, tuple[Path,...] local_roots, _Probe probe) |
| str|None | _type_checking_kind (ast.expr test) |
| list[tuple[ast.Import|ast.ImportFrom, bool]] | _imports_with_laziness (ast.Module tree) |
| tuple[dict[str, bool], set[str]] | collect_imports (ast.Module tree, str module, bool is_package, _Resolver resolver) |
| bool | _covers (str entry, str dep, bool first_party) |
| bool | _is_test_module (Path py_file, Path naming_root, Path project_root) |
| bool | _stdlib_satisfied (str entry, set[str] stdlib) |
| tuple[bool, str] | check_dependencies_match (Path py_file, Path project_root, ast.Module|None tree, str|None docstring=None, *, dict|None memo=None) |
Purpose
-------
Compare a module's ``Dependencies`` docstring section with what the module
actually imports. The advisory lint rule ``dependencies_match`` runs this
on every source module. The section parsing lives in
:mod:`oct.deps.oct_deps`, whose cycle detection leaves lazy and
not-imported entries out, so the rule and ``oct deps`` read an entry alike.
The operator ruled on 2026-09-28 (docs/CHART_C_TRACE_FOLLOWUPS_2026-09-28.md,
section 8, in the workspace):
1. Every import is declared. An import made only inside a function or
under ``TYPE_CHECKING`` is declared with a purpose starting ``lazy``,
and ``oct deps`` leaves lazy entries out of its cycle detection.
2. First-party packages (any package in the workspace) and third-party
packages are both checked; standard-library modules are optional
(declaring one is allowed; it is stale only if nothing of it is
imported).
3. The rule runs at every profile, is advisory, and exempts test modules.
One addition, for the operator to veto: a dependency used without an
import (a CLI, a ``python -m`` subprocess, a pytest plugin, a module
loaded by name) is declared with a purpose starting ``not imported``; it
is never reported stale and never enters cycle detection.
Responsibilities
----------------
- :func:`parse_entries` - the ``Dependencies`` entries of a docstring, with
their markers, and the lines that are not entries.
- :func:`collect_imports` - every dependency a module imports, each marked
eager or lazy, standard library kept apart.
- :func:`check_dependencies_match` - the comparison: missing, stale,
wrongly marked and unrecognised entries, as one verdict and message.
Diagnostics
-----------
Domain: OCT-DEPS
Levels:
L2 - (none) called once per file by the linter; the linter logs verdicts
L3 - workspace roots resolved for a project
L4 - per-file comparison totals
Contracts
---------
- Never raises: any internal error becomes a passing verdict whose message
says the check did not run. A raising rule would make the quality gate
skip every rule for the file, the secret check included.
- A module's dotted name is taken from the workspace subproject root whose
first path component is a package, so a file in a namespace directory of
a package (``oct/oct/core``) is ``oct.core.git``; outside any package,
from Python's own rule.
- First-party names are checked against the filesystem with exact case
(directory listings memoised for one lint run), never by walking the
project, so ``oct git status`` stays fast and Windows and Linux agree.
- An import is recorded as written: ``import a.b.c`` is ``a.b.c``; ``from X
import y`` is ``X.y`` when that is a module, else ``X``. Nothing is
shortened to whatever prefix exists on disk, so an absent generated
module (a setuptools-scm version file) does not change the verdict.
- A first-party entry must name a module exactly, or exactly what an
import names; an attribute (``pkg.mod.Class``) is reported as naming no
module. A third-party or standard-library entry may name the package,
which covers its submodules.
- An ``if TYPE_CHECKING:`` body is lazy and its ``else`` eager; ``if not
TYPE_CHECKING:`` is the reverse; any other test is eager.
- An ``oc_diagnostics`` entry is satisfied by an import of oct's shim
``oct.core.diagnostics`` (Core spec: oc_diagnostics "should always be
listed if the module uses _dbg").
Dependencies
------------
- oct.core.diagnostics (_dbg structured logger)
- oct.core.workspace (lazy; the workspace manifest's subproject roots)
- oct.deps.import_graph (_is_test_path, _resolve_relative - shared rules)
- oct.deps.oct_deps (module_name_for, dependency_items, entry_marker - the shared parsing)