summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorAntoine Pitrou <pitrou@free.fr>2017-09-01 17:16:46 (GMT)
committerGitHub <noreply@github.com>2017-09-01 17:16:46 (GMT)
commitea767915f7476c1fe97f7b1a53304d57f105bdd2 (patch)
treec9945795ded82474153e56aca0560d58cc30ce51 /Lib/test
parent98c849a2f32f6727239b4cce38b8f0ff8adeef22 (diff)
downloadcpython-ea767915f7476c1fe97f7b1a53304d57f105bdd2.zip
cpython-ea767915f7476c1fe97f7b1a53304d57f105bdd2.tar.gz
cpython-ea767915f7476c1fe97f7b1a53304d57f105bdd2.tar.bz2
[3.6] bpo-27144: concurrent.futures as_complete and map iterators do not keep reference to returned object (GH-1560) (#3266)
bpo-27144: concurrent.futures as_complie and map iterators do not keep reference to returned object (cherry picked from commit 97e1b1c81458d2109b2ffed32ffa1eb643a6c3b9)
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_concurrent_futures.py48
1 files changed, 48 insertions, 0 deletions
diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py
index 90dec61..73baf9a 100644
--- a/Lib/test/test_concurrent_futures.py
+++ b/Lib/test/test_concurrent_futures.py
@@ -59,6 +59,10 @@ class MyObject(object):
pass
+def make_dummy_object(_):
+ return MyObject()
+
+
class BaseTestCase(unittest.TestCase):
def setUp(self):
self._thread_key = test.support.threading_setup()
@@ -397,6 +401,38 @@ class AsCompletedTests:
completed = [f for f in futures.as_completed([future1,future1])]
self.assertEqual(len(completed), 1)
+ def test_free_reference_yielded_future(self):
+ # Issue #14406: Generator should not keep references
+ # to finished futures.
+ futures_list = [Future() for _ in range(8)]
+ futures_list.append(create_future(state=CANCELLED_AND_NOTIFIED))
+ futures_list.append(create_future(state=SUCCESSFUL_FUTURE))
+
+ with self.assertRaises(futures.TimeoutError):
+ for future in futures.as_completed(futures_list, timeout=0):
+ futures_list.remove(future)
+ wr = weakref.ref(future)
+ del future
+ self.assertIsNone(wr())
+
+ futures_list[0].set_result("test")
+ for future in futures.as_completed(futures_list):
+ futures_list.remove(future)
+ wr = weakref.ref(future)
+ del future
+ self.assertIsNone(wr())
+ if futures_list:
+ futures_list[0].set_result("test")
+
+ def test_correct_timeout_exception_msg(self):
+ futures_list = [CANCELLED_AND_NOTIFIED_FUTURE, PENDING_FUTURE,
+ RUNNING_FUTURE, SUCCESSFUL_FUTURE]
+
+ with self.assertRaises(futures.TimeoutError) as cm:
+ list(futures.as_completed(futures_list, timeout=0))
+
+ self.assertEqual(str(cm.exception), '2 (of 4) futures unfinished')
+
class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests, BaseTestCase):
pass
@@ -422,6 +458,10 @@ class ExecutorTest:
list(self.executor.map(pow, range(10), range(10))),
list(map(pow, range(10), range(10))))
+ self.assertEqual(
+ list(self.executor.map(pow, range(10), range(10), chunksize=3)),
+ list(map(pow, range(10), range(10))))
+
def test_map_exception(self):
i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5])
self.assertEqual(i.__next__(), (0, 1))
@@ -472,6 +512,14 @@ class ExecutorTest:
"than 0"):
self.executor_type(max_workers=number)
+ def test_free_reference(self):
+ # Issue #14406: Result iterator should not keep an internal
+ # reference to result objects.
+ for obj in self.executor.map(make_dummy_object, range(10)):
+ wr = weakref.ref(obj)
+ del obj
+ self.assertIsNone(wr())
+
class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase):
def test_map_submits_without_iteration(self):