PyGWalker: Turn your dataframe into an interactive UI for visual analysis
This report presents the forensic synthetic code analysis of Kanaries/pygwalker, a Python project with 15,902 GitHub stars. SynthScan v2.0 examined 24,261 lines of code across 220 source files, recording 465 pattern matches distributed across 11 syntactic categories. The overall adjusted score of 20.5 places this repository in the Moderate AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 465 distinct pattern matches across 11 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. 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 diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/src/dataSource/index.tsx | 171 | export function getDatasFromKernelByPayload(comm: ICommunication | null) { | CODE |
| LOW | app/src/tools/saveTool.tsx | 18 | function DocumentTextIconWithRedPoint(iconProps) { | CODE |
| LOW | tests/test_dsl_transform.py | 15 | def test_dsl_to_workflow_returns_valid_workflow(): | CODE |
| LOW | tests/test_dsl_transform.py | 22 | def test_dsl_to_workflow_with_fields(): | CODE |
| LOW | tests/test_dsl_transform.py | 34 | def test_vega_to_dsl_returns_expected_keys(): | CODE |
| LOW | tests/test_dsl_transform.py | 52 | def test_import_error_when_no_js_runtime(): | CODE |
| LOW | tests/test_dsl_transform.py | 66 | def test_runtime_initialized_only_once(): | CODE |
| LOW | tests/test_dsl_transform.py | 82 | def test_reset_runtime_closes_existing_contexts(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 192 | def test_frontend_props_interface_covers_python_props_builder(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 198 | def test_python_props_builder_stringifies_frontend_id(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 205 | def test_frontend_comm_maps_cover_python_comm_handler_endpoints(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 215 | def test_frontend_comm_request_map_uses_types_matching_python_request_models(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 225 | def test_frontend_protocol_interfaces_match_pydantic_aliases(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 232 | def test_generated_frontend_protocol_types_are_fresh(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 239 | def test_comm_handler_register_uses_typed_request_models(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 258 | def test_frontend_dev_typescript_source_maps_are_enabled(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 266 | def test_frontend_tracker_loads_segment_only_after_events_opt_in(): | CODE |
| LOW⚡ | tests/test_frontend_contracts.py | 276 | def test_frontend_http_integrations_initialize_communication(): | CODE |
| LOW | tests/test_frontend_contracts.py | 107 | def _comm_handler_request_models(repo_root: Path) -> dict[str, str]: | CODE |
| LOW | tests/test_frontend_contracts.py | 133 | def _comm_handler_register_calls(repo_root: Path) -> list[ast.Call]: | CODE |
| LOW | tests/test_frontend_contracts.py | 146 | def _typescript_interface_keys(repo_root: Path, interface_name: str) -> set[str]: | CODE |
| LOW | tests/test_frontend_contracts.py | 287 | def test_streamlit_entrypoint_refreshes_props_on_reruns(): | CODE |
| LOW | tests/test_frontend_contracts.py | 302 | def test_frontend_component_state_refreshes_when_props_change(): | CODE |
| LOW | tests/test_frontend_contracts.py | 310 | def test_frontend_pure_renderer_uses_local_data_without_kernel_computation(): | CODE |
| LOW | tests/test_frontend_contracts.py | 327 | def test_frontend_modals_are_lazy_loaded_from_entrypoint(): | CODE |
| LOW | tests/test_frontend_contracts.py | 346 | def test_frontend_save_payload_strips_graphic_walker_export_fields(): | CODE |
| LOW | tests/test_frontend_assets.py | 16 | def test_read_frontend_asset_reads_from_templates_dist(monkeypatch, tmp_path): | CODE |
| LOW | tests/test_frontend_assets.py | 25 | def test_read_frontend_asset_reports_compile_command(monkeypatch, tmp_path): | CODE |
| LOW | tests/test_frontend_assets.py | 36 | def test_read_frontend_asset_report_uses_stable_posix_path_with_windows_paths(monkeypatch, tmp_path): | CODE |
| LOW | tests/test_readme_api_reference.py | 19 | def _read_walk_api_table_rows() -> list[dict[str, str]]: | CODE |
| LOW | tests/test_readme_api_reference.py | 47 | def _read_walk_api_table_params() -> list[str]: | CODE |
| LOW | tests/test_readme_api_reference.py | 51 | def _format_signature_default(parameter: inspect.Parameter) -> str: | CODE |
| LOW | tests/test_readme_api_reference.py | 82 | def test_readme_walk_api_table_matches_jupyter_walk_signature(): | CODE |
| LOW | tests/test_readme_api_reference.py | 93 | def test_readme_walk_api_table_defaults_match_jupyter_walk_signature(): | CODE |
| LOW | tests/test_readme_api_reference.py | 103 | def test_readme_walk_api_table_documents_reusable_walker_input(): | CODE |
| LOW | tests/test_readme_api_reference.py | 136 | def test_public_api_docstrings_document_current_dataset_inputs(relative_path, qualified_name, expected_fragments): | CODE |
| LOW | tests/test_readme_api_reference.py | 144 | def test_readme_walk_api_table_marks_legacy_jupyter_envs_deprecated(): | CODE |
| LOW | tests/test_readme_api_reference.py | 176 | def test_translated_readmes_defer_api_reference_to_english_readme(): | CODE |
| LOW | tests/test_readme_api_reference.py | 185 | def test_translated_readmes_do_not_repeat_stale_api_parameters(): | CODE |
| LOW | tests/test_preview_image.py | 4 | def test_preview_image_tool_renders_on_daemon_thread(monkeypatch): | CODE |
| LOW | tests/test_preview_image.py | 34 | def test_preview_image_tool_keeps_worker_alive_after_render_error(monkeypatch): | CODE |
| LOW⚡ | tests/test_pygwalker_core.py | 1746 | def test_to_html_rejects_live_computation_modes(kwargs): | CODE |
| LOW⚡ | tests/test_pygwalker_core.py | 1751 | def test_to_html_rejects_invalid_computation_mode(): | CODE |
| LOW⚡ | tests/test_pygwalker_core.py | 1756 | def test_to_html_allows_disabled_computation_kwargs(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 29 | def _expected_legacy_computation_warning(kwargs): | CODE |
| LOW | tests/test_pygwalker_core.py | 71 | def _patch_cloud_computation_parser(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 103 | def fake_create_cloud_dataset(self, data_parser, name, is_public, temporary): | CODE |
| LOW | tests/test_pygwalker_core.py | 139 | def test_pygwalker_props_expose_browser_data_path(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 158 | def test_pygwalker_props_expose_kernel_data_path(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 169 | def test_pygwalker_get_props_falls_back_without_props_builder(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 211 | def test_props_tracker_tracks_expected_invocation_fields(): | CODE |
| LOW | tests/test_pygwalker_core.py | 267 | def test_render_manager_preview_handles_parser_exception_and_manual_gid(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 312 | def test_render_manager_chart_preview_uses_chart_indexed_workflow(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 325 | def fake_render_chart_preview(**kwargs): | CODE |
| LOW | tests/test_pygwalker_core.py | 357 | def test_render_manager_chart_preview_returns_empty_for_mismatched_workflow_list(): | CODE |
| LOW | tests/test_pygwalker_core.py | 375 | def test_jupyter_display_manager_convert_html_displays_iframe(): | CODE |
| LOW | tests/test_pygwalker_core.py | 387 | def test_jupyter_display_manager_uploads_large_classic_jupyter_data(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 426 | def test_chart_export_manager_exports_png(monkeypatch): | CODE |
| LOW | tests/test_pygwalker_core.py | 445 | def test_chart_export_manager_exports_svg_variants(): | CODE |
| LOW | tests/test_pygwalker_core.py | 465 | def test_chart_export_manager_display_chart_uses_chart_name_as_default_title(): | CODE |
| 289 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pygwalker/data_parsers/base.py | 186 | except Exception: | CODE |
| LOW | pygwalker/data_parsers/base.py | 230 | except Exception: | CODE |
| LOW | pygwalker/utils/encode.py | 23 | except Exception: | CODE |
| LOW | pygwalker/utils/runtime_env.py | 12 | except Exception: | CODE |
| MEDIUM | pygwalker/utils/runtime_env.py | 4 | def _is_jupyter() -> bool: | CODE |
| LOW | pygwalker/api/webserver.py | 170 | except Exception: | CODE |
| LOW | pygwalker/services/preview_image.py | 118 | except Exception: | CODE |
| LOW⚡ | pygwalker/services/preview_image.py | 130 | except Exception: | CODE |
| LOW⚡ | pygwalker/services/preview_image.py | 143 | except Exception: | CODE |
| MEDIUM | pygwalker/services/preview_image.py | 140 | def _safe_render_next_preview(self): | CODE |
| LOW | pygwalker/services/config.py | 76 | except Exception: | STRING |
| LOW | pygwalker/services/config.py | 151 | except Exception: | CODE |
| LOW | pygwalker/services/track.py | 70 | except Exception: | CODE |
| LOW | pygwalker/services/check_update.py | 109 | except Exception as exc: | CODE |
| LOW⚡ | pygwalker/services/kaggle.py | 16 | except Exception: | CODE |
| LOW | pygwalker/services/kaggle.py | 32 | except Exception: | CODE |
| LOW | pygwalker/services/data_bridge.py | 84 | except Exception: | CODE |
| MEDIUM | pygwalker/services/data_bridge.py | 81 | def warm_kernel_table(self) -> None: | CODE |
| LOW⚡ | pygwalker/services/format_invoke_walk_code.py | 68 | except Exception: | CODE |
| LOW | pygwalker/services/cloud_service.py | 80 | except Exception as e: | CODE |
| LOW | pygwalker/communications/reflex_comm.py | 37 | except Exception as e: | CODE |
| LOW | pygwalker/communications/reflex_comm.py | 77 | except Exception as e: | CODE |
| LOW | pygwalker/communications/streamlit_comm.py | 97 | except Exception: | CODE |
| LOW | pygwalker/communications/streamlit_comm.py | 151 | except Exception: | CODE |
| LOW | pygwalker/communications/base.py | 15 | except Exception: | CODE |
| LOW | pygwalker/communications/base.py | 50 | except Exception as e: | CODE |
| LOW | pygwalker/communications/base.py | 66 | except Exception as e: | CODE |
| LOW | examples/reflex_demo/app/app.py | 34 | except Exception as e: | CODE |
| LOW | examples/reflex_demo/app/app.py | 83 | except Exception as e: | CODE |
| MEDIUM | examples/reflex_demo/app/app.py | 84 | print(f"Error in pygwalker_demo: {e}") | CODE |
| LOW | examples/reflex_demo/app/app.py | 162 | except Exception as e: | CODE |
| LOW | examples/reflex_demo/app/app.py | 174 | except Exception as e: | CODE |
| LOW⚡ | scripts/test-init.py | 17 | except Exception as e: | CODE |
| MEDIUM⚡ | scripts/test-init.py | 18 | print(f"Error: could not download the file\n{e}", file=sys.stderr) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pygwalker/__init__.py | 16 | CODE | |
| LOW | pygwalker/__init__.py | 16 | CODE | |
| LOW | pygwalker/__init__.py | 16 | CODE | |
| LOW | pygwalker/__init__.py | 17 | CODE | |
| LOW | pygwalker/__init__.py | 18 | CODE | |
| LOW | pygwalker/__init__.py | 19 | CODE | |
| LOW | pygwalker/__init__.py | 20 | CODE | |
| LOW | pygwalker/__init__.py | 21 | CODE | |
| LOW | pygwalker/api/streamlit.py | 31 | CODE | |
| LOW | pygwalker/api/webserver.py | 30 | CODE | |
| LOW | pygwalker/api/adapter.py | 13 | CODE | |
| LOW | pygwalker/api/marimo.py | 24 | CODE | |
| LOW | pygwalker/api/anywidget.py | 23 | CODE | |
| LOW | pygwalker/api/jupyter.py | 25 | CODE | |
| LOW | pygwalker/services/data_upload_communication.py | 7 | CODE | |
| LOW | pygwalker/services/data_communication.py | 17 | CODE | |
| LOW | pygwalker/services/desktop_communication.py | 7 | CODE | |
| LOW | pygwalker/services/comm_handler.py | 34 | CODE | |
| LOW | pygwalker/services/spec_communication.py | 15 | CODE | |
| LOW | pygwalker/services/cloud_communication.py | 21 | CODE | |
| LOW | scripts/generate_comm_protocol_ts.py | 1 | CODE | |
| LOW | scripts/local_ci.py | 3 | CODE | |
| LOW | pygwalker_tools/metrics/__init__.py | 1 | CODE | |
| LOW | pygwalker_tools/metrics/__init__.py | 1 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pygwalker/data_parsers/database_parser.py | 212 | CODE | |
| LOW | pygwalker/data_parsers/database_parser.py | 221 | CODE | |
| LOW | pygwalker/data_parsers/cloud_dataset_parser.py | 70 | CODE | |
| LOW | pygwalker/api/streamlit.py | 356 | CODE | |
| LOW | pygwalker/api/streamlit.py | 104 | CODE | |
| LOW | pygwalker/api/reflex.py | 22 | CODE | |
| LOW | pygwalker/api/webserver.py | 214 | CODE | |
| LOW | pygwalker/api/webserver.py | 314 | CODE | |
| LOW | pygwalker/api/webserver.py | 376 | CODE | |
| LOW | pygwalker/api/adapter.py | 16 | CODE | |
| LOW | pygwalker/api/walker.py | 60 | CODE | |
| LOW | pygwalker/api/html.py | 25 | CODE | |
| LOW | pygwalker/api/html.py | 79 | CODE | |
| LOW | pygwalker/api/html.py | 142 | CODE | |
| LOW | pygwalker/api/marimo.py | 64 | CODE | |
| LOW | pygwalker/api/component.py | 426 | CODE | |
| LOW | pygwalker/api/component.py | 309 | CODE | |
| LOW | pygwalker/api/gradio.py | 15 | CODE | |
| LOW | pygwalker/api/anywidget.py | 63 | CODE | |
| LOW | pygwalker/api/jupyter.py | 119 | CODE | |
| LOW | pygwalker/services/comm_handler.py | 43 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | pygwalker/communications/reflex_comm.py | 49 | # Create a FastAPI sub-application for PyGWalker API | COMMENT |
| MEDIUM | pygwalker/communications/reflex_comm.py | 85 | # Create a sub-application for PyGWalker routes | COMMENT |
| MEDIUM | examples/reflex_demo/app/app.py | 66 | # Create a PyGWalker component | COMMENT |
| MEDIUM | examples/reflex_demo/app/app.py | 156 | # Create a Reflex app with the fixed PyGWalker API transformer | COMMENT |
| MEDIUM | scripts/test-init.sh | 14 | # Create the directory if it doesn't exist | COMMENT |
| MEDIUM⚡ | scripts/test-init.py | 11 | # Create the directory if it doesn't exist | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | pygwalker/__init__.py | 31 | __all__ = ["walk", "render", "table", "to_html", "FieldSpec", "GlobalVarManager", "component", "Walker", "spec"] | CODE |
| LOW | pygwalker/data_parsers/database_parser.py | 21 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/data_parsers/spark_parser.py | 15 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/data_parsers/cloud_dataset_parser.py | 14 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/utils/check_walker_params.py | 4 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/api/html.py | 22 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/services/spec_manager.py | 28 | def update_vis_spec(self, vis_spec: List[Dict[str, Any]]) -> None: | CODE |
| LOW | pygwalker/services/preview_image.py | 15 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/services/check_update.py | 25 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/services/format_invoke_walk_code.py | 12 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker/services/cloud_service.py | 16 | logger = logging.getLogger(__name__) | CODE |
| LOW | pygwalker_tools/metrics/__init__.py | 3 | __all__ = ["get_metrics_datas", "MetricsChart"] | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_frontend_contracts.py | 55 | CODE | |
| LOW | tests/test_frontend_contracts.py | 83 | CODE | |
| LOW | tests/test_frontend_contracts.py | 107 | CODE | |
| LOW | tests/test_readme_api_reference.py | 59 | CODE | |
| LOW | pygwalker/api/_walker_reuse.py | 23 | CODE | |
| LOW | pygwalker/api/component.py | 161 | CODE | |
| LOW | pygwalker/api/component.py | 309 | CODE | |
| LOW | pygwalker/services/spec.py | 110 | CODE | |
| LOW | pygwalker/services/spec.py | 132 | CODE | |
| LOW | pygwalker/communications/gradio_comm.py | 51 | CODE | |
| LOW | pygwalker/communications/streamlit_comm.py | 121 | CODE | |
| LOW | pygwalker_tools/metrics/core.py | 177 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | app/src/utils/communication.tsx | 232 | const domain = window.parent.document.location.host.split(".").slice(-2).join('.'); | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | docs/DEVELOPMENT.md | 65 | #### Step 1: Start the Vite Dev Server | COMMENT |
| LOW⚡ | docs/DEVELOPMENT.md | 74 | #### Step 2: Start JupyterLab with Server Proxy | COMMENT |
| LOW⚡ | docs/DEVELOPMENT.md | 83 | #### Step 3: Configure PyGWalker to Use Dev Server | COMMENT |
| LOW | docs/DEVELOPMENT.md | 100 | #### Step 4: Disable Dev Server (Return to Bundled Version) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/test-init.sh | 37 | # Check if the file was downloaded successfully | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/src/utils/communication.tsx | 185 | attributeFilter: ["placeholder"], | CODE |