Hello community, here is the log from the commit of package python-futures for openSUSE:Factory checked in at 2017-12-13 11:56:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-futures (Old) and /work/SRC/openSUSE:Factory/.python-futures.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-futures" Wed Dec 13 11:56:58 2017 rev:14 rq:555887 version:3.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-futures/python-futures.changes 2017-11-17 10:36:53.275487208 +0100 +++ /work/SRC/openSUSE:Factory/.python-futures.new/python-futures.changes 2017-12-13 11:57:03.064494100 +0100 @@ -1,0 +2,16 @@ +Sat Dec 9 17:12:45 UTC 2017 - [email protected] + +- specfile: + * removed CHANGES from %doc (not in tar-ball anymore), added README.rst + +- update to version 3.2.0: + * The ThreadPoolExecutor class constructor now accepts an optional + thread_name_prefix argument to make it possible to customize the + names of the threads created by the pool. Upstream contribution by + Gregory P. Smith in https://bugs.python.org/issue27664. + * Backported fixes from upstream (thanks Lisandro Dalcin): + + python/cpython#1560 + + python/cpython#3270 + + python/cpython#3830 + +------------------------------------------------------------------- Old: ---- futures-3.1.1.tar.gz New: ---- futures-3.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-futures.spec ++++++ --- /var/tmp/diff_new_pack.v5Ntew/_old 2017-12-13 11:57:03.772459923 +0100 +++ /var/tmp/diff_new_pack.v5Ntew/_new 2017-12-13 11:57:03.772459923 +0100 @@ -19,7 +19,7 @@ %define skip_python3 1 %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-futures -Version: 3.1.1 +Version: 3.2.0 Release: 0 Summary: Backport of the concurrent.futures package from Python 3.2 License: Python-2.0 @@ -56,7 +56,7 @@ %files %{python_files} %defattr(-,root,root,-) -%doc CHANGES LICENSE +%doc README.rst LICENSE %{python_sitelib}/concurrent/ %{python_sitelib}/futures-%{version}-py*.egg-info ++++++ futures-3.1.1.tar.gz -> futures-3.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/CHANGES new/futures-3.2.0/CHANGES --- old/futures-3.1.1/CHANGES 2017-04-14 16:32:09.000000000 +0200 +++ new/futures-3.2.0/CHANGES 1970-01-01 01:00:00.000000000 +0100 @@ -1,124 +0,0 @@ -3.1.1 -===== - -- Backported sanity checks for the ``max_workers`` constructor argument for ThreadPoolExecutor and - ProcessPoolExecutor -- Set the default value of ``max_workers`` in ThreadPoolExecutor to ``None``, as in upstream code - (computes the thread pool size based on the number of CPUs) -- Added support for old-style exception objects -- Switched to the PSF license - - -3.1.0 -===== - -(Failed release) - - -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 -===== - -- Made Executor.map() non-greedy - - -3.0.0 -===== - -- Dropped Python 2.5 and 3.1 support -- Removed the deprecated "futures" top level package -- Applied patch for issue 11777 (Executor.map does not submit futures until - iter.next() is called) -- Applied patch for issue 15015 (accessing an non-existing attribute) -- Applied patch for issue 16284 (memory leak) -- Applied patch for issue 20367 (behavior of concurrent.futures.as_completed() - for duplicate arguments) - -2.2.0 -===== - -- Added the set_exception_info() and exception_info() methods to Future - to enable extraction of tracebacks on Python 2.x -- Added support for Future.set_exception_info() to ThreadPoolExecutor - - -2.1.6 -===== - -- Fixed a problem with files missing from the source distribution - - -2.1.5 -===== - -- Fixed Jython compatibility -- Added metadata for wheel support - - -2.1.4 -===== - -- Ported the library again from Python 3.2.5 to get the latest bug fixes - - -2.1.3 -===== - -- Fixed race condition in wait(return_when=ALL_COMPLETED) - (http://bugs.python.org/issue14406) -- thanks Ralf Schmitt -- Added missing setUp() methods to several test classes - - -2.1.2 -===== - -- Fixed installation problem on Python 3.1 - - -2.1.1 -===== - -- Fixed missing 'concurrent' package declaration in setup.py - - -2.1 -=== - -- Moved the code from the 'futures' package to 'concurrent.futures' to provide - a drop in backport that matches the code in Python 3.2 standard library -- Deprecated the old 'futures' package - - -2.0 -=== - -- Changed implementation to match PEP 3148 - - -1.0 -=== - -Initial release. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/PKG-INFO new/futures-3.2.0/PKG-INFO --- old/futures-3.1.1/PKG-INFO 2017-04-14 16:33:21.000000000 +0200 +++ new/futures-3.2.0/PKG-INFO 2017-12-01 00:22:35.000000000 +0100 @@ -1,12 +1,47 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: futures -Version: 3.1.1 -Summary: Backport of the concurrent.futures package from Python 3.2 +Version: 3.2.0 +Summary: Backport of the concurrent.futures package from Python 3 Home-page: https://github.com/agronholm/pythonfutures -Author: Alex Gronholm -Author-email: [email protected] +Author: Alex Grönholm +Author-email: [email protected] License: PSF -Description: UNKNOWN +Description: .. image:: https://travis-ci.org/agronholm/pythonfutures.svg?branch=master + :target: https://travis-ci.org/agronholm/pythonfutures + :alt: Build Status + + This is a backport of the `concurrent.futures`_ standard library module to Python 2. + + It should not be installed on Python 3, although there should be no harm in doing so, as the + standard library takes precedence over third party libraries. + + To conditionally require this library only on Python 2, you can do this in your ``setup.py``: + + .. code-block:: python + + setup( + ... + extras_require={ + ':python_version == "2.7"': ['futures'] + } + ) + + Or, using the newer syntax: + + .. code-block:: python + + setup( + ... + install_requires={ + 'futures; python_version == "2.7"' + } + ) + + .. warning:: The ``ProcessPoolExecutor`` class has known (unfixable) problems on Python 2 and + should not be relied on for mission critical work. + + .. _concurrent.futures: https://docs.python.org/library/concurrent.futures.html + Platform: UNKNOWN Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Development Status :: 5 - Production/Stable @@ -14,3 +49,4 @@ Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 2 :: Only +Requires-Python: >=2.6, <3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/README.rst new/futures-3.2.0/README.rst --- old/futures-3.1.1/README.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/futures-3.2.0/README.rst 2017-12-01 00:22:20.000000000 +0100 @@ -0,0 +1,35 @@ +.. image:: https://travis-ci.org/agronholm/pythonfutures.svg?branch=master + :target: https://travis-ci.org/agronholm/pythonfutures + :alt: Build Status + +This is a backport of the `concurrent.futures`_ standard library module to Python 2. + +It should not be installed on Python 3, although there should be no harm in doing so, as the +standard library takes precedence over third party libraries. + +To conditionally require this library only on Python 2, you can do this in your ``setup.py``: + +.. code-block:: python + + setup( + ... + extras_require={ + ':python_version == "2.7"': ['futures'] + } + ) + +Or, using the newer syntax: + +.. code-block:: python + + setup( + ... + install_requires={ + 'futures; python_version == "2.7"' + } + ) + +.. warning:: The ``ProcessPoolExecutor`` class has known (unfixable) problems on Python 2 and + should not be relied on for mission critical work. + +.. _concurrent.futures: https://docs.python.org/library/concurrent.futures.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/concurrent/futures/_base.py new/futures-3.2.0/concurrent/futures/_base.py --- old/futures-3.1.1/concurrent/futures/_base.py 2017-04-14 16:32:09.000000000 +0200 +++ new/futures-3.2.0/concurrent/futures/_base.py 2017-12-01 00:22:20.000000000 +0100 @@ -172,6 +172,29 @@ return waiter + +def _yield_finished_futures(fs, waiter, ref_collect): + """ + Iterate on the list *fs*, yielding finished futures one by one in + reverse order. + Before yielding a future, *waiter* is removed from its waiters + and the future is removed from each set in the collection of sets + *ref_collect*. + + The aim of this function is to avoid keeping stale references after + the future is yielded and before the iterator resumes. + """ + while fs: + f = fs[-1] + for futures_set in ref_collect: + futures_set.remove(f) + with f._condition: + f._waiters.remove(waiter) + del f + # Careful not to keep a reference to the popped value + yield fs.pop() + + def as_completed(fs, timeout=None): """An iterator over the given futures that yields each as it completes. @@ -194,16 +217,19 @@ end_time = timeout + time.time() fs = set(fs) + total_futures = len(fs) with _AcquireFutures(fs): finished = set( f for f in fs if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) pending = fs - finished waiter = _create_and_install_waiters(fs, _AS_COMPLETED) - + finished = list(finished) try: - for future in finished: - yield future + for f in _yield_finished_futures(finished, waiter, + ref_collect=(fs,)): + f = [f] + yield f.pop() while pending: if timeout is None: @@ -213,7 +239,7 @@ if wait_timeout < 0: raise TimeoutError( '%d (of %d) futures unfinished' % ( - len(pending), len(fs))) + len(pending), total_futures)) waiter.event.wait(wait_timeout) @@ -222,11 +248,15 @@ waiter.finished_futures = [] waiter.event.clear() - for future in finished: - yield future - pending.remove(future) + # reverse to keep finishing order + finished.reverse() + for f in _yield_finished_futures(finished, waiter, + ref_collect=(fs, pending)): + f = [f] + yield f.pop() finally: + # Remove waiter from unfinished futures for f in fs: with f._condition: f._waiters.remove(waiter) @@ -322,17 +352,20 @@ with self._condition: if self._state == FINISHED: if self._exception: - return '<Future at %s state=%s raised %s>' % ( - hex(id(self)), + return '<%s at %#x state=%s raised %s>' % ( + self.__class__.__name__, + id(self), _STATE_TO_DESCRIPTION_MAP[self._state], self._exception.__class__.__name__) else: - return '<Future at %s state=%s returned %s>' % ( - hex(id(self)), + return '<%s at %#x state=%s returned %s>' % ( + self.__class__.__name__, + id(self), _STATE_TO_DESCRIPTION_MAP[self._state], self._result.__class__.__name__) - return '<Future at %s state=%s>' % ( - hex(id(self)), + return '<%s at %#x state=%s>' % ( + self.__class__.__name__, + id(self), _STATE_TO_DESCRIPTION_MAP[self._state]) def cancel(self): @@ -355,7 +388,7 @@ return True def cancelled(self): - """Return True if the future has cancelled.""" + """Return True if the future was cancelled.""" with self._condition: return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED] @@ -573,7 +606,7 @@ raise NotImplementedError() def map(self, fn, *iterables, **kwargs): - """Returns a iterator equivalent to map(fn, iter). + """Returns an iterator equivalent to map(fn, iter). Args: fn: A callable that will take as many arguments as there are @@ -600,11 +633,14 @@ # before the first iterator value is required. def result_iterator(): try: - for future in fs: + # reverse to keep finishing order + fs.reverse() + while fs: + # Careful not to keep a reference to the popped future if timeout is None: - yield future.result() + yield fs.pop().result() else: - yield future.result(end_time - time.time()) + yield fs.pop().result(end_time - time.time()) finally: for future in fs: future.cancel() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/concurrent/futures/thread.py new/futures-3.2.0/concurrent/futures/thread.py --- old/futures-3.1.1/concurrent/futures/thread.py 2017-04-14 16:32:09.000000000 +0200 +++ new/futures-3.2.0/concurrent/futures/thread.py 2017-12-01 00:22:20.000000000 +0100 @@ -5,6 +5,7 @@ import atexit from concurrent.futures import _base +import itertools import Queue as queue import threading import weakref @@ -90,12 +91,17 @@ class ThreadPoolExecutor(_base.Executor): - def __init__(self, max_workers=None): + + # Used to assign unique thread names when thread_name_prefix is not supplied. + _counter = itertools.count().next + + def __init__(self, max_workers=None, thread_name_prefix=''): """Initializes a new ThreadPoolExecutor instance. Args: max_workers: The maximum number of threads that can be used to execute the given calls. + thread_name_prefix: An optional name prefix to give our threads. """ if max_workers is None: # Use this number because ThreadPoolExecutor is often @@ -109,6 +115,8 @@ self._threads = set() self._shutdown = False self._shutdown_lock = threading.Lock() + self._thread_name_prefix = (thread_name_prefix or + ("ThreadPoolExecutor-%d" % self._counter())) def submit(self, fn, *args, **kwargs): with self._shutdown_lock: @@ -130,8 +138,11 @@ q.put(None) # TODO(bquinlan): Should avoid creating new threads if there are more # idle threads than items in the work queue. - if len(self._threads) < self._max_workers: - t = threading.Thread(target=_worker, + num_threads = len(self._threads) + if num_threads < self._max_workers: + thread_name = '%s_%d' % (self._thread_name_prefix or self, + num_threads) + t = threading.Thread(name=thread_name, target=_worker, args=(weakref.ref(self, weakref_cb), self._work_queue)) t.daemon = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/futures.egg-info/PKG-INFO new/futures-3.2.0/futures.egg-info/PKG-INFO --- old/futures-3.1.1/futures.egg-info/PKG-INFO 2017-04-14 16:33:21.000000000 +0200 +++ new/futures-3.2.0/futures.egg-info/PKG-INFO 2017-12-01 00:22:35.000000000 +0100 @@ -1,12 +1,47 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: futures -Version: 3.1.1 -Summary: Backport of the concurrent.futures package from Python 3.2 +Version: 3.2.0 +Summary: Backport of the concurrent.futures package from Python 3 Home-page: https://github.com/agronholm/pythonfutures -Author: Alex Gronholm -Author-email: [email protected] +Author: Alex Grönholm +Author-email: [email protected] License: PSF -Description: UNKNOWN +Description: .. image:: https://travis-ci.org/agronholm/pythonfutures.svg?branch=master + :target: https://travis-ci.org/agronholm/pythonfutures + :alt: Build Status + + This is a backport of the `concurrent.futures`_ standard library module to Python 2. + + It should not be installed on Python 3, although there should be no harm in doing so, as the + standard library takes precedence over third party libraries. + + To conditionally require this library only on Python 2, you can do this in your ``setup.py``: + + .. code-block:: python + + setup( + ... + extras_require={ + ':python_version == "2.7"': ['futures'] + } + ) + + Or, using the newer syntax: + + .. code-block:: python + + setup( + ... + install_requires={ + 'futures; python_version == "2.7"' + } + ) + + .. warning:: The ``ProcessPoolExecutor`` class has known (unfixable) problems on Python 2 and + should not be relied on for mission critical work. + + .. _concurrent.futures: https://docs.python.org/library/concurrent.futures.html + Platform: UNKNOWN Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Development Status :: 5 - Production/Stable @@ -14,3 +49,4 @@ Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 2 :: Only +Requires-Python: >=2.6, <3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/futures.egg-info/SOURCES.txt new/futures-3.2.0/futures.egg-info/SOURCES.txt --- old/futures-3.1.1/futures.egg-info/SOURCES.txt 2017-04-14 16:33:21.000000000 +0200 +++ new/futures-3.2.0/futures.egg-info/SOURCES.txt 2017-12-01 00:22:35.000000000 +0100 @@ -1,6 +1,6 @@ -CHANGES LICENSE MANIFEST.in +README.rst crawl.py primes.py setup.cfg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/setup.cfg new/futures-3.2.0/setup.cfg --- old/futures-3.1.1/setup.cfg 2017-04-14 16:33:21.000000000 +0200 +++ new/futures-3.2.0/setup.cfg 2017-12-01 00:22:35.000000000 +0100 @@ -8,5 +8,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/setup.py new/futures-3.2.0/setup.py --- old/futures-3.1.1/setup.py 2017-04-14 16:32:09.000000000 +0200 +++ new/futures-3.2.0/setup.py 2017-12-01 00:22:20.000000000 +0100 @@ -1,5 +1,7 @@ #!/usr/bin/env python +# coding: utf-8 from warnings import warn +import os.path import sys if sys.version_info[0] > 2: @@ -14,15 +16,21 @@ except ImportError: from distutils.core import setup +here = os.path.dirname(__file__) +with open(os.path.join(here, 'README.rst')) as f: + readme = f.read() + setup(name='futures', - version='3.1.1', - description='Backport of the concurrent.futures package from Python 3.2', + version='3.2.0', + description='Backport of the concurrent.futures package from Python 3', + long_description=readme, author='Brian Quinlan', author_email='[email protected]', - maintainer='Alex Gronholm', - maintainer_email='[email protected]', + maintainer=u'Alex Grönholm', + maintainer_email='[email protected]', url='https://github.com/agronholm/pythonfutures', packages=['concurrent', 'concurrent.futures'], + python_requires='>=2.6, <3', license='PSF', classifiers=['License :: OSI Approved :: Python Software Foundation License', 'Development Status :: 5 - Production/Stable', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/test_futures.py new/futures-3.2.0/test_futures.py --- old/futures-3.1.1/test_futures.py 2017-04-14 16:32:09.000000000 +0200 +++ new/futures-3.2.0/test_futures.py 2017-12-01 00:22:20.000000000 +0100 @@ -29,7 +29,7 @@ If threading is unavailable this function does nothing. """ @functools.wraps(func) - def decorator(*args): + def decorator(*args): key = test_support.threading_setup() try: return func(*args) @@ -50,7 +50,7 @@ # caller is responsible to pass the full environment. if env_vars.pop('__cleanenv', None): env = {} - env.update(env_vars) + env.update(env_vars) cmd_line.extend(args) p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -78,7 +78,7 @@ return _assert_python(True, *args, **env_vars) -def strip_python_stderr(stderr): +def strip_python_stderr(stderr): """Strip the stderr of a Python process from potential debug output emitted by the interpreter. @@ -230,6 +230,31 @@ for t in threads: t.join() + def test_thread_names_assigned(self): + executor = futures.ThreadPoolExecutor( + max_workers=5, thread_name_prefix='SpecialPool') + executor.map(abs, range(-5, 5)) + threads = executor._threads + del executor + gc.collect() + + for t in threads: + self.assertRegexpMatches(t.name, r'^SpecialPool_[0-4]$') + t.join() + + def test_thread_names_default(self): + executor = futures.ThreadPoolExecutor(max_workers=5) + executor.map(abs, range(-5, 5)) + threads = executor._threads + del executor + gc.collect() + + for t in threads: + # Ensure that our default name is reasonably sane and unique when + # no thread_name_prefix was supplied. + self.assertRegexpMatches(t.name, r'ThreadPoolExecutor-\d+_[0-4]$') + t.join() + class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): def _prime_executor(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-3.1.1/tox.ini new/futures-3.2.0/tox.ini --- old/futures-3.1.1/tox.ini 2017-04-14 16:32:09.000000000 +0200 +++ new/futures-3.2.0/tox.ini 2017-12-01 00:22:20.000000000 +0100 @@ -1,10 +1,6 @@ [tox] envlist = py26,py27,pypy,jython -[tox:travis] -2.6 = py26 -2.7 = py27 - [testenv] commands = {envpython} test_futures.py {posargs}
