Data formats¶
--format json and --format csv emit codaviz's internal data model directly, for feeding a dashboard, tracking complexity over time in CI, or diffing two revisions.
Both go to stdout unless -o is given. Progress notices go to stderr, so a pipe stays clean.
The entity model¶
Analysis produces one flat list of entities. Each is a package, a module, or a function, linked to its parent by parent_id. The HTML report derives its tree from those links; the JSON and CSV exporters write the flat list as-is. One source of truth feeds all three consumers.
| Field | Type | Meaning |
|---|---|---|
id |
string | Stable identifier, unique within a report. |
name |
string | Short display name. |
kind |
package | module | function |
What this is. |
path |
string | Source-root-relative path: the file for modules and functions, the directory for packages. |
parent_id |
string | null | Containing entity; null at the top. |
lineno |
int | null | 1-based start line (functions only). |
endline |
int | null | 1-based end line (functions only). |
metrics |
object | Metric values; absent ones are omitted entirely. |
How ids are built¶
- Package: its source-root-relative directory path,
mypkg,mypkg/sub. - Module: its source-root-relative file path, POSIX-style,
mypkg/core.py. - Function:
{module_id}::{name}#{lineno}, e.g.mypkg/core.py::classify#42. Methods use their qualified name:mypkg/core.py::Widget.render#88.
Two functions on the same line collide: two JavaScript arrow functions in one expression, say. The second gets a #2 suffix appended, the third #3. Python has at most one function per line, so Python ids never take this path.
Paths are relative to the source root, not the project root. In a src/ layout, src/mypkg/core.py has the id mypkg/core.py.
Metric keys¶
sloc, cc (cyclomatic), cognitive, mi (maintainability index). A key with no value is left out of the object entirely: a module with no MI has no mi key. See Metrics.
JSON¶
A JSON array of entity objects, indented by 2. Absent metrics are omitted from the nested metrics object; absent lineno/endline are explicit null.
[
{
"id": "demo",
"name": "demo",
"kind": "package",
"path": "demo",
"parent_id": null,
"lineno": null,
"endline": null,
"metrics": {}
},
{
"id": "demo/core.py",
"name": "core.py",
"kind": "module",
"path": "demo/core.py",
"parent_id": "demo",
"lineno": null,
"endline": null,
"metrics": {
"sloc": 6,
"mi": 75.07
}
},
{
"id": "demo/core.py::classify#1",
"name": "classify",
"kind": "function",
"path": "demo/core.py",
"parent_id": "demo/core.py",
"lineno": 1,
"endline": 6,
"metrics": {
"cc": 3,
"cognitive": 2
}
}
]
CSV¶
One row per entity, metrics flattened into their own columns, absent values blank. The header row is always present; line endings are \n.
Columns, in order:
id,name,kind,path,parent_id,lineno,endline,sloc,cc,cognitive,mi
demo,demo,package,demo,,,,,,,
demo/__init__.py,__init__.py,module,demo/__init__.py,demo,,,0,,,100.0
demo/core.py,core.py,module,demo/core.py,demo,,,6,,,75.07
demo/core.py::classify#1,classify,function,demo/core.py,demo/core.py,1,6,,3,2,
What the exports do not include¶
The HTML report computes several things on top of the entity list. None of them appear in JSON or CSV:
- Package aggregates (
cc_sum,cog_max, weighted MI, …): packages export with empty metrics. Recompute them by rolling up modules throughparent_id; see Metrics for the rules. - Per-module derived keys:
cc_max,cc_sum,cog_max,cog_sumare report-side sums and maxima over each module's function rows. Group the function rows byparent_id. - Circular imports: computed during HTML rendering only.
- Source snippets: never exported. Use
lineno/endlineagainstpath. - Absolute file paths: never emitted, so a report or export is safe to share.
Using it in CI¶
Ratcheting a threshold is a few lines, and works the same against JSON or CSV:
codaviz exits 0 whenever the analysis completes, regardless of the numbers. It does not fail a build; comparing against your own budget is the caller's job. 's job.