gh-79940: add introspection API for asynchronous generators to inspect module (#11590)

This commit is contained in:
Thomas Krennwallner 2023-03-11 08:19:40 -05:00 committed by GitHub
parent aa0a73d1bc
commit ced13c96a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 199 additions and 2 deletions

View file

@ -1,3 +1,4 @@
import asyncio
import builtins
import collections
import datetime
@ -65,6 +66,10 @@ def revise(filename, *args):
git = mod.StupidGit()
def tearDownModule():
asyncio.set_event_loop_policy(None)
def signatures_with_lexicographic_keyword_only_parameters():
"""
Yields a whole bunch of functions with only keyword-only parameters,
@ -2321,6 +2326,108 @@ class TestGetCoroutineState(unittest.TestCase):
{'a': None, 'gencoro': gencoro, 'b': 'spam'})
class TestGetAsyncGenState(unittest.IsolatedAsyncioTestCase):
def setUp(self):
async def number_asyncgen():
for number in range(5):
yield number
self.asyncgen = number_asyncgen()
async def asyncTearDown(self):
await self.asyncgen.aclose()
def _asyncgenstate(self):
return inspect.getasyncgenstate(self.asyncgen)
def test_created(self):
self.assertEqual(self._asyncgenstate(), inspect.AGEN_CREATED)
async def test_suspended(self):
value = await anext(self.asyncgen)
self.assertEqual(self._asyncgenstate(), inspect.AGEN_SUSPENDED)
self.assertEqual(value, 0)
async def test_closed_after_exhaustion(self):
countdown = 7
with self.assertRaises(StopAsyncIteration):
while countdown := countdown - 1:
await anext(self.asyncgen)
self.assertEqual(countdown, 1)
self.assertEqual(self._asyncgenstate(), inspect.AGEN_CLOSED)
async def test_closed_after_immediate_exception(self):
with self.assertRaises(RuntimeError):
await self.asyncgen.athrow(RuntimeError)
self.assertEqual(self._asyncgenstate(), inspect.AGEN_CLOSED)
async def test_running(self):
async def running_check_asyncgen():
for number in range(5):
self.assertEqual(self._asyncgenstate(), inspect.AGEN_RUNNING)
yield number
self.assertEqual(self._asyncgenstate(), inspect.AGEN_RUNNING)
self.asyncgen = running_check_asyncgen()
# Running up to the first yield
await anext(self.asyncgen)
self.assertEqual(self._asyncgenstate(), inspect.AGEN_SUSPENDED)
# Running after the first yield
await anext(self.asyncgen)
self.assertEqual(self._asyncgenstate(), inspect.AGEN_SUSPENDED)
def test_easy_debugging(self):
# repr() and str() of a asyncgen state should contain the state name
names = 'AGEN_CREATED AGEN_RUNNING AGEN_SUSPENDED AGEN_CLOSED'.split()
for name in names:
state = getattr(inspect, name)
self.assertIn(name, repr(state))
self.assertIn(name, str(state))
async def test_getasyncgenlocals(self):
async def each(lst, a=None):
b=(1, 2, 3)
for v in lst:
if v == 3:
c = 12
yield v
numbers = each([1, 2, 3])
self.assertEqual(inspect.getasyncgenlocals(numbers),
{'a': None, 'lst': [1, 2, 3]})
await anext(numbers)
self.assertEqual(inspect.getasyncgenlocals(numbers),
{'a': None, 'lst': [1, 2, 3], 'v': 1,
'b': (1, 2, 3)})
await anext(numbers)
self.assertEqual(inspect.getasyncgenlocals(numbers),
{'a': None, 'lst': [1, 2, 3], 'v': 2,
'b': (1, 2, 3)})
await anext(numbers)
self.assertEqual(inspect.getasyncgenlocals(numbers),
{'a': None, 'lst': [1, 2, 3], 'v': 3,
'b': (1, 2, 3), 'c': 12})
with self.assertRaises(StopAsyncIteration):
await anext(numbers)
self.assertEqual(inspect.getasyncgenlocals(numbers), {})
async def test_getasyncgenlocals_empty(self):
async def yield_one():
yield 1
one = yield_one()
self.assertEqual(inspect.getasyncgenlocals(one), {})
await anext(one)
self.assertEqual(inspect.getasyncgenlocals(one), {})
with self.assertRaises(StopAsyncIteration):
await anext(one)
self.assertEqual(inspect.getasyncgenlocals(one), {})
def test_getasyncgenlocals_error(self):
self.assertRaises(TypeError, inspect.getasyncgenlocals, 1)
self.assertRaises(TypeError, inspect.getasyncgenlocals, lambda x: True)
self.assertRaises(TypeError, inspect.getasyncgenlocals, set)
self.assertRaises(TypeError, inspect.getasyncgenlocals, (2,3))
class MySignature(inspect.Signature):
# Top-level to make it picklable;
# used in test_signature_object_pickle