Bug 1309060 - Update futures to version 3.0.5, r?gps draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Mon, 24 Oct 2016 16:04:45 -0400
changeset 439361 26d9c650ea7f0cd206e7d661cf80475f10d1b206
parent 439360 4caa754c45b04e946dfa73485298483c33c126b8
child 439362 15d2b8db61b0c34d40caac5ab9c35c50f43f4f99
push id35982
push userahalberstadt@mozilla.com
push dateTue, 15 Nov 2016 22:19:24 +0000
reviewersgps
bugs1309060
milestone53.0a1
Bug 1309060 - Update futures to version 3.0.5, r?gps We need the fix from https://github.com/agronholm/pythonfutures/issues/25 to allow sending KeyboardInterrupts to thread pools. MozReview-Commit-ID: 5VfBttLbKOr
python/futures/CHANGES
python/futures/PKG-INFO
python/futures/concurrent/futures/_base.py
python/futures/concurrent/futures/process.py
python/futures/concurrent/futures/thread.py
python/futures/docs/index.rst
python/futures/futures.egg-info/PKG-INFO
python/futures/futures.egg-info/pbr.json
python/futures/setup.py
python/futures/test_futures.py
python/futures/tox.ini
--- a/python/futures/CHANGES
+++ b/python/futures/CHANGES
@@ -1,8 +1,26 @@
+3.0.5
+=====
+
+- Fixed OverflowError with ProcessPoolExecutor on Windows (regression introduced in 3.0.4)
+
+
+3.0.4
+=====
+
+- Fixed inability to forcibly terminate the process if there are pending workers
+
+
+3.0.3
+=====
+
+- Fixed AttributeErrors on exit on Python 2.x
+
+
 3.0.2
 =====
 
 - Made multiprocessing optional again on implementations other than just Jython
 
 
 3.0.1
 =====
--- a/python/futures/PKG-INFO
+++ b/python/futures/PKG-INFO
@@ -1,11 +1,11 @@
 Metadata-Version: 1.0
 Name: futures
-Version: 3.0.2
+Version: 3.0.5
 Summary: Backport of the concurrent.futures package from Python 3.2
 Home-page: https://github.com/agronholm/pythonfutures
 Author: Alex Gronholm
 Author-email: alex.gronholm+pypi@nextday.fi
 License: BSD
 Description: UNKNOWN
 Platform: UNKNOWN
 Classifier: License :: OSI Approved :: BSD License
--- a/python/futures/concurrent/futures/_base.py
+++ b/python/futures/concurrent/futures/_base.py
@@ -222,17 +222,18 @@ def as_completed(fs, timeout=None):
                 waiter.event.clear()
 
             for future in finished:
                 yield future
                 pending.remove(future)
 
     finally:
         for f in fs:
-            f._waiters.remove(waiter)
+            with f._condition:
+                f._waiters.remove(waiter)
 
 DoneAndNotDoneFutures = collections.namedtuple(
         'DoneAndNotDoneFutures', 'done not_done')
 def wait(fs, timeout=None, return_when=ALL_COMPLETED):
     """Wait for the futures in the given sequence to complete.
 
     Args:
         fs: The sequence of Futures (possibly created by different Executors) to
@@ -269,17 +270,18 @@ def wait(fs, timeout=None, return_when=A
 
         if len(done) == len(fs):
             return DoneAndNotDoneFutures(done, not_done)
 
         waiter = _create_and_install_waiters(fs, return_when)
 
     waiter.event.wait(timeout)
     for f in fs:
-        f._waiters.remove(waiter)
+        with f._condition:
+            f._waiters.remove(waiter)
 
     done.update(waiter.finished_futures)
     return DoneAndNotDoneFutures(done, set(fs) - done)
 
 class Future(object):
     """Represents the result of an asynchronous computation."""
 
     def __init__(self):
--- a/python/futures/concurrent/futures/process.py
+++ b/python/futures/concurrent/futures/process.py
@@ -68,21 +68,21 @@ import sys
 # threads/processes finish.
 
 _threads_queues = weakref.WeakKeyDictionary()
 _shutdown = False
 
 def _python_exit():
     global _shutdown
     _shutdown = True
-    items = list(_threads_queues.items())
+    items = list(_threads_queues.items()) if _threads_queues else ()
     for t, q in items:
         q.put(None)
     for t, q in items:
-        t.join()
+        t.join(sys.maxint)
 
 # Controls how many more calls than processes will be queued in the call queue.
 # A smaller number will mean that processes spend more time idle waiting for
 # work while a larger number will make Future.cancel() succeed less frequently
 # (Futures in the call queue cannot be cancelled).
 EXTRA_QUEUED_CALLS = 1
 
 class _WorkItem(object):
@@ -342,17 +342,17 @@ class ProcessPoolExecutor(_base.Executor
 
     def shutdown(self, wait=True):
         with self._shutdown_lock:
             self._shutdown_thread = True
         if self._queue_management_thread:
             # Wake up queue management thread
             self._result_queue.put(None)
             if wait:
-                self._queue_management_thread.join()
+                self._queue_management_thread.join(sys.maxint)
         # To reduce the risk of openning too many files, remove references to
         # objects that use file descriptors.
         self._queue_management_thread = None
         self._call_queue = None
         self._result_queue = None
         self._processes = None
     shutdown.__doc__ = _base.Executor.shutdown.__doc__
 
--- a/python/futures/concurrent/futures/thread.py
+++ b/python/futures/concurrent/futures/thread.py
@@ -27,21 +27,21 @@ import sys
 # threads finish.
 
 _threads_queues = weakref.WeakKeyDictionary()
 _shutdown = False
 
 def _python_exit():
     global _shutdown
     _shutdown = True
-    items = list(_threads_queues.items())
+    items = list(_threads_queues.items()) if _threads_queues else ()
     for t, q in items:
         q.put(None)
     for t, q in items:
-        t.join()
+        t.join(sys.maxint)
 
 atexit.register(_python_exit)
 
 class _WorkItem(object):
     def __init__(self, future, fn, args, kwargs):
         self.future = future
         self.fn = fn
         self.args = args
@@ -125,10 +125,10 @@ class ThreadPoolExecutor(_base.Executor)
             _threads_queues[t] = self._work_queue
 
     def shutdown(self, wait=True):
         with self._shutdown_lock:
             self._shutdown = True
             self._work_queue.put(None)
         if wait:
             for t in self._threads:
-                t.join()
+                t.join(sys.maxint)
     shutdown.__doc__ = _base.Executor.shutdown.__doc__
--- a/python/futures/docs/index.rst
+++ b/python/futures/docs/index.rst
@@ -107,17 +107,17 @@ And:
         # it is executing this function.
         print(f.result())
     
     executor = ThreadPoolExecutor(max_workers=1)
     executor.submit(wait_on_future)
 
 .. class:: ThreadPoolExecutor(max_workers)
 
-   Executes calls asynchronously using at pool of at most *max_workers* threads.
+   Executes calls asynchronously using a pool of at most *max_workers* threads.
 
 .. _threadpoolexecutor-example:
 
 ThreadPoolExecutor Example
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 ::
 
     from concurrent import futures
--- a/python/futures/futures.egg-info/PKG-INFO
+++ b/python/futures/futures.egg-info/PKG-INFO
@@ -1,11 +1,11 @@
 Metadata-Version: 1.0
 Name: futures
-Version: 3.0.2
+Version: 3.0.5
 Summary: Backport of the concurrent.futures package from Python 3.2
 Home-page: https://github.com/agronholm/pythonfutures
 Author: Alex Gronholm
 Author-email: alex.gronholm+pypi@nextday.fi
 License: BSD
 Description: UNKNOWN
 Platform: UNKNOWN
 Classifier: License :: OSI Approved :: BSD License
--- a/python/futures/futures.egg-info/pbr.json
+++ b/python/futures/futures.egg-info/pbr.json
@@ -1,1 +1,1 @@
-{"is_release": false, "git_version": "fdbc9c3"}
\ No newline at end of file
+{"is_release": false, "git_version": "6532a74"}
\ No newline at end of file
--- a/python/futures/setup.py
+++ b/python/futures/setup.py
@@ -1,19 +1,26 @@
 #!/usr/bin/env python
+from warnings import warn
+import sys
+
+if sys.version_info[0] > 2:
+    warn('This backport is meant only for Python 2.\n'
+         'Python 3 users do not need it, as the concurrent.futures '
+         'package is available in the standard library.')
 
 extras = {}
 try:
     from setuptools import setup
     extras['zip_safe'] = False
 except ImportError:
     from distutils.core import setup
 
 setup(name='futures',
-      version='3.0.2',
+      version='3.0.5',
       description='Backport of the concurrent.futures package from Python 3.2',
       author='Brian Quinlan',
       author_email='brian@sweetapp.com',
       maintainer='Alex Gronholm',
       maintainer_email='alex.gronholm+pypi@nextday.fi',
       url='https://github.com/agronholm/pythonfutures',
       packages=['concurrent', 'concurrent.futures'],
       license='BSD',
--- a/python/futures/test_futures.py
+++ b/python/futures/test_futures.py
@@ -2,16 +2,17 @@ import os
 import subprocess
 import sys
 import threading
 import functools
 import contextlib
 import logging
 import re
 import time
+import gc
 from StringIO import StringIO
 from test import test_support
 
 from concurrent import futures
 from concurrent.futures._base import (
     PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future)
 
 try:
@@ -217,16 +218,17 @@ class ThreadPoolShutdownTest(ThreadPoolM
         for t in executor._threads:
             t.join()
 
     def test_del_shutdown(self):
         executor = futures.ThreadPoolExecutor(max_workers=5)
         executor.map(abs, range(-5, 5))
         threads = executor._threads
         del executor
+        gc.collect()
 
         for t in threads:
             t.join()
 
 
 class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest):
     def _prime_executor(self):
         pass
@@ -252,16 +254,17 @@ class ProcessPoolShutdownTest(ProcessPoo
             p.join()
 
     def test_del_shutdown(self):
         executor = futures.ProcessPoolExecutor(max_workers=5)
         list(executor.map(abs, range(-5, 5)))
         queue_management_thread = executor._queue_management_thread
         processes = executor._processes
         del executor
+        gc.collect()
 
         queue_management_thread.join()
         for p in processes:
             p.join()
 
 
 class WaitTests(unittest.TestCase):
 
@@ -570,29 +573,29 @@ class FutureTests(unittest.TestCase):
 
         f = Future()
         self.assertTrue(f.cancel())
         f.add_done_callback(fn)
         self.assertTrue(was_cancelled[0])
 
     def test_repr(self):
         self.assertRegexpMatches(repr(PENDING_FUTURE),
-                                 '<Future at 0x[0-9a-f]+ state=pending>')
+                                 '<Future at 0x[0-9a-f]+L? state=pending>')
         self.assertRegexpMatches(repr(RUNNING_FUTURE),
-                                 '<Future at 0x[0-9a-f]+ state=running>')
+                                 '<Future at 0x[0-9a-f]+L? state=running>')
         self.assertRegexpMatches(repr(CANCELLED_FUTURE),
-                                 '<Future at 0x[0-9a-f]+ state=cancelled>')
+                                 '<Future at 0x[0-9a-f]+L? state=cancelled>')
         self.assertRegexpMatches(repr(CANCELLED_AND_NOTIFIED_FUTURE),
-                                 '<Future at 0x[0-9a-f]+ state=cancelled>')
+                                 '<Future at 0x[0-9a-f]+L? state=cancelled>')
         self.assertRegexpMatches(
                 repr(EXCEPTION_FUTURE),
-                '<Future at 0x[0-9a-f]+ state=finished raised IOError>')
+                '<Future at 0x[0-9a-f]+L? state=finished raised IOError>')
         self.assertRegexpMatches(
                 repr(SUCCESSFUL_FUTURE),
-                '<Future at 0x[0-9a-f]+ state=finished returned int>')
+                '<Future at 0x[0-9a-f]+L? state=finished returned int>')
 
     def test_cancel(self):
         f1 = create_future(state=PENDING)
         f2 = create_future(state=RUNNING)
         f3 = create_future(state=CANCELLED)
         f4 = create_future(state=CANCELLED_AND_NOTIFIED)
         f5 = create_future(state=FINISHED, exception=IOError())
         f6 = create_future(state=FINISHED, result=5)
--- a/python/futures/tox.ini
+++ b/python/futures/tox.ini
@@ -1,8 +1,8 @@
 [tox]
-envlist = py26,py27
+envlist = py26,py27,pypy,jython
 
 [testenv]
 commands={envpython} test_futures.py []
 
 [testenv:py26]
 deps=unittest2