[codex] Refactor 0.5 integration hardening and typed API cleanup#734
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55bb6d0d06
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| action: str | ||
| data: Dict[str, Any] = Field(default_factory=dict) | ||
| rid: Optional[str] = None | ||
| gid: Optional[str] = None |
There was a problem hiding this comment.
Allow integer gids in comm envelopes
The public APIs still accept gid: Union[int, str], and PropsBuilder sends that value back to the frontend as id. When a user passes an integer gid under pydantic v2, the frontend posts an envelope with a numeric gid; this new validation rejects it before dispatching to the registered handler, so save/data/export requests fail even though integer gids are documented as supported. Make the envelope accept int | str or coerce before validation.
Useful? React with 👍 / 👎.
| const propsRef = React.useRef<IAppProps | null>(null); | ||
| if (!propsRef.current) { | ||
| propsRef.current = streamlitProps.args as IAppProps; | ||
| propsRef.current.visSpec = FormatSpec(propsRef.current.visSpec, propsRef.current.rawFields); | ||
| } |
There was a problem hiding this comment.
Refresh Streamlit props on reruns
When Streamlit reruns a script with the same component key, withStreamlitConnection re-renders this component with new streamlitProps.args; keeping only the first args in this ref means later changes to visSpec, dataSource, rawFields, or defaultTab are ignored and the app keeps showing the previous dataset/spec. This regresses normal Streamlit reruns where users update inputs without changing gid/key.
Useful? React with 👍 / 👎.
Summary
This PR is the
refactor-0.5integration hardening branch. It is a large but intentionally scoped cleanup of PygWalker’s public API surface, adapter behavior, frontend/backend communication contracts, and regression coverage.The main goal is to make the refactor mergeable by preserving the existing user-facing integrations while making the internals easier to reason about and test. During review and strict browser regression testing, we also found and fixed several correctness issues that were either introduced by the refactor or exposed by running real integrations end to end.
At a high level this PR:
Walkerobject API and supports reusing Walker objects across notebook, webserver, Streamlit, static HTML, and component-style entrypoints.pygwalker.api.pygwalkerimplementation into smaller services for rendering, props building, spec handling, data bridging, chart export, display, and communication.Nonestill allows DataBridge to apply its existing automatic size heuristic.Why this changed
The branch started as a refactor of the PygWalker runtime shape, but the code review made clear that the high-risk areas were not cosmetic structure changes. The real risks were behavioral compatibility across integrations, ambiguous computation-mode resolution, loose communication payloads, and test gaps that allowed silent regressions.
So the final scope was deliberately narrowed around merge-critical correctness:
Some cleanup items were intentionally deferred. For example, deriving every reject-default baseline from constructor signatures is valuable follow-up work, but the reviewer confirmed the current duplicated defaults are not a live bug. The duplicate frontend model cleanup and compression helper cleanup are also lower-risk than the integration correctness work in this branch.
Major backend/API changes
Public Walker object support
This PR adds a first-class Walker object API and routes existing entrypoints through shared validation/reuse helpers.
Notable behavior:
pyg.walk(...)can create and render aPygWalker/Walker-backed object.Refactored rendering and service boundaries
The large API implementation was split into smaller modules:
This reduces the blast radius of changes and makes the integration-specific behavior easier to test directly.
Unified computation option
The branch adds and hardens the shared computation-mode resolver.
Important final semantics:
None, notFalse, so DataBridge can still run its existing automatic size heuristic;False, which is the intended static/export behavior.This was one of the most important review fixes because the regression was silent: a wrong
Falsevalue can disable automatic kernel mode without throwing an error.DataBridge and tabular input hardening
This PR adds broader handling and tests for empty and public tabular inputs, including pandas-like, modin, polars, spark, database, cloud dataset, and pyarrow parser paths.
Fixes include:
Spec handling hardening
Spec parsing and spec IO paths were tightened. One important correctness fix changes empty-string handling to short-circuit only when
specis a real string:isinstance(spec, str) and spec == ""This avoids ambiguous equality checks for array-like values.
Major frontend/communication changes
Typed communication protocol
Frontend communication envelopes and backend communication responses are now typed and validated. Unknown actions and malformed payloads are rejected more deliberately.
This includes typed payloads for:
Frontend telemetry and privacy behavior
Telemetry is now lazier and more explicit:
Frontend build/tooling hardening
The frontend build moved to Vite 6 and CI now enforces frontend type checking. Package builds also rebuild frontend assets, which prevents stale dist artifacts from hiding source/build mismatch.
Integration fixes found by strict regression testing
After the code review fixes, we ran real integration apps and used Chrome/Playwright to interact with the actual UI. This exposed several issues that unit tests alone did not catch.
Streamlit browser computation data source fix
Problem found:
Fix:
pygwalker/api/streamlit.pynow sends serializedorigin_data_sourceinto component props for browser computation.DataFrameEncoder, including timestamp-safe handling.Streamlit pure chart local rendering fix
Problem found:
StreamlitRenderer.chart()in browser computation rendered a blank chart with a frontend console error similar toTypeError: A is not a function.Root cause:
Fix:
app/src/index.tsxnow branches inPureRednererApp:computation;rawData={props.dataSource}.tests/test_frontend_contracts.pynow locks this local-data contract.Component static live-computation rejection
Problem found:
Fix:
Component.explorer().to_html()andComponent.profiling().to_html()now reject kernel/cloud computation with a clearValueError.Reflex live-computation rejection
Problem found:
Fix:
get_componentnow rejects kernel/cloud computation clearly and supports browser computation.Code review fixes addressed
The second-pass reviewer confirmed the main fixes as correct and complete. The key reviewed items addressed in this branch include:
Nonefor unspecified mode so DataBridge auto-detection still runs;PygWalker(kernel_computation=...)without branching on it as a bool first;False;data_sourcecorrectly in both reuse and main branches;Noneregression is covered.Deferred reviewer items are deliberate:
>16MB pyg.walk(...)kernel-mode integration test would be a valuable follow-up guard, but the current PR already covers the resolver and DataBridge heuristic independently plus real browser integrations.Strict integration regression validation
The final regression pass used real applications and real browser interaction. The purpose was to verify that integrations start, render PygWalker, and support actual chart creation/interaction rather than just importing or serving HTML.
Browser validation was performed with Google Chrome launched through Playwright because the Chrome MCP plugin was unavailable in this environment with a sandbox metadata error. This still used a real Chrome browser, real local apps, and real drag/drop UI interaction.
Jupyter / anywidget
Validated:
Evidence captured:
STRICT_PYGWALKER_FILEpointed to this checkout'spygwalker/__init__.py;STRICT_BUNDLE_PATHpointed to this checkout'spygwalker/templates/dist/pygwalker-app.es.js;Streamlit
Validated:
StreamlitRenderer.chart()after the pure-renderer fix.The Streamlit chart bug was found during this pass, fixed, rebuilt, and revalidated successfully.
Gradio
Validated:
Marimo
Validated:
A Marimo websocket keepalive assertion appeared after closing the browser session. It was treated as shutdown cleanup noise, not an app-runtime failure, because the clean session rendered and interacted correctly.
Webserver
Validated:
Static HTML / Component
Validated regenerated static exports for:
to_htmlexplorer output;to_table_htmltable output;to_render_htmlrenderer output;component().bar().to_html();component().explorer().to_html();component().profiling().to_html().The only observed static-server noise was a
/favicon.ico404; the generated HTML artifacts themselves loaded and rendered.Reflex
Validated:
Automated validation
Final local gates run after the last integration fix:
Results:
293 passedReview focus
The highest-value review areas are:
None,False, browser, kernel, and cloud modes;Follow-up work intentionally not included
Recommended follow-ups after this PR:
pyg.walk(...)integration assertion that confirms DataBridge chooses kernel mode through the composed public API;