Thanks to visit codestin.com
Credit goes to github.com

Skip to content

GeneratorExit and asyncio.TaskGroup - missing from _is_base_error? #135736

Open
@ghuser1234523

Description

@ghuser1234523

Bug report

Bug description:

Consider the following code:

import asyncio
  
async def TestGen():
	yield 1
	
async def TestFn():
	async with asyncio.TaskGroup() as tg:
		async for n in TestGen():
			yield n
			
async def Run():
	g = TestFn()
	await g.asend( None )
	await g.aclose()
	
asyncio.run( Run() )

which unexpectedly yields the following output:

  + Exception Group Traceback (most recent call last):
  |   File "<python-input-7>", line 16, in <module>
  |     asyncio.run( Run() )
  |     ~~~~~~~~~~~^^^^^^^^^
  |   File "/usr/lib/python3.13/asyncio/runners.py", line 195, in run
  |     return runner.run(main)
  |            ~~~~~~~~~~^^^^^^
  |   File "/usr/lib/python3.13/asyncio/runners.py", line 118, in run
  |     return self._loop.run_until_complete(task)
  |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  |   File "/usr/lib/python3.13/asyncio/base_events.py", line 719, in run_until_complete
  |     return future.result()
  |            ~~~~~~~~~~~~~^^
  |   File "<python-input-7>", line 14, in Run
  |     await g.aclose()
  |   File "<python-input-7>", line 7, in TestFn
  |     async with asyncio.TaskGroup() as tg:
  |                ~~~~~~~~~~~~~~~~~^^
  |   File "/usr/lib/python3.13/asyncio/taskgroups.py", line 71, in __aexit__
  |     return await self._aexit(et, exc)
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "/usr/lib/python3.13/asyncio/taskgroups.py", line 173, in _aexit
  |     raise BaseExceptionGroup(
  |     ...<2 lines>...
  |     ) from None
  | BaseExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "<python-input-7>", line 9, in TestFn
    |     yield n
    | GeneratorExit
    +------------------------------------

Expectation: no "unhandled errors in a TaskGroup" error.

Quick look through taskgroups.py reveals that GeneratorExit might be missing from _is_base_error() method:

    # Since Python 3.8 Tasks propagate all exceptions correctly,
    # except for KeyboardInterrupt and SystemExit which are
    # still considered special.

    def _is_base_error(self, exc: BaseException) -> bool:
        assert isinstance(exc, BaseException)
        return isinstance(exc, (SystemExit, KeyboardInterrupt))

Adding GeneratorExit to _is_base_error seems to solve issue:

import asyncio

class TaskGroupWithGeneratorExit(asyncio.TaskGroup):
	def _is_base_error(self, exc: BaseException) -> bool:
		if super()._is_base_error( exc ):
			return True
		return isinstance(exc, GeneratorExit)
  
async def TestGen():
	yield 1
	
async def TestFn():
	async with TaskGroupWithGeneratorExit() as tg:
		async for n in TestGen():
			yield n
			
async def Run():
	g = TestFn()
	await g.asend( None )
	await g.aclose()
	
asyncio.run( Run() )

The above yields no output, as expected.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibPython modules in the Lib dirtopic-asynciotype-bugAn unexpected behavior, bug, or error

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions