summaryrefslogtreecommitdiffstats
path: root/Lib/test/_test_multiprocessing.py
diff options
context:
space:
mode:
authorXiang Zhang <angwerzx@126.com>2017-03-29 03:58:54 (GMT)
committerGitHub <noreply@github.com>2017-03-29 03:58:54 (GMT)
commit794623bdb232eafd8925f76470209afcdcbcdcd2 (patch)
tree347ef8d6c630abbe08af35ae9280ada42b101f7d /Lib/test/_test_multiprocessing.py
parentec1f5df46ed37aa3e839d20298c4b361a9a74bc4 (diff)
downloadcpython-794623bdb232eafd8925f76470209afcdcbcdcd2.zip
cpython-794623bdb232eafd8925f76470209afcdcbcdcd2.tar.gz
cpython-794623bdb232eafd8925f76470209afcdcbcdcd2.tar.bz2
bpo-28699: fix abnormal behaviour of pools in multiprocessing.pool (GH-693)
an exception raised at the very first of an iterable would cause pools behave abnormally (swallow the exception or hang)
Diffstat (limited to 'Lib/test/_test_multiprocessing.py')
-rw-r--r--Lib/test/_test_multiprocessing.py59
1 files changed, 58 insertions, 1 deletions
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 1d3bb0f..771bbf2 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -1755,6 +1755,8 @@ class CountedObject(object):
class SayWhenError(ValueError): pass
def exception_throwing_generator(total, when):
+ if when == -1:
+ raise SayWhenError("Somebody said when")
for i in range(total):
if i == when:
raise SayWhenError("Somebody said when")
@@ -1833,6 +1835,32 @@ class _TestPool(BaseTestCase):
except multiprocessing.TimeoutError:
self.fail("pool.map_async with chunksize stalled on null list")
+ def test_map_handle_iterable_exception(self):
+ if self.TYPE == 'manager':
+ self.skipTest('test not appropriate for {}'.format(self.TYPE))
+
+ # SayWhenError seen at the very first of the iterable
+ with self.assertRaises(SayWhenError):
+ self.pool.map(sqr, exception_throwing_generator(1, -1), 1)
+ # again, make sure it's reentrant
+ with self.assertRaises(SayWhenError):
+ self.pool.map(sqr, exception_throwing_generator(1, -1), 1)
+
+ with self.assertRaises(SayWhenError):
+ self.pool.map(sqr, exception_throwing_generator(10, 3), 1)
+
+ class SpecialIterable:
+ def __iter__(self):
+ return self
+ def __next__(self):
+ raise SayWhenError
+ def __len__(self):
+ return 1
+ with self.assertRaises(SayWhenError):
+ self.pool.map(sqr, SpecialIterable(), 1)
+ with self.assertRaises(SayWhenError):
+ self.pool.map(sqr, SpecialIterable(), 1)
+
def test_async(self):
res = self.pool.apply_async(sqr, (7, TIMEOUT1,))
get = TimingWrapper(res.get)
@@ -1863,6 +1891,13 @@ class _TestPool(BaseTestCase):
if self.TYPE == 'manager':
self.skipTest('test not appropriate for {}'.format(self.TYPE))
+ # SayWhenError seen at the very first of the iterable
+ it = self.pool.imap(sqr, exception_throwing_generator(1, -1), 1)
+ self.assertRaises(SayWhenError, it.__next__)
+ # again, make sure it's reentrant
+ it = self.pool.imap(sqr, exception_throwing_generator(1, -1), 1)
+ self.assertRaises(SayWhenError, it.__next__)
+
it = self.pool.imap(sqr, exception_throwing_generator(10, 3), 1)
for i in range(3):
self.assertEqual(next(it), i*i)
@@ -1889,6 +1924,17 @@ class _TestPool(BaseTestCase):
if self.TYPE == 'manager':
self.skipTest('test not appropriate for {}'.format(self.TYPE))
+ # SayWhenError seen at the very first of the iterable
+ it = self.pool.imap_unordered(sqr,
+ exception_throwing_generator(1, -1),
+ 1)
+ self.assertRaises(SayWhenError, it.__next__)
+ # again, make sure it's reentrant
+ it = self.pool.imap_unordered(sqr,
+ exception_throwing_generator(1, -1),
+ 1)
+ self.assertRaises(SayWhenError, it.__next__)
+
it = self.pool.imap_unordered(sqr,
exception_throwing_generator(10, 3),
1)
@@ -1970,7 +2016,7 @@ class _TestPool(BaseTestCase):
except Exception as e:
exc = e
else:
- raise AssertionError('expected RuntimeError')
+ self.fail('expected RuntimeError')
self.assertIs(type(exc), RuntimeError)
self.assertEqual(exc.args, (123,))
cause = exc.__cause__
@@ -1984,6 +2030,17 @@ class _TestPool(BaseTestCase):
sys.excepthook(*sys.exc_info())
self.assertIn('raise RuntimeError(123) # some comment',
f1.getvalue())
+ # _helper_reraises_exception should not make the error
+ # a remote exception
+ with self.Pool(1) as p:
+ try:
+ p.map(sqr, exception_throwing_generator(1, -1), 1)
+ except Exception as e:
+ exc = e
+ else:
+ self.fail('expected SayWhenError')
+ self.assertIs(type(exc), SayWhenError)
+ self.assertIs(exc.__cause__, None)
@classmethod
def _test_wrapped_exception(cls):