Skip to content

Commit 2150b24

Browse files
lcarvaclaude
andcommitted
feat: add --json output flag to auditwheel show
Enable scripting by adding a --json flag that outputs structured JSON instead of human-readable text, including wheel tag, compatibility flags, versioned symbols, external libs, and policy upgrade info. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b10e60c commit 2150b24

4 files changed

Lines changed: 543 additions & 0 deletions

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ repos:
4242
- pytest
4343
- types-docker
4444
- types-requests
45+
- types-jsonschema
4546

4647
- repo: https://github.com/zizmorcore/zizmor-pre-commit
4748
rev: v1.24.1

src/auditwheel/main_show.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,22 @@
99
if TYPE_CHECKING:
1010
import argparse
1111

12+
from auditwheel.wheel_abi import WheelAbIInfo
13+
1214
logger = logging.getLogger(__name__)
1315

1416

1517
def configure_parser(sub_parsers: Any) -> None: # noqa: ANN401
1618
help_ = "Audit a wheel for external shared library dependencies."
1719
p = sub_parsers.add_parser("show", help=help_, description=help_)
1820
p.add_argument("WHEEL_FILE", type=Path, help="Path to wheel file.")
21+
p.add_argument(
22+
"--json",
23+
dest="JSON",
24+
action="store_true",
25+
default=False,
26+
help="Output results in JSON format",
27+
)
1928
options.disable_isa_check(p)
2029
options.allow_pure_python_wheel(p)
2130
options.ldpaths(p)
@@ -29,6 +38,42 @@ def printp(text: str) -> None:
2938
print("\n".join(wrap(text, break_long_words=False, break_on_hyphens=False)))
3039

3140

41+
def _output_json(fn: str, winfo: WheelAbIInfo) -> None:
42+
from auditwheel import json
43+
44+
policies = winfo.policies
45+
libs = winfo.external_refs[policies.lowest.name].libs
46+
47+
policy_upgrades: dict[str, dict[str, Any]] = {}
48+
for p in policies:
49+
if p > winfo.overall_policy:
50+
entry: dict[str, Any] = {}
51+
p_libs = winfo.external_refs[p.name].libs
52+
if len(p_libs):
53+
entry["libs_to_eliminate"] = sorted(p_libs.keys())
54+
blacklist = winfo.external_refs[p.name].blacklist
55+
if len(blacklist):
56+
entry["blacklisted_symbols"] = {k: sorted(v) for k, v in sorted(blacklist.items())}
57+
if entry:
58+
policy_upgrades[p.name] = entry
59+
60+
result: dict[str, Any] = {
61+
"version": 1,
62+
"wheel": fn,
63+
"pure": False,
64+
"overall_tag": winfo.overall_policy.name,
65+
"sym_tag": winfo.sym_policy.name,
66+
"pyfpe": winfo.pyfpe_policy == policies.linux,
67+
"ucs2": winfo.ucs_policy == policies.linux,
68+
"unsupported_isa": winfo.machine_policy == policies.linux,
69+
"versioned_symbols": {k: sorted(v) for k, v in sorted(winfo.versioned_symbols.items())},
70+
"external_libs": {str(k): str(v) if v else None for k, v in sorted(libs.items())},
71+
"policy_upgrades": policy_upgrades,
72+
}
73+
74+
print(json.dumps(result))
75+
76+
3277
def execute(args: argparse.Namespace, parser: argparse.ArgumentParser) -> int:
3378
from auditwheel import json
3479
from auditwheel.error import NonPlatformWheelError, WheelToolsError
@@ -69,9 +114,17 @@ def execute(args: argparse.Namespace, parser: argparse.ArgumentParser) -> int:
69114
except NonPlatformWheelError as e:
70115
logger.info("%s", e.message)
71116
if is_pure_python and args.ALLOW_PURE_PY_WHEEL:
117+
if args.JSON:
118+
print(json.dumps({"version": 1, "wheel": fn, "pure": True}))
72119
return 0
120+
if args.JSON:
121+
print(json.dumps({"version": 1, "wheel": fn, "error": e.message}))
73122
return 1
74123

124+
if args.JSON:
125+
_output_json(fn, winfo)
126+
return 0
127+
75128
policies = winfo.policies
76129

77130
libs_with_versions = [f"{k} with versions {v}" for k, v in winfo.versioned_symbols.items()]

src/auditwheel/show-schema.json

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"title": "auditwheel show",
4+
"description": "Output schema for `auditwheel show --json`.",
5+
"oneOf": [
6+
{ "$ref": "#/$defs/result_pure" },
7+
{ "$ref": "#/$defs/result_platform" },
8+
{ "$ref": "#/$defs/error" }
9+
],
10+
"$defs": {
11+
"result_pure": {
12+
"type": "object",
13+
"properties": {
14+
"version": {
15+
"const": 1,
16+
"description": "Schema version."
17+
},
18+
"wheel": {
19+
"type": "string",
20+
"description": "Wheel filename."
21+
},
22+
"pure": {
23+
"const": true,
24+
"description": "Indicates a pure Python wheel."
25+
}
26+
},
27+
"required": ["version", "wheel", "pure"],
28+
"additionalProperties": false
29+
},
30+
"result_platform": {
31+
"type": "object",
32+
"properties": {
33+
"version": {
34+
"const": 1,
35+
"description": "Schema version."
36+
},
37+
"wheel": {
38+
"type": "string",
39+
"description": "Wheel filename."
40+
},
41+
"pure": {
42+
"const": false,
43+
"description": "Indicates a platform wheel."
44+
},
45+
"overall_tag": {
46+
"type": "string",
47+
"description": "The highest compatible platform tag for the wheel."
48+
},
49+
"sym_tag": {
50+
"type": "string",
51+
"description": "Platform tag constrained by symbol versioning."
52+
},
53+
"pyfpe": {
54+
"type": "boolean",
55+
"description": "Whether the wheel uses PyFPE_jbuf (incompatible with manylinux/musllinux)."
56+
},
57+
"ucs2": {
58+
"type": "boolean",
59+
"description": "Whether the wheel is compiled against narrow unicode (UCS2)."
60+
},
61+
"unsupported_isa": {
62+
"type": "boolean",
63+
"description": "Whether the wheel depends on unsupported ISA extensions."
64+
},
65+
"versioned_symbols": {
66+
"type": "object",
67+
"additionalProperties": {
68+
"type": "array",
69+
"items": { "type": "string" }
70+
},
71+
"description": "Mapping of shared library names to their referenced symbol versions."
72+
},
73+
"external_libs": {
74+
"type": "object",
75+
"additionalProperties": {
76+
"type": ["string", "null"]
77+
},
78+
"description": "Mapping of external shared library names to their resolved paths (or null)."
79+
},
80+
"policy_upgrades": {
81+
"type": "object",
82+
"additionalProperties": {
83+
"type": "object",
84+
"properties": {
85+
"libs_to_eliminate": {
86+
"type": "array",
87+
"items": { "type": "string" }
88+
},
89+
"blacklisted_symbols": {
90+
"type": "object",
91+
"additionalProperties": {
92+
"type": "array",
93+
"items": { "type": "string" }
94+
}
95+
}
96+
},
97+
"additionalProperties": false
98+
},
99+
"description": "Per-policy info on what must be eliminated to achieve a higher tag."
100+
}
101+
},
102+
"required": [
103+
"version",
104+
"wheel",
105+
"pure",
106+
"overall_tag",
107+
"sym_tag",
108+
"pyfpe",
109+
"ucs2",
110+
"unsupported_isa",
111+
"versioned_symbols",
112+
"external_libs",
113+
"policy_upgrades"
114+
],
115+
"additionalProperties": false
116+
},
117+
"error": {
118+
"type": "object",
119+
"properties": {
120+
"version": {
121+
"const": 1,
122+
"description": "Schema version."
123+
},
124+
"wheel": {
125+
"type": "string",
126+
"description": "Wheel filename."
127+
},
128+
"error": {
129+
"type": "string",
130+
"description": "Error message."
131+
}
132+
},
133+
"required": ["version", "wheel", "error"],
134+
"additionalProperties": false
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)