From 7aab2ed7ac44a9791bee4034e6c367131918ca86 Mon Sep 17 00:00:00 2001 From: Huanyi Xie <74809554+xiehuanyi@users.noreply.github.com> Date: Tue, 6 Oct 2026 12:39:31 +0300 Subject: [PATCH] fix(extract): preserve cross-drive syntax warnings Keep warning path formatting from aborting a recovered extraction. AI assistance: Codex drafted the change and the actual extraction regression. Co-Authored-By: Codex (cherry picked from commit 1e91fc2f1b40857fd5968ea5e7d2dc7aedfde8a0) --- graphify/extract.py | 7 ++++- tests/test_partial_extraction_warning.py | 33 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/graphify/extract.py b/graphify/extract.py index be3ebf42d..c04311e0f 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -7824,7 +7824,12 @@ def extract( # #2520 Luau case). `multiline_error` is absent from pre-fix cached # results, so those fall back to the file-node-only arm. if len(_res.get("nodes", [])) <= 1 or _pe.get("multiline_error"): - _rel = os.path.relpath(str(_p), str(root)).replace("\\", "/") + try: + _rel = os.path.relpath(str(_p), str(root)).replace("\\", "/") + except ValueError: + # Included files may live on another Windows drive. A display + # warning must not discard the graph recovered by the parser. + _rel = _p.as_posix() # Symbols recovered from the file, excluding its own file node. This # is what separates the two cases the warning otherwise blurs: a file # that contributed nothing but its file node is a total loss, while diff --git a/tests/test_partial_extraction_warning.py b/tests/test_partial_extraction_warning.py index f859bcd8a..bf5c1b1b4 100644 --- a/tests/test_partial_extraction_warning.py +++ b/tests/test_partial_extraction_warning.py @@ -13,6 +13,7 @@ region. Both rendered as "may be partially extracted". Part 1 of #2788 — the Astro frontmatter parse itself — is NOT addressed here; that belongs to the .svelte/.astro AST work in #2731. """ +import ntpath import re import pytest @@ -66,6 +67,38 @@ def test_warning_still_reports_the_first_error_line(tmp_path, capsys): assert re.search(r"first error at line \d+", err), err +def test_syntax_warning_survives_cross_drive_paths_without_changing_the_graph( + tmp_path, capsys, monkeypatch, +): + """The real recovery parse must return its graph even if display relpath fails.""" + import graphify.extract as ex + + source = _partial_parse_fixture(tmp_path) + original = extract([source], root=tmp_path) + original_warning = capsys.readouterr().err + assert "may be partially extracted: broken.lua (" in original_warning + assert source.as_posix() not in original_warning + original_relpath = ex.os.path.relpath + cross_drive_calls = [] + + def cross_drive_relpath(path, start=None): + if str(path) == str(source) and str(start) == str(tmp_path): + cross_drive_calls.append((path, start)) + return ntpath.relpath("D:/included/broken.lua", "C:/scan-root") + return original_relpath(path, start) + + monkeypatch.setattr(ex.os.path, "relpath", cross_drive_relpath) + result = extract([source], root=tmp_path) + assert cross_drive_calls + assert result["nodes"] == original["nodes"] + assert result["edges"] == original["edges"] + warning = capsys.readouterr().err + assert "partially extracted" in warning + assert source.as_posix() in warning + assert re.search(r"first error at line \d+", warning) + assert "yielded no symbols" not in warning + + def test_a_clean_file_is_silent(tmp_path, capsys): f = tmp_path / "fine.py" f.write_text("def ok():\n return 1\n", encoding="utf-8")