Skip to content

Increase coverage#1690

Open
svlandeg wants to merge 63 commits into
fastapi:drop-clickfrom
svlandeg:feat/vendor_part4
Open

Increase coverage#1690
svlandeg wants to merge 63 commits into
fastapi:drop-clickfrom
svlandeg:feat/vendor_part4

Conversation

@svlandeg
Copy link
Copy Markdown
Member

@svlandeg svlandeg commented Apr 13, 2026

Continue work from #1525, #1601 and #1680, vendoring Click.

After the prep work from previous PRs, this PR contains a lot of work to finish the refactor:

  • Removing stuff we don't need in Typer
  • Writing unit tests for things we do need/document but weren't thoroughly tested in Typer's test suite yet
  • Adjusting the vendored code to adhere to Typer's code style
  • Adding colorama as dependency for Windows. It's in fact already pulled in by pytest anyway, but I figured explicit is better.

It's big to review, but all edits should be relatively local, so the diff can be reviewed as one (and not per-commit). No code has been moved around - it's almost all pure deletions or test additions.

Removed stuff

Sebastián: if there's anything in the list below that we do want to keep as functionality, let me know, then I'll write additional unit tests instead of removing the relevant code.

  • Remove unused code paths with UNSET (originally introduced in this PR). Typer has its own Default(...) to cover these use-cases.
  • Remove unused functionality: FLAG_NEEDS_VALUE, __debug__ statements, batch(), protected_args, Parameter.deprecated
  • Remove force_readable and force_writable as those were set to True in get_text_stdin, get_text_stdout, get_text_stderr anyway
  • _pause_echo & EchoingStdin in _click/testing.py, which wasn't used

This was all done 100% manually.

Refactored stuff

  • Make _click.Command, _click.Parameter and _click.ShellComplete abstract
  • Adapt original Click code to use Typer's code style: remove Sphinx-specific docs styling, remove from __future__ import annotations, import directly from typing and collections, remove usage of gettext, use f-strings

This was all done 100% manually.

Added tests

Added tests for:

  • _click.types.py & typer._types.py:
    • repr functions mostly added to existing type tutorial tests
    • convert functions into tests/test_type_conversion.py
    • shell_completion functionality into tests/test_completion dir (incl. several new files)
    • other bits into ‎tests/test_types.py, ‎tests/test_types_files.py (new)
  • _click._compat.py
    • _AtomicFile stuff in tests/test_atomic_file.py (new)
    • more file stuff in tests/test_types_file.py
  • _click._winconsole.py:
    • all in one file tests/test_win_console.py (new)
  • _click.termui.py and _click._termui_impl.py:
    • progressbar stuff in tests/test_progress_bar.py (new)
    • launch stuff in tests/test_launch.py
    • other bits into tests/test_termui.py (new)
  • _click.core.py and some of the new functionality in typer.core.py:
    • in tests/test_core.py (new)
  • _click.utils.py:
    • help string stuff in tests/test_cli/test_help.py
    • program name stuff in tests/test_cli/test_program_name.py (new)
    • (lazy) file stuff in tests/test_types_file.py
  • _click.testing.py:
    • make_input_stream stuff in tests/test_types_file.py
    • other stuff in tests/test_termui.py
  • _click.exceptions.py:
    • mostly in tests/test_others.py
  • _click.formatting.py & _click._textwrap.py:
    • mostly in tests/test_cli/test_help.py
  • _click.parser.py
    • mostly in tests/test_cli/test_parser.py (new)
  • _click.shell_completion.py
    • mostly in tests/test_completion/test_completion.py

This was done with AI assistance, micromanaged & thoroughly reviewed by me.

I tried to mostly use public APIs from Typer for these tests, to really showcase user functionality. When this wasn't possible, the relevant code was a candidate for deletion, cf previous section ☝️

Coverage stats

This branch, before this PR:

13538 statements, 1037 missing (92.3% coverage)

This branch, after "cleaning" the original Click files:

13195 statements, 860 missing (93.5% coverage)

This branch, after adding unit tests for missing coverage:

14663 statements, 0 missing (100% coverage)

@svlandeg svlandeg self-assigned this Apr 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 15, 2026

📝 Docs preview

Last commit e22a7e2 at: https://063fabe3.typertiangolo.pages.dev

@svlandeg svlandeg changed the title WIP: cleanup after vendoring Increase coverage Apr 15, 2026
Copy link
Copy Markdown
Member Author

@svlandeg svlandeg left a comment

Choose a reason for hiding this comment

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

Status update: I'm more or less "done", but I want to review this once more with Claude before I turn this over to Sebastián. Probably next week.

Copy link
Copy Markdown
Member Author

@svlandeg svlandeg left a comment

Choose a reason for hiding this comment

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

Reviewing this with Claude, capturing some of the most risky decisions in this PR and my reasoning around them. Would be good for @tiangolo to review these points as well.

Issue 1

The UNSETNone collapse in consume_value is the riskiest change

(this is in typer._click.core.py)

I don't actually think this is an issue. I've tried to carefully remove the UNSET logic to keep everything else the same, and Typer tests kept succeeding. Typer has its own logic using Default which should be properly tested. Nevertheless, this is good to keep in the back of our minds in case we see something funny in the future.

Issue 2

value_is_missing stub in Parameter base class: The logic that was here should be verified it's now duplicated in TyperArgument/TyperOption.

Yes, both reimplement that function and I wouldn't expect Typer users to subclass Parameter themselves?

Issue 3

Removed deprecation warning for deprecated parameters

AFAIK, Typer only supports a deprecated flag for commands, not for options/arguments. Something to consider in the future, but I don't think removing the related code in Parameter is currently breaking - it's dead code from Typer's perspective IMO.

Issue 4

check_iter simplification is a behavioral change: (the new) AssertionError is not caught by Click's error handling and will surface as an unhandled exception rather than a BadParameter (as it was previously).

This refers to this commit and I think it's a valid concern. I reverted this behaviour to raise BadParameter like it was, and wrote a unit test to avoid future regressions: 44cb483

Issue 5

Error message changes break existing tests

There are indeed a few cases where I simplified the Click error code to not use gettext, but also to not have an if/else structure to determine plural. This might change the wording of the error slightly, and might break user's tests if they're testing for specific wording. Should we revert this and reinstate the error messages verbatim?

Issue 6

Context.invoke() was simplified to only support callables; the invoke(Command, ...) overload was removed. Typer may not use this, but it was part of Click's public API and could affect users who access the underlying context object.

I think this is fine, as we'll probably want to refactor out the context in the future anyway?

Issue 7

NoArgsIsHelpError show method writes to err=True. This is a behavioral change from typical Click behavior where --help goes to stdout.

I double checked this, but I think this is a False Positive from Claude's reviewing. err=True was already present in NoArgsIsHelpError.show, as we can see from this diff. There is a new unit test test_no_args_is_help_show in test_others.py that specifically checks the output is in result.stderr. To be sure, I double checked and tested this one on master, where it also succeeds. So as far as I can see, there's no behavioural change.

Issue 8

_depr_flag_needs_value reference remains in TyperOption

Right, this looks like dead code and has now been removed.

Issue 9

Several TODO: test or remove? comments remain — these should be resolved before merging

I left those in on purpose, these could be cleaned up in future work, in an attempt for this PR to be as least breaking as possible.

Issue 10

make_str was removed — this was used in _click_resolve_command. The replacement args[0] assumes args are always strings, which is fine for CLI usage but removes bytes-path handling that existed for edge cases

I'm not super sure about this one. What type of Typer usage would this edge case be? Oh, let's ask Claude! Now it says

I can't write a meaningful unit test for this because exercising it would require bypassing the public API entirely. This means my concern about removing make_str there was unfounded — it was dead code in the Typer context, and the replacement args[0] is correct.

So actually I think this one is fine as well.

@svlandeg svlandeg marked this pull request as ready for review May 12, 2026 14:36
@svlandeg svlandeg removed their assignment May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants