Skip to content

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
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 through parent_id; see Metrics for the rules.
  • Per-module derived keys: cc_max, cc_sum, cog_max, cog_sum are report-side sums and maxima over each module's function rows. Group the function rows by parent_id.
  • Circular imports: computed during HTML rendering only.
  • Source snippets: never exported. Use lineno/endline against path.
  • 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 . -f json \
  | jq '[.[] | select(.kind == "function") | .metrics.cc] | max'
codaviz . -f csv \
  | awk -F, 'NR > 1 && $3 == "function" && $9 > 15 { print $1, $9 }'

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.