Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3.6
Changeset: r93354:2d7ef69f48bd
Date: 2017-12-10 21:33 +0100
http://bitbucket.org/pypy/pypy/changeset/2d7ef69f48bd/
Log: Scandir: Add a context manager, and a ResourceWarning when it is not
explictly closed.
diff --git a/pypy/module/posix/interp_scandir.py
b/pypy/module/posix/interp_scandir.py
--- a/pypy/module/posix/interp_scandir.py
+++ b/pypy/module/posix/interp_scandir.py
@@ -51,11 +51,25 @@
self.dirfd = dirfd
self.w_path_prefix = w_path_prefix
self.result_is_bytes = result_is_bytes
+ self.register_finalizer(space)
- @rgc.must_be_light_finalizer
- def __del__(self):
- if self.dirp:
- rposix_scandir.closedir(self.dirp)
+ def _finalize_(self):
+ if not self.dirp:
+ return
+ space = self.space
+ try:
+ msg = ("unclosed scandir iterator %s" %
+ space.text_w(space.repr(self)))
+ space.warn(space.newtext(msg), space.w_ResourceWarning)
+ except OperationError as e:
+ # Spurious errors can appear at shutdown
+ if e.match(space, space.w_Warning):
+ e.write_unraisable(space, '', self)
+ self._close()
+
+ def _close(self):
+ rposix_scandir.closedir(self.dirp)
+ self.dirp = rposix_scandir.NULL_DIRP
def iter_w(self):
return self
@@ -96,16 +110,31 @@
#
known_type = rposix_scandir.get_known_type(entry)
inode = rposix_scandir.get_inode(entry)
+ except:
+ self._close()
+ raise
finally:
self._in_next = False
direntry = W_DirEntry(self, name, known_type, inode)
return direntry
+ def close_w(self):
+ self._close()
+
+ def enter_w(self):
+ return self
+
+ def exit_w(self, space, __args__):
+ self._close()
+
W_ScandirIterator.typedef = TypeDef(
'posix.ScandirIterator',
__iter__ = interp2app(W_ScandirIterator.iter_w),
__next__ = interp2app(W_ScandirIterator.next_w),
+ __enter__ = interp2app(W_ScandirIterator.enter_w),
+ __exit__ = interp2app(W_ScandirIterator.exit_w),
+ close = interp2app(W_ScandirIterator.close_w),
)
W_ScandirIterator.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/posix/test/test_scandir.py
b/pypy/module/posix/test/test_scandir.py
--- a/pypy/module/posix/test/test_scandir.py
+++ b/pypy/module/posix/test/test_scandir.py
@@ -170,3 +170,34 @@
posix = self.posix
d = next(posix.scandir(self.dir1))
assert repr(d) == "<DirEntry 'file1'>"
+
+ def test_resource_warning(self):
+ posix = self.posix
+ import warnings, gc
+ iterator = posix.scandir(self.dir1)
+ next(iterator)
+ with warnings.catch_warnings(record=True) as l:
+ warnings.simplefilter("always")
+ del iterator
+ gc.collect()
+ assert isinstance(l[0].message, ResourceWarning)
+ #
+ iterator = posix.scandir(self.dir1)
+ next(iterator)
+ with warnings.catch_warnings(record=True) as l:
+ warnings.simplefilter("always")
+ iterator.close()
+ del iterator
+ gc.collect()
+ assert len(l) == 0
+
+ def test_context_manager(self):
+ posix = self.posix
+ import warnings, gc
+ with warnings.catch_warnings(record=True) as l:
+ warnings.simplefilter("always")
+ with posix.scandir(self.dir1) as iterator:
+ next(iterator)
+ del iterator
+ gc.collect()
+ assert not l
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit