-
- Notifications
You must be signed in to change notification settings - Fork 33.6k
Description
Bug report
Bug description:
Given the following code:
import asyncio import time class Foo: def __repr__(self): time.sleep(1) print('i am a repr, i should not be called. ') return '<Foo>' async def get_foo(): return Foo() asyncio.run(get_foo()) print('Done')Output:
$ python t.py i am a repr, i should not be called. i am a repr, i should not be called. DoneThis was caused by the new SIGINT handler installed by asyncio.run here: f08a191
Upon investigation, changing the code with:
import asyncio import time class Foo: def __repr__(self): time.sleep(1) print('i am a repr, i should not be called. ') raise BaseException('where is this called???????') return '<Foo>' async def get_foo(): return Foo() asyncio.run(get_foo()) print('Done')It shows:
i am a repr, i should not be called. Traceback (most recent call last): File "t.py", line 15, in <module> asyncio.run(get_foo()) File "lib/python3.12/asyncio/runners.py", line 194, in run return runner.run(main) ^^^^^^^^^^^^^^^^ File "lib/python3.12/asyncio/runners.py", line 127, in run and signal.getsignal(signal.SIGINT) is sigint_handler ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/signal.py", line 63, in getsignal return _int_to_enum(handler, Handlers) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/signal.py", line 29, in _int_to_enum return enum_klass(value) ^^^^^^^^^^^^^^^^^ File "lib/python3.12/enum.py", line 740, in __call__ return cls.__new__(cls, value) ^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/enum.py", line 1152, in __new__ ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__)) ^^^^^ File "lib/python3.12/reprlib.py", line 21, in wrapper result = user_function(self) ^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/asyncio/base_tasks.py", line 30, in _task_repr info = ' '.join(_task_repr_info(task)) ^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/asyncio/base_tasks.py", line 10, in _task_repr_info info = base_futures._future_repr_info(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/asyncio/base_futures.py", line 54, in _future_repr_info result = reprlib.repr(future._result) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/reprlib.py", line 58, in repr return self.repr1(x, self.maxlevel) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/reprlib.py", line 68, in repr1 return self.repr_instance(x, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "lib/python3.12/reprlib.py", line 170, in repr_instance s = builtins.repr(x) ^^^^^^^^^^^^^^^^ File "t.py", line 8, in __repr__ raise BaseException('where is this called???????') BaseException: where is this called??????? This looks like a series unfortunate events, running on 3.12.0:
- signal.getsignal tries to convert the handler function to enum in case this is part of Handlers:
Line 29 in 0fb18b0
return enum_klass(value) - enum raises a ValueError with the repr of the handler function:
Line 1152 in 0fb18b0
ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__)) - the handler asyncio.run installs uses a functools.partial, it's repr will include the repr of the task:
cpython/Lib/asyncio/runners.py
Line 105 in 0fb18b0
sigint_handler = functools.partial(self._on_sigint, main_task=task) - when the repr is actually called at the end (one in
signal.getsignal, the other insignal.signal), the repr of the asyncio task will include the repr of the result:cpython/Lib/asyncio/runners.py
Lines 127 to 129 in 0fb18b0
and signal.getsignal(signal.SIGINT) is sigint_handler ): signal.signal(signal.SIGINT, signal.default_int_handler)
While one can argument calling __repr__ shouldn't cause issues, but I think we could avoid them in the signal._int_to_enum function completely, by only trying to convert to enum when it's an integer:
def _int_to_enum(value, enum_klass): """Convert a numeric value to an IntEnum member. If it's not a known member, return the numeric value itself. """ if not isinstance(value, int): return value try: return enum_klass(value) except ValueError: return valueThis should be more efficient on its own anyway.
This function's doc is also inaccurate, since it also accepts non integers (usually a callable).
Am I missing something?
CPython versions tested on:
3.11, 3.12
Operating systems tested on:
Linux
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status