From e74c8f2879159367eded0933c9f89b9315f07df8 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Apr 2008 02:23:57 +0000 Subject: [PATCH] Added kill, terminate and send_signal to subprocess.Popen The bits and pieces for the Windows side were already in place. The POSIX side is trivial (as usual) and uses os.kill(). --- Doc/library/subprocess.rst | 23 +++++++++++++++++++ Lib/subprocess.py | 32 ++++++++++++++++++++++++++ Lib/test/test_subprocess.py | 46 +++++++++++++++++++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 103 insertions(+) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 901ce4d014b..09dbbd18c6e 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -208,6 +208,29 @@ Instances of the :class:`Popen` class have the following methods: size is large or unlimited. +.. method:: Popen.send_signal(signal) + + Sends the signal *signal* to the child. + + .. note:: + + On Windows only SIGTERM is supported so far. It's an alias for + *terminate*. + + +.. method:: Popen.terminate() + + Stop the child. On Posix OSs the method sends SIGTERM to the + child. On Windows the Win32 API function TerminateProcess is called + to stop the child. + + +.. method:: Popen.kill() + + Kills the child. On Posix OSs the function sends SIGKILL to the child. + On Windows *kill* is an alias for *terminate*. + + The following attributes are also available: .. attribute:: Popen.stdin diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 975a924aba3..dc639c953aa 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -357,6 +357,7 @@ import os import types import traceback import gc +import signal # Exception classes used by this module. class CalledProcessError(Exception): @@ -384,6 +385,7 @@ if mswindows: from win32process import CreateProcess, STARTUPINFO, \ GetExitCodeProcess, STARTF_USESTDHANDLES, \ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE + from win32process import TerminateProcess from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 else: from _subprocess import * @@ -906,6 +908,21 @@ class Popen(object): self.wait() return (stdout, stderr) + def send_signal(self, sig): + """Send a signal to the process + """ + if sig == signal.SIGTERM: + self.terminate() + else: + raise ValueError("Only SIGTERM is supported on Windows") + + def terminate(self): + """Terminates the process + """ + TerminateProcess(self._handle, 1) + + kill = terminate + else: # # POSIX methods @@ -1184,6 +1201,21 @@ class Popen(object): self.wait() return (stdout, stderr) + def send_signal(self, sig): + """Send a signal to the process + """ + os.kill(self.pid, sig) + + def terminate(self): + """Terminate the process with SIGTERM + """ + self.send_signal(signal.SIGTERM) + + def kill(self): + """Kill the process with SIGKILL + """ + self.send_signal(signal.SIGKILL) + def _demo_posix(): # diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 9886f3d8fa2..ccefb674b80 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -584,6 +584,29 @@ class ProcessTestCase(unittest.TestCase): os.remove(fname) self.assertEqual(rc, 47) + def test_send_signal(self): + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.send_signal(signal.SIGINT) + self.assertNotEqual(p.wait(), 0) + + def test_kill(self): + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.kill() + self.assertEqual(p.wait(), -signal.SIGKILL) + + def test_terminate(self): + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.terminate() + self.assertEqual(p.wait(), -signal.SIGTERM) # # Windows tests @@ -655,6 +678,29 @@ class ProcessTestCase(unittest.TestCase): ' -c "import sys; sys.exit(47)"') self.assertEqual(rc, 47) + def test_send_signal(self): + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.send_signal(signal.SIGTERM) + self.assertNotEqual(p.wait(), 0) + + def test_kill(self): + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.kill() + self.assertNotEqual(p.wait(), 0) + + def test_terminate(self): + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.terminate() + self.assertNotEqual(p.wait(), 0) def test_main(): test_support.run_unittest(ProcessTestCase) diff --git a/Misc/NEWS b/Misc/NEWS index 6ae6e46942b..660651a86b5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,8 @@ Core and builtins Extensions Modules ------------------ +- Added kill, terminate and send_signal(sig) to subprocess.Popen. + - Added phase(z) -> phi, polar(z) -> r, phi and rect(r, phi) -> z to the cmath module.