summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorINADA Naoki <methane@users.noreply.github.com>2017-04-25 01:57:18 (GMT)
committerGitHub <noreply@github.com>2017-04-25 01:57:18 (GMT)
commit3e2ad8ec61a322370a6fbdfb2209cf74546f5e08 (patch)
tree0285efcc8b8d9b7215e4b8dbe106960187b1e628
parentf6448e5d65c349576df6e83b8324b9c208e77615 (diff)
downloadcpython-3e2ad8ec61a322370a6fbdfb2209cf74546f5e08.zip
cpython-3e2ad8ec61a322370a6fbdfb2209cf74546f5e08.tar.gz
cpython-3e2ad8ec61a322370a6fbdfb2209cf74546f5e08.tar.bz2
bpo-29617: Remove Python 3.3 support from asyncio (GH-232)
-rw-r--r--Lib/asyncio/base_events.py17
-rw-r--r--Lib/asyncio/base_subprocess.py15
-rw-r--r--Lib/asyncio/compat.py12
-rw-r--r--Lib/asyncio/events.py9
-rw-r--r--Lib/asyncio/futures.py122
-rw-r--r--Lib/asyncio/proactor_events.py15
-rw-r--r--Lib/asyncio/selector_events.py15
-rw-r--r--Lib/asyncio/sslproto.py15
-rw-r--r--Lib/asyncio/tasks.py24
-rw-r--r--Lib/asyncio/test_utils.py11
-rw-r--r--Lib/asyncio/transports.py4
-rw-r--r--Lib/asyncio/unix_events.py29
12 files changed, 65 insertions, 223 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 6624ac1..3ff511b 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -29,7 +29,6 @@ import sys
import warnings
import weakref
-from . import compat
from . import coroutines
from . import events
from . import futures
@@ -499,16 +498,12 @@ class BaseEventLoop(events.AbstractEventLoop):
"""Returns True if the event loop was closed."""
return self._closed
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self.is_closed():
- warnings.warn("unclosed event loop %r" % self, ResourceWarning,
- source=self)
- if not self.is_running():
- self.close()
+ def __del__(self):
+ if not self.is_closed():
+ warnings.warn("unclosed event loop %r" % self, ResourceWarning,
+ source=self)
+ if not self.is_running():
+ self.close()
def is_running(self):
"""Returns True if the event loop is running."""
diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py
index a00d9d5..cac8d96 100644
--- a/Lib/asyncio/base_subprocess.py
+++ b/Lib/asyncio/base_subprocess.py
@@ -2,7 +2,6 @@ import collections
import subprocess
import warnings
-from . import compat
from . import protocols
from . import transports
from .coroutines import coroutine
@@ -121,15 +120,11 @@ class BaseSubprocessTransport(transports.SubprocessTransport):
# Don't clear the _proc reference yet: _post_init() may still run
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self._closed:
- warnings.warn("unclosed transport %r" % self, ResourceWarning,
- source=self)
- self.close()
+ def __del__(self):
+ if not self._closed:
+ warnings.warn("unclosed transport %r" % self, ResourceWarning,
+ source=self)
+ self.close()
def get_pid(self):
return self._pid
diff --git a/Lib/asyncio/compat.py b/Lib/asyncio/compat.py
index 4790bb4..520ec68 100644
--- a/Lib/asyncio/compat.py
+++ b/Lib/asyncio/compat.py
@@ -2,17 +2,5 @@
import sys
-PY34 = sys.version_info >= (3, 4)
PY35 = sys.version_info >= (3, 5)
PY352 = sys.version_info >= (3, 5, 2)
-
-
-def flatten_list_bytes(list_of_data):
- """Concatenate a sequence of bytes-like objects."""
- if not PY34:
- # On Python 3.3 and older, bytes.join() doesn't handle
- # memoryview.
- list_of_data = (
- bytes(data) if isinstance(data, memoryview) else data
- for data in list_of_data)
- return b''.join(list_of_data)
diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py
index e85634e..6af9137 100644
--- a/Lib/asyncio/events.py
+++ b/Lib/asyncio/events.py
@@ -19,20 +19,15 @@ import sys
import threading
import traceback
-from asyncio import compat
-
def _get_function_source(func):
- if compat.PY34:
- func = inspect.unwrap(func)
- elif hasattr(func, '__wrapped__'):
- func = func.__wrapped__
+ func = inspect.unwrap(func)
if inspect.isfunction(func):
code = func.__code__
return (code.co_filename, code.co_firstlineno)
if isinstance(func, functools.partial):
return _get_function_source(func.func)
- if compat.PY34 and isinstance(func, functools.partialmethod):
+ if isinstance(func, functools.partialmethod):
return _get_function_source(func.func)
return None
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index d11d289..39721ea 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -27,86 +27,6 @@ _FINISHED = base_futures._FINISHED
STACK_DEBUG = logging.DEBUG - 1 # heavy-duty debugging
-class _TracebackLogger:
- """Helper to log a traceback upon destruction if not cleared.
-
- This solves a nasty problem with Futures and Tasks that have an
- exception set: if nobody asks for the exception, the exception is
- never logged. This violates the Zen of Python: 'Errors should
- never pass silently. Unless explicitly silenced.'
-
- However, we don't want to log the exception as soon as
- set_exception() is called: if the calling code is written
- properly, it will get the exception and handle it properly. But
- we *do* want to log it if result() or exception() was never called
- -- otherwise developers waste a lot of time wondering why their
- buggy code fails silently.
-
- An earlier attempt added a __del__() method to the Future class
- itself, but this backfired because the presence of __del__()
- prevents garbage collection from breaking cycles. A way out of
- this catch-22 is to avoid having a __del__() method on the Future
- class itself, but instead to have a reference to a helper object
- with a __del__() method that logs the traceback, where we ensure
- that the helper object doesn't participate in cycles, and only the
- Future has a reference to it.
-
- The helper object is added when set_exception() is called. When
- the Future is collected, and the helper is present, the helper
- object is also collected, and its __del__() method will log the
- traceback. When the Future's result() or exception() method is
- called (and a helper object is present), it removes the helper
- object, after calling its clear() method to prevent it from
- logging.
-
- One downside is that we do a fair amount of work to extract the
- traceback from the exception, even when it is never logged. It
- would seem cheaper to just store the exception object, but that
- references the traceback, which references stack frames, which may
- reference the Future, which references the _TracebackLogger, and
- then the _TracebackLogger would be included in a cycle, which is
- what we're trying to avoid! As an optimization, we don't
- immediately format the exception; we only do the work when
- activate() is called, which call is delayed until after all the
- Future's callbacks have run. Since usually a Future has at least
- one callback (typically set by 'yield from') and usually that
- callback extracts the callback, thereby removing the need to
- format the exception.
-
- PS. I don't claim credit for this solution. I first heard of it
- in a discussion about closing files when they are collected.
- """
-
- __slots__ = ('loop', 'source_traceback', 'exc', 'tb')
-
- def __init__(self, future, exc):
- self.loop = future._loop
- self.source_traceback = future._source_traceback
- self.exc = exc
- self.tb = None
-
- def activate(self):
- exc = self.exc
- if exc is not None:
- self.exc = None
- self.tb = traceback.format_exception(exc.__class__, exc,
- exc.__traceback__)
-
- def clear(self):
- self.exc = None
- self.tb = None
-
- def __del__(self):
- if self.tb:
- msg = 'Future/Task exception was never retrieved\n'
- if self.source_traceback:
- src = ''.join(traceback.format_list(self.source_traceback))
- msg += 'Future/Task created at (most recent call last):\n'
- msg += '%s\n' % src.rstrip()
- msg += ''.join(self.tb).rstrip()
- self.loop.call_exception_handler({'message': msg})
-
-
class Future:
"""This class is *almost* compatible with concurrent.futures.Future.
@@ -164,25 +84,21 @@ class Future:
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, ' '.join(self._repr_info()))
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self._log_traceback:
- # set_exception() was not called, or result() or exception()
- # has consumed the exception
- return
- exc = self._exception
- context = {
- 'message': ('%s exception was never retrieved'
- % self.__class__.__name__),
- 'exception': exc,
- 'future': self,
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
+ def __del__(self):
+ if not self._log_traceback:
+ # set_exception() was not called, or result() or exception()
+ # has consumed the exception
+ return
+ exc = self._exception
+ context = {
+ 'message': ('%s exception was never retrieved'
+ % self.__class__.__name__),
+ 'exception': exc,
+ 'future': self,
+ }
+ if self._source_traceback:
+ context['source_traceback'] = self._source_traceback
+ self._loop.call_exception_handler(context)
def cancel(self):
"""Cancel the future and schedule callbacks.
@@ -317,13 +233,7 @@ class Future:
self._exception = exception
self._state = _FINISHED
self._schedule_callbacks()
- if compat.PY34:
- self._log_traceback = True
- else:
- self._tb_logger = _TracebackLogger(self, exception)
- # Arrange for the logger to be activated after all callbacks
- # have had a chance to call result() or exception().
- self._loop.call_soon(self._tb_logger.activate)
+ self._log_traceback = True
def __iter__(self):
if not self.done():
diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py
index ff12877..c85d4da 100644
--- a/Lib/asyncio/proactor_events.py
+++ b/Lib/asyncio/proactor_events.py
@@ -10,7 +10,6 @@ import socket
import warnings
from . import base_events
-from . import compat
from . import constants
from . import futures
from . import sslproto
@@ -86,15 +85,11 @@ class _ProactorBasePipeTransport(transports._FlowControlMixin,
self._read_fut.cancel()
self._read_fut = None
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._sock is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning,
- source=self)
- self.close()
+ def __del__(self):
+ if self._sock is not None:
+ warnings.warn("unclosed transport %r" % self, ResourceWarning,
+ source=self)
+ self.close()
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 9dbe550..4b40356 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -18,7 +18,6 @@ except ImportError: # pragma: no cover
ssl = None
from . import base_events
-from . import compat
from . import constants
from . import events
from . import futures
@@ -621,15 +620,11 @@ class _SelectorTransport(transports._FlowControlMixin,
self._loop._remove_writer(self._sock_fd)
self._loop.call_soon(self._call_connection_lost, None)
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._sock is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning,
- source=self)
- self._sock.close()
+ def __del__(self):
+ if self._sock is not None:
+ warnings.warn("unclosed transport %r" % self, ResourceWarning,
+ source=self)
+ self._sock.close()
def _fatal_error(self, exc, message='Fatal error on transport'):
# Should be called from exception handler only.
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index ab7ff0b..61d31a3 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -6,7 +6,6 @@ except ImportError: # pragma: no cover
ssl = None
from . import base_events
-from . import compat
from . import protocols
from . import transports
from .log import logger
@@ -325,15 +324,11 @@ class _SSLProtocolTransport(transports._FlowControlMixin,
self._closed = True
self._ssl_protocol._start_shutdown()
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if not self._closed:
- warnings.warn("unclosed transport %r" % self, ResourceWarning,
- source=self)
- self.close()
+ def __del__(self):
+ if not self._closed:
+ warnings.warn("unclosed transport %r" % self, ResourceWarning,
+ source=self)
+ self.close()
def pause_reading(self):
"""Pause the receiving end.
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index f91e70a..4fbcf3e 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -76,20 +76,16 @@ class Task(futures.Future):
self._loop.call_soon(self._step)
self.__class__._all_tasks.add(self)
- # On Python 3.3 or older, objects with a destructor that are part of a
- # reference cycle are never destroyed. That's not the case any more on
- # Python 3.4 thanks to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._state == futures._PENDING and self._log_destroy_pending:
- context = {
- 'task': self,
- 'message': 'Task was destroyed but it is pending!',
- }
- if self._source_traceback:
- context['source_traceback'] = self._source_traceback
- self._loop.call_exception_handler(context)
- futures.Future.__del__(self)
+ def __del__(self):
+ if self._state == futures._PENDING and self._log_destroy_pending:
+ context = {
+ 'task': self,
+ 'message': 'Task was destroyed but it is pending!',
+ }
+ if self._source_traceback:
+ context['source_traceback'] = self._source_traceback
+ self._loop.call_exception_handler(context)
+ futures.Future.__del__(self)
def _repr_info(self):
return base_tasks._task_repr_info(self)
diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py
index b12d5db..d273b08 100644
--- a/Lib/asyncio/test_utils.py
+++ b/Lib/asyncio/test_utils.py
@@ -26,7 +26,6 @@ except ImportError: # pragma: no cover
ssl = None
from . import base_events
-from . import compat
from . import events
from . import futures
from . import selectors
@@ -465,16 +464,6 @@ class TestCase(unittest.TestCase):
# in an except block of a generator
self.assertEqual(sys.exc_info(), (None, None, None))
- if not compat.PY34:
- # Python 3.3 compatibility
- def subTest(self, *args, **kwargs):
- class EmptyCM:
- def __enter__(self):
- pass
- def __exit__(self, *exc):
- pass
- return EmptyCM()
-
@contextlib.contextmanager
def disable_logger():
diff --git a/Lib/asyncio/transports.py b/Lib/asyncio/transports.py
index 0db0875..a94079f 100644
--- a/Lib/asyncio/transports.py
+++ b/Lib/asyncio/transports.py
@@ -1,7 +1,5 @@
"""Abstract Transport class."""
-from asyncio import compat
-
__all__ = ['BaseTransport', 'ReadTransport', 'WriteTransport',
'Transport', 'DatagramTransport', 'SubprocessTransport',
]
@@ -104,7 +102,7 @@ class WriteTransport(BaseTransport):
The default implementation concatenates the arguments and
calls write() on the result.
"""
- data = compat.flatten_list_bytes(list_of_data)
+ data = b''.join(list_of_data)
self.write(data)
def write_eof(self):
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index 2806ea8..bf682a1 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -13,7 +13,6 @@ import warnings
from . import base_events
from . import base_subprocess
-from . import compat
from . import constants
from . import coroutines
from . import events
@@ -413,15 +412,11 @@ class _UnixReadPipeTransport(transports.ReadTransport):
if not self._closing:
self._close(None)
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._pipe is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning,
- source=self)
- self._pipe.close()
+ def __del__(self):
+ if self._pipe is not None:
+ warnings.warn("unclosed transport %r" % self, ResourceWarning,
+ source=self)
+ self._pipe.close()
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
# should be called by exception handler only
@@ -614,15 +609,11 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
# write_eof is all what we needed to close the write pipe
self.write_eof()
- # On Python 3.3 and older, objects with a destructor part of a reference
- # cycle are never destroyed. It's not more the case on Python 3.4 thanks
- # to the PEP 442.
- if compat.PY34:
- def __del__(self):
- if self._pipe is not None:
- warnings.warn("unclosed transport %r" % self, ResourceWarning,
- source=self)
- self._pipe.close()
+ def __del__(self):
+ if self._pipe is not None:
+ warnings.warn("unclosed transport %r" % self, ResourceWarning,
+ source=self)
+ self._pipe.close()
def abort(self):
self._close(None)