Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

code_parser.py 5.3 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  1. import ast
  2. from dataclasses import dataclass, field
  3. from typing import List, Dict, Optional
  4. @dataclass
  5. class FunctionParameter:
  6. name: str
  7. has_default: bool
  8. @dataclass
  9. class FunctionParameters:
  10. _params: List[FunctionParameter] = field(default_factory=dict)
  11. @property
  12. def all(self) -> List[str]:
  13. return [param.name for param in self._params]
  14. @property
  15. def required(self) -> List[str]:
  16. return [param.name for param in self._params if not param.has_default]
  17. @property
  18. def optional(self) -> List[str]:
  19. return [param.name for param in self._params if param.has_default]
  20. @dataclass
  21. class FunctionSignature:
  22. name: str
  23. line_num: int
  24. params: FunctionParameters
  25. def parse_imports(code: str) -> Dict[str, str]:
  26. """Extract function signatures from the given code.
  27. >>> parse_imports("import package.library_v1 as library")
  28. {'package.library_v1': 'library'}
  29. >>> parse_imports("import package.library")
  30. {'package.library': 'package.library'}
  31. :param code: The Python code to analyze.
  32. :return: Dictionary mapping full imported object/package name to import it's alias.
  33. """
  34. tree = ast.parse(code)
  35. imports = {}
  36. for node in ast.walk(tree):
  37. if isinstance(node, ast.Import):
  38. for alias in node.names:
  39. original_name = alias.name
  40. aliased_name = alias.asname if alias.asname else alias.name
  41. imports[original_name] = aliased_name
  42. elif isinstance(node, ast.ImportFrom):
  43. module = node.module
  44. for alias in node.names:
  45. original_name = f"{module}.{alias.name}" if module else alias.name
  46. aliased_name = alias.asname if alias.asname else alias.name
  47. imports[original_name] = aliased_name
  48. return imports
  49. def parse_functions_signatures(code: str) -> Dict[str, FunctionSignature]:
  50. """Extract function signatures from the given Python code.
  51. Example:
  52. >>> code = "def add(a, b=5):\\n return a + b"
  53. >>> parse_functions_signatures(code)
  54. {
  55. 'add': FunctionSignature(
  56. name='add',
  57. line_num=1,
  58. params=FunctionParameters(
  59. [FunctionParameter(name='a', has_default=False), FunctionParameter(name='b', has_default=True)]
  60. )
  61. )
  62. }
  63. :param code: The Python code to analyze.
  64. :return: Dictionary mapping function name to function parameters, encapsulated in a FunctionSignature object.
  65. """
  66. tree = ast.parse(code)
  67. signatures = {}
  68. def extract_methods_from_class(class_node: ast.ClassDef, derived_class_name: Optional[str] = None) -> Dict[str, FunctionSignature]:
  69. """
  70. Recursively extract methods from a class and its all its base classes.
  71. Given a class node from the AST, this function will extract the methods defined in the class
  72. as well as any methods inherited from its base classes. It produces a dictionary of method
  73. names (prefixed by the derived class, if specified) mapped to their `FunctionSignature` objects.
  74. :param class_node: The AST node representing the class.
  75. :param derived_class_name : (Optional) The name of the derived class (if any) to prefix the method names.
  76. :return: Dictionary mapping method names to their signatures.
  77. """
  78. derived_class_name = derived_class_name or class_node.name
  79. methods = {}
  80. # Extracting methods from the current class node
  81. for method in class_node.body:
  82. if isinstance(method, ast.FunctionDef):
  83. method_name = f"{derived_class_name}.{method.name}"
  84. methods[method_name] = FunctionSignature(name=method_name, line_num=method.lineno, params=parse_parameters(method.args))
  85. # Recursively extract methods from base classes
  86. for base in class_node.bases:
  87. if isinstance(base, ast.Name) and base.id in classes:
  88. base_class_methods = extract_methods_from_class(class_node=classes[base.id], derived_class_name=derived_class_name)
  89. methods.update(base_class_methods)
  90. return methods
  91. # Extract top-level functions and classes
  92. classes = {} # Store all the classes with their node
  93. for node in tree.body:
  94. if isinstance(node, ast.FunctionDef):
  95. signatures[node.name] = FunctionSignature(name=node.name, line_num=node.lineno, params=parse_parameters(node.args))
  96. elif isinstance(node, ast.ClassDef):
  97. classes[node.name] = node
  98. signatures.update(extract_methods_from_class(class_node=node))
  99. return signatures
  100. def parse_parameters(args: ast.arguments) -> FunctionParameters:
  101. """Extracts the parameters from the given args object.
  102. :param args: Object from the AST (Abstract Syntax Tree).
  103. :return: A FunctionParameters object representing the parameters, including their names and default values.
  104. """
  105. defaults = [None] * (len(args.args) - len(args.defaults)) + args.defaults
  106. parameters = FunctionParameters([FunctionParameter(name=arg.arg, has_default=default is not None) for arg, default in zip(args.args, defaults)])
  107. return parameters
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...