Hello community, here is the log from the commit of package python-futures for openSUSE:Factory checked in at 2015-05-10 10:46:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-futures (Old) and /work/SRC/openSUSE:Factory/.python-futures.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-futures" Changes: -------- --- /work/SRC/openSUSE:Factory/python-futures/python-futures.changes 2015-03-01 14:47:08.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-futures.new/python-futures.changes 2015-05-10 10:46:19.000000000 +0200 @@ -1,0 +2,18 @@ +Tue May 5 15:16:24 UTC 2015 - [email protected] + +- update to version 3.0.1: + * Made Executor.map() non-greedy +- additional changes from version 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) +- remove CFLAGS: this is a python only module +- remove futures from package files: not provided anymore + +------------------------------------------------------------------- Old: ---- futures-2.2.0.tar.gz New: ---- futures-3.0.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-futures.spec ++++++ --- /var/tmp/diff_new_pack.q9GVHH/_old 2015-05-10 10:46:19.000000000 +0200 +++ /var/tmp/diff_new_pack.q9GVHH/_new 2015-05-10 10:46:19.000000000 +0200 @@ -17,7 +17,7 @@ Name: python-futures -Version: 2.2.0 +Version: 3.0.1 Release: 0 Summary: Backport of the concurrent.futures package from Python 3.2 License: BSD-2-Clause @@ -43,19 +43,18 @@ %setup -q -n futures-%{version} %build -CFLAGS="%{optflags}" python setup.py build +python setup.py build %install python setup.py install --prefix=%{_prefix} --root=%{buildroot} #%%check -#python test +#python test_futures.py %files %defattr(-,root,root,-) %doc CHANGES LICENSE %{python_sitelib}/concurrent/ -%{python_sitelib}/futures/ %{python_sitelib}/futures-%{version}-py*.egg-info %changelog ++++++ futures-2.2.0.tar.gz -> futures-3.0.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/CHANGES new/futures-3.0.1/CHANGES --- old/futures-2.2.0/CHANGES 2014-09-08 05:46:16.000000000 +0200 +++ new/futures-3.0.1/CHANGES 2015-05-03 08:28:16.000000000 +0200 @@ -1,3 +1,21 @@ +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 ===== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/PKG-INFO new/futures-3.0.1/PKG-INFO --- old/futures-2.2.0/PKG-INFO 2014-09-25 23:20:56.000000000 +0200 +++ new/futures-3.0.1/PKG-INFO 2015-05-03 08:32:05.000000000 +0200 @@ -1,19 +1,16 @@ Metadata-Version: 1.0 Name: futures -Version: 2.2.0 +Version: 3.0.1 Summary: Backport of the concurrent.futures package from Python 3.2 -Home-page: http://code.google.com/p/pythonfutures +Home-page: https://github.com/agronholm/pythonfutures Author: Alex Gronholm Author-email: [email protected] License: BSD -Download-URL: http://pypi.python.org/pypi/futures/ Description: UNKNOWN Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.1 +Classifier: Programming Language :: Python :: 2 :: Only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/concurrent/futures/__init__.py new/futures-3.0.1/concurrent/futures/__init__.py --- old/futures-2.2.0/concurrent/futures/__init__.py 2013-10-28 00:12:04.000000000 +0100 +++ new/futures-3.0.1/concurrent/futures/__init__.py 2015-05-03 07:24:12.000000000 +0200 @@ -15,9 +15,11 @@ wait, as_completed) from concurrent.futures.thread import ThreadPoolExecutor +import sys -# Jython doesn't have multiprocessing try: from concurrent.futures.process import ProcessPoolExecutor except ImportError: - pass + # Jython doesn't have multiprocessing + if not sys.platform.startswith('java'): + raise diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/concurrent/futures/_base.py new/futures-3.0.1/concurrent/futures/_base.py --- old/futures-2.2.0/concurrent/futures/_base.py 2014-09-06 16:05:41.000000000 +0200 +++ new/futures-3.0.1/concurrent/futures/_base.py 2015-05-03 08:27:36.000000000 +0200 @@ -1,18 +1,12 @@ # Copyright 2009 Brian Quinlan. All Rights Reserved. # Licensed to PSF under a Contributor Agreement. -from __future__ import with_statement +import collections import logging import threading +import itertools import time -from concurrent.futures._compat import reraise - -try: - from collections import namedtuple -except ImportError: - from concurrent.futures._compat import namedtuple - __author__ = 'Brian Quinlan ([email protected])' FIRST_COMPLETED = 'FIRST_COMPLETED' @@ -188,7 +182,8 @@ Returns: An iterator that yields the given Futures as they complete (finished or - cancelled). + cancelled). If any given Futures are duplicated, they will be returned + once. Raises: TimeoutError: If the entire result iterator could not be generated @@ -197,11 +192,12 @@ if timeout is not None: end_time = timeout + time.time() + fs = set(fs) with _AcquireFutures(fs): finished = set( f for f in fs if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) - pending = set(fs) - finished + pending = fs - finished waiter = _create_and_install_waiters(fs, _AS_COMPLETED) try: @@ -233,7 +229,7 @@ for f in fs: f._waiters.remove(waiter) -DoneAndNotDoneFutures = namedtuple( +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. @@ -356,7 +352,7 @@ def __get_result(self): if self._exception: - reraise(self._exception, self._traceback) + raise type(self._exception), self._exception, self._traceback else: return self._result @@ -497,8 +493,8 @@ return True else: LOGGER.critical('Future %s in unexpected state: %s', - id(self.future), - self.future._state) + id(self), + self._state) raise RuntimeError('Future in unexpected state') def set_result(self, result): @@ -572,17 +568,21 @@ if timeout is not None: end_time = timeout + time.time() - fs = [self.submit(fn, *args) for args in zip(*iterables)] + fs = [self.submit(fn, *args) for args in itertools.izip(*iterables)] - try: - for future in fs: - if timeout is None: - yield future.result() - else: - yield future.result(end_time - time.time()) - finally: - for future in fs: - future.cancel() + # Yield must be hidden in closure so that the futures are submitted + # before the first iterator value is required. + def result_iterator(): + try: + for future in fs: + if timeout is None: + yield future.result() + else: + yield future.result(end_time - time.time()) + finally: + for future in fs: + future.cancel() + return result_iterator() def shutdown(self, wait=True): """Clean-up the resources associated with the Executor. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/concurrent/futures/_compat.py new/futures-3.0.1/concurrent/futures/_compat.py --- old/futures-2.2.0/concurrent/futures/_compat.py 2014-09-06 16:21:19.000000000 +0200 +++ new/futures-3.0.1/concurrent/futures/_compat.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,111 +0,0 @@ -from keyword import iskeyword as _iskeyword -from operator import itemgetter as _itemgetter -import sys as _sys - - -def namedtuple(typename, field_names): - """Returns a new subclass of tuple with named fields. - - >>> Point = namedtuple('Point', 'x y') - >>> Point.__doc__ # docstring for the new class - 'Point(x, y)' - >>> p = Point(11, y=22) # instantiate with positional args or keywords - >>> p[0] + p[1] # indexable like a plain tuple - 33 - >>> x, y = p # unpack like a regular tuple - >>> x, y - (11, 22) - >>> p.x + p.y # fields also accessable by name - 33 - >>> d = p._asdict() # convert to a dictionary - >>> d['x'] - 11 - >>> Point(**d) # convert from a dictionary - Point(x=11, y=22) - >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields - Point(x=100, y=22) - - """ - - # Parse and validate the field names. Validation serves two purposes, - # generating informative error messages and preventing template injection attacks. - if isinstance(field_names, basestring): - field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas - field_names = tuple(map(str, field_names)) - for name in (typename,) + field_names: - if not all(c.isalnum() or c=='_' for c in name): - raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name) - if _iskeyword(name): - raise ValueError('Type names and field names cannot be a keyword: %r' % name) - if name[0].isdigit(): - raise ValueError('Type names and field names cannot start with a number: %r' % name) - seen_names = set() - for name in field_names: - if name.startswith('_'): - raise ValueError('Field names cannot start with an underscore: %r' % name) - if name in seen_names: - raise ValueError('Encountered duplicate field name: %r' % name) - seen_names.add(name) - - # Create and fill-in the class template - numfields = len(field_names) - argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes - reprtxt = ', '.join('%s=%%r' % name for name in field_names) - dicttxt = ', '.join('%r: t[%d]' % (name, pos) for pos, name in enumerate(field_names)) - template = '''class %(typename)s(tuple): - '%(typename)s(%(argtxt)s)' \n - __slots__ = () \n - _fields = %(field_names)r \n - def __new__(_cls, %(argtxt)s): - return _tuple.__new__(_cls, (%(argtxt)s)) \n - @classmethod - def _make(cls, iterable, new=tuple.__new__, len=len): - 'Make a new %(typename)s object from a sequence or iterable' - result = new(cls, iterable) - if len(result) != %(numfields)d: - raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result)) - return result \n - def __repr__(self): - return '%(typename)s(%(reprtxt)s)' %% self \n - def _asdict(t): - 'Return a new dict which maps field names to their values' - return {%(dicttxt)s} \n - def _replace(_self, **kwds): - 'Return a new %(typename)s object replacing specified fields with new values' - result = _self._make(map(kwds.pop, %(field_names)r, _self)) - if kwds: - raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) - return result \n - def __getnewargs__(self): - return tuple(self) \n\n''' % locals() - for i, name in enumerate(field_names): - template += ' %s = _property(_itemgetter(%d))\n' % (name, i) - - # Execute the template string in a temporary namespace and - # support tracing utilities by setting a value for frame.f_globals['__name__'] - namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, - _property=property, _tuple=tuple) - try: - exec(template, namespace) - except SyntaxError: - e = _sys.exc_info()[1] - raise SyntaxError(e.message + ':\n' + template) - result = namespace[typename] - - # For pickling to work, the __module__ variable needs to be set to the frame - # where the named tuple is created. Bypass this step in enviroments where - # sys._getframe is not defined (Jython for example). - if hasattr(_sys, '_getframe'): - result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__') - - return result - - -if _sys.version_info[0] < 3: - def reraise(exc, traceback): - locals_ = {'exc_type': type(exc), 'exc_value': exc, 'traceback': traceback} - exec('raise exc_type, exc_value, traceback', {}, locals_) -else: - def reraise(exc, traceback): - # Tracebacks are embedded in exceptions in Python 3 - raise exc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/concurrent/futures/process.py new/futures-3.0.1/concurrent/futures/process.py --- old/futures-2.2.0/concurrent/futures/process.py 2014-09-06 15:56:05.000000000 +0200 +++ new/futures-3.0.1/concurrent/futures/process.py 2015-05-03 07:36:12.000000000 +0200 @@ -43,20 +43,14 @@ _ResultItems in "Request Q" """ -from __future__ import with_statement import atexit +from concurrent.futures import _base +import Queue as queue import multiprocessing import threading import weakref import sys -from concurrent.futures import _base - -try: - import queue -except ImportError: - import Queue as queue - __author__ = 'Brian Quinlan ([email protected])' # Workers are created as daemon threads and processes. This is done to allow the @@ -220,6 +214,8 @@ work_item.future.set_exception(result_item.exception) else: work_item.future.set_result(result_item.result) + # Delete references to object. See issue16284 + del work_item # Check whether we should start shutting down. executor = executor_reference() # No more work items can be added if: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/concurrent/futures/thread.py new/futures-3.0.1/concurrent/futures/thread.py --- old/futures-2.2.0/concurrent/futures/thread.py 2014-09-06 16:02:09.000000000 +0200 +++ new/futures-3.0.1/concurrent/futures/thread.py 2015-05-03 07:36:12.000000000 +0200 @@ -3,19 +3,13 @@ """Implements ThreadPoolExecutor.""" -from __future__ import with_statement import atexit +from concurrent.futures import _base +import Queue as queue import threading import weakref import sys -from concurrent.futures import _base - -try: - import queue -except ImportError: - import Queue as queue - __author__ = 'Brian Quinlan ([email protected])' # Workers are created as daemon threads. This is done to allow the interpreter @@ -71,6 +65,8 @@ work_item = work_queue.get(block=True) if work_item is not None: work_item.run() + # Delete references to object. See issue16284 + del work_item continue executor = executor_reference() # Exit if: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/docs/index.rst new/futures-3.0.1/docs/index.rst --- old/futures-2.2.0/docs/index.rst 2012-08-28 07:08:15.000000000 +0200 +++ new/futures-3.0.1/docs/index.rst 2015-05-03 07:36:12.000000000 +0200 @@ -335,11 +335,13 @@ .. function:: as_completed(fs, timeout=None) - Returns an iterator over the :class:`Future` instances (possibly created - by different :class:`Executor` instances) given by *fs* that yields futures - as they complete (finished or were cancelled). Any futures that completed - before :func:`as_completed()` was called will be yielded first. The returned - iterator raises a :exc:`TimeoutError` if :meth:`__next__()` is called and - the result isn't available after *timeout* seconds from the original call - to :func:`as_completed()`. *timeout* can be an int or float. If *timeout* - is not specified or ``None`` then there is no limit to the wait time. + Returns an iterator over the :class:`Future` instances (possibly created by + different :class:`Executor` instances) given by *fs* that yields futures as + they complete (finished or were cancelled). Any futures given by *fs* that + are duplicated will be returned once. Any futures that completed + before :func:`as_completed` is called will be yielded first. The returned + iterator raises a :exc:`TimeoutError` if :meth:`~iterator.__next__` is + called and the result isn't available after *timeout* seconds from the + original call to :func:`as_completed`. *timeout* can be an int or float. + If *timeout* is not specified or ``None``, there is no limit to the wait + time. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures/__init__.py new/futures-3.0.1/futures/__init__.py --- old/futures-2.2.0/futures/__init__.py 2012-08-28 07:08:15.000000000 +0200 +++ new/futures-3.0.1/futures/__init__.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,24 +0,0 @@ -# Copyright 2009 Brian Quinlan. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Execute computations asynchronously using threads or processes.""" - -import warnings - -from concurrent.futures import (FIRST_COMPLETED, - FIRST_EXCEPTION, - ALL_COMPLETED, - CancelledError, - TimeoutError, - Future, - Executor, - wait, - as_completed, - ProcessPoolExecutor, - ThreadPoolExecutor) - -__author__ = 'Brian Quinlan ([email protected])' - -warnings.warn('The futures package has been deprecated. ' - 'Use the concurrent.futures package instead.', - DeprecationWarning) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures/process.py new/futures-3.0.1/futures/process.py --- old/futures-2.2.0/futures/process.py 2012-08-28 07:08:15.000000000 +0200 +++ new/futures-3.0.1/futures/process.py 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -from concurrent.futures import ProcessPoolExecutor diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures/thread.py new/futures-3.0.1/futures/thread.py --- old/futures-2.2.0/futures/thread.py 2012-08-28 07:08:15.000000000 +0200 +++ new/futures-3.0.1/futures/thread.py 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures.egg-info/PKG-INFO new/futures-3.0.1/futures.egg-info/PKG-INFO --- old/futures-2.2.0/futures.egg-info/PKG-INFO 2014-09-25 23:20:56.000000000 +0200 +++ new/futures-3.0.1/futures.egg-info/PKG-INFO 2015-05-03 08:32:05.000000000 +0200 @@ -1,19 +1,16 @@ Metadata-Version: 1.0 Name: futures -Version: 2.2.0 +Version: 3.0.1 Summary: Backport of the concurrent.futures package from Python 3.2 -Home-page: http://code.google.com/p/pythonfutures +Home-page: https://github.com/agronholm/pythonfutures Author: Alex Gronholm Author-email: [email protected] License: BSD -Download-URL: http://pypi.python.org/pypi/futures/ Description: UNKNOWN Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.1 +Classifier: Programming Language :: Python :: 2 :: Only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures.egg-info/SOURCES.txt new/futures-3.0.1/futures.egg-info/SOURCES.txt --- old/futures-2.2.0/futures.egg-info/SOURCES.txt 2014-09-25 23:20:56.000000000 +0200 +++ new/futures-3.0.1/futures.egg-info/SOURCES.txt 2015-05-03 08:32:05.000000000 +0200 @@ -10,18 +10,15 @@ concurrent/__init__.py concurrent/futures/__init__.py concurrent/futures/_base.py -concurrent/futures/_compat.py concurrent/futures/process.py concurrent/futures/thread.py docs/Makefile docs/conf.py docs/index.rst docs/make.bat -futures/__init__.py -futures/process.py -futures/thread.py futures.egg-info/PKG-INFO futures.egg-info/SOURCES.txt futures.egg-info/dependency_links.txt futures.egg-info/not-zip-safe +futures.egg-info/pbr.json futures.egg-info/top_level.txt \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures.egg-info/pbr.json new/futures-3.0.1/futures.egg-info/pbr.json --- old/futures-2.2.0/futures.egg-info/pbr.json 1970-01-01 01:00:00.000000000 +0100 +++ new/futures-3.0.1/futures.egg-info/pbr.json 2015-05-03 08:29:11.000000000 +0200 @@ -0,0 +1 @@ +{"is_release": false, "git_version": "fdbc9c3"} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/futures.egg-info/top_level.txt new/futures-3.0.1/futures.egg-info/top_level.txt --- old/futures-2.2.0/futures.egg-info/top_level.txt 2014-09-25 23:20:56.000000000 +0200 +++ new/futures-3.0.1/futures.egg-info/top_level.txt 2015-05-03 08:32:05.000000000 +0200 @@ -1,2 +1 @@ concurrent -futures diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/setup.cfg new/futures-3.0.1/setup.cfg --- old/futures-2.2.0/setup.cfg 2014-09-25 23:20:56.000000000 +0200 +++ new/futures-3.0.1/setup.cfg 2015-05-03 08:32:05.000000000 +0200 @@ -1,6 +1,3 @@ -[wheel] -universal = 1 - [build_sphinx] build-dir = build/sphinx source-dir = docs @@ -13,7 +10,3 @@ [upload_docs] upload-dir = build/sphinx/html -[metadata] -requires-dist = - multiprocessing; python_version == '2.5' and platform.python_implementation != 'Jython' - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/setup.py new/futures-3.0.1/setup.py --- old/futures-2.2.0/setup.py 2014-09-06 16:02:09.000000000 +0200 +++ new/futures-3.0.1/setup.py 2015-05-03 08:31:35.000000000 +0200 @@ -1,34 +1,27 @@ #!/usr/bin/env python -import sys -import os extras = {} try: from setuptools import setup extras['zip_safe'] = False - if sys.version_info < (2, 6) and os.name != 'java': - extras['install_requires'] = ['multiprocessing'] except ImportError: from distutils.core import setup setup(name='futures', - version='2.2.0', + version='3.0.1', description='Backport of the concurrent.futures package from Python 3.2', author='Brian Quinlan', author_email='[email protected]', maintainer='Alex Gronholm', maintainer_email='[email protected]', - url='http://code.google.com/p/pythonfutures', - download_url='http://pypi.python.org/pypi/futures/', - packages=['futures', 'concurrent', 'concurrent.futures'], + url='https://github.com/agronholm/pythonfutures', + packages=['concurrent', 'concurrent.futures'], license='BSD', classifiers=['License :: OSI Approved :: BSD License', 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', - 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.1'], + 'Programming Language :: Python :: 2 :: Only'], **extras ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/test_futures.py new/futures-3.0.1/test_futures.py --- old/futures-2.2.0/test_futures.py 2014-09-06 16:05:11.000000000 +0200 +++ new/futures-3.0.1/test_futures.py 2015-05-03 07:36:12.000000000 +0200 @@ -1,4 +1,3 @@ -from __future__ import with_statement import os import subprocess import sys @@ -8,6 +7,8 @@ import logging import re import time +from StringIO import StringIO +from test import test_support from concurrent import futures from concurrent.futures._base import ( @@ -18,21 +19,6 @@ except ImportError: import unittest -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -try: - from test import test_support -except ImportError: - from test import support as test_support - -try: - next -except NameError: - next = lambda x: x.next() - def reap_threads(func): """Use this function when threads are being used. This will @@ -437,6 +423,13 @@ SUCCESSFUL_FUTURE]), completed_futures) + def test_duplicate_futures(self): + # Issue 20367. Duplicate futures should not raise exceptions or give + # duplicate responses. + future1 = self.executor.submit(time.sleep, 2) + completed = [f for f in futures.as_completed([future1,future1])] + self.assertEqual(len(completed), 1) + class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests): pass @@ -484,7 +477,15 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): - pass + def test_map_submits_without_iteration(self): + """Tests verifying issue 11777.""" + finished = [] + def record_finished(n): + finished.append(n) + + self.executor.map(record_finished, range(10)) + self.executor.shutdown(wait=True) + self.assertEqual(len(finished), 10) class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/futures-2.2.0/tox.ini new/futures-3.0.1/tox.ini --- old/futures-2.2.0/tox.ini 2013-06-23 22:59:56.000000000 +0200 +++ new/futures-3.0.1/tox.ini 2015-05-02 22:49:00.000000000 +0200 @@ -1,5 +1,5 @@ [tox] -envlist = py26,py27,py31 +envlist = py26,py27 [testenv] commands={envpython} test_futures.py []
