summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-10-29 10:38:18 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2010-10-29 10:38:18 (GMT)
commite033e06db077d5abcb4bc3729d03f8a4a09b2486 (patch)
tree04445ffa669d4d0df240d680249c7d7a7f661bd4 /Lib
parent9cbdd75ec5deda8f55edd7caab42dff65d009da2 (diff)
downloadcpython-e033e06db077d5abcb4bc3729d03f8a4a09b2486.zip
cpython-e033e06db077d5abcb4bc3729d03f8a4a09b2486.tar.gz
cpython-e033e06db077d5abcb4bc3729d03f8a4a09b2486.tar.bz2
Issue #10093: ResourceWarnings are now issued when files and sockets are
deallocated without explicit closing. These warnings are silenced by default, except in pydebug mode.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/socket.py2
-rw-r--r--Lib/test/test_io.py41
-rw-r--r--Lib/test/test_socket.py17
-rw-r--r--Lib/xml/etree/ElementTree.py33
4 files changed, 81 insertions, 12 deletions
diff --git a/Lib/socket.py b/Lib/socket.py
index 6af1964..2dc9736 100644
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -108,7 +108,7 @@ class socket(_socket.socket):
if s.startswith("<socket object"):
s = "<%s.%s%s%s" % (self.__class__.__module__,
self.__class__.__name__,
- (self._closed and " [closed] ") or "",
+ getattr(self, '_closed', False) and " [closed] " or "",
s[7:])
return s
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 8784e34..7ce9753 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -29,6 +29,7 @@ import weakref
import abc
import signal
import errno
+import warnings
from itertools import cycle, count
from collections import deque
from test import support
@@ -2525,6 +2526,46 @@ class MiscIOTest(unittest.TestCase):
# baseline "io" module.
self._check_abc_inheritance(io)
+ def _check_warn_on_dealloc(self, *args, **kwargs):
+ f = open(*args, **kwargs)
+ r = repr(f)
+ with self.assertWarns(ResourceWarning) as cm:
+ f = None
+ support.gc_collect()
+ self.assertIn(r, str(cm.warning.args[0]))
+
+ def test_warn_on_dealloc(self):
+ self._check_warn_on_dealloc(support.TESTFN, "wb", buffering=0)
+ self._check_warn_on_dealloc(support.TESTFN, "wb")
+ self._check_warn_on_dealloc(support.TESTFN, "w")
+
+ def _check_warn_on_dealloc_fd(self, *args, **kwargs):
+ fds = []
+ try:
+ r, w = os.pipe()
+ fds += r, w
+ self._check_warn_on_dealloc(r, *args, **kwargs)
+ # When using closefd=False, there's no warning
+ r, w = os.pipe()
+ fds += r, w
+ with warnings.catch_warnings(record=True) as recorded:
+ open(r, *args, closefd=False, **kwargs)
+ support.gc_collect()
+ self.assertEqual(recorded, [])
+ finally:
+ for fd in fds:
+ try:
+ os.close(fd)
+ except EnvironmentError as e:
+ if e.errno != errno.EBADF:
+ raise
+
+ def test_warn_on_dealloc_fd(self):
+ self._check_warn_on_dealloc_fd("rb", buffering=0)
+ self._check_warn_on_dealloc_fd("rb")
+ self._check_warn_on_dealloc_fd("r")
+
+
class CMiscIOTest(MiscIOTest):
io = io
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 699efc0..e20364d 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -706,6 +706,23 @@ class GeneralModuleTests(unittest.TestCase):
def test_sendall_interrupted_with_timeout(self):
self.check_sendall_interrupted(True)
+ def test_dealloc_warn(self):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ r = repr(sock)
+ with self.assertWarns(ResourceWarning) as cm:
+ sock = None
+ support.gc_collect()
+ self.assertIn(r, str(cm.warning.args[0]))
+ # An open socket file object gets dereferenced after the socket
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ f = sock.makefile('rb')
+ r = repr(sock)
+ sock = None
+ support.gc_collect()
+ with self.assertWarns(ResourceWarning):
+ f = None
+ support.gc_collect()
+
@unittest.skipUnless(thread, 'Threading required for this test.')
class BasicTCPTest(SocketConnectedTest):
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index ecc8ea7..9f5717e 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -662,17 +662,23 @@ class ElementTree:
# @exception ParseError If the parser fails to parse the document.
def parse(self, source, parser=None):
+ close_source = False
if not hasattr(source, "read"):
source = open(source, "rb")
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- while 1:
- data = source.read(65536)
- if not data:
- break
- parser.feed(data)
- self._root = parser.close()
- return self._root
+ close_source = True
+ try:
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ while 1:
+ data = source.read(65536)
+ if not data:
+ break
+ parser.feed(data)
+ self._root = parser.close()
+ return self._root
+ finally:
+ if close_source:
+ source.close()
##
# Creates a tree iterator for the root element. The iterator loops
@@ -1226,16 +1232,19 @@ def parse(source, parser=None):
# @return A (event, elem) iterator.
def iterparse(source, events=None, parser=None):
+ close_source = False
if not hasattr(source, "read"):
source = open(source, "rb")
+ close_source = True
if not parser:
parser = XMLParser(target=TreeBuilder())
- return _IterParseIterator(source, events, parser)
+ return _IterParseIterator(source, events, parser, close_source)
class _IterParseIterator:
- def __init__(self, source, events, parser):
+ def __init__(self, source, events, parser, close_source=False):
self._file = source
+ self._close_file = close_source
self._events = []
self._index = 0
self.root = self._root = None
@@ -1282,6 +1291,8 @@ class _IterParseIterator:
except IndexError:
if self._parser is None:
self.root = self._root
+ if self._close_file:
+ self._file.close()
raise StopIteration
# load event buffer
del self._events[:]