Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions diffgraph/structural.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Deterministic, local DiffGraph v2 extraction from exact Git snapshots.

This first baseline intentionally supports Python only. Other languages remain in
``files`` and produce scoped ``UNSUPPORTED_LANGUAGE`` warnings; no capability is
inferred from a filename beyond that explicit boundary.
This first baseline intentionally supports Python source and stub files only.
Other languages remain in ``files`` and produce scoped ``UNSUPPORTED_LANGUAGE``
warnings; no capability is inferred from a filename beyond that explicit boundary.
"""
from __future__ import annotations

Expand Down Expand Up @@ -34,6 +34,7 @@

ANALYZER = "diffgraph-python-tree-sitter"
QUERY_VERSION = "python-structure-v2"
PYTHON_SUFFIXES = frozenset({".py", ".pyi"})
_PARSER_STATE = threading.local()

# Resolver failures are part of the public artifact contract. Keep their
Expand Down Expand Up @@ -744,7 +745,7 @@ def _unsupported_language_warning(entry: SnapshotEntry, path: str) -> Dict[str,
return _warning(
"UNSUPPORTED_LANGUAGE",
path,
"Deterministic extraction currently supports Python (.py) only; "
"Deterministic extraction currently supports Python (.py and .pyi) only; "
"pre-change blob {}; post-change blob {}.".format(
entry.old_oid or "absent", entry.new_oid or "absent",
),
Expand Down Expand Up @@ -947,7 +948,7 @@ def analyze_local_diff(
"python"
if not binary_sides
and not non_regular_modes
and Path(path).suffix.lower() == ".py"
and Path(path).suffix.lower() in PYTHON_SUFFIXES
else None
),
"change_kind": _change_kind(entry.status, entry.old_oid, entry.new_oid),
Expand Down
24 changes: 22 additions & 2 deletions tests/test_structural.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,26 @@ def test_pathspec_scope_is_not_widened(tmp_path):
assert [item["path"] for item in artifact["files"]] == ["inside/a.py"]


def test_python_stub_files_are_analyzed_with_tree_sitter_provenance(tmp_path):
"""Typed Python stubs are part of the deterministic Python baseline."""
root = repo(tmp_path)
write(root, "api.pyi", "def load(value: str) -> int: ...\n")
commit(root)
write(root, "api.pyi", "def load(value: str, retries: int = 0) -> int: ...\n")

artifact = analyze_local_diff(str(root))

assert_valid(artifact)
assert artifact["files"][0]["language"] == "python"
assert artifact["metadata"]["files_analyzed"] == 1
assert artifact["metadata"]["warnings"] == []
symbol = artifact["symbols"][0]
assert (symbol["id"], symbol["name"], symbol["change_kind"]) == (
"sym::api.pyi::load", "load", "modified"
)
assert "parser=tree-sitter-language-pack@" in symbol["evidence"][0]["detail"]


def test_unsupported_language_is_explicit_and_not_overclaimed(tmp_path):
"""Unsupported snapshots keep their explicit capability boundary and blobs."""
root = repo(tmp_path)
Expand All @@ -194,7 +214,7 @@ def test_unsupported_language_is_explicit_and_not_overclaimed(tmp_path):
assert artifact["metadata"]["files_skipped"] == 1
assert artifact["metadata"]["warnings"][0]["code"] == "UNSUPPORTED_LANGUAGE"
assert artifact["metadata"]["warnings"][0]["detail"] == (
"Deterministic extraction currently supports Python (.py) only; "
"Deterministic extraction currently supports Python (.py and .pyi) only; "
"pre-change blob {}; post-change blob {}."
).format(old_oid, new_oid)

Expand All @@ -218,7 +238,7 @@ def test_unsupported_language_one_sided_blob_is_absent(tmp_path, change_kind):
artifact = analyze_local_diff(str(root))
assert_valid(artifact)
assert artifact["metadata"]["warnings"][0]["detail"] == (
"Deterministic extraction currently supports Python (.py) only; "
"Deterministic extraction currently supports Python (.py and .pyi) only; "
"pre-change blob {}; post-change blob {}."
).format(old_oid, new_oid)

Expand Down
Loading