diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 4fec647828e2506..093335f12181db1 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2218,6 +2218,14 @@ features: The :func:`scandir` iterator supports the :term:`context manager` protocol and has the following method: + .. method:: scandir.dirfd() + + Return directory file descriptor. + + .. versionadded:: 3.9 + + .. availability:: POSIX + .. method:: scandir.close() Close the iterator and free acquired resources. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 64361bb17f8a47d..07b6899a0c82b23 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -169,6 +169,9 @@ Exposed the Linux-specific :func:`os.pidfd_open` (:issue:`38692`) and :data:`os.P_PIDFD` (:issue:`38713`) for process management with file descriptors. +Added :meth:`~os.scandir.dirfd` method. +(Contributed by Giampaolo Rodola in :issue:`39099`) + threading --------- diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index f44ddbad7d64183..196fd2c9a7ebf9a 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -4001,6 +4001,13 @@ def test_resource_warning(self): with self.check_no_resource_warning(): del iterator + def test_dirfd(self): + with os.scandir('.') as itr: + if not hasattr(itr, 'dirfd'): + self.skipTest("not supported") + self.assertGreater(itr.dirfd(), 0) + self.assertRaises(ValueError, itr.dirfd) + class TestPEP519(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2019-12-19-19-37-01.bpo-39099.bZ8tpO.rst b/Misc/NEWS.d/next/Library/2019-12-19-19-37-01.bpo-39099.bZ8tpO.rst new file mode 100644 index 000000000000000..d8238df31e87335 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-12-19-19-37-01.bpo-39099.bZ8tpO.rst @@ -0,0 +1,2 @@ +os.scandir() object has a new dirfd() method. (patch contributed by +Giampaolo Rodola) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 322c2159812cdd0..0facf76d7242cc2 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13180,6 +13180,23 @@ ScandirIterator_close(ScandirIterator *self, PyObject *args) Py_RETURN_NONE; } +#ifdef HAVE_DIRFD +static PyObject * +ScandirIterator_dirfd(ScandirIterator *self, PyObject *args) +{ + int fd; + + if (ScandirIterator_is_closed(self)) { + PyErr_SetString(PyExc_ValueError, "I/O operation on closed directory"); + return NULL; + } + fd = dirfd(self->dirp); + if (fd == -1) + return path_error(&self->path); + return Py_BuildValue("i", fd); +} +#endif /* HAVE_DIRFD */ + static PyObject * ScandirIterator_enter(PyObject *self, PyObject *args) { @@ -13235,6 +13252,9 @@ ScandirIterator_dealloc(ScandirIterator *iterator) static PyMethodDef ScandirIterator_methods[] = { {"__enter__", (PyCFunction)ScandirIterator_enter, METH_NOARGS}, {"__exit__", (PyCFunction)ScandirIterator_exit, METH_VARARGS}, +#ifdef HAVE_DIRFD + {"dirfd", (PyCFunction)ScandirIterator_dirfd, METH_NOARGS}, +#endif {"close", (PyCFunction)ScandirIterator_close, METH_NOARGS}, {NULL} };