Skip to content

tests: failure caused exceptions groups in test_webbrowser #5929

@amurzeau

Description

@amurzeau

Checklist

Streamlink version

streamlink 6.7.2

Description

While updating the Streamlink Debian package for Debian Stable, I got tests failure in tests/webbrowser/test_webbrowser.py.

The failure is from the exception group handling.

This code exception an exception like KeyboardInterrupt but what is raised is an BaseExceptionGroup with a single exception, the KeyboardInterrupt exception for example.

with pytest.raises(exception):  # noqa: PT012
    async with webbrowser_launch() as (_nursery, process):
        assert process.poll() is None, "process is still running"
        raise exception()

I'm not sure where to fix this (in tests only or in the code that cause the BaseExceptionGroup to be raised), but wrapping with catch(...) calls with this fix the tests:

        try:
            with catch(...):
                [...]
        # Unwrap single exception as done in more recent versions of python/exceptiongroup
        except BaseExceptionGroup as exc:
            if len(exc.exceptions) == 1:
                raise exc.exceptions[0]
            raise exc

The cause is that Debian Stable has exceptiongroup v1.1.0 which doesn't do this unwraping.
Installing exceptiongroup v1.2.0 using pip fixes the tests.

This was implemented in exceptiongroup from this commit: agronholm/exceptiongroup@821d5eb

I don't know if you really want to handle this case, but I'm interrested to know where it is best to handle this unwrapping ?

  • In any code using with catch(...)
  • In tests only so they don't fail

Thanks!

Debug log

============================= test session starts ==============================
platform linux -- Python 3.11.2, pytest-7.2.1, pluggy-1.0.0+repack
cachedir: /workspaces/streamlink-debian/.pytest_cache
rootdir: /workspaces/streamlink-debian/.pybuild/cpython3_3.11/build, configfile: ../../../pyproject.toml, testpaths: build_backend, tests
plugins: requests-mock-1.9.3, asyncio-0.20.3, trio-0.8.0
asyncio: mode=Mode.STRICT
collected 6887 items

tests/testutils/test_handshake.py ......                                 [  0%]
tests/utils/test_args.py ............................................... [  0%]
.....................                                                    [  1%]
tests/utils/test_cache.py .                                              [  1%]
tests/utils/test_crypto.py ..                                            [  1%]
tests/utils/test_data.py ......                                          [  1%]
tests/utils/test_formatter.py ...                                        [  1%]
tests/utils/test_l10n.py ............................................... [  2%]
.                                                                        [  2%]
tests/utils/test_module.py ...                                           [  2%]
tests/utils/test_named_pipe.py .......ssssss                             [  2%]
tests/utils/test_parse.py .......................                        [  2%]
tests/utils/test_path.py ...........                                     [  2%]
tests/utils/test_processoutput.py ........                               [  3%]
tests/utils/test_random.py .........                                     [  3%]
tests/utils/test_times.py .............................................. [  3%]
........................................................................ [  5%]
.........................................                                [  5%]
tests/utils/test_url.py ...................                              [  5%]
tests/session/test_http.py ............................                  [  6%]
tests/session/test_options.py ............................               [  6%]
tests/session/test_plugins.py ........................                   [  7%]
tests/session/test_session.py .............                              [  7%]
tests/test_api_validate.py ............................................. [  8%]
........................................................................ [  9%]
........................................................................ [ 10%]
...........                                                              [ 10%]
tests/test_api_websocket.py ..................                           [ 10%]
tests/test_buffers.py .................                                  [ 11%]
tests/test_cache.py .....................                                [ 11%]
tests/test_compat.py ......                                              [ 11%]
tests/test_logger.py ........................................            [ 12%]
tests/test_options.py ........................                           [ 12%]
tests/test_plugin.py ................................................... [ 13%]
..                                                                       [ 13%]
tests/test_plugin_userinput.py ....                                      [ 13%]
tests/test_streamlink_api.py .....                                       [ 13%]
tests/webbrowser/test_chromium.py ..................                     [ 13%]
tests/webbrowser/test_webbrowser.py ........FF...                        [ 14%]
tests/webbrowser/cdp/test_client.py .................................... [ 14%]
..........                                                               [ 14%]
tests/webbrowser/cdp/test_connection.py ..........................       [ 15%]
tests/stream/test_ffmpegmux.py ......................................... [ 15%]
                                                                         [ 15%]
tests/stream/test_file.py ..                                             [ 15%]
tests/stream/test_segmented.py .                                         [ 15%]
tests/stream/test_stream_json.py ........                                [ 16%]
tests/stream/test_stream_to_url.py ........                              [ 16%]
tests/stream/test_stream_wrappers.py .                                   [ 16%]
tests/stream/dash/test_dash.py ...........................               [ 16%]
tests/stream/dash/test_manifest.py ..................................... [ 17%]
....                                                                     [ 17%]
tests/stream/hls/test_hls.py ........................................... [ 17%]
.........                                                                [ 18%]
tests/stream/hls/test_hls_filtered.py ......                             [ 18%]
tests/stream/hls/test_m3u8.py .......................................... [ 18%]
........................                                                 [ 19%]
tests/test_plugins.py .................................................. [ 19%]
........................................................................ [ 21%]
........................................................................ [ 22%]
........................................................................ [ 23%]
........................................................................ [ 24%]
........................................................................ [ 25%]
........................................................................ [ 26%]
........................................................................ [ 27%]
........................................................................ [ 29%]
........................................................................ [ 30%]
........................................................................ [ 31%]
........................................................................ [ 32%]
........................................................................ [ 33%]
........................................................................ [ 34%]
........................................................................ [ 35%]
........................................................................ [ 37%]
........................................................................ [ 38%]
........................................................................ [ 39%]
........................................................................ [ 40%]
........................................................................ [ 41%]
........................................................................ [ 42%]
........................................................................ [ 43%]
........................................................................ [ 44%]
........................................................................ [ 46%]
........................................................................ [ 47%]
........................................................................ [ 48%]
........................................................................ [ 49%]
........................................................................ [ 50%]
........................................................................ [ 51%]
........................................................................ [ 52%]
..........................................................               [ 53%]
tests/plugins/test_abematv.py ..................                         [ 54%]
tests/plugins/test_adultswim.py ............                             [ 54%]
tests/plugins/test_afreeca.py ...............                            [ 54%]
tests/plugins/test_albavision.py ....................................... [ 55%]
.........                                                                [ 55%]
tests/plugins/test_aloula.py ...........................                 [ 55%]
tests/plugins/test_app17.py .........                                    [ 55%]
tests/plugins/test_ard_live.py .........                                 [ 56%]
tests/plugins/test_ard_mediathek.py ..................                   [ 56%]
tests/plugins/test_artetv.py ..............................              [ 56%]
tests/plugins/test_atpchallenger.py .........                            [ 56%]
tests/plugins/test_atresplayer.py ..............                         [ 57%]
tests/plugins/test_bbciplayer.py ..........                              [ 57%]
tests/plugins/test_bfmtv.py ...................                          [ 57%]
tests/plugins/test_bigo.py .......                                       [ 57%]
tests/plugins/test_bilibili.py ........                                  [ 57%]
tests/plugins/test_blazetv.py ...............                            [ 58%]
tests/plugins/test_bloomberg.py ..................                       [ 58%]
tests/plugins/test_booyah.py ..........................                  [ 58%]
tests/plugins/test_brightcove.py ........                                [ 58%]
tests/plugins/test_btv.py .........                                      [ 59%]
tests/plugins/test_cbsnews.py ....................                       [ 59%]
tests/plugins/test_cdnbg.py ................................             [ 59%]
tests/plugins/test_ceskatelevize.py ...................                  [ 60%]
tests/plugins/test_cinergroup.py .................                       [ 60%]
tests/plugins/test_clubbingtv.py ..........                              [ 60%]
tests/plugins/test_cmmedia.py ................                           [ 60%]
tests/plugins/test_cnews.py ..........                                   [ 60%]
tests/plugins/test_crunchyroll.py .................................      [ 61%]
tests/plugins/test_dailymotion.py .............                          [ 61%]
tests/plugins/test_dash.py ............................................. [ 62%]
..........................                                               [ 62%]
tests/plugins/test_delfi.py ...........                                  [ 62%]
tests/plugins/test_deutschewelle.py ...............                      [ 63%]
tests/plugins/test_dlive.py ......................                       [ 63%]
tests/plugins/test_dogan.py .........................                    [ 63%]
tests/plugins/test_dogus.py ..............                               [ 64%]
tests/plugins/test_drdk.py ............                                  [ 64%]
tests/plugins/test_earthcam.py ........                                  [ 64%]
tests/plugins/test_euronews.py .....................                     [ 64%]
tests/plugins/test_facebook.py ............                              [ 65%]
tests/plugins/test_filmon.py ..........................................  [ 65%]
tests/plugins/test_galatasaraytv.py ..........                           [ 65%]
tests/plugins/test_goltelevision.py ..............                       [ 66%]
tests/plugins/test_goodgame.py .................................         [ 66%]
tests/plugins/test_googledrive.py .......                                [ 66%]
tests/plugins/test_gulli.py .................                            [ 66%]
tests/plugins/test_hiplayer.py ........                                  [ 67%]
tests/plugins/test_hls.py .............................................. [ 67%]
................................................                         [ 68%]
tests/plugins/test_http.py .......................                       [ 68%]
tests/plugins/test_htv.py ........................                       [ 69%]
tests/plugins/test_huajiao.py ........                                   [ 69%]
tests/plugins/test_huya.py .........                                     [ 69%]
tests/plugins/test_idf1.py ............                                  [ 69%]
tests/plugins/test_indihometv.py .........                               [ 69%]
tests/plugins/test_invintus.py ...........                               [ 70%]
tests/plugins/test_kugou.py ............                                 [ 70%]
tests/plugins/test_linelive.py ...........                               [ 70%]
tests/plugins/test_livestream.py .............................           [ 70%]
tests/plugins/test_lnk.py ...............                                [ 71%]
tests/plugins/test_lrt.py ..............                                 [ 71%]
tests/plugins/test_ltv_lsm_lv.py .................                       [ 71%]
tests/plugins/test_mangomolo.py ............                             [ 71%]
tests/plugins/test_mdstrm.py ...............                             [ 72%]
tests/plugins/test_mediaklikk.py ..................                      [ 72%]
tests/plugins/test_mediavitrina.py ..................................... [ 72%]
..                                                                       [ 72%]
tests/plugins/test_mildom.py ..........                                  [ 73%]
tests/plugins/test_mitele.py ................                            [ 73%]
tests/plugins/test_mixcloud.py ....................                      [ 73%]
tests/plugins/test_mjunoon.py ...........                                [ 73%]
tests/plugins/test_mrtmk.py ...........                                  [ 74%]
tests/plugins/test_n13tv.py ..................                           [ 74%]
tests/plugins/test_nasaplus.py ........                                  [ 74%]
tests/plugins/test_nhkworld.py .......                                   [ 74%]
tests/plugins/test_nicolive.py ..............                            [ 74%]
tests/plugins/test_nimotv.py ...........                                 [ 74%]
tests/plugins/test_nos.py ................                               [ 75%]
tests/plugins/test_nownews.py ............                               [ 75%]
tests/plugins/test_nowtvtr.py ...........                                [ 75%]
tests/plugins/test_nrk.py ...................                            [ 75%]
tests/plugins/test_okru.py .............                                 [ 76%]
tests/plugins/test_olympicchannel.py ..................                  [ 76%]
tests/plugins/test_oneplusone.py ...............                         [ 76%]
tests/plugins/test_onetv.py .....................                        [ 76%]
tests/plugins/test_openrectv.py .........                                [ 77%]
tests/plugins/test_pandalive.py ........                                 [ 77%]
tests/plugins/test_piaulizaportal.py ............                        [ 77%]
tests/plugins/test_picarto.py ................                           [ 77%]
tests/plugins/test_piczel.py ..........                                  [ 77%]
tests/plugins/test_pixiv.py .........                                    [ 77%]
tests/plugins/test_pluto.py ............................................ [ 78%]
..........                                                               [ 78%]
tests/plugins/test_pluzz.py .................                            [ 79%]
tests/plugins/test_radiko.py ............                                [ 79%]
tests/plugins/test_radionet.py ..................                        [ 79%]
tests/plugins/test_raiplay.py ................                           [ 79%]
tests/plugins/test_reuters.py ............                               [ 79%]
tests/plugins/test_rtpa.py ........                                      [ 80%]
tests/plugins/test_rtpplay.py ..................                         [ 80%]
tests/plugins/test_rtve.py ..................                            [ 80%]
tests/plugins/test_rtvs.py ................                              [ 80%]
tests/plugins/test_ruv.py ....................                           [ 81%]
tests/plugins/test_sbscokr.py ..............                             [ 81%]
tests/plugins/test_showroom.py ............                              [ 81%]
tests/plugins/test_sportal.py .........                                  [ 81%]
tests/plugins/test_sportschau.py ........                                [ 81%]
tests/plugins/test_ssh101.py ...........                                 [ 82%]
tests/plugins/test_stadium.py ...........                                [ 82%]
tests/plugins/test_steam.py .............                                [ 82%]
tests/plugins/test_streamable.py .......                                 [ 82%]
tests/plugins/test_streann.py ................                           [ 82%]
tests/plugins/test_stv.py ........                                       [ 82%]
tests/plugins/test_svtplay.py .................                          [ 83%]
tests/plugins/test_swisstxt.py ..................                        [ 83%]
tests/plugins/test_telefe.py ..............                              [ 83%]
tests/plugins/test_telemadrid.py .........                               [ 83%]
tests/plugins/test_tf1.py ............................                   [ 84%]
tests/plugins/test_trovo.py ..............................               [ 84%]
tests/plugins/test_turkuvaz.py ................................          [ 85%]
tests/plugins/test_tv360.py .......                                      [ 85%]
tests/plugins/test_tv3cat.py .........................                   [ 85%]
tests/plugins/test_tv4play.py ..........                                 [ 85%]
tests/plugins/test_tv5monde.py .............                             [ 86%]
tests/plugins/test_tv8.py .......                                        [ 86%]
tests/plugins/test_tv999.py ............                                 [ 86%]
tests/plugins/test_tvibo.py .........                                    [ 86%]
tests/plugins/test_tviplayer.py ..........                               [ 86%]
tests/plugins/test_tvp.py .....................................          [ 87%]
tests/plugins/test_tvrby.py ............                                 [ 87%]
tests/plugins/test_tvrplus.py ...............                            [ 87%]
tests/plugins/test_tvtoya.py ..............                              [ 87%]
tests/plugins/test_twitcasting.py .......                                [ 88%]
tests/plugins/test_twitch.py ........................................... [ 88%]
............                                                             [ 88%]
tests/plugins/test_ustreamtv.py ...........................              [ 89%]
tests/plugins/test_ustvnow.py .........                                  [ 89%]
tests/plugins/test_vidio.py ..........                                   [ 89%]
tests/plugins/test_vimeo.py ..........................                   [ 90%]
tests/plugins/test_vinhlongtv.py ...........                             [ 90%]
tests/plugins/test_vk.py ..............................                  [ 90%]
tests/plugins/test_vkplay.py ...........                                 [ 90%]
tests/plugins/test_vtvgo.py ..................                           [ 91%]
tests/plugins/test_webtv.py .................                            [ 91%]
tests/plugins/test_welt.py ...........                                   [ 91%]
tests/plugins/test_wwenetwork.py ..........                              [ 91%]
tests/plugins/test_youtube.py .......................................... [ 92%]
.................                                                        [ 92%]
tests/plugins/test_yupptv.py ........                                    [ 92%]
tests/plugins/test_zattoo.py ......................................      [ 93%]
tests/plugins/test_zdf_mediathek.py .................                    [ 93%]
tests/plugins/test_zeenews.py ........                                   [ 93%]
tests/plugins/test_zengatv.py ............                               [ 94%]
tests/plugins/test_zhanqi.py .......                                     [ 94%]
tests/cli/test_argparser.py ...............................              [ 94%]
tests/cli/test_cmdline.py ....                                           [ 94%]
tests/cli/test_cmdline_title.py ....sssss                                [ 94%]
tests/cli/test_console.py ..............                                 [ 95%]
tests/cli/test_main.py .......................                           [ 95%]
tests/cli/test_main_check_file_output.py ......                          [ 95%]
tests/cli/test_main_formatter.py .........                               [ 95%]
tests/cli/test_main_logging.py ............................              [ 96%]
tests/cli/test_main_setup_config_args.py ............                    [ 96%]
tests/cli/test_plugin_args_and_options.py ...                            [ 96%]
tests/cli/test_streamrunner.py .....................                     [ 96%]
tests/cli/output/test_file.py ....s                                      [ 96%]
tests/cli/output/test_player.py ........s.......s.ss.....s.s............ [ 97%]
                                                                         [ 97%]
tests/cli/utils/test_formatter.py ...                                    [ 97%]
tests/cli/utils/test_path.py .................................s.s.s...s  [ 98%]
tests/cli/utils/test_player.py sssss.....                                [ 98%]
tests/cli/utils/test_progress.py ....................................... [ 98%]
......................................................s..                [ 99%]
tests/cli/utils/test_versioncheck.py ...............                     [100%]

=================================== FAILURES ===================================
____ TestLaunch.test_terminate_on_nursery_baseexception[KeyboardInterrupt] _____
  + Exception Group Traceback (most recent call last):
  |   File "/usr/lib/python3/dist-packages/trio/_core/_run.py", line 850, in __aexit__
  |     raise combined_error_from_nursery
  | trio.MultiError: BaseExceptionGroup('', [KeyboardInterrupt()])
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "/usr/lib/python3/dist-packages/pytest_trio/plugin.py", line 195, in _fixture_manager
    |     yield nursery_fixture
    |   File "/usr/lib/python3/dist-packages/pytest_trio/plugin.py", line 250, in run
    |     await self._func(**resolved_kwargs)
    |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/test_webbrowser.py", line 104, in test_terminate_on_nursery_baseexception
    |     async with webbrowser_launch() as (_nursery, process):
    |   File "/usr/lib/python3.11/contextlib.py", line 222, in __aexit__
    |     await self.gen.athrow(typ, value, traceback)
    |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/conftest.py", line 58, in webbrowser_launch
    |     async with webbrowser.launch(*args, **kwargs) as nursery:
    |   File "/usr/lib/python3.11/contextlib.py", line 222, in __aexit__
    |     await self.gen.athrow(typ, value, traceback)
    |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/streamlink/webbrowser/webbrowser.py", line 86, in launch
    |     with catch({  # type: ignore[dict-item]  # bug in exceptiongroup==1.2.0
    |   File "/usr/lib/python3/dist-packages/exceptiongroup/_catch.py", line 36, in __exit__
    |     raise unhandled from None
    | BaseExceptionGroup:  (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "/usr/lib/python3/dist-packages/exceptiongroup/_catch.py", line 52, in handle_exception
      |     handler(matched)
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/streamlink/webbrowser/webbrowser.py", line 84, in handle_baseexception
      |     raise exc_grp.exceptions[0] from exc_grp.exceptions[0].__context__
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/streamlink/webbrowser/webbrowser.py", line 106, in launch
      |     yield nursery
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/conftest.py", line 66, in webbrowser_launch
      |     yield nursery, process
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/test_webbrowser.py", line 106, in test_terminate_on_nursery_baseexception
      |     raise exception()
      | KeyboardInterrupt
      +------------------------------------
------------------------------ Captured log call -------------------------------
info     streamlink.webbrowser.webbrowser:webbrowser.py:90 Launching web browser: /usr/bin/python3.11
debug    streamlink.webbrowser.webbrowser:webbrowser.py:113 Waiting for web browser process to terminate
________ TestLaunch.test_terminate_on_nursery_baseexception[SystemExit] ________
  + Exception Group Traceback (most recent call last):
  |   File "/usr/lib/python3/dist-packages/trio/_core/_run.py", line 850, in __aexit__
  |     raise combined_error_from_nursery
  | trio.MultiError: BaseExceptionGroup('', [SystemExit()])
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "/usr/lib/python3/dist-packages/pytest_trio/plugin.py", line 195, in _fixture_manager
    |     yield nursery_fixture
    |   File "/usr/lib/python3/dist-packages/pytest_trio/plugin.py", line 250, in run
    |     await self._func(**resolved_kwargs)
    |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/test_webbrowser.py", line 104, in test_terminate_on_nursery_baseexception
    |     async with webbrowser_launch() as (_nursery, process):
    |   File "/usr/lib/python3.11/contextlib.py", line 222, in __aexit__
    |     await self.gen.athrow(typ, value, traceback)
    |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/conftest.py", line 58, in webbrowser_launch
    |     async with webbrowser.launch(*args, **kwargs) as nursery:
    |   File "/usr/lib/python3.11/contextlib.py", line 222, in __aexit__
    |     await self.gen.athrow(typ, value, traceback)
    |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/streamlink/webbrowser/webbrowser.py", line 86, in launch
    |     with catch({  # type: ignore[dict-item]  # bug in exceptiongroup==1.2.0
    |   File "/usr/lib/python3/dist-packages/exceptiongroup/_catch.py", line 36, in __exit__
    |     raise unhandled from None
    | BaseExceptionGroup:  (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "/usr/lib/python3/dist-packages/exceptiongroup/_catch.py", line 52, in handle_exception
      |     handler(matched)
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/streamlink/webbrowser/webbrowser.py", line 84, in handle_baseexception
      |     raise exc_grp.exceptions[0] from exc_grp.exceptions[0].__context__
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/streamlink/webbrowser/webbrowser.py", line 106, in launch
      |     yield nursery
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/conftest.py", line 66, in webbrowser_launch
      |     yield nursery, process
      |   File "/workspaces/streamlink-debian/.pybuild/cpython3_3.11/build/tests/webbrowser/test_webbrowser.py", line 106, in test_terminate_on_nursery_baseexception
      |     raise exception()
      | SystemExit
      +------------------------------------
------------------------------ Captured log call -------------------------------
info     streamlink.webbrowser.webbrowser:webbrowser.py:90 Launching web browser: /usr/bin/python3.11
debug    streamlink.webbrowser.webbrowser:webbrowser.py:113 Waiting for web browser process to terminate
=========================== short test summary info ============================
FAILED tests/webbrowser/test_webbrowser.py::TestLaunch::test_terminate_on_nursery_baseexception[KeyboardInterrupt]
FAILED tests/webbrowser/test_webbrowser.py::TestLaunch::test_terminate_on_nursery_baseexception[SystemExit]
================== 2 failed, 6309 passed, 28 skipped in 9.84s ==================

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions