diff -r efcf163d04f5 Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py Sat Jan 04 23:04:27 2014 -0700 +++ b/Lib/asyncio/base_events.py Sun Jan 05 11:15:49 2014 +0100 @@ -15,7 +15,6 @@ to modify the meaning of the API call it import collections -import concurrent.futures import heapq import logging import socket @@ -23,6 +22,10 @@ import subprocess import time import os import sys +try: + import concurrent.futures +except ImportError: + concurrent = None from . import events from . import futures @@ -250,21 +253,22 @@ class BaseEventLoop(events.AbstractEvent self._write_to_self() return handle - def run_in_executor(self, executor, callback, *args): - if isinstance(callback, events.Handle): - assert not args - assert not isinstance(callback, events.TimerHandle) - if callback._cancelled: - f = futures.Future(loop=self) - f.set_result(None) - return f - callback, args = callback._callback, callback._args - if executor is None: - executor = self._default_executor + if concurrent is not None: + def run_in_executor(self, executor, callback, *args): + if isinstance(callback, events.Handle): + assert not args + assert not isinstance(callback, events.TimerHandle) + if callback._cancelled: + f = futures.Future(loop=self) + f.set_result(None) + return f + callback, args = callback._callback, callback._args if executor is None: - executor = concurrent.futures.ThreadPoolExecutor(_MAX_WORKERS) - self._default_executor = executor - return futures.wrap_future(executor.submit(callback, *args), loop=self) + executor = self._default_executor + if executor is None: + executor = concurrent.futures.ThreadPoolExecutor(_MAX_WORKERS) + self._default_executor = executor + return futures.wrap_future(executor.submit(callback, *args), loop=self) def set_default_executor(self, executor): self._default_executor = executor diff -r efcf163d04f5 Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py Sat Jan 04 23:04:27 2014 -0700 +++ b/Lib/asyncio/futures.py Sun Jan 05 11:15:49 2014 +0100 @@ -2,10 +2,9 @@ __all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', - 'Future', 'wrap_future', + 'Future', ] -import concurrent.futures._base import logging import sys import traceback @@ -13,6 +12,27 @@ import traceback from . import events from .log import logger +try: + import concurrent.futures + import concurrent.futures._base +except ImportError: + concurrent = None + class Error(Exception): + """Base class for all future-related exceptions.""" + pass + + class CancelledError(Error): + """The Future was cancelled.""" + pass + + class TimeoutError(Error): + """The operation exceeded the given deadline.""" + pass +else: + Error = concurrent.futures._base.Error + CancelledError = concurrent.futures.CancelledError + TimeoutError = concurrent.futures.TimeoutError + # States for Future. _PENDING = 'PENDING' _CANCELLED = 'CANCELLED' @@ -20,11 +40,6 @@ from .log import logger _PY34 = sys.version_info >= (3, 4) -# TODO: Do we really want to depend on concurrent.futures internals? -Error = concurrent.futures._base.Error -CancelledError = concurrent.futures.CancelledError -TimeoutError = concurrent.futures.TimeoutError - STACK_DEBUG = logging.DEBUG - 1 # heavy-duty debugging @@ -341,22 +356,24 @@ class Future: return self.result() # May raise too. -def wrap_future(fut, *, loop=None): - """Wrap concurrent.futures.Future object.""" - if isinstance(fut, Future): - return fut - assert isinstance(fut, concurrent.futures.Future), \ - 'concurrent.futures.Future is expected, got {!r}'.format(fut) - if loop is None: - loop = events.get_event_loop() - new_future = Future(loop=loop) +if concurrent is not None: + def wrap_future(fut, *, loop=None): + """Wrap concurrent.futures.Future object.""" + if isinstance(fut, Future): + return fut + assert isinstance(fut, concurrent.futures.Future), \ + 'concurrent.futures.Future is expected, got {!r}'.format(fut) + if loop is None: + loop = events.get_event_loop() + new_future = Future(loop=loop) - def _check_cancel_other(f): - if f.cancelled(): - fut.cancel() + def _check_cancel_other(f): + if f.cancelled(): + fut.cancel() - new_future.add_done_callback(_check_cancel_other) - fut.add_done_callback( - lambda future: loop.call_soon_threadsafe( - new_future._copy_state, fut)) - return new_future + new_future.add_done_callback(_check_cancel_other) + fut.add_done_callback( + lambda future: loop.call_soon_threadsafe( + new_future._copy_state, fut)) + return new_future + __all__.append('wrap_future') diff -r efcf163d04f5 Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py Sat Jan 04 23:04:27 2014 -0700 +++ b/Lib/asyncio/tasks.py Sun Jan 05 11:15:49 2014 +0100 @@ -8,7 +8,6 @@ ] import collections -import concurrent.futures import functools import inspect import linecache @@ -19,6 +18,17 @@ from . import events from . import futures from .log import logger +try: + import concurrent.futures +except ImportError: + FIRST_COMPLETED = 'FIRST_COMPLETED' + FIRST_EXCEPTION = 'FIRST_EXCEPTION' + ALL_COMPLETED = 'ALL_COMPLETED' +else: + FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED + FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION + ALL_COMPLETED = concurrent.futures.ALL_COMPLETED + # If you set _DEBUG to true, @coroutine will wrap the resulting # generator objects in a CoroWrapper instance (defined below). That # instance will log a message when the generator is never iterated @@ -338,10 +348,6 @@ class Task(futures.Future): # wait() and as_completed() similar to those in PEP 3148. -FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED -FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION -ALL_COMPLETED = concurrent.futures.ALL_COMPLETED - @coroutine def wait(fs, *, loop=None, timeout=None, return_when=ALL_COMPLETED): diff -r efcf163d04f5 Lib/test/test_asyncio/__init__.py --- a/Lib/test/test_asyncio/__init__.py Sat Jan 04 23:04:27 2014 -0700 +++ b/Lib/test/test_asyncio/__init__.py Sun Jan 05 11:15:49 2014 +0100 @@ -5,8 +5,6 @@ from test.support import run_unittest, i # Skip tests if we don't have threading. import_module('threading') -# Skip tests if we don't have concurrent.futures. -import_module('concurrent.futures') def suite(): diff -r efcf163d04f5 Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py Sat Jan 04 23:04:27 2014 -0700 +++ b/Lib/test/test_asyncio/test_futures.py Sun Jan 05 11:15:49 2014 +0100 @@ -1,14 +1,19 @@ """Tests for futures.py.""" -import concurrent.futures import threading import unittest import unittest.mock +from test.support import import_module from asyncio import events from asyncio import futures from asyncio import test_utils +# Skip tests if we don't have concurrent.futures. +import_module('concurrent.futures') + +import concurrent.futures + def _fakefunc(f): return f