From 855170cd8f32f11bad22f322d221fc9d55e288d5 Mon Sep 17 00:00:00 2001 From: nia-sg-bot Date: Wed, 26 Aug 2026 15:03:49 +0530 Subject: [PATCH] fix(structural): surface parser dependency failures as warnings --- diffgraph/structural.py | 7 ++++++- tests/test_structural.py | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/diffgraph/structural.py b/diffgraph/structural.py index 09bc372..96f0201 100644 --- a/diffgraph/structural.py +++ b/diffgraph/structural.py @@ -567,7 +567,12 @@ def analyze_local_diff( continue parser_errors = ( - UnicodeDecodeError, ValueError, RuntimeError, OSError, TypeError + StructuralDependencyError, + UnicodeDecodeError, + ValueError, + RuntimeError, + OSError, + TypeError, ) try: old_symbols, old_imports, _old_calls, _old_bindings, _old_rebindings = ( diff --git a/tests/test_structural.py b/tests/test_structural.py index d91710b..16923b2 100644 --- a/tests/test_structural.py +++ b/tests/test_structural.py @@ -911,7 +911,36 @@ def invalid_artifact(*args, **kwargs): cli._validate_structural_artifact({}) -def test_missing_parser_dependency_is_a_run_level_cli_error(tmp_path, monkeypatch): +def test_missing_parser_dependency_is_a_scoped_structural_warning(tmp_path, monkeypatch): + """A parser installation failure must not turn exact Git input into a false change.""" + from diffgraph.structural import StructuralDependencyError + + root = repo(tmp_path) + write(root, "app.py", "def value():\n return 1\n") + git(root, "add", "app.py") + + def unavailable(): + raise StructuralDependencyError("parser dependency is unavailable") + + monkeypatch.setattr("diffgraph.structural._parser", unavailable) + artifact = analyze_local_diff(str(root), staged=True) + + assert_valid(artifact) + assert artifact["symbols"] == [] + assert artifact["relationships"] == [] + assert artifact["metadata"]["files_analyzed"] == 0 + assert artifact["metadata"]["files_skipped"] == 1 + assert artifact["metadata"]["warnings"] == [{ + "code": "PARSE_FAILURE", + "file": "app.py", + "detail": ( + "post-change: StructuralDependencyError: " + "parser dependency is unavailable" + ), + }] + + +def test_cli_emits_valid_artifact_when_parser_dependency_is_unavailable(tmp_path, monkeypatch): from click.testing import CliRunner from diffgraph.cli import main from diffgraph.structural import StructuralDependencyError @@ -928,9 +957,11 @@ def unavailable(): result = CliRunner().invoke( main, ["--structural-json", "-", "diff", "--staged"] ) - assert result.exit_code == 1 - assert "parser dependency is unavailable" in result.output - assert "PARSE_FAILURE" not in result.output + + assert result.exit_code == 0, result.output + artifact = json.loads(result.output) + assert_valid(artifact) + assert artifact["metadata"]["warnings"][0]["code"] == "PARSE_FAILURE" def test_missing_ai_dependency_is_a_click_error(tmp_path, monkeypatch):