oct.deps.oct_deps module#

Purpose#

Analyse inter-module dependencies within an Option C project by parsing the Dependencies docstring section from all Python files.

Responsibilities#

  • Walk the project tree and extract Dependencies sections from module docstrings.

  • Build a directed dependency graph (adjacency list).

  • Detect circular dependencies via depth-first search.

  • Output the graph in multiple formats: terminal summary, JSON, Mermaid, and DOT.

Diagnostics#

Domain: OCT-DEPS Levels:

L2 — lifecycle L3 — semantic details L4 — deep tracing

Contracts#

  • Must not import project modules; analysis is purely static.

  • Must exit 1 if circular dependencies are detected.

  • Must handle missing or malformed Dependencies sections gracefully.

oct.deps.oct_deps.audit_pins(root: Path, json_output: bool = False) int[source]#

Audit pyproject.toml dependencies for unpinned version specifiers.

Reads [project.dependencies] and [project.optional-dependencies] from pyproject.toml. Reports dependencies that use open ranges (>=, >) with no exact or upper-bound constraint alongside those that are strictly pinned.

Parameters:
  • root – Project root containing pyproject.toml.

  • json_output – If True, prints a JSON summary. Otherwise prints a human- readable table.

Returns:

  • Exit code (0 if all dependencies have upper-bound or exact pins,)

  • 1 if any open-ended >=-only or >-only specs are found,

  • 2 if pyproject.toml could not be read.

oct.deps.oct_deps.build_dependency_graph(root: Path) dict[str, list[str]][source]#

Walk the project and build an adjacency list from Dependencies sections.

Keys are dotted import paths (OI-521), so modules sharing a stem across packages no longer overwrite one another.

oct.deps.oct_deps.detect_cycles(graph: dict[str, list[str]]) list[list[str]][source]#

Detect circular dependencies using DFS. Returns list of cycle paths.

oct.deps.oct_deps.extract_dependencies(source: str) list[str][source]#

Parse the Dependencies section from a module docstring.

Returns a list of dependency module names.

oct.deps.oct_deps.module_name_for(py_file: Path, root: Path) str[source]#

Compute a dotted import-path key for py_file relative to root.

OI-521: using py_file.stem collided whenever two packages contain modules of the same name (e.g. a/util.py and b/util.py both reduced to util). Returning the dotted import path makes each key unique and aligns with the dotted names typically used in Dependencies docstring sections.

__init__.py resolves to its parent package’s dotted name; a file directly under root keeps its stem as the fallback.

oct.deps.oct_deps.run_deps(root: Path, argv: list[str] | None = None) int[source]#

Run dependency analysis on the given project root.

Returns exit code: 0 if no cycles, 1 if circular dependencies found.

oct.deps.oct_deps.to_dot(graph: dict[str, list[str]]) str[source]#

Format dependency graph as DOT (Graphviz) syntax.

oct.deps.oct_deps.to_json(graph: dict[str, list[str]], cycles: list[list[str]]) str[source]#

Format dependency graph as JSON.

oct.deps.oct_deps.to_mermaid(graph: dict[str, list[str]]) str[source]#

Format dependency graph as Mermaid diagram syntax.