Python composable command line interface toolkit
This report summarizes scanner evidence for pallets/click, a Python project with 17,786 GitHub stars. SynthScan examined 39,988 lines of code across 157 source files, recording 619 pattern matches distributed across 16 syntactic categories. The legacy adjusted pattern signal is 16.9 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 468 finding(s).
Are imports declared and package/API names verified? 93 finding(s).
Are wrappers, guards, and repeated structures necessary? 489 finding(s).
Which changes need focused human review? 619 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 619 distinct pattern matches across 16 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_parser.py | 22 | def test_parser_default_prefixes(): | CODE |
| LOW | tests/test_parser.py | 27 | def test_parser_collects_prefixes(): | CODE |
| LOW | tests/test_shell_completion.py | 79 | def test_group_command_same_option(): | CODE |
| LOW | tests/test_shell_completion.py | 153 | def test_choice_special_characters(): | CODE |
| LOW | tests/test_shell_completion.py | 160 | def test_choice_conflicting_prefix(): | CODE |
| LOW | tests/test_shell_completion.py | 227 | def test_flag_option_with_nargs_option(): | CODE |
| LOW | tests/test_shell_completion.py | 336 | def test_completion_item_data(): | CODE |
| LOW | tests/test_shell_completion.py | 357 | def test_full_source_powershell(runner): | CODE |
| LOW | tests/test_shell_completion.py | 394 | def test_source_uses_lf_line_endings(monkeypatch): | CODE |
| LOW | tests/test_shell_completion.py | 459 | def test_zsh_full_complete_with_colons( | CODE |
| LOW⚡ | tests/test_shell_completion.py | 497 | def test_choice_case_sensitive(value, expect): | CODE |
| LOW⚡ | tests/test_shell_completion.py | 507 | def _restore_available_shells(tmpdir): | CODE |
| LOW⚡ | tests/test_shell_completion.py | 516 | def test_add_completion_class(): | CODE |
| LOW | tests/test_shell_completion.py | 536 | def test_add_completion_class_with_name(): | CODE |
| LOW | tests/test_shell_completion.py | 562 | def test_add_completion_class_decorator(): | CODE |
| LOW | tests/test_shell_completion.py | 599 | def test_fish_format_completion_escapes_help(): | CODE |
| LOW | tests/test_shell_completion.py | 607 | def test_powershell_format_completion_escapes_help(): | CODE |
| LOW | tests/test_basic.py | 73 | def test_param_squatting_help_option_name(runner): | CODE |
| LOW | tests/test_basic.py | 90 | def test_option_reusing_help_flag(runner): | CODE |
| LOW | tests/test_basic.py | 395 | def test_flag_value_dual_options(runner, default, args, expected): | CODE |
| LOW | tests/test_basic.py | 565 | def test_choice_argument_enum(runner): | CODE |
| LOW | tests/test_basic.py | 592 | def test_choice_argument_custom_type(runner): | CODE |
| LOW | tests/test_basic.py | 623 | def test_choice_argument_none(runner): | CODE |
| LOW | tests/test_basic.py | 651 | def test_choice_argument_optional_metavar(runner): | CODE |
| LOW | tests/test_basic.py | 678 | def test_datetime_argument_optional_metavar(runner): | CODE |
| LOW | tests/test_basic.py | 691 | def test_datetime_option_default(runner): | CODE |
| LOW | tests/test_basic.py | 718 | def test_datetime_option_custom(runner): | CODE |
| LOW | tests/test_basic.py | 846 | def test_help_invalid_default(runner): | CODE |
| LOW | tests/test_basic.py | 863 | def test_version_option_resolves_import_name_to_distribution(runner, monkeypatch): | CODE |
| LOW | tests/test_basic.py | 893 | def test_version_option_ambiguous_import_name_errors(runner, monkeypatch): | CODE |
| LOW | tests/test_basic.py | 922 | def test_version_option_unknown_package_errors(runner, monkeypatch): | CODE |
| LOW | tests/test_basic.py | 943 | def test_custom_version_option(runner, args): | CODE |
| LOW | tests/test_basic.py | 954 | def test_custom_version_option_receives_context(runner): | CODE |
| LOW⚡ | tests/test_termui.py | 230 | def test_progressbar_init_exceptions(runner): | CODE |
| LOW⚡ | tests/test_termui.py | 235 | def test_progressbar_iter_outside_with_exceptions(runner): | CODE |
| LOW⚡ | tests/test_termui.py | 242 | def test_progressbar_is_iterator(runner, monkeypatch): | CODE |
| LOW⚡ | tests/test_termui.py | 597 | def test_editor_env_passed_through(): | CODE |
| LOW⚡ | tests/test_termui.py | 607 | def test_editor_failure_exception(): | CODE |
| LOW⚡ | tests/test_termui.py | 614 | def test_editor_nonexistent_exception(): | CODE |
| LOW | tests/test_termui.py | 44 | def test_progressbar_strip_regression(runner, monkeypatch): | CODE |
| LOW | tests/test_termui.py | 60 | def test_progressbar_length_hint(runner, monkeypatch): | CODE |
| LOW | tests/test_termui.py | 101 | def test_progressbar_hidden_manual(runner, monkeypatch): | CODE |
| LOW | tests/test_termui.py | 114 | def test_progressbar_lands_on_final_position(monkeypatch, update_min_steps, drive): | CODE |
| LOW | tests/test_termui.py | 144 | def test_progressbar_time_per_iteration(runner, avg, expected): | CODE |
| LOW | tests/test_termui.py | 167 | def test_progressbar_format_eta(runner, eta, expected): | CODE |
| LOW | tests/test_termui.py | 173 | def test_progressbar_format_pos(runner, pos, length): | CODE |
| LOW | tests/test_termui.py | 186 | def test_progressbar_format_bar(runner, length, finished, pos, avg, expected): | CODE |
| LOW | tests/test_termui.py | 203 | def test_progressbar_format_progress_line( | CODE |
| LOW | tests/test_termui.py | 217 | def test_progressbar_format_progress_line_with_show_func(runner, test_item): | CODE |
| LOW | tests/test_termui.py | 257 | def test_choices_list_in_prompt(runner, monkeypatch): | CODE |
| LOW | tests/test_termui.py | 285 | def test_file_prompt_default_format(runner, file_kwargs): | CODE |
| LOW | tests/test_termui.py | 313 | def test_progressbar_yields_all_items(runner): | CODE |
| LOW | tests/test_termui.py | 341 | def test_progressbar_item_show_func(runner, monkeypatch): | CODE |
| LOW | tests/test_termui.py | 357 | def test_progressbar_update_with_item_show_func(runner, monkeypatch): | CODE |
| LOW | tests/test_termui.py | 377 | def test_progress_bar_update_min_steps(runner): | CODE |
| LOW | tests/test_termui.py | 403 | def test_getchar_special_key_windows(runner, monkeypatch, special_key_char, key_char): | CODE |
| LOW | tests/test_termui.py | 416 | def test_getchar_windows_exceptions(runner, monkeypatch, key_char, exc): | CODE |
| LOW | tests/test_termui.py | 558 | def test_editor_path_normalization(editor_cmd, filenames, expected_args): | CODE |
| LOW | tests/test_termui.py | 585 | def test_editor_windows_path_normalization(editor_cmd, expected_cmd): | CODE |
| LOW | tests/test_termui.py | 688 | def _run_get_pager_file_with_real_pager(monkeypatch, capfd, writer, color=False): | CODE |
| 358 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | examples/aliases/aliases.py | 22 | except configparser.NoSectionError: | CODE |
| HIGH | src/click/_winconsole.py | 204 | except Exception: | CODE |
| HIGH | src/click/types.py | 1393 | except TypeError: | CODE |
| HIGH | src/click/termui.py | 1020 | except (KeyboardInterrupt, EOFError): | CODE |
| HIGH | src/click/utils.py | 45 | except Exception: | CODE |
| HIGH | src/click/_compat.py | 77 | except Exception: | CODE |
| HIGH | src/click/_compat.py | 568 | except Exception: | CODE |
| HIGH | src/click/_compat.py | 170 | except Exception: | CODE |
| HIGH | src/click/_termui_impl.py | 599 | except BrokenPipeError: | CODE |
| HIGH | src/click/_termui_impl.py | 615 | except BrokenPipeError: | CODE |
| HIGH | src/click/_termui_impl.py | 961 | except termios.error: | CODE |
| HIGH | src/click/_termui_impl.py | 629 | except KeyboardInterrupt: | CODE |
| HIGH | src/click/testing.py | 797 | except OSError: | CODE |
| HIGH | src/click/testing.py | 571 | except Exception: | CODE |
| HIGH | src/click/testing.py | 581 | except Exception: | CODE |
| HIGH | src/click/decorators.py | 226 | except AttributeError: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_basic.py | 1 | CODE | |
| LOW | tests/test_stream_lifecycle.py | 40 | CODE | |
| LOW | tests/test_compat.py | 1 | CODE | |
| LOW | tests/typing/typing_aliased_group.py | 3 | CODE | |
| LOW | tests/typing/typing_progressbar.py | 1 | CODE | |
| LOW | src/click/_winconsole.py | 9 | CODE | |
| LOW | src/click/_textwrap.py | 1 | CODE | |
| LOW | src/click/globals.py | 1 | CODE | |
| LOW | src/click/__init__.py | 8 | CODE | |
| LOW | src/click/__init__.py | 10 | CODE | |
| LOW | src/click/__init__.py | 11 | CODE | |
| LOW | src/click/__init__.py | 12 | CODE | |
| LOW | src/click/__init__.py | 13 | CODE | |
| LOW | src/click/__init__.py | 14 | CODE | |
| LOW | src/click/__init__.py | 15 | CODE | |
| LOW | src/click/__init__.py | 16 | CODE | |
| LOW | src/click/__init__.py | 17 | CODE | |
| LOW | src/click/__init__.py | 18 | CODE | |
| LOW | src/click/__init__.py | 19 | CODE | |
| LOW | src/click/__init__.py | 20 | CODE | |
| LOW | src/click/__init__.py | 21 | CODE | |
| LOW | src/click/__init__.py | 22 | CODE | |
| LOW | src/click/__init__.py | 23 | CODE | |
| LOW | src/click/__init__.py | 24 | CODE | |
| LOW | src/click/__init__.py | 25 | CODE | |
| LOW | src/click/__init__.py | 26 | CODE | |
| LOW | src/click/__init__.py | 27 | CODE | |
| LOW | src/click/__init__.py | 28 | CODE | |
| LOW | src/click/__init__.py | 29 | CODE | |
| LOW | src/click/__init__.py | 30 | CODE | |
| LOW | src/click/__init__.py | 31 | CODE | |
| LOW | src/click/__init__.py | 32 | CODE | |
| LOW | src/click/__init__.py | 33 | CODE | |
| LOW | src/click/__init__.py | 34 | CODE | |
| LOW | src/click/__init__.py | 35 | CODE | |
| LOW | src/click/__init__.py | 36 | CODE | |
| LOW | src/click/__init__.py | 37 | CODE | |
| LOW | src/click/__init__.py | 38 | CODE | |
| LOW | src/click/__init__.py | 39 | CODE | |
| LOW | src/click/__init__.py | 40 | CODE | |
| LOW | src/click/__init__.py | 41 | CODE | |
| LOW | src/click/__init__.py | 42 | CODE | |
| LOW | src/click/__init__.py | 43 | CODE | |
| LOW | src/click/__init__.py | 44 | CODE | |
| LOW | src/click/__init__.py | 45 | CODE | |
| LOW | src/click/__init__.py | 46 | CODE | |
| LOW | src/click/__init__.py | 47 | CODE | |
| LOW | src/click/__init__.py | 48 | CODE | |
| LOW | src/click/__init__.py | 49 | CODE | |
| LOW | src/click/__init__.py | 50 | CODE | |
| LOW | src/click/__init__.py | 51 | CODE | |
| LOW | src/click/__init__.py | 52 | CODE | |
| LOW | src/click/__init__.py | 53 | CODE | |
| LOW | src/click/__init__.py | 54 | CODE | |
| LOW | src/click/__init__.py | 55 | CODE | |
| LOW | src/click/__init__.py | 56 | CODE | |
| LOW | src/click/__init__.py | 57 | CODE | |
| LOW | src/click/__init__.py | 58 | CODE | |
| LOW | src/click/__init__.py | 59 | CODE | |
| LOW | src/click/__init__.py | 60 | CODE | |
| 26 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 57 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 59 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 108 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 110 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 184 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 186 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 292 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 294 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 369 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 371 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 483 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_stream_lifecycle.py | 490 | # --------------------------------------------------------------------------- | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_commands.py | 160 | except Exception as e: | CODE |
| MEDIUM | tests/test_commands.py | 157 | def parse_args(self, ctx, args): | CODE |
| LOW | examples/imagepipe/imagepipe.py | 97 | except Exception as e: | CODE |
| LOW | examples/imagepipe/imagepipe.py | 117 | except Exception as e: | CODE |
| LOW | src/click/_winconsole.py | 204 | except Exception: | CODE |
| LOW | src/click/core.py | 2978 | except Exception: | STRING |
| LOW | src/click/utils.py | 45 | except Exception: | CODE |
| MEDIUM | src/click/_compat.py | 74 | def __del__(self) -> None: | CODE |
| LOW⚡ | src/click/_compat.py | 136 | except Exception: | CODE |
| LOW⚡ | src/click/_compat.py | 139 | except Exception: | CODE |
| LOW⚡ | src/click/_compat.py | 149 | except Exception: | CODE |
| LOW⚡ | src/click/_compat.py | 157 | except Exception: | CODE |
| LOW⚡ | src/click/_compat.py | 166 | except Exception: | CODE |
| LOW⚡ | src/click/_compat.py | 170 | except Exception: | CODE |
| LOW | src/click/_compat.py | 77 | except Exception: | CODE |
| LOW | src/click/_compat.py | 124 | except Exception: | CODE |
| LOW | src/click/_compat.py | 543 | except Exception: | CODE |
| LOW | src/click/_compat.py | 561 | except Exception: | CODE |
| LOW | src/click/_compat.py | 568 | except Exception: | CODE |
| LOW | src/click/_termui_impl.py | 602 | except Exception as e: | CODE |
| LOW | src/click/testing.py | 571 | except Exception: | CODE |
| LOW | src/click/testing.py | 581 | except Exception: | CODE |
| LOW | src/click/testing.py | 705 | except Exception as e: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_arguments.py | 166 | CODE | |
| LOW | examples/termui/termui.py | 145 | CODE | |
| LOW | src/click/_textwrap.py | 66 | CODE | |
| LOW | src/click/core.py | 887 | CODE | |
| LOW | src/click/core.py | 1132 | CODE | |
| LOW | src/click/core.py | 1515 | CODE | |
| LOW | src/click/core.py | 3449 | CODE | |
| LOW | src/click/core.py | 3614 | CODE | |
| LOW | src/click/types.py | 307 | CODE | |
| LOW | src/click/parser.py | 51 | CODE | |
| LOW | src/click/parser.py | 169 | CODE | |
| LOW | src/click/parser.py | 327 | CODE | |
| LOW | src/click/termui.py | 168 | CODE | |
| LOW | src/click/termui.py | 289 | CODE | |
| LOW | src/click/shell_completion.py | 696 | CODE | |
| LOW | src/click/_termui_impl.py | 520 | CODE | |
| LOW | src/click/_termui_impl.py | 799 | CODE | |
| LOW | src/click/testing.py | 399 | CODE | |
| LOW | src/click/testing.py | 596 | CODE | |
| LOW | src/click/decorators.py | 421 | CODE | |
| LOW | src/click/decorators.py | 501 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | README.md | 0 | simple program that greets name for a total of count times. | STRING |
| HIGH | tests/typing/typing_help_option.py | 0 | simple program that greets name for a total of count times. | STRING |
| HIGH | tests/typing/typing_simple_example.py | 0 | simple program that greets name for a total of count times. | STRING |
| HIGH | docs/index.md | 0 | simple program that greets name for a total of count times. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_testing.py | 691 | # Create a writer backed by the real fd 2, simulating a handler | COMMENT |
| MEDIUM | tests/test_utils/test_open_file.py | 107 | # Create a test file to get the expected permissions for new files | COMMENT |
| MEDIUM | examples/repo/repo.py | 51 | # Create a repo object and remember it as the context object. From | COMMENT |
| MEDIUM | src/click/_winconsole.py | 1 | # This module is based on the excellent work by Adam Bartoš who | COMMENT |
| MEDIUM | src/click/core.py | 2749 | # Define the conversion function based on nargs and type. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/click/core.py | 370 | CODE | |
| LOW | src/click/core.py | 1065 | CODE | |
| LOW | src/click/core.py | 2406 | CODE | |
| LOW | src/click/core.py | 3149 | CODE | |
| LOW | src/click/types.py | 1107 | CODE | |
| LOW | src/click/termui.py | 139 | CODE | |
| LOW | src/click/termui.py | 154 | CODE | |
| LOW | src/click/termui.py | 168 | CODE | |
| LOW | src/click/termui.py | 403 | CODE | |
| LOW | src/click/termui.py | 423 | CODE | |
| LOW | src/click/termui.py | 443 | CODE | |
| LOW | src/click/termui.py | 641 | CODE | |
| LOW | src/click/_termui_impl.py | 44 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_formatting.py | 430 | text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit" | CODE |
| LOW⚡ | tests/test_formatting.py | 430 | text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit" | CODE |
| LOW⚡ | tests/test_formatting.py | 431 | formatter = click.HelpFormatter(width=len(" Lorem ipsum dolor sit amet,")) | CODE |
| LOW⚡ | tests/test_formatting.py | 431 | formatter = click.HelpFormatter(width=len(" Lorem ipsum dolor sit amet,")) | CODE |
| LOW⚡ | tests/test_formatting.py | 435 | expected = " Lorem ipsum dolor sit amet,\n consectetur adipiscing elit\n" | CODE |
| LOW⚡ | tests/test_formatting.py | 435 | expected = " Lorem ipsum dolor sit amet,\n consectetur adipiscing elit\n" | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/click/core.py | 461 | allow_interspersed_args = command.allow_interspersed_args | COMMENT |
| LOW | src/click/core.py | 1581 | # standalone mode is disabled, otherwise collect the message and the | COMMENT |
| LOW | src/click/core.py | 1741 | command_class: type[Command] | None = None | COMMENT |
| LOW | src/click/core.py | 2841 | # Legacy case: provide a temporarily manipulated context to the callback | COMMENT |
| LOW | src/click/types.py | 1401 | #: perspective this appears to just be the same as `STRING` but | COMMENT |
| LOW | src/click/parser.py | 341 | return | COMMENT |
| LOW | src/click/shell_completion.py | 461 | except IndexError: | COMMENT |
| LOW | src/click/_termui_impl.py | 881 | import msvcrt | COMMENT |
| LOW | src/click/_termui_impl.py | 901 | # resulting Unicode string reads as "a with grave" + "capital H". | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/click/_termui_impl.py | 819 | return subprocess.Popen(args, stderr=null).wait() | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_context.py | 462 | def set_level(self, ctx: Context, param: Parameter, value: str) -> None: | CODE |
| LOW | src/click/core.py | 961 | def set_parameter_source(self, name: str, source: ParameterSource) -> None: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_utils/test_echo_via_pager.py | 36 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_options.py | 1992 | # Print the value received by the callback as-is, so we can check for it. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_types/test_File.py | 14 | """Ensures that the error handling in ``click.File`` is robust. | STRING |