Coverage for src/renaissance/integrations/python/ast/ast_node.py: 82%

45 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-10-02 13:12 +0000

1"""Implementation that patches the native ast using 'traits' mechanism. 

2 

3Requires minimum amount of code to make the matcher work. 

4""" 

5 

6import ast 

7 

8from renaissance.integrations.python.ast.kinds import PYTHON_KIND_MAP 

9from renaissance.syntax_tree.semantic_kind import SemanticKind 

10 

11 

12class ASTExtension: 

13 """AI: Static trait methods patched onto the stdlib ast.AST class to satisfy the node protocol.""" 

14 

15 @staticmethod 

16 def load_from_ast(text, file): 

17 """AI: Parse text as Python source (attributed to file) into a native ast.AST tree.""" 

18 root = ast.parse(text, file) 

19 return root 

20 

21 @staticmethod 

22 @property 

23 def ast_node(self): 

24 """AI: Return this node itself.""" 

25 return self 

26 

27 @staticmethod 

28 @property 

29 def parser_kind(self): 

30 """AI: Return this node's ast class name as its parser kind.""" 

31 return type(self).__name__ 

32 

33 @staticmethod 

34 @property 

35 def semantic_kind(self): 

36 """AI: Return the semantic kind mapped from this node's ast class name.""" 

37 return PYTHON_KIND_MAP.get(type(self).__name__, SemanticKind.NODE) 

38 

39 @staticmethod 

40 @property 

41 def ast_properties(self): 

42 """AI: Return this node's non-AST fields as a name-to-value dict.""" 

43 return {field: getattr(self, field) for field in self._fields if not isinstance(getattr(self, field), ast.AST)} 

44 

45 @staticmethod 

46 @property 

47 def ast_children(self): 

48 """AI: Return this node's direct child AST nodes, including those held in list fields.""" 

49 children = [getattr(self, field) for field in self._fields if isinstance(getattr(self, field), (ast.AST))] 

50 [children.extend(getattr(self, field)) for field in self._fields if isinstance(getattr(self, field), (list))] 

51 return children 

52 

53 @staticmethod 

54 @property 

55 def ast_signature(self): 

56 """AI: Return the unparsed source text of this node.""" 

57 return ast.unparse(self) 

58 

59 @staticmethod 

60 @property 

61 def ast_name(self): 

62 """AI: Return this node's identifying name, derived from its specific ast node type.""" 

63 if isinstance(self, ast.arg): 

64 signature = self.arg 

65 elif isinstance(self, ast.Name): 

66 signature = self.id 

67 elif isinstance(self, ast.Expr) and isinstance(self.value, ast.Name): 

68 signature = self.value.id 

69 else: 

70 signature = str(self) 

71 return signature