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
2 changes: 1 addition & 1 deletion lint-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"RUF013": 2,
"RUF015": 2,
"RUF059": 2,
"S101": 203,
"S101": 204,
"S110": 4,
"S603": 5,
"S608": 1,
Expand Down
1 change: 1 addition & 0 deletions src/renaissance/integrations/python/ast/kinds.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"Try": SemanticKind.STATEMENT,
"TryStar": SemanticKind.STATEMENT,
"Delete": SemanticKind.STATEMENT,
"TypeAlias": SemanticKind.STATEMENT,
"Expr": SemanticKind.EXPRESSION,
"Await": SemanticKind.EXPRESSION,
"Yield": SemanticKind.EXPRESSION,
Expand Down
21 changes: 21 additions & 0 deletions test/python/ast/test_python_protocol_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,32 @@

from renaissance.integrations.python.ast.cst_node import PythonCstNode
from renaissance.integrations.python.ast.factory import PythonFactory
from renaissance.integrations.python.ast.kinds import PYTHON_KIND_MAP
from renaissance.integrations.python.ast.rst_node import PythonRstNode
from renaissance.syntax_tree.ast_rewriter import Rewritable
from renaissance.syntax_tree.semantic_kind import SemanticKind


def _all_subclasses(base: type) -> list[type]:
"""Collect every subclass of base, recursively."""
found: list[type] = []
for subclass in base.__subclasses__():
found.append(subclass)
found.extend(_all_subclasses(subclass))
return found


def test_every_python_statement_type_is_classified() -> None:
"""Assert no ast statement type falls through to NODE, so a new Python grammar cannot add one unnoticed."""
unclassified = sorted(
statement.__name__
for statement in _all_subclasses(ast.stmt)
if PYTHON_KIND_MAP.get(statement.__name__, SemanticKind.NODE) is SemanticKind.NODE
)

assert not unclassified, f"PYTHON_KIND_MAP has no entry for {unclassified}"


def test_python_nodes_satisfy_rewritable() -> None:
"""AI: Assert Python CST and RST nodes satisfy Rewritable; the annotations also gate this statically."""
cst: Rewritable = PythonCstNode.load_from_text("f(1)")
Expand Down
12 changes: 12 additions & 0 deletions test/python/ast/test_python_rst_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ def test_corner_case(self) -> None:
node = factory.create_from_text("class ŻP𭻊鲖ÉØ_ąň𣑗: pass\n")
assert_that(node.children[0].semantic_kind is not SemanticKind.NODE, is_(True))

@pytest.mark.parametrize(
"code",
[
"type Alias = int\n",
"type Alias[T] = list[T]\n",
],
)
def test_type_alias_statement_is_classified(self, code: str) -> None:
"""Verify a PEP 695 type alias statement is classified as a statement rather than an unclassified node."""
node = PythonRstNode.load_from_text(code)
assert_that(node[0].semantic_kind, is_(SemanticKind.STATEMENT))

@pytest.mark.parametrize(
"code, expected_kind",
[
Expand Down
Loading