Skip to content

Fix CLI error detail and BOM handling for JSON input - #438

Merged
vinitkumar merged 5 commits into
masterfrom
fix/cli-input-error-details
Sep 23, 2026
Merged

vinitkumar merged 5 commits into
masterfrom
fix/cli-input-error-details

Conversation

@vinitkumar

@vinitkumar vinitkumar commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

Three fixes, one commit each, plus a small test follow-up.

Before:

$ json2xml-py examples/wrongjson.json
Error: Could not parse JSON file: examples/wrongjson.json. Check that the file contains valid JSON. (Invalid JSON File)

After:

Error: Could not parse JSON file: examples/wrongjson.json. Check that the file contains valid JSON. (Invalid JSON File: Expecting ',' delimiter: line 372 column 3 (char 8920))

Error prefixes are unchanged, so existing callers matching on them are unaffected. No library code changed for #439; the CustomNumber test helpers gain __hash__, the affected payloads are declared as JSONValue, and one test that asserted a bare literal now compares the result.

Test plan

  • Regression tests written first and observed failing, then passing (8 new tests: file, string, URL, and end-to-end CLI)
  • make test on CPython: 100% coverage; full suite also passes on PyPy 3.10
  • make lint and make typecheck clean with ty 0.0.83
  • lat check passes; lat.md/tests.md and lat.md/behavior.md updated

Summary by Sourcery

Improve JSON input diagnostics and compatibility by preserving decoder locations and accepting UTF-8 BOMs across all readers.

New Features:

  • Accept leading UTF-8 byte order marks in file, URL, and string JSON input.

Bug Fixes:

  • Include JSON decoder error details, including line and column, in reader errors so the CLI identifies where malformed input fails.
  • Update affected test fixtures and helpers for compatibility with ty 0.0.83.

Documentation:

  • Document decoder positions in invalid-input errors and UTF-8 BOM support for JSON readers.

Tests:

  • Add regression coverage for decoder positions, BOM-prefixed file, URL, string, and CLI input.

The file, string, and URL readers replaced the JSONDecodeError with
a fixed message, so the CLI could only say the input was invalid.
Append the decoder message so users see the line and column.

Fixes #436
Files, URL bodies, and strings starting with a BOM were rejected as
invalid JSON. Windows tools such as PowerShell and Notepad write the
BOM by default, so decode with utf-8-sig and drop a leading U+FEFF
from string input.

Fixes #437
@sourcery-ai

sourcery-ai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Updates all JSON readers to accept leading UTF-8 BOMs and preserve decoder error details, including line and column positions, while maintaining existing error prefixes; adds end-to-end coverage and behavioral documentation.

Flow diagram for BOM-tolerant JSON input and detailed errors

flowchart LR
    File["File input"] --> FileReader[readfromjson]
    URL["URL input"] --> URLReader[readfromurl]
    String["String or stdin input"] --> StringReader[readfromstring]
    FileReader --> Decode["Decode JSON after removing leading BOM"]
    URLReader --> Decode
    StringReader --> Decode
    Decode --> Parsed["Parsed JSON"]
    Decode --> Error["Source-specific error with decoder line and column"]
    Error --> CLI["CLI displays unchanged error prefix plus details"]
Loading

File-Level Changes

Change Details Files
Preserve JSON decoder diagnostics in source-specific reader errors.
  • Append the underlying parse exception to file, URL, and string reader messages.
  • Retain existing error prefixes for caller compatibility.
  • Verify line/column details through reader and CLI regression tests.
json2xml/utils.py
tests/test_utils.py
tests/test_cli.py
Support leading UTF-8 BOMs across all JSON input paths.
  • Use utf-8-sig for file decoding.
  • Decode URL response bytes with utf-8-sig.
  • Strip a leading U+FEFF from string input before parsing.
  • Cover BOM handling for files, URLs, strings, and the CLI.
json2xml/utils.py
tests/test_utils.py
tests/test_cli.py
Document the updated reader behavior and test expectations.
  • Document decoder positions in wrapped errors.
  • Document BOM acceptance for all three readers.
  • Link regression tests to the corresponding behavioral requirements.
lat.md/behavior.md
lat.md/tests.md

Assessment against linked issues

Issue Objective Addressed Explanation
#436 Preserve and expose the JSON decoder's detailed error message, including line and column information, when malformed file, string, URL, or stdin JSON is wrapped by the input readers and reported by the CLI. ✅
#437 Accept JSON input prefixed with a UTF-8 BOM when reading from files. ✅
#437 Accept JSON input containing a leading U+FEFF when reading from strings, including stdin and --string input. ✅
#437 Accept JSON input prefixed with a UTF-8 BOM when reading response bodies from URLs. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (a5d436d) to head (0fe2f5a).
⚠️ Report is 13 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #438   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            7         7           
  Lines         1032      1032           
=========================================
  Hits          1032      1032           
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

PyPy reports the unterminated object at line 1 for the sample file
while CPython reports the missing comma at line 372. The CLI contract
is that a position is shown, so match the pattern, not the text.

Refs #436
ty 0.0.83 marks Number.__hash__ abstract and enforces dict and list
invariance, so the CustomNumber helpers could not be instantiated and
nested payload literals were not assignable to JSONValue. Implement
__hash__ and declare the payloads as JSONValue. Also make the
omit-list test compare the result instead of asserting a literal.

Fixes #439
…-details

# Conflicts:
#	tests/test_dict2xml.py
@vinitkumar
vinitkumar merged commit cdde5f2 into master Sep 23, 2026
65 checks passed
@vinitkumar vinitkumar mentioned this pull request Sep 23, 2026
3 of 4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant