Ejemplo n.º 1
0
 def visit_Match(self, node):
     match_node = self.generic_visit(node)
     line_numbers = set()
     find_line_numbers(match_node, line_numbers)
     first_line_number = min(line_numbers)
     new_nodes = [self._create_context_call('start_assignment')]
     try_body = [match_node]
     finally_body = [self._create_context_call('end_assignment')]
     new_nodes.append(
         Try(body=try_body,
             finalbody=finally_body,
             handlers=[],
             orelse=[],
             lineno=first_line_number))
     match_node.subject = self._create_bare_context_call(
         'set_assignment_value', [match_node.subject])
     for case in match_node.cases:
         try:
             format_string = self._wrap_assignment_targets((case.pattern, ))
         except ValueError:
             # Not a capture pattern, nothing to report.
             format_string = None
         if format_string is not None:
             case.body.insert(
                 0,
                 self._create_context_call(
                     'report_assignment',
                     [Str(s=format_string),
                      Num(n=case.pattern.lineno)]))
Ejemplo n.º 2
0
 def visit_Module(self, node):
     new_node = self.generic_visit(node)
     line_numbers = set()
     new_body = []
     try_body = new_node.body
     if try_body:
         while try_body and self._is_module_header(try_body[0]):
             # noinspection PyUnresolvedReferences
             new_body.append(try_body.pop(0))
         find_line_numbers(new_node, line_numbers)
     if line_numbers:
         first_line_number = min(line_numbers)
         last_line_number = max(line_numbers)
         handler_body = [self._create_context_call('exception'),
                         Raise()]
         handler = ExceptHandler(body=handler_body,
                                 lineno=last_line_number)
         new_body.append(Try(body=try_body,
                             handlers=[handler],
                             orelse=[],
                             finalbody=[]))
         new_node.body = new_body
         self._set_statement_line_numbers(try_body, first_line_number)
         self._set_statement_line_numbers(handler_body, last_line_number)
     return new_node
Ejemplo n.º 3
0
    def visit_FunctionDef(self, node):
        """ Instrument a function definition by creating a new report builder
        for this stack frame and putting it in a local variable. The local
        variable has the same name as the global variable so all calls can
        use the same CONTEXT_NAME symbol, but it means that I had to use this:
        x = globals()['x'].start_frame()
        Kind of ugly, but I think it was worth it to handle recursive calls.
        """
        if node.name == '__repr__':
            return node
        
        new_node = self.generic_visit(node)
        
        line_numbers = set()
        self._find_line_numbers(new_node, line_numbers)
        first_line_number = min(line_numbers)
        last_line_number = max(line_numbers)
        args = [Num(n=first_line_number),
                Num(n=last_line_number)]
        try_body = new_node.body
        globals_call = Call(func=Name(id='globals', ctx=Load()), 
                            args=[], 
                            keywords=[], 
                            starargs=None, 
                            kwargs=None)
        global_context = Subscript(value=globals_call, 
                                   slice=Index(value=Str(s=CONTEXT_NAME)), 
                                   ctx=Load())
        start_frame_call = Call(func=Attribute(value=global_context, 
                                               attr='start_frame', 
                                               ctx=Load()), 
                                args=args, 
                                keywords=[], 
                                starargs=None, 
                                kwargs=None)
        context_assign = Assign(targets=[Name(id=CONTEXT_NAME, ctx=Store())],
                                value=start_frame_call)
        new_node.body = [context_assign]
        
        # trace function parameter values
        for target in new_node.args.args:
            if isinstance(target, Name) and target.id == 'self':
                continue
            if arg and isinstance(target, arg) and target.arg == 'self':
                continue
            new_node.body.append(self._trace_assignment(target, node.lineno))

        handler_body = [self._create_context_call('exception'),
                        Raise()]
        new_node.body.append(
            Try(body=try_body,
                handlers=[ExceptHandler(body=handler_body)],
                orelse=[],
                finalbody=[]))
        self._set_statement_line_numbers(try_body, first_line_number)
        self._set_statement_line_numbers(handler_body, last_line_number)
        return new_node
Ejemplo n.º 4
0
 def _create_end_assignment(self, new_nodes, try_body, first_line_number,
                            last_line_number):
     end_assignment = self._create_context_call('end_assignment')
     finally_body = [end_assignment]
     new_nodes.append(
         Try(body=try_body,
             finalbody=finally_body,
             handlers=[],
             orelse=[],
             lineno=first_line_number))
     self._set_statement_line_numbers(try_body, first_line_number)
     self._set_statement_line_numbers(finally_body, last_line_number)
Ejemplo n.º 5
0
    def visitTry(self, node: ast.Try) -> None:
        def get_handler_tracker(handler: ast.ExceptHandler) -> str:
            """gets a variable name to track exception state for aliased global"""
            handler_type = handler.type
            if isinstance(handler_type, Name):
                desc = handler_type.id
            elif handler.type is None:
                desc = "bare"
            else:
                desc = "complex"

            return f"<{desc} {handler.name} at {str(id(handler))}>"

        for i, handler in enumerate(node.handlers):
            handler_name = handler.name
            if handler_name is None or not self.feature_extractor.is_global(
                handler_name, self.scope
            ):
                continue
            if handler_name not in self.builtins:
                continue

            tracker_name = get_handler_tracker(handler)
            self.scope.add_def(tracker_name)

            if not isinstance(node.body, TryBodyHook):
                node.body = [TryBodyHook(node.body)]
            cast(TryBodyHook, node.body[0]).trackers.append(tracker_name)

            handler.body = [TryHandlerBodyHook(handler.body, tracker_name)]

            if not isinstance(node.finalbody, TryFinallyHook):
                node.finalbody = [TryFinallyHook(node.finalbody)]
            cast(TryFinallyHook, node.finalbody[0]).handlers_to_restore.append(
                (tracker_name, handler_name)
            )

        super().visitTry(node)
        return
Ejemplo n.º 6
0
    def visit_Assign(self, node):
        existing_node = self.generic_visit(node)
        try:
            targets = existing_node.targets
        except AttributeError:
            targets = [existing_node.target]
        if any(map(self._is_untraceable_attribute, targets)):
            return existing_node
        if existing_node.value is None:
            return existing_node
        line_numbers = set()
        find_line_numbers(existing_node, line_numbers)
        first_line_number = min(line_numbers)
        last_line_number = max(line_numbers)
        if len(targets) == 1 and isinstance(targets[0], Name):
            existing_node.value = self._create_bare_context_call(
                'assign', [
                    Str(s=targets[0].id), existing_node.value,
                    Num(n=first_line_number)
                ])
            return existing_node
        new_nodes = []
        format_string = self._wrap_assignment_targets(targets)
        if (len(targets) == 1 and isinstance(targets[0], Tuple)):
            existing_node.value = Call(func=Name(id='tuple', ctx=Load()),
                                       args=[existing_node.value],
                                       keywords=[],
                                       starargs=None,
                                       kwargs=None)
        existing_node.value = self._create_bare_context_call(
            'set_assignment_value', [existing_node.value])
        new_nodes.append(self._create_context_call('start_assignment'))
        try_body = [existing_node]
        if format_string is not None:
            try_body.append(
                self._create_context_call(
                    'report_assignment',
                    [Str(s=format_string),
                     Num(n=existing_node.lineno)]))
        end_assignment = self._create_context_call('end_assignment')
        finally_body = [end_assignment]
        new_nodes.append(
            Try(body=try_body,
                finalbody=finally_body,
                handlers=[],
                orelse=[],
                lineno=first_line_number))
        self._set_statement_line_numbers(try_body, first_line_number)
        self._set_statement_line_numbers(finally_body, last_line_number)

        return new_nodes
Ejemplo n.º 7
0
    def visit_AugAssign(self, node):
        read_target = deepcopy(node.target)
        existing_node = self.generic_visit(node)
        line_numbers = set()
        find_line_numbers(existing_node, line_numbers)
        first_line_number = min(line_numbers)
        last_line_number = max(line_numbers)
        new_nodes = []
        try_body = [existing_node]
        new_nodes.append(self._create_context_call('start_assignment'))
        format_string = self._wrap_assignment_target(existing_node.target)
        if format_string is not None:
            if ':' in format_string:
                existing_node.value = self._create_bare_context_call(
                    'set_assignment_value', [existing_node.value])
                operator_char = OPERATOR_CHARS.get(type(existing_node.op), '?')
                format_string += ' {}= {{}} '.format(operator_char)
            else:
                self._wrap_assignment_target(read_target, index_to_get=-1)
                read_target.ctx = Load()
                set_assignment_value = self._create_context_call(
                    'set_assignment_value', [read_target])
                try_body.append(set_assignment_value)
                format_string += ' = {}'
            try_body.append(
                self._create_context_call(
                    'report_assignment',
                    [Str(s=format_string),
                     Num(n=existing_node.lineno)]))
        end_assignment = self._create_context_call('end_assignment')
        finally_body = [end_assignment]
        new_nodes.append(
            Try(body=try_body,
                finalbody=finally_body,
                handlers=[],
                orelse=[],
                lineno=first_line_number))
        self._set_statement_line_numbers(try_body, first_line_number)
        self._set_statement_line_numbers(finally_body, last_line_number)

        return new_nodes
Ejemplo n.º 8
0
 def visit_Module(self, node):
     new_node = self.generic_visit(node)
     line_numbers = set()
     self._find_line_numbers(new_node, line_numbers)
     if line_numbers:
         first_line_number = min(line_numbers)
         last_line_number = max(line_numbers)
     else:
         first_line_number = last_line_number = 1
     try_body = new_node.body
     handler_body = [self._create_context_call('exception')]
     handler = ExceptHandler(body=handler_body, lineno=last_line_number)
     if not try_body:
         # empty module
         new_node.body = try_body
     else:
         new_node.body = [
             Try(body=try_body, handlers=[handler], orelse=[], finalbody=[])
         ]
     self._set_statement_line_numbers(try_body, first_line_number)
     self._set_statement_line_numbers(handler_body, last_line_number)
     return new_node
Ejemplo n.º 9
0
    def validate_except_handlers(self, try_node: ast.Try):
        if len(try_node.handlers) > 1:
            exception_handlers: List[ast.ExceptHandler] = try_node.handlers.copy()
            general_exc_handler: ast.ExceptHandler = next(
                (handler
                 for handler in exception_handlers
                 if (handler.type is None or  # no specified exception or is BaseException
                     (isinstance(handler.type, ast.Name) and handler.type.id == BaseException.__name__)
                     )
                 ), exception_handlers[0]
            )

            try_node.handlers = [general_exc_handler]
            exception_handlers.remove(general_exc_handler)

            for handler in exception_handlers:
                warnings = len(self.warnings)
                self.visit(handler)
                if warnings == len(self.warnings):
                    self._log_using_specific_exception_warning(handler.type)

        if len(try_node.handlers) == 1:
            self.visit(try_node.handlers[0])
Ejemplo n.º 10
0
    def visit_FunctionDef(self, node):
        """ Instrument a function definition by creating a new report builder
        for this stack frame and putting it in a local variable. The local
        variable has the same name as the global variable so all calls can
        use the same CONTEXT_NAME symbol, but it means that I had to use this:
        x = globals()['x'].start_frame()
        Kind of ugly, but I think it was worth it to handle recursive calls.
        """
        new_node = self.generic_visit(node)

        line_numbers = set()
        find_line_numbers(new_node, line_numbers)
        first_line_number = min(line_numbers)
        last_line_number = max(line_numbers)
        args = [Num(n=first_line_number), Num(n=last_line_number)]
        start_frame_keywords = []
        for decorator in new_node.decorator_list:
            if getattr(decorator, 'id', None) == 'traced':
                start_frame_keywords.append(
                    keyword(arg='is_decorated',
                            value=Name(id='True', ctx=Load())))
        try_body = new_node.body
        globals_call = Call(func=Name(id='globals', ctx=Load()),
                            args=[],
                            keywords=[],
                            starargs=None,
                            kwargs=None)
        global_context = Subscript(value=globals_call,
                                   slice=Index(value=Str(s=CONTEXT_NAME)),
                                   ctx=Load())
        start_frame_call = Call(func=Attribute(value=global_context,
                                               attr='start_frame',
                                               ctx=Load()),
                                args=args,
                                keywords=start_frame_keywords,
                                starargs=None,
                                kwargs=None)
        context_assign = Assign(targets=[Name(id=CONTEXT_NAME, ctx=Store())],
                                value=start_frame_call)
        new_node.body = [context_assign]
        if isinstance(try_body[0], Expr) and isinstance(
                try_body[0].value, Str):
            # Move docstring back to top of function.
            # noinspection PyUnresolvedReferences
            new_node.body.insert(0, try_body.pop(0))

        # trace function parameter values
        arg_nodes = []
        arg_nodes.extend(getattr(new_node.args, 'posonlyargs', []))
        arg_nodes.extend(new_node.args.args)
        arg_nodes.append(new_node.args.kwarg)
        arg_nodes.append(new_node.args.vararg)
        arg_nodes.extend(new_node.args.kwonlyargs)
        for target in arg_nodes:
            if target is None:
                continue
            if isinstance(target, Name) and target.id == 'self':
                continue
            if isinstance(target, arg) and target.arg == 'self':
                continue
            new_node.body.append(self._trace_assignment(target, node.lineno))

        if try_body:
            handler_body = [self._create_context_call('exception'), Raise()]
            new_node.body.append(
                Try(body=try_body,
                    handlers=[ExceptHandler(body=handler_body)],
                    orelse=[],
                    finalbody=[]))
            self._set_statement_line_numbers(try_body, first_line_number)
            self._set_statement_line_numbers(handler_body, last_line_number)
        return new_node
Ejemplo n.º 11
0
def empty_script_tree(project_id: str, add_main_loop: bool = True) -> Module:
    """Creates barebones of the script (empty 'main' function).

    Returns
    -------
    """

    main_body: List[stmt] = [
        Assign(
            targets=[Name(id="aps", ctx=Store())],
            value=Call(func=Name(id="ActionPoints", ctx=Load()),
                       args=[Name(id="res", ctx=Load())],
                       keywords=[]),
            type_comment=None,
        )
    ]

    if add_main_loop:
        main_body.append(
            While(test=NameConstant(value=True, kind=None),
                  body=[Pass()],
                  orelse=[]))
    else:
        """put there "pass" in order to make code valid even if there is no
        other statement (e.g. no object from resources)"""
        main_body.append(Pass())

    # TODO helper function for try ... except

    tree = Module(
        body=[
            FunctionDef(
                name="main",
                args=arguments(
                    args=[
                        arg(arg="res",
                            annotation=Name(id=RES_CLS, ctx=Load()),
                            type_comment=None)
                    ],
                    vararg=None,
                    kwonlyargs=[],
                    kw_defaults=[],
                    kwarg=None,
                    defaults=[],
                ),
                body=main_body,
                decorator_list=[],
                returns=NameConstant(value=None, kind=None),
                type_comment=None,
            ),
            If(
                test=Compare(left=Name(id="__name__", ctx=Load()),
                             ops=[Eq()],
                             comparators=[Str(s="__main__", kind="")]),
                body=[
                    Try(
                        body=[
                            With(
                                items=[
                                    withitem(
                                        context_expr=Call(
                                            func=Name(id=RES_CLS, ctx=Load()),
                                            args=[Str(s=project_id, kind="")],
                                            keywords=[],
                                        ),
                                        optional_vars=Name(id="res",
                                                           ctx=Store()),
                                    )
                                ],
                                body=[
                                    Expr(value=Call(
                                        func=Name(id="main", ctx=Load()),
                                        args=[Name(id="res", ctx=Load())],
                                        keywords=[],
                                    ))
                                ],
                                type_comment=None,
                            )
                        ],
                        handlers=[
                            ExceptHandler(
                                type=Name(id=Exception.__name__, ctx=Load()),
                                name="e",
                                body=[
                                    Expr(value=Call(
                                        func=Name(id=arcor2.exceptions.runtime.
                                                  print_exception.__name__,
                                                  ctx=Load()),
                                        args=[Name(id="e", ctx=Load())],
                                        keywords=[],
                                    ))
                                ],
                            )
                        ],
                        orelse=[],
                        finalbody=[],
                    )
                ],
                orelse=[],
            ),
        ],
        type_ignores=[],
    )

    add_import(tree, arcor2.exceptions.runtime.__name__,
               arcor2.exceptions.runtime.print_exception.__name__)
    add_import(tree, RES_MODULE, RES_CLS, try_to_import=False)
    add_import(tree, "action_points", "ActionPoints", try_to_import=False)

    return tree