mirror of
https://github.com/nlohmann/json.git
synced 2026-07-12 13:35:13 +00:00
Fix cross-environment API-surface drift and lint findings from CI
extract_api.py's own extraction wasn't deterministic across machines, which CI's drift check caught immediately: JSON_HAS_RANGES auto-detects via the standard library's __cpp_lib_ranges feature-test macro, which isn't reliably gated to C++20 mode by every stdlib -- undefined under -std=c++17 with macOS's libc++, but defined under the identical flag with the Ubuntu stdlib CI uses, so parse()/accept()/from_*() extracted different signatures purely depending on which machine ran the extraction. Pinned to -DJSON_HAS_RANGES=0: the deterministic and safe choice, since pinning to 1 was tried first and found to fail to parse on a stdlib without full <ranges> support even when the macro claims otherwise. Also found and fixed a second, independent source of the same class of drift: get_identity_name() used cursor.spelling verbatim for CONVERSION_FUNCTION cursors, which libclang renders as its own internally-canonicalized form of the return type rather than what's literally written. Confirmed for json_pointer::operator string_t() spelling differently on two machines pinned to the identical libclang==18.1.1 wheel, with the JSON_HAS_RANGES fix above ruled out as the cause. Now derived from the cursor's own raw source text instead, immune to libclang's dependent-type resolution differences and incidentally more readable than the libclang-internal forms it replaces. Bumped SURFACE_FORMAT_VERSION to 3 and regenerated all 27 history snapshots and the committed api_surface.json; both fixes are documented in tools/api_checker/history/README.md's format-history log. Also fixes diff_api.py's format_version guard, which only compared the two loaded surfaces against each other and never against SURFACE_FORMAT_VERSION (what this build actually understands) -- two surfaces on the same, newer-than-expected format_version would have silently passed the guard. Remaining fixes are the concretely actionable findings from Codacy's review of the new tools/api_checker/ files: unused imports/variables, a stray f-string with no placeholders. Left the docstring-formatting nitpicks (pydocstyle D2xx/D4xx) and generic subprocess-usage notices alone -- the former has no established convention elsewhere in this codebase's Python tooling to conform to, and the latter are inherent to a dev tool that shells out to git/clang with developer-controlled arguments, not user input. Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -214,7 +214,7 @@ def print_diff(diff: dict, old_desc: str, new_desc: str) -> bool:
|
||||
|
||||
breaking = bool(diff['removed'] or diff['changed'])
|
||||
if breaking:
|
||||
print(f"\nWARNING: Potential BREAKING CHANGES detected:")
|
||||
print("\nWARNING: Potential BREAKING CHANGES detected:")
|
||||
print(f" - {len(diff['removed'])} removed entries")
|
||||
print(f" - {len(diff['changed'])} changed overloads")
|
||||
if diff['added']:
|
||||
@@ -264,13 +264,20 @@ def main():
|
||||
|
||||
old_fmt = old_surface.get('format_version')
|
||||
new_fmt = new_surface.get('format_version')
|
||||
if old_fmt != new_fmt and not args.allow_format_mismatch:
|
||||
print(f"Error: format_version mismatch ({old_desc}: {old_fmt!r} vs {new_desc}: {new_fmt!r}).")
|
||||
# Check both surfaces against SURFACE_FORMAT_VERSION (what *this build* of diff_api.py
|
||||
# understands), not just against each other: two surfaces on the same format_version could
|
||||
# still both be on a version this build predates and doesn't correctly interpret.
|
||||
mismatched = old_fmt != SURFACE_FORMAT_VERSION or new_fmt != SURFACE_FORMAT_VERSION
|
||||
if mismatched and not args.allow_format_mismatch:
|
||||
print(f"Error: format_version mismatch. This build of diff_api.py understands "
|
||||
f"format_version {SURFACE_FORMAT_VERSION!r}, but {old_desc} is {old_fmt!r} and "
|
||||
f"{new_desc} is {new_fmt!r}.")
|
||||
print("The identity/signature algorithm may differ between these two surfaces, making a diff unsound.")
|
||||
print("Re-run with --allow-format-mismatch to proceed anyway.")
|
||||
sys.exit(1)
|
||||
elif old_fmt != new_fmt:
|
||||
print(f"WARNING: proceeding with mismatched format_version ({old_fmt!r} vs {new_fmt!r}) as requested.")
|
||||
elif mismatched:
|
||||
print(f"WARNING: proceeding with mismatched format_version (this build understands "
|
||||
f"{SURFACE_FORMAT_VERSION!r}; {old_desc}={old_fmt!r}, {new_desc}={new_fmt!r}) as requested.")
|
||||
|
||||
old_api = build_identity_dict(old_surface['public_api'])
|
||||
new_api = build_identity_dict(new_surface['public_api'])
|
||||
|
||||
Reference in New Issue
Block a user