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
def insert_with_block_check(self, node): """Modifies a with statement node in-place to add an initial check for whether or not the block should be executed. If the block is not executed it will raise a XonshBlockError containing the required information. """ nwith = self._nwith # the nesting level of the current with-statement lineno = get_lineno(node) col = get_col(node, 0) # Add or discover target names targets = set() i = 0 # index of unassigned items def make_next_target(): nonlocal i targ = '__xonsh_with_target_{}_{}__'.format(nwith, i) n = Name(id=targ, ctx=Store(), lineno=lineno, col_offset=col) targets.add(targ) i += 1 return n for item in node.items: if item.optional_vars is None: if has_elts(item.context_expr): targs = [make_next_target() for _ in item.context_expr.elts] optvars = Tuple(elts=targs, ctx=Store(), lineno=lineno, col_offset=col) else: optvars = make_next_target() item.optional_vars = optvars else: targets.update(gather_names(item.optional_vars)) # Ok, now that targets have been found / created, make the actual check # to see if we are in a non-executing block. This is equivalent to # writing the following condition: # # if getattr(targ0, '__xonsh_block__', False) or \ # getattr(targ1, '__xonsh_block__', False) or ...: # raise XonshBlockError(lines, globals(), locals()) tests = [_getblockattr(t, lineno, col) for t in sorted(targets)] if len(tests) == 1: test = tests[0] else: test = BoolOp(op=Or(), values=tests, lineno=lineno, col_offset=col) ldx, udx = self._find_with_block_line_idx(node) lines = [Str(s=s, lineno=lineno, col_offset=col) for s in self.lines[ldx:udx]] check = If(test=test, body=[ Raise(exc=xonsh_call('XonshBlockError', args=[List(elts=lines, ctx=Load(), lineno=lineno, col_offset=col), xonsh_call('globals', args=[], lineno=lineno, col=col), xonsh_call('locals', args=[], lineno=lineno, col=col)], lineno=lineno, col=col), cause=None, lineno=lineno, col_offset=col)], orelse=[], lineno=lineno, col_offset=col) node.body.insert(0, check)
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( TryExcept(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
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