def test_report(self): source = """\ import example_printing __live_coding_context__ = globals()['report_builder'] # variable name is important! example_printing.custom_print('42', 'xyz') """ expected_report_python2 = """\ print '42xyz' """ expected_report_python3 = """\ print('42xyz') """ expected_report = (expected_report_python3 if version_info.major >= 3 else expected_report_python2) report_builder = ReportBuilder() environment = dict(report_builder=report_builder) swallower = FileSwallower(sys.stdout) with patch('sys.stdout', swallower): exec(source, environment, environment) report = report_builder.report() self.assertReportEqual(expected_report, report)
def test_format_stderr(self): # SETUP expected_report = "sys.stderr.write('abc') | x = None" # EXEC builder = ReportBuilder() builder.add_output('abc', 1, target_name='sys.stderr') builder.assign(name='x', value=None, line_number=1) # VERIFY self.assertReportEqual(expected_report, builder.report())
def test_output_without_newline(self): # SETUP expected_report = """\ sys.stdout.write('a') """ # EXEC builder = ReportBuilder() builder.add_output('a', 1) # VERIFY self.assertReportEqual(expected_report, builder.report())
def test_output(self): # SETUP expected_report = """\ print('a') """ # EXEC builder = ReportBuilder() builder.add_output('a\n', 1) # VERIFY self.assertReportEqual(expected_report, builder.report())
def test_assign_function(self): # SETUP expected_report = '' f = lambda n: n + 1 # EXEC builder = ReportBuilder() builder.assign(name='f', value=f, line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_output_stderr(self): # SETUP expected_report = """\ sys.stderr.write('a\\n') """ # EXEC builder = ReportBuilder() builder.add_output('a\n', 1, target_name='sys.stderr') # VERIFY self.assertReportEqual(expected_report, builder.report())
def test_multiple_messages(self): # SETUP expected_report = """\ x = 1 y = 2 """ # EXEC builder = ReportBuilder() builder.assign(name='x', value=1, line_number=1) builder.assign(name='y', value=2, line_number=1) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_assign_object_without_repr(self): # SETUP expected_report = '' class class_without_repr(object): pass # EXEC builder = ReportBuilder() builder.assign(name='x', value=class_without_repr(), line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_multiple_messages(self): # SETUP expected_report = """\ x = 1 y = 2 """ # EXEC builder = ReportBuilder() builder.assign(name='x', value=1, line_number=1) builder.assign(name='y', value=2, line_number=1) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_delete_item(self): # SETUP expected_report = "d = {'a': 1}" d = {'a': 1, 'b': 2} expected_d = {'a': 1} # EXEC builder = ReportBuilder() del builder.record_delete(name='d', target=d, line_number=1)['b'] report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(expected_d, d)
def test_assign_object_without_repr(self): # SETUP expected_report = '' class class_without_repr(object): pass # EXEC builder = ReportBuilder() builder.assign(name='x', value=class_without_repr(), line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_assign_function(self): # SETUP expected_report = '' def f(n): return n+1 # EXEC builder = ReportBuilder() builder.assign(name='f', value=f, line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_assign_function(self): # SETUP expected_report = '' def f(n): return n + 1 # EXEC builder = ReportBuilder() builder.assign(name='f', value=f, line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def trace_code(self, source, module_name=None): builder = ReportBuilder(self.message_limit) builder.max_width = self.max_width try: tree = parse(source) new_tree = Tracer().visit(tree) fix_missing_locations(new_tree) LineNumberCleaner().visit(new_tree) # from ast import dump # print(dump(new_tree, include_attributes=False)) code = compile(new_tree, PSEUDO_FILENAME, 'exec') self.environment[CONTEXT_NAME] = builder if module_name is None: environment = self.environment else: mod = types.ModuleType(module_name) sys.modules[module_name] = mod # Any reason to set mod.__file__? mod.__dict__.update(self.environment) environment = mod.__dict__ exec(code, environment) for value in environment.values(): if isinstance(value, types.GeneratorType): value.close() except SyntaxError: ex = sys.exc_info()[1] messages = traceback.format_exception_only(type(ex), ex) builder.add_message(messages[-1].strip() + ' ', ex.lineno) except: etype, value, tb = sys.exc_info() is_reported = False builder.message_limit = None # make sure we don't hit limit builder.max_width = None # make sure we don't hit limit messages = traceback.format_exception_only(etype, value) message = messages[-1].strip() + ' ' entries = traceback.extract_tb(tb) for filename, line_number, _, _ in entries: if filename == PSEUDO_FILENAME: builder.add_extra_message(message, line_number) is_reported = True if not is_reported: builder.add_message(message, 1) # print('=== Unexpected Exception in tracing code ===') # traceback.print_exception(etype, value, tb) return builder.report()
def test_assign_object_with_repr_exception(self): # SETUP expected_report = '' class BadReprClass(object): def __repr__(self): raise NotImplementedError() # EXEC builder = ReportBuilder() builder.assign(name='m', value=BadReprClass(), line_number=1) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_lambda(self): # SETUP expected_report = '(23 => 24)' min_line = max_line = 1 # EXEC builder = ReportBuilder() y = list( map(lambda x: builder.report_lambda(min_line, max_line, x, x + 1), [23])) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual([24], y)
def test_multiple_lines(self): # SETUP expected_report = """\ a = 3 b = 'xyz' """ # EXEC builder = ReportBuilder() builder.assign(name='a', value=3, line_number=1) builder.assign(name='b', value="xyz", line_number=3) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_multiple_lines(self): # SETUP expected_report = """\ a = 3 b = 'xyz' """ # EXEC builder = ReportBuilder() builder.assign(name='a', value=3, line_number=1) builder.assign(name='b', value="xyz", line_number=3) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_lambda_multiple_calls(self): # SETUP expected_report = "('a', 'b' => 'ab') | (1, 2 => 3)" min_line = max_line = 1 # EXEC builder = ReportBuilder() list( map( lambda x, y: builder.report_lambda(min_line, max_line, x, y, x + y), ['a', 1], ['b', 2])) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_multiple_outputs_different_lines(self): # SETUP expected_report = """\ print('a') print('b') """ # EXEC builder = ReportBuilder() builder.add_output('a\n', 1) builder.add_output('b\n', 3) # VERIFY self.assertReportEqual(expected_report, builder.report())
def test_return(self): # SETUP expected_value = 'bob' expected_report = """\ return 'bob' """ # EXEC builder = ReportBuilder() value = builder.return_value(value=expected_value, line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines()) self.assertEqual(expected_value, value)
def test_return(self): # SETUP expected_value = 'bob' expected_report = """\ return 'bob' """ # EXEC builder = ReportBuilder() value = builder.return_value(value=expected_value, line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(expected_value, value)
def test_assign(self): # SETUP expected_value = 5 expected_report = """\ x = 5 """ # EXEC builder = ReportBuilder() value = builder.assign(name='x', value=expected_value, line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(expected_value, value)
def test_assign_value_after_indexes(self): # SETUP expected_report = "a[0][23] = 99 " # EXEC builder = ReportBuilder() builder.start_assignment() builder.add_assignment_index(0) builder.add_assignment_index(23) builder.set_assignment_value(99) builder.report_assignment('a[{!r}][{!r}] = {!r}', line_number=1) builder.end_assignment() report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_assign(self): # SETUP expected_value = 5 expected_report = """\ x = 5 """ # EXEC builder = ReportBuilder() value = builder.assign(name='x', value=expected_value, line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines()) self.assertEqual(expected_value, value)
def test_lambda_multiple_params(self): # SETUP expected_report = "('a', 'b' => 'ab')" min_line = max_line = 1 # EXEC builder = ReportBuilder() z = list( map( lambda x, y: builder.report_lambda(min_line, max_line, x, y, x + y), ['a'], ['b'])) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(['ab'], z)
def test_frames(self): # SETUP expected_report = """\ i = 1 | i = 2 n = 2 | """ # EXEC builder = ReportBuilder() frame1 = builder.start_frame(1, 2) frame1.assign(name='i', value=1, line_number=1) frame2 = builder.start_frame(1, 2) frame2.assign(name='i', value=2, line_number=1) frame1.assign(name='n', value=2, line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_call_no_change(self): # SETUP expected_report = "" expected_result = 23 # EXEC builder = ReportBuilder() result = builder.record_call(names=['a'], displays_before=['[1, 2]'], result=expected_result, displays_after=['[1, 2]'], line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(expected_result, result)
def test_multiple_visits(self): # SETUP expected_report = """\ x = 'first' | x = 'second' y = 'continue' | """ # EXEC builder = ReportBuilder() builder.start_block(1, 2) builder.assign(name='x', value='first', line_number=1) builder.assign(name='y', value='continue', line_number=2) builder.start_block(1, 2) builder.assign(name='x', value='second', line_number=1) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_message_limit(self): # SETUP expected_report = """\ a = 10 b = 20 """ # EXEC builder = ReportBuilder(message_limit=4) builder.assign('a', 10, 1) builder.assign('b', 20, 2) with self.assertRaisesRegex(RuntimeError, r'message limit exceeded'): builder.assign('c', 30, 3) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_frames_with_extra_message(self): # SETUP expected_report = """\ i = 1 | i = 2 | extra message""" # EXEC builder = ReportBuilder() frame1 = builder.start_frame(1, 2) frame1.assign(name='i', value=1, line_number=1) frame2 = builder.start_frame(1, 2) frame2.assign(name='i', value=2, line_number=1) builder.add_extra_message('extra message', 2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_call_no_change(self): # SETUP expected_report = "" expected_result = 23 # EXEC builder = ReportBuilder() result = builder.record_call(name='a', display_before='[1, 2]', result=expected_result, display_after='[1, 2]', line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines()) self.assertEqual(expected_result, result)
def test_frames_with_extra_message(self): # SETUP expected_report = """\ i = 1 | i = 2 | extra message""" # EXEC builder = ReportBuilder() frame1 = builder.start_frame(1, 2) frame1.assign(name='i', value=1, line_number=1) frame2 = builder.start_frame(1, 2) frame2.assign(name='i', value=2, line_number=1) builder.add_extra_message('extra message', 2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_assign_object_with_multiline_repr(self): # SETUP expected_report = 'm = multiline_class(1, 2) ' class multiline_class(object): def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return "multiline_class(%r,\n%r)" % (self.x, self.y) # EXEC builder = ReportBuilder() builder.assign(name='m', value=multiline_class(1, 2), line_number=1) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_multiple_visits(self): # SETUP expected_report = """\ x = 'first' | x = 'second' y = 'continue' | """ # EXEC builder = ReportBuilder() builder.start_block(1, 2) builder.assign(name='x', value='first', line_number=1) builder.assign(name='y', value='continue', line_number=2) builder.start_block(1, 2) builder.assign(name='x', value='second', line_number=1) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_frames(self): # SETUP expected_report = """\ i = 1 | i = 2 n = 2 | """ # EXEC builder = ReportBuilder() frame1 = builder.start_frame(1, 2) frame1.assign(name='i', value=1, line_number=1) frame2 = builder.start_frame(1, 2) frame2.assign(name='i', value=2, line_number=1) frame1.assign(name='n', value=2, line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_message_limit_with_empty_blocks(self): # SETUP expected_report = """\ """ # EXEC builder = ReportBuilder(message_limit=2) builder.start_frame(1, 5) builder.start_block(1, 3) builder.start_block(1, 3) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_separate_scopes(self): # SETUP expected_report = """\ x = 'child' | x = 'child again' y = 'main' """ # EXEC builder = ReportBuilder() builder.assign(name='y', value='main', line_number=3) builder.start_block(1, 1) builder.assign(name='x', value='child', line_number=1) builder.start_block(1, 1) builder.assign(name='x', value='child again', line_number=1) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_separate_scopes(self): # SETUP expected_report = """\ x = 'child' | x = 'child again' y = 'main' """ # EXEC builder = ReportBuilder() builder.assign(name='y', value='main', line_number=3) builder.start_block(1, 1) builder.assign(name='x', value='child', line_number=1) builder.start_block(1, 1) builder.assign(name='x', value='child again', line_number=1) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_assign_object_with_multiline_repr(self): # SETUP expected_report = 'm = multiline_class(1, 2) ' class multiline_class(object): def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return "multiline_class(%r,\n%r)" % (self.x, self.y) # EXEC builder = ReportBuilder() builder.assign(name='m', value=multiline_class(1, 2), line_number=1) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_return_multiline(self): # SETUP class Multiline(object): def __repr__(self): return 'Multiline(\n)' expected_value = Multiline() expected_report = """\ return Multiline( ) """ # EXEC builder = ReportBuilder() value = builder.return_value(value=expected_value, line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(expected_value, value)
def test_exception_multiline_message(self): # SETUP source = """\ try: raise RuntimeError('a\\nb') except: builder.exception()""" expected_report = """\ RuntimeError: a b """ # EXEC builder = ReportBuilder() environment = dict(builder=builder) exec(source, environment, environment) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report)
def test_exception(self): # SETUP source = """\ try: raise RuntimeError('foo') except: builder.exception()""" expected_report = """\ RuntimeError: foo """ # EXEC builder = ReportBuilder() environment = dict(builder=builder) exec_code(source, environment, environment) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_nested_blocks(self): # SETUP expected_report = """\ x = 'first' | x = 'second' | y = 1 | y = 2 """ # EXEC builder = ReportBuilder() builder.start_block(1, 2) builder.assign(name='x', value='first', line_number=1) builder.start_block(1, 2) builder.assign(name='x', value='second', line_number=1) builder.start_block(2, 2) builder.assign(name='y', value=1, line_number=2) builder.start_block(2, 2) builder.assign(name='y', value=2, line_number=2) report = builder.report() # VERIFY self.assertEqual(expected_report.splitlines(), report.splitlines())
def test_call_multiple_changes(self): # SETUP expected_report = """\ a = [1, 2] b = 6 """ expected_result = 23 # EXEC builder = ReportBuilder() result = builder.record_call(names=['a', 'b'], displays_before=['[2, 1]', '5'], result=expected_result, displays_after=['[1, 2]', '6'], line_number=2) report = builder.report() # VERIFY self.assertReportEqual(expected_report, report) self.assertEqual(expected_result, result)
def trace_code(self, source): builder = ReportBuilder(self.message_limit) builder.max_width = self.max_width try: tree = parse(source) visitor = TraceAssignments() new_tree = visitor.visit(tree) fix_missing_locations(new_tree) # from ast import dump # print(dump(new_tree, include_attributes=False)) code = compile(new_tree, PSEUDO_FILENAME, 'exec') self.environment[CONTEXT_NAME] = builder exec(code, self.environment, self.environment) except SyntaxError: ex = sys.exc_info()[1] messages = traceback.format_exception_only(type(ex), ex) builder.add_message(messages[-1].strip() + ' ', ex.lineno) except: etype, value, tb = sys.exc_info() is_reported = False builder.message_limit = None # make sure we don't hit limit builder.max_width = None # make sure we don't hit limit messages = traceback.format_exception_only(etype, value) message = messages[-1].strip() + ' ' entries = traceback.extract_tb(tb) for filename, line_number, _, _ in entries: if filename == PSEUDO_FILENAME: builder.add_extra_message(message, line_number) is_reported = True if not is_reported: builder.add_message(message, 1) # print('=== Unexpected Exception in tracing code ===') # traceback.print_exception(etype, value, tb) return builder.report()