def test_only(self): for n in range(5): gen = (i for i in range(n)) if n == 1: self.assertEqual(only(gen), 0) else: with self.assertRaises(NotOneValueFound): only(gen)
def __init__(self, pp_object, args, deep): self.config = pp_object.config self.args = args depth = getattr(self.config.thread_local, 'depth', 0) frame = inspect.currentframe().f_back.f_back self.event = Event(FrameInfo(frame), 'log', None, depth) formatted = self.config.formatter.format_log(self.event) self.config.write(formatted) self.returns = None try: assert not NO_ASTTOKENS self.call = call = Source.executing(frame).node assert isinstance(call, ast.Call) assert len(args) == len(call.args) except Exception: if deep: self.returns = args[0] = args[0]() for i, arg in enumerate(args): self.write_placeholder(i, arg) else: if deep: call_arg = only(call.args) assert isinstance( call_arg, ast.Lambda ), "You must pass a lambda DIRECTLY to pp.deep, not as a result of any other expression" self.returns = self.deep_pp(call_arg.body, frame) else: self.plain_pp(args, call.args)
def executing_piece(self) -> range: """ The piece (range of lines) containing the line currently being executed by the interpreter in this frame. Raises an exception if .scope is None, which usually means the source code for this frame is unavailable. """ return only(piece for piece in self.scope_pieces if self.lineno in piece)
def tester(arg, returns=None): frame = inspect.currentframe().f_back Source.lazycache(frame) call = Source.executing(frame).node result = eval( compile(ast.Expression(only(call.args)), '<>', 'eval'), frame.f_globals, frame.f_locals, ) assert result == result, (result, arg) if returns is None: return arg return returns
def check_code(self, code, nodes): linestarts = dict(dis.findlinestarts(code)) instructions = get_instructions(code) lineno = None for inst in instructions: if time.time() - self.start_time > 45 * 60: # Avoid travis time limit of 50 minutes raise TimeOut lineno = linestarts.get(inst.offset, lineno) if not inst.opname.startswith(( 'BINARY_', 'UNARY_', 'LOAD_ATTR', 'LOAD_METHOD', 'LOOKUP_METHOD', 'SLICE+', 'COMPARE_OP', 'CALL_', 'IS_OP', 'CONTAINS_OP', )): continue frame = C() frame.f_lasti = inst.offset frame.f_code = code frame.f_globals = globals() frame.f_lineno = lineno source = Source.for_frame(frame) node = None try: try: node = Source.executing(frame).node except Exception: if inst.opname.startswith(('COMPARE_OP', 'CALL_')): continue if isinstance(only(source.statements_at_line(lineno)), (ast.AugAssign, ast.Import)): continue raise except Exception: print(source.text, lineno, inst, node and ast.dump(node), code, file=sys.stderr, sep='\n') raise nodes[node].append((inst, frame.__dict__)) yield [inst.opname, node_string(source, node)] for const in code.co_consts: if isinstance(const, type(code)): for x in self.check_code(const, nodes): yield x
def test_markers(): options = Options(before=0, after=0) line = only(FrameInfo(inspect.currentframe(), options).lines) assert line.is_current assert re.match(r"<Line \d+ ", repr(line)) assert ( " (current=True) " "' line = only(FrameInfo(inspect.currentframe(), options).lines)'" " of " in repr(line)) assert repr(line).endswith("test_core.py>") assert repr(LINE_GAP) == "LINE_GAP" assert '*'.join(t.string for t in line.tokens) == \ 'line*=*only*(*FrameInfo*(*inspect*.*currentframe*(*)*,*options*)*.*lines*)*\n' def convert_token_range(r): if r.data.type == token.NAME: return '[[', ']]' markers = markers_from_ranges(line.token_ranges, convert_token_range) assert line.render(markers) == \ '[[line]] = [[only]]([[FrameInfo]]([[inspect]].[[currentframe]](), [[options]]).[[lines]])' assert line.render(markers, strip_leading_indent=False) == \ ' [[line]] = [[only]]([[FrameInfo]]([[inspect]].[[currentframe]](), [[options]]).[[lines]])' def convert_variable_range(r): return '[[', ' of type {}]]'.format(r.data[0].value.__class__.__name__) markers = markers_from_ranges(line.variable_ranges, convert_variable_range) assert sorted(markers) == [ (4, True, '[['), (8, False, ' of type Line]]'), (50, True, '[['), (57, False, ' of type Options]]'), ] line.text += ' # < > " & done' assert line.render(markers) == \ '[[line of type Line]] = only(FrameInfo(inspect.currentframe(), [[options of type Options]]).lines)' \ ' # < > " & done' assert line.render(markers, escape_html=True) == \ '[[line of type Line]] = only(FrameInfo(inspect.currentframe(), [[options of type Options]]).lines)' \ ' # < > " & done'
def assigned_names(node, *, allow_one: bool, allow_loops: bool) -> Tuple[Tuple[str], ast.AST]: """ Finds the names being assigned to in the nearest ancestor of the given node that assigns names and satisfies the given conditions. If allow_loops is false, this only considers assignment statements, e.g. `x, y = ...`. If it's true, then for loops and comprehensions are also considered. If allow_one is false, nodes which assign only one name are ignored. Returns: 1. a tuple of strings containing the names of the nodes being assigned 2. The AST node where the assignment happens """ while hasattr(node, 'parent'): node = node.parent target = None if NAMED_EXPR_SUPPORT and isinstance(node, ast.NamedExpr): target = node.target elif isinstance(node, ast.Assign): target = only(node.targets) elif isinstance(node, (ast.For, ast.comprehension)) and allow_loops: target = node.target if not target: continue names = node_names(target) if len(names) > 1 or allow_one: break else: raise TypeError('No assignment found') return names, node
def check_code(self, code, nodes): linestarts = dict(dis.findlinestarts(code)) instructions = get_instructions(code) lineno = None for inst in instructions: lineno = linestarts.get(inst.offset, lineno) if not inst.opname.startswith(( 'BINARY_', 'UNARY_', 'LOAD_ATTR', 'LOAD_METHOD', 'LOOKUP_METHOD', 'SLICE+', 'COMPARE_OP', 'CALL_', )): continue frame = C() frame.f_lasti = inst.offset frame.f_code = code frame.f_globals = globals() frame.f_lineno = lineno source = Source.for_frame(frame) node = None try: try: node = Source.executing(frame).node except Exception: if inst.opname.startswith(('COMPARE_OP', 'CALL_')): continue if isinstance(only(source.statements_at_line(lineno)), (ast.AugAssign, ast.Import)): continue raise try: self.assertIsNone(nodes[node]) except KeyError: print(ast.dump(source.tree), list(ast.walk(source.tree)), nodes, node, ast.dump(node), file=sys.stderr, sep='\n') except Exception: print(source.text, lineno, inst, node and ast.dump(node), code, file=sys.stderr, sep='\n') raise nodes[node] = (inst, frame.__dict__) yield [inst.opname, node_string(source, node)] for const in code.co_consts: if isinstance(const, type(code)): for x in self.check_code(const, nodes): yield x