From 86ebe126e6c9a3b652feb7fe79a4a10fd5272127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Sun, 3 May 2015 01:17:47 +0300 Subject: [PATCH] Dropped Python 2.5 and 3.1 support and the "futures" compatibility package --- CHANGES | 7 +++ concurrent/futures/__init__.py | 6 +- concurrent/futures/_base.py | 13 +--- concurrent/futures/_compat.py | 111 --------------------------------- concurrent/futures/process.py | 10 +-- concurrent/futures/thread.py | 10 +-- futures/__init__.py | 24 ------- futures/process.py | 1 - futures/thread.py | 1 - setup.cfg | 7 --- setup.py | 10 +-- test_futures.py | 18 +----- tox.ini | 2 +- 13 files changed, 23 insertions(+), 197 deletions(-) delete mode 100644 concurrent/futures/_compat.py delete mode 100644 futures/__init__.py delete mode 100644 futures/process.py delete mode 100644 futures/thread.py diff --git a/CHANGES b/CHANGES index c99eff1..1a9ef82 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +3.0.0 +===== + +- Dropped Python 2.5 and 3.1 support +- Removed the deprecated "futures" top level package + + 2.2.0 ===== diff --git a/concurrent/futures/__init__.py b/concurrent/futures/__init__.py index fef5281..4059308 100644 --- a/concurrent/futures/__init__.py +++ b/concurrent/futures/__init__.py @@ -15,9 +15,11 @@ from concurrent.futures._base import (FIRST_COMPLETED, 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 --git a/concurrent/futures/_base.py b/concurrent/futures/_base.py index 6f0c0f3..4b20803 100644 --- a/concurrent/futures/_base.py +++ b/concurrent/futures/_base.py @@ -1,18 +1,11 @@ # 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 time -from concurrent.futures._compat import reraise - -try: - from collections import namedtuple -except ImportError: - from concurrent.futures._compat import namedtuple - __author__ = 'Brian Quinlan (brian@sweetapp.com)' FIRST_COMPLETED = 'FIRST_COMPLETED' @@ -233,7 +226,7 @@ def as_completed(fs, timeout=None): 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 +349,7 @@ class Future(object): def __get_result(self): if self._exception: - reraise(self._exception, self._traceback) + raise type(self._exception), self._exception, self._traceback else: return self._result diff --git a/concurrent/futures/_compat.py b/concurrent/futures/_compat.py deleted file mode 100644 index e77cf0e..0000000 --- a/concurrent/futures/_compat.py +++ /dev/null @@ -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 --git a/concurrent/futures/process.py b/concurrent/futures/process.py index 98684f8..6a57531 100644 --- a/concurrent/futures/process.py +++ b/concurrent/futures/process.py @@ -43,20 +43,14 @@ Process #1..n: _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 (brian@sweetapp.com)' # Workers are created as daemon threads and processes. This is done to allow the diff --git a/concurrent/futures/thread.py b/concurrent/futures/thread.py index 930d167..46ba8eb 100644 --- a/concurrent/futures/thread.py +++ b/concurrent/futures/thread.py @@ -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 (brian@sweetapp.com)' # Workers are created as daemon threads. This is done to allow the interpreter diff --git a/futures/__init__.py b/futures/__init__.py deleted file mode 100644 index 8f8b234..0000000 --- a/futures/__init__.py +++ /dev/null @@ -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 (brian@sweetapp.com)' - -warnings.warn('The futures package has been deprecated. ' - 'Use the concurrent.futures package instead.', - DeprecationWarning) diff --git a/futures/process.py b/futures/process.py deleted file mode 100644 index e9d37b1..0000000 --- a/futures/process.py +++ /dev/null @@ -1 +0,0 @@ -from concurrent.futures import ProcessPoolExecutor diff --git a/futures/thread.py b/futures/thread.py deleted file mode 100644 index f6bd05d..0000000 --- a/futures/thread.py +++ /dev/null @@ -1 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor diff --git a/setup.cfg b/setup.cfg index 320967a..0a9f4f5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,13 +1,6 @@ -[wheel] -universal = 1 - [build_sphinx] source-dir = docs build-dir = build/sphinx [upload_docs] upload-dir = build/sphinx/html - -[metadata] -requires-dist = - multiprocessing; python_version == '2.5' and platform.python_implementation != 'Jython' diff --git a/setup.py b/setup.py index 4739df2..e809582 100755 --- a/setup.py +++ b/setup.py @@ -1,13 +1,9 @@ #!/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 @@ -19,15 +15,13 @@ setup(name='futures', maintainer='Alex Gronholm', maintainer_email='alex.gronholm+pypi@nextday.fi', url='https://github.com/agronholm/pythonfutures', - packages=['futures', 'concurrent', 'concurrent.futures'], + 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 --git a/test_futures.py b/test_futures.py index dd7fd3e..6cc7781 100644 --- a/test_futures.py +++ b/test_futures.py @@ -1,4 +1,3 @@ -from __future__ import with_statement import os import subprocess import sys @@ -8,6 +7,8 @@ import contextlib 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 @@ try: 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 diff --git a/tox.ini b/tox.ini index c1ff2f1..4948bd1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26,py27,py31 +envlist = py26,py27 [testenv] commands={envpython} test_futures.py []