diff options
| -rw-r--r-- | Lib/test/test_runpy.py | 94 | ||||
| -rw-r--r-- | Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst | 1 | ||||
| -rw-r--r-- | Modules/main.c | 4 | 
3 files changed, 92 insertions, 7 deletions
diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index f8274a981c..2954dfedc7 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -1,15 +1,18 @@  # Test the runpy module -import unittest -import os +import contextlib +import importlib.machinery, importlib.util  import os.path -import sys +import pathlib +import py_compile  import re +import signal +import subprocess +import sys  import tempfile -import importlib, importlib.machinery, importlib.util -import py_compile +import textwrap +import unittest  import warnings -import pathlib -from test.support import verbose, no_tracing +from test.support import no_tracing, verbose  from test.support.import_helper import forget, make_legacy_pyc, unload  from test.support.os_helper import create_empty_file, temp_dir  from test.support.script_helper import make_script, make_zip_script @@ -752,5 +755,82 @@ s = "non-ASCII: h\xe9"              self.assertEqual(result['s'], "non-ASCII: h\xe9") +class TestExit(unittest.TestCase): +    STATUS_CONTROL_C_EXIT = 0xC000013A +    EXPECTED_CODE = ( +        STATUS_CONTROL_C_EXIT +        if sys.platform == "win32" +        else -signal.SIGINT +    ) +    @staticmethod +    @contextlib.contextmanager +    def tmp_path(*args, **kwargs): +        with temp_dir() as tmp_fn: +            yield pathlib.Path(tmp_fn) + + +    def run(self, *args, **kwargs): +        with self.tmp_path() as tmp: +            self.ham = ham = tmp / "ham.py" +            ham.write_text( +                textwrap.dedent( +                    """\ +                    raise KeyboardInterrupt +                    """ +                ) +            ) +            super().run(*args, **kwargs) + +    def assertSigInt(self, *args, **kwargs): +        proc = subprocess.run(*args, **kwargs, text=True, stderr=subprocess.PIPE) +        self.assertTrue(proc.stderr.endswith("\nKeyboardInterrupt\n")) +        self.assertEqual(proc.returncode, self.EXPECTED_CODE) + +    def test_pymain_run_file(self): +        self.assertSigInt([sys.executable, self.ham]) + +    def test_pymain_run_file_runpy_run_module(self): +        tmp = self.ham.parent +        run_module = tmp / "run_module.py" +        run_module.write_text( +            textwrap.dedent( +                """\ +                import runpy +                runpy.run_module("ham") +                """ +            ) +        ) +        self.assertSigInt([sys.executable, run_module], cwd=tmp) + +    def test_pymain_run_file_runpy_run_module_as_main(self): +        tmp = self.ham.parent +        run_module_as_main = tmp / "run_module_as_main.py" +        run_module_as_main.write_text( +            textwrap.dedent( +                """\ +                import runpy +                runpy._run_module_as_main("ham") +                """ +            ) +        ) +        self.assertSigInt([sys.executable, run_module_as_main], cwd=tmp) + +    def test_pymain_run_command_run_module(self): +        self.assertSigInt( +            [sys.executable, "-c", "import runpy; runpy.run_module('ham')"], +            cwd=self.ham.parent, +        ) + +    def test_pymain_run_command(self): +        self.assertSigInt([sys.executable, "-c", "import ham"], cwd=self.ham.parent) + +    def test_pymain_run_stdin(self): +        self.assertSigInt([sys.executable], input="import ham", cwd=self.ham.parent) + +    def test_pymain_run_module(self): +        ham = self.ham +        self.assertSigInt([sys.executable, "-m", ham.stem], cwd=ham.parent) + +  if __name__ == "__main__":      unittest.main() diff --git a/Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst b/Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst new file mode 100644 index 0000000000..fa3d2f1aa3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-08-25-19-25-36.bpo-41602.Z64s0I.rst @@ -0,0 +1 @@ +Add tests for SIGINT handling in the runpy module. diff --git a/Modules/main.c b/Modules/main.c index 4a76f4461b..2cc891f61a 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -287,7 +287,11 @@ pymain_run_module(const wchar_t *modname, int set_argv0)          Py_DECREF(module);          return pymain_exit_err_print();      } +    _Py_UnhandledKeyboardInterrupt = 0;      result = PyObject_Call(runmodule, runargs, NULL); +    if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) { +        _Py_UnhandledKeyboardInterrupt = 1; +    }      Py_DECREF(runpy);      Py_DECREF(runmodule);      Py_DECREF(module);  | 
