Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

asyncio.run unnecessarily calls the repr of the task result twice since Python 3.11 #112559

Closed
Labels
3.11only security fixes3.12only security fixes3.13bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error
@yilei

Description

@yilei

Bug report

Bug description:

Given the following code:

importasyncioimporttimeclassFoo:def__repr__(self):time.sleep(1)print('i am a repr, i should not be called. ')return'<Foo>'asyncdefget_foo():returnFoo()asyncio.run(get_foo())print('Done')

Output:

$ python t.pyi am a repr, i should not be called.i am a repr, i should not be called.Done

This was caused by the new SIGINT handler installed by asyncio.run here:f08a191

Upon investigation, changing the code with:

importasyncioimporttimeclassFoo:def__repr__(self):time.sleep(1)print('i am a repr, i should not be called. ')raiseBaseException('where is this called???????')return'<Foo>'asyncdefget_foo():returnFoo()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:

  1. signal.getsignal tries to convert the handler function to enum in case this is part of Handlers:
    returnenum_klass(value)
  2. enum raises a ValueError with the repr of the handler function:
    ve_exc=ValueError("%r is not a valid %s"% (value,cls.__qualname__))
  3. the handler asyncio.run installs uses a functools.partial, it's repr will include the repr of the task:
    sigint_handler=functools.partial(self._on_sigint,main_task=task)
  4. when the repr is actually called at the end (one insignal.getsignal, the other insignal.signal), the repr of the asyncio task will include the repr of the result:
    andsignal.getsignal(signal.SIGINT)issigint_handler
    ):
    signal.signal(signal.SIGINT,signal.default_int_handler)

While one can argument calling__repr__ shouldn't cause issues, but Ithink we could avoid them in thesignal._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.    """ifnotisinstance(value,int):returnvaluetry:returnenum_klass(value)exceptValueError:returnvalue

This 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

No one assigned

    Labels

    3.11only security fixes3.12only security fixes3.13bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp