diff -r 46329eec5515 Doc/library/warnings.rst --- a/Doc/library/warnings.rst Mon Mar 21 16:36:48 2016 +0100 +++ b/Doc/library/warnings.rst Mon Mar 21 17:14:19 2016 +0100 @@ -300,7 +300,7 @@ Available Functions ------------------- -.. function:: warn(message, category=None, stacklevel=1) +.. function:: warn(message, category=None, stacklevel=1, source=None) Issue a warning, or maybe ignore it or raise an exception. The *category* argument, if given, must be a warning category class (see above); it defaults to @@ -318,6 +318,12 @@ Available Functions source of :func:`deprecation` itself (since the latter would defeat the purpose of the warning message). + *source*, if supplied, is the destroyed object which emitted a + :exc:`ResourceWarning`. + + .. versionchanged:: 3.6 + Added *source* parameter. + .. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None) diff -r 46329eec5515 Lib/_pyio.py --- a/Lib/_pyio.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/_pyio.py Mon Mar 21 17:14:19 2016 +0100 @@ -1514,7 +1514,7 @@ class FileIO(RawIOBase): if self._fd >= 0 and self._closefd and not self.closed: import warnings warnings.warn('unclosed file %r' % (self,), ResourceWarning, - stacklevel=2) + stacklevel=2, source=self) self.close() def __getstate__(self): diff -r 46329eec5515 Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/base_events.py Mon Mar 21 17:14:19 2016 +0100 @@ -412,7 +412,8 @@ class BaseEventLoop(events.AbstractEvent if compat.PY34: def __del__(self): if not self.is_closed(): - warnings.warn("unclosed event loop %r" % self, ResourceWarning) + warnings.warn("unclosed event loop %r" % self, ResourceWarning, + source=self) if not self.is_running(): self.close() diff -r 46329eec5515 Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/base_subprocess.py Mon Mar 21 17:14:19 2016 +0100 @@ -122,7 +122,8 @@ class BaseSubprocessTransport(transports if compat.PY34: def __del__(self): if not self._closed: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + warnings.warn("unclosed transport %r" % self, ResourceWarning, + source=self) self.close() def get_pid(self): diff -r 46329eec5515 Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/proactor_events.py Mon Mar 21 17:14:19 2016 +0100 @@ -86,7 +86,8 @@ class _ProactorBasePipeTransport(transpo if compat.PY34: def __del__(self): if self._sock is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + warnings.warn("unclosed transport %r" % self, ResourceWarning, + source=self) self.close() def _fatal_error(self, exc, message='Fatal error on pipe transport'): diff -r 46329eec5515 Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/selector_events.py Mon Mar 21 17:14:19 2016 +0100 @@ -573,7 +573,8 @@ class _SelectorTransport(transports._Flo if compat.PY34: def __del__(self): if self._sock is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + warnings.warn("unclosed transport %r" % self, ResourceWarning, + source=self) self._sock.close() def _fatal_error(self, exc, message='Fatal error on transport'): diff -r 46329eec5515 Lib/asyncio/sslproto.py --- a/Lib/asyncio/sslproto.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/sslproto.py Mon Mar 21 17:14:19 2016 +0100 @@ -324,7 +324,8 @@ class _SSLProtocolTransport(transports._ if compat.PY34: def __del__(self): if not self._closed: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + warnings.warn("unclosed transport %r" % self, ResourceWarning, + source=self) self.close() def pause_reading(self): diff -r 46329eec5515 Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/unix_events.py Mon Mar 21 17:14:19 2016 +0100 @@ -378,7 +378,8 @@ class _UnixReadPipeTransport(transports. if compat.PY34: def __del__(self): if self._pipe is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + warnings.warn("unclosed transport %r" % self, ResourceWarning, + source=self) self._pipe.close() def _fatal_error(self, exc, message='Fatal error on pipe transport'): @@ -567,7 +568,8 @@ class _UnixWritePipeTransport(transports if compat.PY34: def __del__(self): if self._pipe is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + warnings.warn("unclosed transport %r" % self, ResourceWarning, + source=self) self._pipe.close() def abort(self): diff -r 46329eec5515 Lib/asyncio/windows_utils.py --- a/Lib/asyncio/windows_utils.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncio/windows_utils.py Mon Mar 21 17:14:19 2016 +0100 @@ -159,7 +159,8 @@ class PipeHandle: def __del__(self): if self._handle is not None: - warnings.warn("unclosed %r" % self, ResourceWarning) + warnings.warn("unclosed %r" % self, ResourceWarning, + source=self) self.close() def __enter__(self): diff -r 46329eec5515 Lib/asyncore.py --- a/Lib/asyncore.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/asyncore.py Mon Mar 21 17:14:19 2016 +0100 @@ -595,7 +595,8 @@ if os.name == 'posix': def __del__(self): if self.fd >= 0: - warnings.warn("unclosed file %r" % self, ResourceWarning) + warnings.warn("unclosed file %r" % self, ResourceWarning + source=self) self.close() def recv(self, *args): diff -r 46329eec5515 Lib/tempfile.py --- a/Lib/tempfile.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/tempfile.py Mon Mar 21 17:14:19 2016 +0100 @@ -797,7 +797,6 @@ class TemporaryDirectory(object): _shutil.rmtree(name) _warnings.warn(warn_message, ResourceWarning) - def __repr__(self): return "<{} {!r}>".format(self.__class__.__name__, self.name) diff -r 46329eec5515 Lib/warnings.py --- a/Lib/warnings.py Mon Mar 21 16:36:48 2016 +0100 +++ b/Lib/warnings.py Mon Mar 21 17:14:19 2016 +0100 @@ -233,7 +233,7 @@ def _next_external_frame(frame): # Code typically replaced by _warnings -def warn(message, category=None, stacklevel=1): +def warn(message, category=None, stacklevel=1, source=None): """Issue a warning, or maybe ignore it or raise an exception.""" # Check if message is already a Warning object if isinstance(message, Warning): @@ -283,7 +283,7 @@ def warn(message, category=None, stackle filename = module registry = globals.setdefault("__warningregistry__", {}) warn_explicit(message, category, filename, lineno, module, registry, - globals) + globals, source) def warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, diff -r 46329eec5515 Python/_warnings.c --- a/Python/_warnings.c Mon Mar 21 16:36:48 2016 +0100 +++ b/Python/_warnings.c Mon Mar 21 17:14:19 2016 +0100 @@ -787,18 +787,19 @@ do_warn(PyObject *message, PyObject *cat static PyObject * warnings_warn(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kw_list[] = { "message", "category", "stacklevel", 0 }; - PyObject *message, *category = NULL; + static char *kw_list[] = {"message", "category", "stacklevel", + "source", NULL}; + PyObject *message, *category = NULL, *source = NULL; Py_ssize_t stack_level = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list, - &message, &category, &stack_level)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OnO:warn", kw_list, + &message, &category, &stack_level, &source)) return NULL; category = get_category(message, category); if (category == NULL) return NULL; - return do_warn(message, category, stack_level, NULL); + return do_warn(message, category, stack_level, source); } static PyObject *