https://github.com/python/cpython/commit/312c427fe4169c5bee10b399667f155d398d8184
commit: 312c427fe4169c5bee10b399667f155d398d8184
branch: main
author: Michael J. Sullivan <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-10-28T13:47:42+05:30
summary:
gh-158192: expose the future in asyncio FutureIter as `fi_future` (#158470)
files:
A Misc/NEWS.d/next/Library/2026-09-29-19-34-30.gh-issue-158192.6wPjiU.rst
M Lib/asyncio/futures.py
M Lib/test/test_asyncio/test_futures.py
M Modules/_asynciomodule.c
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 11858a0274a69f..76675988c2bfe2 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -293,7 +293,7 @@ def set_exception(self, exception):
self.__schedule_callbacks()
self.__log_traceback = True
- def __await__(self):
+ def _await(self):
if not self.done():
self._asyncio_future_blocking = True
yield self # This tells Task to wait for completion.
@@ -301,9 +301,43 @@ def __await__(self):
raise RuntimeError("await wasn't used with future")
return self.result() # May raise too.
+ def __await__(self):
+ # Return an object that exposes fi_future in addition to being
+ # a generator, for compatability with the C version.
+ return _FutureIter(self)
+
__iter__ = __await__ # make compatible with 'yield from'.
+class _FutureIter:
+ __slots__ = ('__future', '__gen')
+
+ def __init__(self, fut):
+ self.__future = fut
+ self.__gen = fut._await()
+
+ @property
+ def fi_future(self):
+ return self.__future
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ return self.__gen.__next__()
+
+ def send(self, v, /):
+ return self.__gen.send(v)
+
+ def throw(self, *args):
+ self.__future = None
+ return self.__gen.throw(*args)
+
+ def close(self):
+ self.__future = None
+ self.__gen.close()
+
+
# Needed for testing purposes.
_PyFuture = Future
diff --git a/Lib/test/test_asyncio/test_futures.py
b/Lib/test/test_asyncio/test_futures.py
index 5ed3ec582224c6..b244301e98e7ee 100644
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -712,6 +712,10 @@ def test_future_stop_iteration_args(self):
self.fail('StopIteration was expected')
self.assertEqual(result, (1, 2))
+ def test_future_iter_fut(self):
+ fut = self._new_future(loop=self.loop)
+ self.assertIs(iter(fut).fi_future, fut)
+
def test_future_iter_throw(self):
fut = self._new_future(loop=self.loop)
fi = iter(fut)
diff --git
a/Misc/NEWS.d/next/Library/2026-09-29-19-34-30.gh-issue-158192.6wPjiU.rst
b/Misc/NEWS.d/next/Library/2026-09-29-19-34-30.gh-issue-158192.6wPjiU.rst
new file mode 100644
index 00000000000000..b0634084c6af8a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-29-19-34-30.gh-issue-158192.6wPjiU.rst
@@ -0,0 +1 @@
+Expose the future being waited on by a ``FutureIter`` as ``fi_future``.
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index 5569f7a3670378..73404cb75b5d1f 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -1988,6 +1988,22 @@ static PyMethodDef FutureIter_methods[] = {
{NULL, NULL} /* Sentinel */
};
+static PyObject *
+FutureIter_get_fi_future(PyObject *op, void *Py_UNUSED(closure))
+{
+ futureiterobject *it = (futureiterobject*)op;
+ PyObject *fut;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ fut = it->future ? Py_NewRef(it->future) : Py_None;
+ Py_END_CRITICAL_SECTION();
+ return fut;
+}
+
+static PyGetSetDef FutureIter_getsetlist[] = {
+ {"fi_future", FutureIter_get_fi_future, NULL, NULL},
+ {NULL} /* Sentinel */
+};
+
static PyType_Slot FutureIter_slots[] = {
{Py_tp_dealloc, FutureIter_dealloc},
{Py_tp_getattro, PyObject_GenericGetAttr},
@@ -1996,6 +2012,7 @@ static PyType_Slot FutureIter_slots[] = {
{Py_tp_iter, PyObject_SelfIter},
{Py_tp_iternext, FutureIter_iternext},
{Py_tp_methods, FutureIter_methods},
+ {Py_tp_getset, FutureIter_getsetlist},
// async methods
{Py_am_send, FutureIter_am_send},
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]