|
oct
|
Classes | |
| class | ImportGraph |
Functions | |
| bool | _is_test_path (Path py_file, Path root) |
| str|None | _resolve_relative (str module, bool is_package, int level, str|None name) |
| str|None | _resolve_in_project (str candidate, set[str] modules) |
| ImportGraph | build_import_graph (Path root) |
| str | _package_of (str module, int depth) |
| dict[tuple[str, str], int] | collapse_to_packages (dict[str, list[str]] edges, int depth=2) |
| str | _mermaid_id (str name) |
| str | to_mermaid_flowchart (dict[tuple[str, str], int] package_edges) |
| str | to_dot (dict[str, list[str]] edges, str title="modules") |
Variables | |
| frozenset | _TEST_DIR_NAMES = frozenset({"tests", "test"}) |
Purpose
-------
Build a project's dependency graph from what its modules actually
``import``, and collapse it to package level for an overview chart.
:mod:`oct.deps.oct_deps` builds a graph from the ``Dependencies`` section
each module docstring declares. That is a contract, and a useful one, but
a structural picture that can drift from the code is worse than none, so
the overview chart on every subproject's ``dependencies`` page is derived
from the AST instead: ``import x``, ``from x import y``, and relative
imports resolved against the importing module's package. Only imports
that resolve to a module inside the project become edges; third-party and
standard-library imports are counted, not drawn.
Responsibilities
----------------
- :func:`build_import_graph` - modules and edges from the AST, tests and
the standard exclusions skipped.
- :func:`collapse_to_packages` - the package-level overview: one node per
top-level package, edges weighted by how many module-level edges they
stand for.
- :func:`to_mermaid_flowchart` and :func:`to_dot` - render either level.
Diagnostics
-----------
Domain: OCT-DEPS
Levels:
L2 - build entry / exit with sizes
L3 - per-module resolution decisions
L4 - individual unresolved imports
Contracts
---------
- Purely static: no project module is ever imported or executed.
- A file that does not parse contributes no edges and is reported at L3;
it never aborts the graph, because a docs build must not die on one
broken module and the linter already blocks that module elsewhere.
- Module keys are dotted paths relative to the project root, the same
scheme :func:`oct.deps.oct_deps.module_name_for` uses, so the two graphs
can be compared key for key.
- ``__init__.py`` resolves to its package; an import of a package resolves
to that package node, not to every module in it.
Dependencies
------------
- oct.core.diagnostics (_dbg structured logger)
- oct.deps.oct_deps (module_name_for, _should_skip - shared key scheme)
|
protected |
True when the file sits under a test or non-source directory. Only a top-level ``docs`` counts as non-source; a package that happens to contain a ``docs`` subpackage (``oct.docs``) is source.
Definition at line 105 of file import_graph.py.
|
protected |
Definition at line 238 of file import_graph.py.
|
protected |
The package node *module* belongs to at *depth*. The first *depth* dotted components; a name with fewer components is its own node, so a package's ``__init__`` (``pkg.core``) and its members (``pkg.core.git``) collapse to the same node. A dunder module (``oct.__main__``) folds into its parent rather than standing alone.
Definition at line 206 of file import_graph.py.
|
protected |
Return the longest project module that *candidate* names, or ``None``. ``from oct.core import git`` may name the module ``oct.core.git`` or the attribute ``git`` of the package ``oct.core``; the walk from the longest prefix down picks whichever exists.
Definition at line 137 of file import_graph.py.
|
protected |
Resolve ``from ..x import y`` to a dotted name, or ``None`` if it escapes the root. *module* is the importing module's dotted name; a package's ``__init__`` imports relative to itself, a plain module relative to its parent, which is why *is_package* matters.
Definition at line 120 of file import_graph.py.
| ImportGraph oct.deps.import_graph.build_import_graph | ( | Path | root | ) |
Walk *root* and build the import-derived module graph. Skips the standard exclusion directories and every test directory. See the module docstring for the resolution rules.
Definition at line 152 of file import_graph.py.
| dict[tuple[str, str], int] oct.deps.import_graph.collapse_to_packages | ( | dict[str, list[str]] | edges, |
| int | depth = 2 ) |
Collapse module edges to package edges, weighted by count. *depth* is how many dotted components make a package. For a project laid out as ``<dist>/<pkg>/<subpkg>/module.py`` the natural overview is depth 2 (``oct.core``, ``oct.git``); a flat project wants 1. Edges inside one package are dropped - the overview is about the seams.
Definition at line 220 of file import_graph.py.
| str oct.deps.import_graph.to_dot | ( | dict[str, list[str]] | edges, |
| str | title = "modules" ) |
Render module-level edges as Graphviz DOT, clustered by package. Clusters make the module graph readable at oct's size: dot lays each package out as a box, and the cross-package edges are the picture.
Definition at line 258 of file import_graph.py.
| str oct.deps.import_graph.to_mermaid_flowchart | ( | dict[tuple[str, str], int] | package_edges | ) |
Render package-level edges as a Mermaid ``flowchart LR``. Edge labels carry the weight when it is more than one, so the chart shows where the heavy coupling is without a second diagram.
Definition at line 242 of file import_graph.py.
|
protected |
Definition at line 69 of file import_graph.py.