This is a database of 300.000+ symbols containing Equities, ETFs, Funds, Indices, Currencies, Cryptocurrencies and Money Markets.
This report summarizes scanner evidence for JerBouma/FinanceDatabase, a Python project with 9,462 GitHub stars. SynthScan examined 17,587 lines of code across 139 source files, recording 306 pattern matches distributed across 11 syntactic categories. The legacy adjusted pattern signal is 30.9 (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? 251 finding(s).
Are imports declared and package/API names verified? 11 finding(s).
Are wrappers, guards, and repeated structures necessary? 256 finding(s).
Which changes need focused human review? 306 finding(s).
Run additional scans to build a history of the legacy pattern signal. Score changes are not a measure of AI adoption or code quality.
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 306 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 | financedatabase/mcp_server/ranking_model.py | 334 | def keep_top_company_together( | CODE |
| LOW | financedatabase/mcp_server/provider_model.py | 100 | def redirect_stdout_to_stderr(): | CODE |
| LOW | financedatabase/mcp_server/setup_model.py | 113 | def get_claude_code_config_path() -> pathlib.Path: | CODE |
| LOW | tests/conftest.py | 41 | def _regenerate_compression_artifacts() -> None: | CODE |
| LOW | tests/conftest.py | 56 | def _snapshot_compression_artifacts() -> dict[pathlib.Path, bytes | None]: | CODE |
| LOW | tests/conftest.py | 64 | def _restore_compression_artifacts(snapshot: dict[pathlib.Path, bytes | None]) -> None: | CODE |
| LOW | tests/test_database_controller.py | 26 | def test_polars_output_has_the_same_rows_as_pandas(asset, method, kwargs) -> None: | CODE |
| LOW⚡ | tests/test_database_controller.py | 39 | def test_show_options_as_polars() -> None: | CODE |
| LOW⚡ | tests/test_database_controller.py | 49 | def test_search_supports_python_only_regex() -> None: | CODE |
| LOW⚡ | tests/test_database_controller.py | 58 | def test_data_can_be_replaced_for_tests(monkeypatch) -> None: | CODE |
| LOW | tests/test_database_controller.py | 77 | def test_module_show_options_as_polars() -> None: | CODE |
| LOW | tests/test_invariants.py | 13 | def test_equities_read_rewrite_is_byte_identical() -> None: | CODE |
| LOW | tests/test_invariants.py | 65 | def test_no_symbol_collisions_across_asset_classes() -> None: | CODE |
| LOW | tests/test_invariants.py | 102 | def test_no_isin_collisions_across_asset_classes() -> None: | CODE |
| LOW | tests/test_invariants.py | 124 | def test_delisted_is_strictly_boolean() -> None: | CODE |
| LOW | tests/test_invariants.py | 144 | def test_equity_categories_follow_tree() -> None: | CODE |
| LOW | tests/test_invariants.py | 176 | def test_equities_hold_only_company_shares() -> None: | CODE |
| LOW | tests/test_categories_model.py | 14 | def test_blank_categories_are_learned_from_name_terms_and_isins() -> None: | CODE |
| LOW | tests/test_readme_stats.py | 45 | def test_section_is_regenerated_between_markers(tmp_path: Path) -> None: | CODE |
| LOW | tests/test_readme_stats.py | 65 | def test_regeneration_is_idempotent(tmp_path: Path) -> None: | CODE |
| LOW | tests/test_readme_stats.py | 76 | def test_missing_markers_change_nothing(tmp_path: Path) -> None: | CODE |
| LOW | tests/test_update_markets.py | 12 | def test_update_cryptos_adds_top_coins_and_drops_dead_ones() -> None: | CODE |
| LOW | tests/test_update_markets.py | 64 | def test_update_currencies_follows_iso() -> None: | CODE |
| LOW | tests/test_update_markets.py | 97 | def test_update_indices_adds_only_new_symbols() -> None: | CODE |
| LOW | tests/test_update_markets.py | 125 | def test_inav_categories_follow_their_index() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 52 | def test_main_venues_lead_the_country_most_of_their_listings_come_from() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 59 | def test_home_listing_is_primary() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 66 | def test_largest_main_venue_abroad_without_a_home_listing() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 73 | def test_home_listing_off_the_main_venues() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 80 | def test_listing_without_a_country_joins_the_name_it_starts_with() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 85 | def test_delisted_listings_never_hide_a_listed_one() -> None: | CODE |
| LOW⚡ | tests/test_listings_model.py | 95 | def test_trailing_words_are_measured_on_the_names() -> None: | CODE |
| LOW | tests/test_listings_model.py | 106 | def test_share_classes_and_preferred_shares_are_not_primary() -> None: | CODE |
| LOW | tests/test_listings_model.py | 125 | def test_names_match_with_or_without_dots() -> None: | CODE |
| LOW | tests/test_listings_model.py | 133 | def test_names_match_without_accents() -> None: | CODE |
| LOW | tests/test_listings_model.py | 147 | def _get_primary_with_currencies(rows: list[tuple]) -> set[str]: | CODE |
| LOW | tests/test_listings_model.py | 157 | def test_lines_abroad_in_another_currency_are_not_primary() -> None: | CODE |
| LOW | tests/test_listings_model.py | 170 | def test_local_receipts_are_not_primary() -> None: | CODE |
| LOW | tests/test_listings_model.py | 184 | def test_one_primary_line_per_company_and_exchange() -> None: | CODE |
| LOW | tests/test_listings_model.py | 213 | def test_lines_without_a_home_are_never_receipts() -> None: | CODE |
| LOW⚡ | tests/test_query_model.py | 20 | def test_exclude_delisted_rows() -> None: | CODE |
| LOW⚡ | tests/test_query_model.py | 26 | def test_validate_filter_values_ignores_case() -> None: | CODE |
| LOW⚡ | tests/test_query_model.py | 34 | def test_filter_rows_and_primary_listings() -> None: | CODE |
| LOW⚡ | tests/test_query_model.py | 41 | def test_primary_listings_use_the_given_symbols() -> None: | CODE |
| LOW⚡ | tests/test_query_model.py | 49 | def test_match_pattern_falls_back_to_python_regex() -> None: | CODE |
| LOW⚡ | tests/test_query_model.py | 55 | def test_search_rows_ignores_unknown_columns(caplog) -> None: | CODE |
| LOW | tests/test_update_listings.py | 80 | def test_yahoo_canada_symbols() -> None: | CODE |
| LOW | tests/test_update_listings.py | 89 | def test_canada_names_distinguish_classes() -> None: | CODE |
| LOW | tests/test_update_listings.py | 105 | def test_symbol_key_and_name_normalisation() -> None: | CODE |
| LOW | tests/test_update_listings.py | 116 | def test_dated_name_skips_debt_but_keeps_shares() -> None: | CODE |
| LOW | tests/test_update_listings.py | 140 | def test_check_non_share_finds_papers_but_keeps_shares() -> None: | CODE |
| LOW | tests/test_update_listings.py | 173 | def test_parse_tsx_skips_debt_and_ambiguous_funds() -> None: | CODE |
| LOW | tests/test_update_listings.py | 189 | def test_parse_nasdaq_trader_only_etfs() -> None: | CODE |
| LOW | tests/test_update_listings.py | 205 | def test_parse_european_etf_lists() -> None: | CODE |
| LOW | tests/test_update_listings.py | 248 | def test_broken_source_is_rejected() -> None: | CODE |
| LOW | tests/test_update_listings.py | 257 | def test_apply_source_adds_dedupes_and_delists(tmp_path: Path) -> None: | CODE |
| LOW | tests/test_update_listings.py | 309 | def test_too_many_delistings_are_not_applied(tmp_path: Path, monkeypatch) -> None: | CODE |
| LOW | tests/test_update_listings.py | 328 | def test_untouched_files_are_not_rewritten(tmp_path: Path) -> None: | CODE |
| LOW | tests/test_update_listings.py | 344 | def test_learn_categories_requires_agreement() -> None: | CODE |
| LOW | tests/test_update_listings.py | 412 | def test_openfigi_enrichment_fills_and_refiles(monkeypatch) -> None: | CODE |
| 145 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | financedatabase/database_controller.py | 225 | Filter the dataset lazily after validating the filter values. Args: filters (dict[str, Any | STRING |
| HIGH | financedatabase/database_controller.py | 328 | Collect the sorted unique values of columns, shared by every show_options(). Args: selecti | STRING |
| HIGH | financedatabase/database_controller.py | 413 | Show the category options of an asset class without initializing it. Args: selection (str | None, opti | STRING |
| HIGH | financedatabase/cache_model.py | 141 | Get the Parquet cache of a remote file, checked for changes (ETag) once a day. Args: url (str): The UR | STRING |
| HIGH | financedatabase/categories_model.py | 16 | Read a file from a local path or a URL. Args: location (str): The path or URL. use_local_locat | STRING |
| HIGH | financedatabase/categories_model.py | 40 | Get the category options of an asset class, from Parquet or else the gzip CSV. Args: location (str): T | STRING |
| HIGH | financedatabase/frame_model.py | 36 | Convert the FinanceFrame to a Finance Toolkit object for its tickers. Args: api_key (str | | STRING |
| HIGH | financedatabase/query_model.py | 125 | Match a regular expression with Python's semantics, falling back to re when needed. Args: column (pl.E | STRING |
| HIGH | financedatabase/indices/indices_controller.py | 35 | Select indices based on the category group, category, currency and other criteria. Returns all indices | STRING |
| HIGH | financedatabase/indices/indices_controller.py | 89 | Show the available values of the indices filters. The options can be narrowed down with the same filte | STRING |
| HIGH | financedatabase/currencies/currencies_controller.py | 29 | Select currency pairs based on the base and quote currency. Returns all currency pairs when no input i | STRING |
| HIGH | financedatabase/currencies/currencies_controller.py | 71 | Show the available values of the currencies filters. The options can be narrowed down with the same fi | STRING |
| HIGH | financedatabase/cryptos/cryptos_controller.py | 29 | Select cryptocurrencies based on the cryptocurrency and the currency it is quoted in. Returns all cryp | STRING |
| HIGH | financedatabase/cryptos/cryptos_controller.py | 69 | Show the available values of the cryptocurrencies filters. The options can be narrowed down with the s | STRING |
| HIGH | financedatabase/etfs/etfs_controller.py | 41 | Select ETFs based on the category group, category, family and other criteria. Returns all ETFs when no | STRING |
| HIGH | financedatabase/etfs/etfs_controller.py | 104 | Show the available values of the ETFs filters. The options can be narrowed down with the same filters | STRING |
| HIGH | financedatabase/funds/funds_controller.py | 42 | Select funds based on the category group, category, family and other criteria. Returns all funds when | STRING |
| HIGH | financedatabase/funds/funds_controller.py | 100 | Show the available values of the funds filters. The options can be narrowed down with the same filters | STRING |
| HIGH | financedatabase/mcp_server/tools_model.py | 96 | Resolve an asset class selection: 'all', a name, or comma-separated names. Args: value (An | STRING |
| HIGH | financedatabase/mcp_server/provider_model.py | 151 | Get the cached instance for an asset class, creating it on first use. Args: tool_name (str | STRING |
| HIGH | financedatabase/mcp_server/provider_model.py | 229 | Turn raw filter input into the lists of values the package expects. Args: tool_name (str): | STRING |
| HIGH | financedatabase/mcp_server/provider_model.py | 313 | Run a package call, turning its ValueError into a QueryError with suggestions. Args: tool_ | STRING |
| HIGH | financedatabase/mcp_server/provider_model.py | 374 | Validate requested column names (case-insensitive) against the dataset. Args: tool_name (s | STRING |
| HIGH | financedatabase/mcp_server/provider_model.py | 612 | Run a lazy select() with an optional query and return one page. Args: tool_name (str): The | STRING |
| HIGH | financedatabase/mcp_server/provider_model.py | 669 | Show the available values per field via the package's show_options. Args: tool_name (str): | STRING |
| HIGH | financedatabase/equities/equities_controller.py | 47 | Select equities by country, sector, industry group, industry and more. Returns all equities when no in | STRING |
| HIGH | financedatabase/equities/equities_controller.py | 116 | Show the available values of the equities filters. The options can be narrowed down with the same filt | STRING |
| HIGH | financedatabase/moneymarkets/moneymarkets_controller.py | 31 | Select money markets based on the currency and family. Returns all money markets when no input is give | STRING |
| HIGH | financedatabase/moneymarkets/moneymarkets_controller.py | 73 | Show the available values of the money markets filters. The options can be narrowed down with the same | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | financedatabase/indices/indices_controller.py | 0 | show the available values of the funds filters. the options can be narrowed down with the same filters as select(). args | STRING |
| HIGH | financedatabase/etfs/etfs_controller.py | 0 | show the available values of the funds filters. the options can be narrowed down with the same filters as select(). args | STRING |
| HIGH | financedatabase/funds/funds_controller.py | 0 | show the available values of the funds filters. the options can be narrowed down with the same filters as select(). args | STRING |
| HIGH | tests/indices/test_indices_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/currencies/test_currencies_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/cryptos/test_cryptos_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/etfs/test_etfs_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/funds/test_funds_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/equities/test_equities_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/moneymarkets/test_moneymarkets_controller.py | 0 | search() matches an independent pandas filter of the same data (structure, not a snapshot). | STRING |
| HIGH | tests/indices/test_indices_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| HIGH | tests/currencies/test_currencies_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| HIGH | tests/cryptos/test_cryptos_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| HIGH | tests/etfs/test_etfs_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| HIGH | tests/funds/test_funds_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| HIGH | tests/equities/test_equities_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| HIGH | tests/moneymarkets/test_moneymarkets_controller.py | 0 | `select(<filter>=...)` raises valueerror for values not in show_options(). | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | financedatabase/cache_model.py | 214 | except requests.exceptions.RequestException: | CODE |
| HIGH | financedatabase/categories_model.py | 63 | except (FileNotFoundError, requests.exceptions.HTTPError): | CODE |
| HIGH | tests/conftest.py | 72 | except OSError: | CODE |
| HIGH | scripts/listings/enrichment_model.py | 199 | except requests.RequestException: | CODE |
| HIGH | scripts/listings/enrichment_model.py | 212 | except requests.RequestException: | CODE |
| HIGH | scripts/listings/helpers.py | 130 | except requests.RequestException: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | financedatabase/mcp_server/registry_model.py | 51 | except Exception as error: | CODE |
| LOW | financedatabase/mcp_server/analytics_model.py | 230 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | financedatabase/mcp_server/analytics_model.py | 329 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | financedatabase/mcp_server/analytics_model.py | 345 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | financedatabase/mcp_server/tools_model.py | 142 | except Exception as error: | CODE |
| LOW | financedatabase/mcp_server/mcp_controller.py | 301 | except Exception as error: | CODE |
| LOW | scripts/listings/enrichment_model.py | 155 | except Exception as error: | CODE |
| LOW | scripts/listings/enrichment_model.py | 339 | except Exception as error: | CODE |
| LOW | scripts/listings/enrichment_model.py | 387 | except Exception as error: | CODE |
| LOW | scripts/listings/listings_controller.py | 231 | except Exception as error: | CODE |
| LOW | scripts/listings/listings_controller.py | 261 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | scripts/listings/listings_controller.py | 293 | except Exception as error: | CODE |
| LOW | scripts/listings/helpers.py | 164 | except Exception as error: | CODE |
| LOW | scripts/readme/readme_controller.py | 43 | except Exception as error: # never fail the weekly pipeline over the README | CODE |
| LOW | scripts/markets/markets_controller.py | 35 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | scripts/markets/markets_controller.py | 100 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | scripts/equities/equities_controller.py | 133 | except Exception as error: # noqa: BLE001 | CODE |
| LOW | scripts/equities/equities_model.py | 159 | except Exception as error: # noqa: BLE001 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH⚡ | tests/test_cache_model.py | 150 | assert frame.equals(typed) | CODE |
| HIGH⚡ | tests/test_cache_model.py | 161 | assert frame.equals(typed) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | financedatabase/__init__.py | 5 | CODE | |
| LOW | financedatabase/__init__.py | 6 | CODE | |
| LOW | financedatabase/__init__.py | 7 | CODE | |
| LOW | financedatabase/__init__.py | 8 | CODE | |
| LOW | financedatabase/__init__.py | 9 | CODE | |
| LOW | financedatabase/__init__.py | 10 | CODE | |
| LOW | financedatabase/__init__.py | 11 | CODE | |
| LOW | financedatabase/__init__.py | 12 | CODE | |
| LOW | scripts/listings/enrichment_model.py | 19 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | financedatabase/query_model.py | 156 | CODE | |
| LOW | financedatabase/mcp_server/analytics_model.py | 183 | CODE | |
| LOW | tests/helpers.py | 73 | CODE | |
| LOW | scripts/listings/sources_model.py | 267 | CODE | |
| LOW | scripts/listings/enrichment_model.py | 76 | CODE | |
| LOW | scripts/listings/listings_controller.py | 36 | CODE | |
| LOW | scripts/listings/categories_model.py | 106 | CODE | |
| LOW | scripts/validation/validation_controller.py | 57 | CODE | |
| LOW | scripts/validation/categories_model.py | 8 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | financedatabase/frame_model.py | 19 | CODE | |
| LOW | financedatabase/etfs/etfs_controller.py | 29 | CODE | |
| LOW | financedatabase/etfs/etfs_controller.py | 92 | CODE | |
| LOW | financedatabase/funds/funds_controller.py | 31 | CODE | |
| LOW | financedatabase/funds/funds_controller.py | 89 | CODE | |
| LOW | financedatabase/equities/equities_controller.py | 32 | CODE | |
| LOW | financedatabase/equities/equities_controller.py | 101 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | docker-compose.yml | 1 | # This file is meant for deploying the MCP server using Docker Compose. This, together with | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | financedatabase/__init__.py | 14 | __all__ = [ | CODE |
| LOW | scripts/compression/compression_controller.py | 20 | def update_datasets(database: str, compression: str) -> None: | CODE |
| LOW | scripts/compression/compression_controller.py | 37 | def update_categories(database: str, compression: str) -> None: | CODE |