diff --git a/docs/changelog/2493.bugfix.rst b/docs/changelog/2493.bugfix.rst new file mode 100644 index 000000000..1ac87c85a --- /dev/null +++ b/docs/changelog/2493.bugfix.rst @@ -0,0 +1,3 @@ +When no discovery plugins are found, the application would crash with a StopIteration. +This change catches the StopIteration and raises a RuntimeError with a more informative message. +Contributed by :user:`esafak`. diff --git a/src/virtualenv/run/plugin/discovery.py b/src/virtualenv/run/plugin/discovery.py index a963042d0..5e8b2392f 100644 --- a/src/virtualenv/run/plugin/discovery.py +++ b/src/virtualenv/run/plugin/discovery.py @@ -16,10 +16,15 @@ def get_discover(parser, args): choices = _get_default_discovery(discover_types) # prefer the builtin if present, otherwise fallback to first defined type choices = sorted(choices, key=lambda a: 0 if a == "builtin" else 1) + try: + default_discovery = next(iter(choices)) + except StopIteration as e: + msg = "No discovery plugin found. Try reinstalling virtualenv to fix this issue." + raise RuntimeError(msg) from e discovery_parser.add_argument( "--discovery", choices=choices, - default=next(iter(choices)), + default=default_discovery, required=False, help="interpreter discovery method", ) diff --git a/tests/unit/config/test___main__.py b/tests/unit/config/test___main__.py index b7c1850c5..0bd2569d6 100644 --- a/tests/unit/config/test___main__.py +++ b/tests/unit/config/test___main__.py @@ -52,6 +52,16 @@ def test_fail_no_traceback(raise_on_session_done, tmp_path, capsys): assert err == "err\n" +def test_discovery_fails_no_discovery_plugin(mocker, tmp_path, capsys): + mocker.patch("virtualenv.run.plugin.discovery.Discovery.entry_points_for", return_value={}) + with pytest.raises(SystemExit) as context: + run_with_catch([str(tmp_path)]) + assert context.value.code == 1 + out, err = capsys.readouterr() + assert "RuntimeError: No discovery plugin found. Try reinstalling virtualenv to fix this issue." in out + assert not err + + def test_fail_with_traceback(raise_on_session_done, tmp_path, capsys): raise_on_session_done(TypeError("something bad"))