| import contextlib |
| import io |
| import unittest |
| from unittest.mock import patch |
| from textwrap import dedent |
| |
| from test.support import force_not_colorized |
| |
| from _pyrepl.console import InteractiveColoredConsole |
| from _pyrepl.simple_interact import _more_lines |
| |
| class TestSimpleInteract(unittest.TestCase): |
| def test_multiple_statements(self): |
| namespace = {} |
| code = dedent("""\ |
| class A: |
| def foo(self): |
| |
| |
| pass |
| |
| class B: |
| def bar(self): |
| pass |
| |
| a = 1 |
| a |
| """) |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| f = io.StringIO() |
| with ( |
| patch.object(InteractiveColoredConsole, "showsyntaxerror") as showsyntaxerror, |
| patch.object(InteractiveColoredConsole, "runsource", wraps=console.runsource) as runsource, |
| contextlib.redirect_stdout(f), |
| ): |
| more = console.push(code, filename="<stdin>", _symbol="single") # type: ignore[call-arg] |
| self.assertFalse(more) |
| showsyntaxerror.assert_not_called() |
| |
| |
| def test_multiple_statements_output(self): |
| namespace = {} |
| code = dedent("""\ |
| b = 1 |
| b |
| a = 1 |
| a |
| """) |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| f = io.StringIO() |
| with contextlib.redirect_stdout(f): |
| more = console.push(code, filename="<stdin>", _symbol="single") # type: ignore[call-arg] |
| self.assertFalse(more) |
| self.assertEqual(f.getvalue(), "1\n") |
| |
| def test_empty(self): |
| namespace = {} |
| code = "" |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| f = io.StringIO() |
| with contextlib.redirect_stdout(f): |
| more = console.push(code, filename="<stdin>", _symbol="single") # type: ignore[call-arg] |
| self.assertFalse(more) |
| self.assertEqual(f.getvalue(), "") |
| |
| def test_runsource_compiles_and_runs_code(self): |
| console = InteractiveColoredConsole() |
| source = "print('Hello, world!')" |
| with patch.object(console, "runcode") as mock_runcode: |
| console.runsource(source) |
| mock_runcode.assert_called_once() |
| |
| def test_runsource_returns_false_for_successful_compilation(self): |
| console = InteractiveColoredConsole() |
| source = "print('Hello, world!')" |
| f = io.StringIO() |
| with contextlib.redirect_stdout(f): |
| result = console.runsource(source) |
| self.assertFalse(result) |
| |
| @force_not_colorized |
| def test_runsource_returns_false_for_failed_compilation(self): |
| console = InteractiveColoredConsole() |
| source = "print('Hello, world!'" |
| f = io.StringIO() |
| with contextlib.redirect_stderr(f): |
| result = console.runsource(source) |
| self.assertFalse(result) |
| self.assertIn('SyntaxError', f.getvalue()) |
| |
| def test_runsource_shows_syntax_error_for_failed_compilation(self): |
| console = InteractiveColoredConsole() |
| source = "print('Hello, world!'" |
| with patch.object(console, "showsyntaxerror") as mock_showsyntaxerror: |
| console.runsource(source) |
| mock_showsyntaxerror.assert_called_once() |
| source = dedent("""\ |
| match 1: |
| case {0: _, 0j: _}: |
| pass |
| """) |
| with patch.object(console, "showsyntaxerror") as mock_showsyntaxerror: |
| console.runsource(source) |
| mock_showsyntaxerror.assert_called_once() |
| |
| def test_no_active_future(self): |
| console = InteractiveColoredConsole() |
| source = "x: int = 1; print(__annotations__)" |
| f = io.StringIO() |
| with contextlib.redirect_stdout(f): |
| result = console.runsource(source) |
| self.assertFalse(result) |
| self.assertEqual(f.getvalue(), "{'x': <class 'int'>}\n") |
| |
| |
| class TestMoreLines(unittest.TestCase): |
| def test_invalid_syntax_single_line(self): |
| namespace = {} |
| code = "if foo" |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_empty_line(self): |
| namespace = {} |
| code = "" |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_valid_single_statement(self): |
| namespace = {} |
| code = "foo = 1" |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_multiline_single_assignment(self): |
| namespace = {} |
| code = dedent("""\ |
| foo = [ |
| 1, |
| 2, |
| 3, |
| ]""") |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_multiline_single_block(self): |
| namespace = {} |
| code = dedent("""\ |
| def foo(): |
| '''docs''' |
| |
| return 1""") |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertTrue(_more_lines(console, code)) |
| |
| def test_multiple_statements_single_line(self): |
| namespace = {} |
| code = "foo = 1;bar = 2" |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_multiple_statements(self): |
| namespace = {} |
| code = dedent("""\ |
| import time |
| |
| foo = 1""") |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertTrue(_more_lines(console, code)) |
| |
| def test_multiple_blocks(self): |
| namespace = {} |
| code = dedent("""\ |
| from dataclasses import dataclass |
| |
| @dataclass |
| class Point: |
| x: float |
| y: float""") |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertTrue(_more_lines(console, code)) |
| |
| def test_multiple_blocks_empty_newline(self): |
| namespace = {} |
| code = dedent("""\ |
| from dataclasses import dataclass |
| |
| @dataclass |
| class Point: |
| x: float |
| y: float |
| """) |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_multiple_blocks_indented_newline(self): |
| namespace = {} |
| code = ( |
| "from dataclasses import dataclass\n" |
| "\n" |
| "@dataclass\n" |
| "class Point:\n" |
| " x: float\n" |
| " y: float\n" |
| " " |
| ) |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertFalse(_more_lines(console, code)) |
| |
| def test_incomplete_statement(self): |
| namespace = {} |
| code = "if foo:" |
| console = InteractiveColoredConsole(namespace, filename="<stdin>") |
| self.assertTrue(_more_lines(console, code)) |