Postgres CLI with autocompletion and syntax highlighting
This report summarizes scanner evidence for dbcli/pgcli, a Python project with 13,414 GitHub stars. SynthScan examined 16,884 lines of code across 93 source files, recording 446 pattern matches distributed across 11 syntactic categories. The legacy adjusted pattern signal is 30.2 (High 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? 411 finding(s).
Are imports declared and package/API names verified? 0 finding(s).
Are wrappers, guards, and repeated structures necessary? 420 finding(s).
Which changes need focused human review? 446 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 446 distinct pattern matches across 11 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 | release.py | 56 | def get_merged_prs_since_last_tag(): | CODE |
| LOW | release.py | 99 | def create_distribution_files(): | CODE |
| LOW | release.py | 104 | def upload_distribution_files(): | CODE |
| LOW | pgcli/pgcompleter.py | 612 | def get_join_condition_matches(self, suggestion, word_before_cursor): | CODE |
| LOW | pgcli/pgcompleter.py | 709 | def get_from_clause_item_matches(self, suggestion, word_before_cursor): | CODE |
| LOW | pgcli/pyev.py | 94 | def calculate_planner_estimate(self, plan): | CODE |
| LOW | pgcli/pgtoolbar.py | 19 | def create_toolbar_tokens_func(pgcli): | CODE |
| LOW | pgcli/pgexecute.py | 27 | def remove_beginning_comments(command): | CODE |
| LOW | pgcli/main.py | 408 | def register_special_commands(self): | CODE |
| LOW | pgcli/main.py | 1416 | def _handle_server_closed_connection(self, text): | CODE |
| LOW | pgcli/main.py | 1450 | def _on_completions_refreshed(self, new_completer, persist_priorities): | CODE |
| LOW | pgcli/main.py | 1999 | def obfuscate_process_password(): | CODE |
| LOW | pgcli/main.py | 403 | def _is_named_query_execution(self, text): | STRING |
| LOW | pgcli/main.py | 1027 | def _check_ongoing_transaction_and_allow_quitting(self): | STRING |
| LOW | pgcli/packages/sqlcompletion.py | 185 | def _split_multiple_statements(full_text, text_before_cursor, parsed): | CODE |
| LOW | pgcli/packages/sqlcompletion.py | 304 | def suggest_based_on_last_token(token, stmt): | CODE |
| LOW | pgcli/packages/prompt_utils.py | 6 | def confirm_destructive_query(queries, keywords, alias, force=False): | CODE |
| LOW | pgcli/packages/parseutils/__init__.py | 23 | def query_is_unconditional_update(query): | CODE |
| LOW | pgcli/packages/parseutils/__init__.py | 56 | def parse_destructive_warning(warning_level): | CODE |
| LOW | pgcli/packages/parseutils/tables.py | 75 | def extract_table_identifiers(token_stream, allow_functions=True): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 509 | def test_multiple_queries_same_line(executor): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 517 | def test_multiple_queries_with_special_command_same_line(executor, pgspecial): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 526 | def test_multiple_queries_same_line_syntaxerror(executor, exception_formatter): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 542 | def test_special_command_help(executor, pgspecial): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 549 | def test_bytea_field_support_in_output(executor): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 557 | def test_unicode_support_in_unknown_type(executor): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 562 | def test_unicode_support_in_enum_type(executor): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 570 | def test_json_renders_without_u_prefix(executor, expanded): | CODE |
| LOW⚡ | tests/test_pgexecute.py | 579 | def test_jsonb_renders_without_u_prefix(executor, expanded): | CODE |
| LOW | tests/test_pgexecute.py | 74 | def test_bools_are_treated_as_strings(executor): | CODE |
| LOW | tests/test_pgexecute.py | 98 | def test_schemata_table_views_and_columns_query(executor): | CODE |
| LOW | tests/test_pgexecute.py | 227 | def test_invalid_syntax_verbose(executor): | CODE |
| LOW | tests/test_pgexecute.py | 277 | def test_execute_from_file_no_arg(executor, pgspecial): | CODE |
| LOW | tests/test_pgexecute.py | 288 | def test_execute_from_file_io_error(os, executor, pgspecial): | CODE |
| LOW | tests/test_pgexecute.py | 302 | def test_execute_from_commented_file_that_executes_another_file(executor, pgspecial, tmpdir): | CODE |
| LOW | tests/test_pgexecute.py | 320 | def test_execute_commented_first_line_and_special(executor, pgspecial, tmpdir): | CODE |
| LOW | tests/test_pgexecute.py | 418 | def test_execute_commented_first_line_and_normal(executor, pgspecial, tmpdir): | CODE |
| LOW | tests/test_pgexecute.py | 609 | def test_large_numbers_render_directly(executor, value): | CODE |
| LOW | tests/test_pgexecute.py | 628 | def test_raises_with_no_formatter(executor, sql): | CODE |
| LOW | tests/test_pgexecute.py | 655 | def test_nonexistent_function_definition(executor): | CODE |
| LOW | tests/test_pgexecute.py | 677 | def test_function_notice_order(executor): | CODE |
| LOW | tests/test_pgexecute.py | 722 | def test_nonexistent_view_definition(executor): | CODE |
| LOW | tests/test_pgexecute.py | 759 | def test_explain_mode_does_not_wrap_special_command(executor): | CODE |
| LOW | tests/test_pgexecute.py | 784 | def test_explain_mode_runs_describe_as_special(executor, pgspecial): | CODE |
| LOW | tests/test_pgexecute.py | 794 | def test_explain_mode_wraps_normal_sql(executor, pgspecial): | CODE |
| LOW | tests/test_pgexecute.py | 815 | def test_exit_without_active_connection(executor): | CODE |
| LOW | tests/test_pgexecute.py | 258 | def test_unicode_support_in_output(executor, expanded): | STRING |
| LOW | tests/test_ssh_tunnel.py | 14 | def mock_ssh_tunnel_forwarder() -> MagicMock: | CODE |
| LOW | tests/test_ssh_tunnel.py | 110 | def test_ssh_tunnel_preserves_original_host_for_pgpass(mock_ssh_tunnel_forwarder: MagicMock, mock_pgexecute: MagicMock) | CODE |
| LOW | tests/test_ssh_tunnel.py | 123 | def test_ssh_tunnel_with_dsn_preserves_host(mock_ssh_tunnel_forwarder: MagicMock, mock_pgexecute: MagicMock) -> None: | CODE |
| LOW | tests/test_ssh_tunnel.py | 137 | def test_no_ssh_tunnel_does_not_set_hostaddr(mock_pgexecute: MagicMock) -> None: | CODE |
| LOW | tests/test_rowlimit.py | 95 | def test_row_limit_on_non_select(over_limit): | CODE |
| LOW | tests/metadata.py | 112 | def columns_functions_and_keywords(self, tbl, parent="public", typ="tables", pos=0): | CODE |
| LOW | tests/metadata.py | 118 | def schemas_and_from_clause_items(self, parent="public", pos=0): | CODE |
| LOW⚡ | tests/test_tuples_only.py | 8 | def test_tuples_only_flag_passed_to_pgcli(): | CODE |
| LOW⚡ | tests/test_tuples_only.py | 17 | def test_tuples_only_long_form(): | CODE |
| LOW⚡ | tests/test_tuples_only.py | 26 | def test_tuples_only_not_set_by_default(): | CODE |
| LOW⚡ | tests/test_tuples_only.py | 35 | def test_tuples_only_leaves_the_configured_table_format_alone(): | CODE |
| LOW⚡ | tests/test_tuples_only.py | 40 | def test_tuples_only_turns_off_timing(): | CODE |
| LOW⚡ | tests/test_tuples_only.py | 45 | def test_tuples_only_prints_rows_only(): | CODE |
| 323 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | pgcli/magic.py | 54 | except SystemExit: | CODE |
| HIGH | pgcli/pgexecute.py | 281 | except ValueError: | CODE |
| HIGH | pgcli/pgexecute.py | 413 | except special.CommandNotFound: | CODE |
| HIGH | pgcli/main.py | 994 | except KeyboardInterrupt: | CODE |
| HIGH | pgcli/main.py | 1853 | except Exception: | CODE |
| HIGH | pgcli/packages/sqlcompletion.py | 458 | except ValueError: | CODE |
| HIGH | tests/utils.py | 51 | except Exception: | CODE |
| HIGH | tests/features/steps/basic_commands.py | 237 | except pexpect.TIMEOUT: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/features/steps/crud_database.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| HIGH | tests/features/steps/named_queries.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| HIGH | tests/features/steps/crud_table.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| HIGH | tests/features/steps/basic_commands.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| HIGH | tests/features/steps/pgbouncer.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| HIGH | tests/features/steps/specials.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| HIGH | tests/features/steps/expanded.py | 0 | steps for behavioral style tests are defined in this module. each step is defined by the string decorating it. this stri | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/auth.py | 39 | except Exception as e: | CODE |
| LOW | pgcli/auth.py | 51 | except Exception as e: | CODE |
| MEDIUM | pgcli/auth.py | 48 | def keyring_set_password(key, passwd): | CODE |
| MEDIUM | pgcli/main.py | 526 | def change_table_format(self, pattern, **_): | CODE |
| LOW | pgcli/main.py | 808 | except Exception as e: | CODE |
| LOW | pgcli/main.py | 865 | except Exception as e: # Connecting to a database could fail. | CODE |
| LOW | pgcli/main.py | 1786 | except Exception: | CODE |
| LOW | pgcli/main.py | 1853 | except Exception: | CODE |
| LOW | pgcli/main.py | 1869 | except Exception: | CODE |
| LOW | pgcli/main.py | 1974 | except Exception: | CODE |
| LOW | pgcli/main.py | 2016 | except Exception: | CODE |
| LOW | pgcli/main.py | 2028 | except Exception: | CODE |
| LOW | pgcli/main.py | 952 | except Exception as e: | STRING |
| LOW | pgcli/main.py | 1073 | except Exception as e: | STRING |
| LOW | pgcli/main.py | 1102 | except Exception as e: | STRING |
| LOW | tests/utils.py | 30 | except Exception: | CODE |
| LOW | tests/utils.py | 51 | except Exception: | CODE |
| LOW | tests/features/environment.py | 198 | except Exception as x: | CODE |
| LOW | tests/features/db_utils.py | 48 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | pgcli/completion_refresher.py | 55 | # Create a new pgexecute method to populate the completions. | COMMENT |
| MEDIUM | tests/test_main.py | 868 | # Create a new named query (editor returns SQL, no error). | COMMENT |
| MEDIUM | tests/test_init_commands_simple.py | 54 | # Create a temporary config file with init-commands | COMMENT |
| MEDIUM | tests/test_init_commands_simple.py | 72 | # Create a temporary config file with init-commands | COMMENT |
| MEDIUM | tests/features/steps/file_option.py | 14 | # Create a temporary file that will be cleaned up automatically | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/pgcompleter.py | 892 | CODE | |
| LOW | pgcli/pyev.py | 159 | CODE | |
| LOW | pgcli/pgexecute.py | 320 | CODE | |
| LOW | pgcli/main.py | 1723 | CODE | |
| LOW | pgcli/main.py | 2123 | CODE | |
| LOW | pgcli/main.py | 873 | CODE | |
| LOW | pgcli/main.py | 911 | CODE | |
| LOW | pgcli/main.py | 1057 | CODE | |
| LOW | pgcli/main.py | 1458 | CODE | |
| LOW | pgcli/packages/sqlcompletion.py | 229 | CODE | |
| LOW | pgcli/packages/sqlcompletion.py | 304 | CODE | |
| LOW | pgcli/packages/formatter/sqlformatter.py | 26 | CODE | |
| LOW | pgcli/packages/parseutils/tables.py | 36 | CODE | |
| LOW | pgcli/packages/parseutils/tables.py | 75 | CODE | |
| LOW | pgcli/packages/parseutils/meta.py | 24 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/main.py | 734 | # Check if DSN contains a password - if so, don't use PGPASSWORD | COMMENT |
| LOW | pgcli/main.py | 1012 | # Check if we need to update completions, in order of most | STRING |
| LOW | tests/test_completion_refresher.py | 91 | # Set refreshers to 0: we're not testing refresh logic here | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/packages/sqlcompletion.py | 341 | return (Keyword(), Special()) | COMMENT |
| LOW | pgcli/packages/parseutils/tables.py | 141 | # abc is the table name, but if we don't stop at the first lparen, then | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/main.py | 249 | # make sure to use self.config_writer, not self.config | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/main.py | 216 | CODE | |
| LOW | tests/test_pgexecute.py | 14 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pgcli/pgstyle.py | 10 | logger = logging.getLogger(__name__) | CODE |