Skip to content

Conversation

svlandeg
Copy link
Member

@svlandeg svlandeg commented Aug 18, 2025

Follow-up of #1262

The core issue: running a CLI with the no_args_is_help feature enabled displays an error block and a duplicated "Usage" line, whenever Rich ánd Click >= 8.2.0 is used (supported since Typer 0.16.0). The error does not occur without Rich, or with an older version of Click.

To replicate, run python docs_src/commands/index/tutorial003.py and inspect the console output.

There's two aspects to consider here:

Bug fix

Ensure this duplicate print & error message is avoided. Note that we can't import NoArgsIsHelpError from Click directly because that would break compatibility with Click 8.0 and 8.1, as this new error type was only introduced in 8.2.0.

Potentially breaking behaviour

Decide on the exit code of a function call without arguments but with no_args_is_help=True. Should it be 0 (as before) or 2 (as Click is doing since pallets/click#1489)?

  • If we want the exit code to be the same for any version of Typer/Click, we can test for its value explicitely in test_tutorial003.test_no_arg. We'll then need to add a custom workaround in Typer to change the behaviour compared to what Click does.
  • If we're happy to stick with whatever Click does, we should see this as a breaking change introduced since Click 8.2. (see also this discussion). This is what the current state of the PR assumes.

@svlandeg svlandeg added the bug Something isn't working label Aug 18, 2025
@svlandeg svlandeg added the click Related to Click functionality label Aug 18, 2025
@svlandeg svlandeg self-assigned this Aug 18, 2025
@svlandeg
Copy link
Member Author

svlandeg commented Aug 18, 2025

A little bit more explanation as to why/how this happens:

At L211-220 we have this in core.py:

        except click.ClickException as e:
            if not standalone_mode:
                raise
            # Typer override
            if rich and rich_markup_mode is not None:
                rich_utils.rich_format_error(e)
            else:
                e.show()
            # Typer override end
            sys.exit(e.exit_code)

When Rich isn't used, the else structure goes to e.show() which shows the help message as before, after the changes from pallets/click#1489, where NoArgsIsHelpError.show() is calling echo(self.format_message(), ...) and thus the output looks as before.

But when Rich is used, this gets bypassed and in rich_format_error we get an additional:

  • console.print(ctx.get_usage()) -> the duplicated Usage line
  • console.print(RICH_HELP.format(...)) -> the reference to --help
  • console.print(... self.format_message() ...) -> the (empty) error message

@svlandeg svlandeg removed their assignment Aug 18, 2025
@svlandeg svlandeg marked this pull request as ready for review August 18, 2025 14:05
Copy link
Member

@tiangolo tiangolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the investigation and clean fix! 🙌 🚀

This is available in Typer 0.16.1, just released. 🎉

@tiangolo tiangolo merged commit c7d957c into fastapi:master Aug 18, 2025
24 checks passed
@svlandeg svlandeg deleted the fix/noargsishelp branch August 19, 2025 07:11
@mmakaay
Copy link

mmakaay commented Aug 21, 2025

Thanks @svlandeg
This definitely trumps my PR for fixing the issue,
and for completeness sake: works like a charm 😄👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working click Related to Click functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants