Fix ResourceWarning in asyncio.BaseSubprocessTransport
authorVictor Stinner <victor.stinner@gmail.com>
Fri, 31 Jul 2015 15:49:43 +0000 (17:49 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Fri, 31 Jul 2015 15:49:43 +0000 (17:49 +0200)
Issue #24763: Fix resource warnings when asyncio.BaseSubprocessTransport
constructor fails, if subprocess.Popen raises an exception for example.

Patch written by Martin Richard, test written by me.

Lib/asyncio/base_subprocess.py
Lib/test/test_asyncio/test_subprocess.py

index c1477b8248db4ea87589658fdcf4c413582d408a..a6971b1d8581e2da4fbb3e8e8cfb9d37364e89dc 100644 (file)
@@ -35,8 +35,13 @@ class BaseSubprocessTransport(transports.SubprocessTransport):
             self._pipes[2] = None
 
         # Create the child process: set the _proc attribute
-        self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
-                    stderr=stderr, bufsize=bufsize, **kwargs)
+        try:
+            self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
+                        stderr=stderr, bufsize=bufsize, **kwargs)
+        except:
+            self.close()
+            raise
+
         self._pid = self._proc.pid
         self._extra['subprocess'] = self._proc
 
index ea85e1912e8e409a3a7e59b667e8672d06f5dc6b..d138c263c1c1cc6d33acdc3dd473b41ae4c7ecf3 100644 (file)
@@ -1,6 +1,7 @@
 import signal
 import sys
 import unittest
+import warnings
 from unittest import mock
 
 import asyncio
@@ -413,6 +414,20 @@ class SubprocessMixin:
         # the transport was not notified yet
         self.assertFalse(killed)
 
+    def test_popen_error(self):
+        # Issue #24763: check that the subprocess transport is closed
+        # when BaseSubprocessTransport fails
+        with mock.patch('subprocess.Popen') as popen:
+            exc = ZeroDivisionError
+            popen.side_effect = exc
+
+            create = asyncio.create_subprocess_exec(sys.executable, '-c',
+                                                    'pass', loop=self.loop)
+            with warnings.catch_warnings(record=True) as warns:
+                with self.assertRaises(exc):
+                    self.loop.run_until_complete(create)
+                self.assertEqual(warns, [])
+
 
 if sys.platform != 'win32':
     # Unix