Skip to content

Add JSON output for uv tree - #19904

Closed
charliermarsh wants to merge 3 commits into
mainfrom
charlie/uv-tree-json
Closed

Add JSON output for uv tree#19904
charliermarsh wants to merge 3 commits into
mainfrom
charlie/uv-tree-json

Conversation

@charliermarsh

Copy link
Copy Markdown
Member

Summary

This adds --format json to uv tree, providing a machine-readable representation of the selected dependency graph while preserving the existing text format by default.

The output follows the NetworkX node-link format: packages appear once in nodes, while dependency relationships appear separately in edges and refer to package IDs through source and target. The graph is directed and a multigraph, allowing the same package pair to retain distinct production, optional-extra, and dependency-group relationships.

{
  "directed": true,
  "multigraph": true,
  "graph": {
    "schema": { "version": "preview" },
    "roots": [{ "id": 0 }],
    "inverted": false
  },
  "nodes": [
    {
      "id": 0,
      "name": "example",
      "version": "0.1.0",
      "source": { "editable": "." }
    },
    {
      "id": 1,
      "name": "anyio",
      "version": "4.9.0",
      "source": { "registry": "https://pypi.org/simple" }
    }
  ],
  "edges": [
    {
      "source": 0,
      "target": 1,
      "key": 0,
      "kind": "production",
      "requested_extras": []
    }
  ]
}

Node IDs are deterministic within the document. Package nodes include normalized names, versions, and tagged source metadata, with latest_version and size_bytes when requested. Edges distinguish production, optional, and development dependencies and retain activating extras, dependency groups, and requested extras. The graph metadata records the preview schema version, the displayed roots, and whether the graph was inverted.

The JSON projection operates on the same dependency graph as the text tree and supports its filtering and display options, including depth limits and inversion. Depth traversal tracks each package together with its expanded extras so an extra-only descendant is emitted only when its activating path is within the requested depth. JSON also remains available under --quiet, allowing resolution progress to be suppressed without discarding the command result.

@astral-sh-bot

astral-sh-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

uv test inventory changes

This PR changes the tests when compared with the latest main baseline.

  • Added tests: 3
  • Removed tests: 0
  • Changed suites: 1
uv::project: +3 / -0

Added:

  • uv::project::tree::json_output
  • uv::project::tree::json_output_depth_with_extra_context
  • uv::project::tree::json_output_virtual_root

Removed: none

Comment thread crates/uv-cli/src/lib.rs

/// The format in which to display the dependency graph.
#[arg(long, value_enum, default_value_t = TreeFormat::default())]
pub format: TreeFormat,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

output_format is canonical

},
"roots": [
{
"id": 3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'd want to use the ids from uv workspace metadata? cc @Gankra on this pull request you're probably the best reviewer?

Comment on lines +116 to +118
"schema": {
"version": "preview"
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the schema version nested inside the graph key?

Comment on lines +881 to +892
#[derive(Debug, Serialize)]
struct JsonNode<'env> {
id: usize,
name: &'env PackageName,
#[serde(skip_serializing_if = "Option::is_none")]
version: Option<&'env Version>,
source: JsonSource,
#[serde(skip_serializing_if = "Option::is_none")]
latest_version: Option<&'env Version>,
#[serde(skip_serializing_if = "Option::is_none")]
size_bytes: Option<u64>,
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to my other comment, I think we'll want to be consistent with uv workspace metadata in some way for the structure of the nodes

Gankra added a commit that referenced this pull request Jul 14, 2026
This is #19904 reworked to use the
`uv workspace metadata` format, which got really out of control as I
tried to write down actual semantics and encountered many issues which
for the moment I am proposing punting on so we can land this and unblock
the usecase:

* #19972
* #19973
* #19975
* #19976
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants