diff --git a/Doc/library/select.rst b/Doc/library/select.rst index 4e60f4ad883..b73f11e2276 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -47,11 +47,14 @@ The module defines the following: to :const:`EPOLL_CLOEXEC`, which causes the epoll descriptor to be closed automatically when :func:`os.execve` is called. See section :ref:`epoll-objects` below for the methods supported by epolling objects. - + They also support the :keyword:`with` statement. .. versionchanged:: 3.3 Added the *flags* parameter. + .. versionchanged:: 3.4 + Support for the :keyword:`with` statement was added. + .. function:: poll() diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py index 7f9547ff959..b9b1492862d 100644 --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -87,6 +87,13 @@ class TestEPoll(unittest.TestCase): self.assertRaises(TypeError, select.epoll, ['foo']) self.assertRaises(TypeError, select.epoll, {}) + def test_context_manager(self): + with select.epoll(16) as ep: + self.assertGreater(ep.fileno(), 0) + self.assertFalse(ep.closed) + self.assertTrue(ep.closed) + self.assertRaises(ValueError, ep.fileno) + def test_add(self): server, client = self._connected_pair() diff --git a/Misc/NEWS b/Misc/NEWS index 7b8636a730a..7b71524210a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -167,6 +167,9 @@ Core and Builtins Library ------- +- Issue #16488: epoll() objects now support the `with` statement. Patch + by Serhiy Storchaka. + - Issue #16298: In HTTPResponse.read(), close the socket when there is no Content-Length and the incoming stream is finished. Patch by Eran Rundstein. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index c0f56a79e9f..52be4d8eea0 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1394,6 +1394,24 @@ Wait for events on the epoll file descriptor for a maximum time of timeout\n\ in seconds (as float). -1 makes poll wait indefinitely.\n\ Up to maxevents are returned to the caller."); +static PyObject * +pyepoll_enter(pyEpoll_Object *self, PyObject *args) +{ + if (self->epfd < 0) + return pyepoll_err_closed(); + + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +pyepoll_exit(PyObject *self, PyObject *args) +{ + _Py_IDENTIFIER(close); + + return _PyObject_CallMethodId(self, &PyId_close, NULL); +} + static PyMethodDef pyepoll_methods[] = { {"fromfd", (PyCFunction)pyepoll_fromfd, METH_VARARGS | METH_CLASS, pyepoll_fromfd_doc}, @@ -1409,6 +1427,10 @@ static PyMethodDef pyepoll_methods[] = { METH_VARARGS | METH_KEYWORDS, pyepoll_unregister_doc}, {"poll", (PyCFunction)pyepoll_poll, METH_VARARGS | METH_KEYWORDS, pyepoll_poll_doc}, + {"__enter__", (PyCFunction)pyepoll_enter, METH_NOARGS, + NULL}, + {"__exit__", (PyCFunction)pyepoll_exit, METH_VARARGS, + NULL}, {NULL, NULL}, };