diff --git a/src/click/parser.py b/src/click/parser.py index 1ea1f7166e..45486d3dd8 100644 --- a/src/click/parser.py +++ b/src/click/parser.py @@ -490,6 +490,19 @@ def _process_opts(self, arg: str, state: _ParsingState) -> None: # short option code and will instead raise the no option # error. if arg[:2] not in self._opt_prefixes: + multichar_opt = max( + ( + opt + for opt in self._long_opt + if _split_opt(opt)[0] == arg[:1] and arg.startswith(opt) + ), + default=None, + key=len, + ) + + if multichar_opt is not None and multichar_opt != arg: + raise NoSuchOption(multichar_opt, ctx=self.ctx) + self._match_short_opt(arg, state) return diff --git a/tests/test_options.py b/tests/test_options.py index f198d10183..9e28b3c8d6 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -144,6 +144,17 @@ def cli(): assert f"No such option: {unknown_flag}" in result.output +def test_unknown_multichar_short_option_reports_full_option(runner): + @click.command() + @click.option("-dbg", is_flag=True) + def cli(dbg): + pass + + result = runner.invoke(cli, ["-dbgwrong"]) + assert result.exception + assert "No such option: -dbg" in result.output + + @pytest.mark.parametrize( ("value", "expect"), [