def parse(self, node: ast.Call, module: Module, context: Context): """Process a ``ast.Call`` node and extract relevant stats. A ``ast.Call`` node has the following fields: - ``func`` that represents the function, which will often be a ``ast.Name`` or ``ast.Attribute`` node - ``args`` that represents a list of the arguments passed by position - ``keywords`` that represents a list of keyword objects representing arguments passed by keyword - ``starargs`` holds a single node, for arguments passed as *args. This is removed in Python 3.5. - ``kwargs`` holds a single node, for arguments passed as **kwargs. This is removed in Python 3.5. :param node: The node that represents a call expression. :param module: The python module where this call is encountered. :param context: The context of the given node. :return: The CallEntity instance created from the given ``ast.Call`` node. """ call: CallEntity = CallEntity(node, context) context.stack_ast_node(call) super().parse(node, module, context) context.unstack_ast_node() module.add_call(call) return call
def parse(self, node: ast.Starred, module: Module, context: Context): """Parse the value type of the ``ast.Starred`` node. Typically, the value is going to be a ``ast.Name`` node, but might be something else, although it's very improbable. Still, something like the following is valid Python code and will get executed :: def f1(): return [1, 2, 3] def f2(*args): for arg in args: print(arg) f2(*f1()) The above example will yield :: 1 2 3 """ starred_variable: StarredEntity = StarredEntity(node) context.stack_ast_node(starred_variable) parser = self.get_parser(node.value) entity = parser.parse(node.value, module, context) starred_variable.set_value_entity(entity) context.unstack_ast_node() module.add_starred_variable(starred_variable) return starred_variable
def parse(self, node: Any, module: Module, context: Context): """Process one of `[ast.List, ast.Tuple]` nodes and extract relevant stats. Tuple and List nodes have two fields: - `elts` that represents the elements of the array - `ctx` that represents the context under which the array is used (Store or Load) """ entity = self.create_new_entity(node) context.stack_ast_node(entity) # if isinstance(node.ctx, ast.Store): # context[UNPACKING_VALUES] = True # existing_context = set() # for key in context: # if key in IS_PART_OF_MAPPER: # existing_context.add(IS_PART_OF_MAPPER[key]) # # # create a hierarchy of which # if self.node_type not in context: # context[self.node_type] = '' # delimiter = '' # last_node_type_appearance = 0 # else: # delimiter = '_' # last_node_type_appearance = len(context[self.node_type].split('_')) - 1 # remove 1 that is going to be accounted for in the intersection statement # # context[self.node_type] = f'{context[self.node_type]}' \ # f'{delimiter}' \ # f'{len(existing_context.intersection(COMPLEX_DATA_TYPES)) + 1 + last_node_type_appearance}' for element in node.elts: parser = self.get_parser(element) element_entity = parser.parse(element, module, context) entity.add_element(element_entity) context.unstack_ast_node() self.add_entity_to_module(entity, module, context) return entity
def parse(self, node: ast.Assign, module: Module, context: Context): """Process an `ast.Assign` node and extract relevant stats. An ``ast.Assign`` node has two fields: - ``targets`` that represents a list of nodes - ``value`` that is a single node that is assigned to targets :param node: The node that represents an assignment operation. :param module: The python module where this variable is encountered. :param context: The context of the given node. :return: The AssignmentEntity instance created from the given ``ast.Assign`` node. """ assignment = AssignmentEntity(node) context.stack_ast_node(assignment) super().parse(node, module, context) context.unstack_ast_node() module.add_assignment(assignment) return assignment
def parse(self, node: Any, module: Module, context: Context): """Process a ``ast.IfExp`` node and extract relevant stats. A ``ast.IfExp`` node has the following fields: - ``test`` that represents the condition to be evaluated - ``body`` that represents the value to be assigned in case the condition evaluates to true - ``orelse`` that represents the value to be assigned in case the condition evaluates to false :param node: The node that represents an if expression. :param module: The python module where this expression is encountered. :param context: The context of the given node. :return: The ``pycodealizer.entities.IfExpressionEntity`` instance created from the given ``ast.IfExp`` node. """ if_expression: IfExpressionEntity = IfExpressionEntity(node) context.stack_ast_node(if_expression) super().parse(node, module, context) context.unstack_ast_node() module.add_if_expression(if_expression) return if_expression
def parse(self, node: Any): """Process the given node and extract relevant info from it.""" parser = self.get_parser(node) parser.parse(node, self.modules[-1], Context(self.modules[-1]))
def test_context_current_ast_node_prop(ast_var_node: ast.Name, context: Context): context.stack_ast_node(ast_var_node) assert context.current_ast_node == ast_var_node
def test_context_current_execution_context_prop(variable_load_entity: VariableEntity, context: Context): context.stack_execution_context(variable_load_entity) assert context.current_execution_context == variable_load_entity
def test_context_unstack_ast_node(ast_var_node: ast.Name, context: Context): context.stack_ast_node(ast_var_node) context.unstack_ast_node() assert len(context.ast_context) == 1
def test_context_stack_ast_node(ast_var_node: ast.Name, context: Context): context.stack_ast_node(ast_var_node) assert len(context.ast_context) == 2 and context.ast_context[-1] == ast_var_node
def test_context_unstack_execution_context(variable_load_entity: VariableEntity, context: Context): context.stack_execution_context(variable_load_entity) context.unstack_execution_context() assert len(context.execution_context) == 1
def test_context_stack_execution_context(variable_load_entity: VariableEntity, context: Context): context.stack_execution_context(variable_load_entity) assert len(context.execution_context) == 2 and context.execution_context[-1] == variable_load_entity
def test_context_initialization(module_entity: Module): context = Context(module_entity) assert len(context.execution_context) == 1 and context.execution_context[0] == module_entity assert len(context.ast_context) == 1 and context.ast_context[0] == module_entity
def call_entity(): return CallEntity(ast_call, Context(Module('test')))
def context(): return Context(Module('test'))