Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ae46229

Browse filesBrowse files
authored
[3.8] bpo-41602: raise SIGINT exit code on KeyboardInterrupt from pymain_run_module (GH-21956) (#22398)
Closes bpo issue 41602. (cherry picked from commit a68a2ad) Co-authored-by: Thomas Grainger <tagrain@gmail.com>
1 parent 87ca11b commit ae46229
Copy full SHA for ae46229

File tree

3 files changed

+91
-6
lines changed
Filter options

3 files changed

+91
-6
lines changed

‎Lib/test/test_runpy.py

Copy file name to clipboardExpand all lines: Lib/test/test_runpy.py
+86-6Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
# Test the runpy module
2-
import unittest
3-
import os
2+
import contextlib
3+
import importlib.machinery, importlib.util
44
import os.path
5-
import sys
5+
import pathlib
6+
import py_compile
67
import re
8+
import signal
9+
import subprocess
10+
import sys
711
import tempfile
8-
import importlib, importlib.machinery, importlib.util
9-
import py_compile
12+
import textwrap
13+
import unittest
1014
import warnings
11-
import pathlib
1215
from test.support import (
1316
forget, make_legacy_pyc, unload, verbose, no_tracing,
1417
create_empty_file, temp_dir)
@@ -752,5 +755,82 @@ def test_encoding(self):
752755
self.assertEqual(result['s'], "non-ASCII: h\xe9")
753756

754757

758+
class TestExit(unittest.TestCase):
759+
STATUS_CONTROL_C_EXIT = 0xC000013A
760+
EXPECTED_CODE = (
761+
STATUS_CONTROL_C_EXIT
762+
if sys.platform == "win32"
763+
else -signal.SIGINT
764+
)
765+
@staticmethod
766+
@contextlib.contextmanager
767+
def tmp_path(*args, **kwargs):
768+
with temp_dir() as tmp_fn:
769+
yield pathlib.Path(tmp_fn)
770+
771+
772+
def run(self, *args, **kwargs):
773+
with self.tmp_path() as tmp:
774+
self.ham = ham = tmp / "ham.py"
775+
ham.write_text(
776+
textwrap.dedent(
777+
"""\
778+
raise KeyboardInterrupt
779+
"""
780+
)
781+
)
782+
super().run(*args, **kwargs)
783+
784+
def assertSigInt(self, *args, **kwargs):
785+
proc = subprocess.run(*args, **kwargs, text=True, stderr=subprocess.PIPE)
786+
self.assertTrue(proc.stderr.endswith("\nKeyboardInterrupt\n"))
787+
self.assertEqual(proc.returncode, self.EXPECTED_CODE)
788+
789+
def test_pymain_run_file(self):
790+
self.assertSigInt([sys.executable, self.ham])
791+
792+
def test_pymain_run_file_runpy_run_module(self):
793+
tmp = self.ham.parent
794+
run_module = tmp / "run_module.py"
795+
run_module.write_text(
796+
textwrap.dedent(
797+
"""\
798+
import runpy
799+
runpy.run_module("ham")
800+
"""
801+
)
802+
)
803+
self.assertSigInt([sys.executable, run_module], cwd=tmp)
804+
805+
def test_pymain_run_file_runpy_run_module_as_main(self):
806+
tmp = self.ham.parent
807+
run_module_as_main = tmp / "run_module_as_main.py"
808+
run_module_as_main.write_text(
809+
textwrap.dedent(
810+
"""\
811+
import runpy
812+
runpy._run_module_as_main("ham")
813+
"""
814+
)
815+
)
816+
self.assertSigInt([sys.executable, run_module_as_main], cwd=tmp)
817+
818+
def test_pymain_run_command_run_module(self):
819+
self.assertSigInt(
820+
[sys.executable, "-c", "import runpy; runpy.run_module('ham')"],
821+
cwd=self.ham.parent,
822+
)
823+
824+
def test_pymain_run_command(self):
825+
self.assertSigInt([sys.executable, "-c", "import ham"], cwd=self.ham.parent)
826+
827+
def test_pymain_run_stdin(self):
828+
self.assertSigInt([sys.executable], input="import ham", cwd=self.ham.parent)
829+
830+
def test_pymain_run_module(self):
831+
ham = self.ham
832+
self.assertSigInt([sys.executable, "-m", ham.stem], cwd=ham.parent)
833+
834+
755835
if __name__ == "__main__":
756836
unittest.main()
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add tests for SIGINT handling in the runpy module.

‎Modules/main.c

Copy file name to clipboardExpand all lines: Modules/main.c
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,11 @@ pymain_run_module(const wchar_t *modname, int set_argv0)
299299
Py_DECREF(module);
300300
return pymain_exit_err_print();
301301
}
302+
_Py_UnhandledKeyboardInterrupt = 0;
302303
result = PyObject_Call(runmodule, runargs, NULL);
304+
if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) {
305+
_Py_UnhandledKeyboardInterrupt = 1;
306+
}
303307
Py_DECREF(runpy);
304308
Py_DECREF(runmodule);
305309
Py_DECREF(module);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.