-
Notifications
You must be signed in to change notification settings - Fork 25
feat(pkg-py): Add support for streamlit, gradio, and dash #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
020bdc8 to
78d46ef
Compare
Add support for building querychat applications with popular Python web frameworks beyond Shiny: - Streamlit: `querychat.streamlit.QueryChat` with `.app()` and `.sidebar()` - Gradio: `querychat.gradio.QueryChat` with `.app()` and `.ui()` - Dash: `querychat.dash.QueryChat` with `.app()`, `.ui()`, and `.init_app()` Architecture changes: - Extract shared logic into `_querychat_base.py` and `_querychat_core.py` - Add `StateDictAccessorMixin` for state deserialization across frameworks - Modularize Dash UI into `_dash_ui.py` with reusable components - Use AG Grid instead of DataTable for better table display - Add CSS/JS assets for each framework's suggestion handling Includes example apps for each framework demonstrating basic and custom usage. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add end-to-end tests using Playwright to verify: - Streamlit chat submission and data filtering - Gradio chat interactions - Dash callback functionality Includes CI workflow for running e2e tests on pull requests. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add comprehensive documentation for using querychat with Streamlit, Gradio, and Dash: - Framework-specific guides with code examples and screenshots - Refactored examples to external files with include shortcodes - Updated navigation and index page - Added screenshots for all framework examples Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add --ignore=pkg-py/tests/playwright to pytest command in Makefile (playwright tests run separately in e2e workflow) - Add dummy OPENAI_API_KEY fixture to test_frameworks.py (tests don't call API but chatlas client requires key on init) Co-Authored-By: Claude Opus 4.5 <[email protected]>
78d46ef to
b1e59b3
Compare
1fda74d to
54bb3a5
Compare
- Add parallel test execution with pytest-xdist for ~6x speedup - Add preset greetings to example apps for deterministic test behavior - Run apps in-process (threads) except Streamlit (subprocess) - Simplify test configuration: all tests require OPENAI_API_KEY - Use pypi environment in CI for API key access - Fix Makefile help regex to show e2e targets Co-Authored-By: Claude Opus 4.5 <[email protected]>
54bb3a5 to
16bf3ae
Compare
- Fix regex operator precedence bug in SQL_SURVIVED_FILTER pattern - Refactor _start_server_with_retry to use factory pattern for fresh ports on retries - Add SO_REUSEADDR to _find_free_port() to mitigate TOCTOU race condition - Add pytest-rerunfailures for flaky E2E test handling (--reruns 2) - Add stream_response edge case tests (empty, single chunk, exceptions) - Add negative/boundary tests for normalize_client and normalize_data_source - Expand test_frameworks.py coverage for Dash and Streamlit - Add comprehensive docstrings to app loader helper functions - Document test isolation strategy and fixture organization Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Fix resource leak in _start_server_with_retry: now cleans up threads, processes, and servers on failed startup attempts - Fix subprocess pipe deadlock: use DEVNULL instead of PIPE for Streamlit - Simplify verbose docstrings and remove section divider comments Co-Authored-By: Claude Opus 4.5 <[email protected]>
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove dead code: delete unused state_to_ui function from _gradio.py - Consolidate GREETING_PROMPT constant in _querychat_core.py - Replace max_display_rows parameter with warn_if_large_dataframe() - Removes row truncation, adds warning for datasets >10k rows - Applied consistently across all four frameworks - Make state_holder callbacks fail loudly instead of silently skipping - Document API differences across frameworks in build-intro.qmd - Simplify test app loaders by removing fragile qc fallback Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove the large dataframe warning functionality to defer for a follow-up issue. The eventual implementation will use a max_rows parameter on .app() to limit displayed data and provide better user feedback. Co-Authored-By: Claude Opus 4.5 <[email protected]>
gadenbuie
approved these changes
Jan 15, 2026
Contributor
gadenbuie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broad strokes: this looks great! I didn't review all the code in detail, but the architectural design choices seem sounds and you've nicely re-organized the querychat internals to be re-usable across so many backends. Nice work!
Rename *_suggestion.js files to *.js (dash.js, gradio.js, streamlit.js) and corresponding variables (DASH_JS, GRADIO_JS, STREAMLIT_JS) to allow for future non-suggestion JS in these files. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR extends querychat's Python package to support three additional web frameworks alongside Shiny: Streamlit, Gradio, and Dash. Each framework gets a dedicated
QueryChatclass with a consistent API for integrating natural language data exploration.Key highlights:
querychat.streamlit,querychat.gradio,querychat.dashQueryChatBaseclass andAppStatefor state management.app()for quick start,.ui()for custom layoutsBreaking Changes
df()return type: Methods likeexecute_query(),get_data(), anddf()now return anarwhals.DataFrameinstead ofpandas.DataFrame. Call.to_native()to get a pandas DataFrame if needed.pip install querychat[pandas]orpip install querychat[polars]Architecture
The implementation follows a layered architecture:
Key design decisions:
QueryChatBasecentralizes common logic, framework classes inherit and add UI methodsAppStatecan be serialized/deserialized for frameworks with external state stores (Gradio, Dash)st.session_statedirectly; Gradio/Dash usegr.State/dcc.Storewith serialized dictsstream_response_async) to avoid blocking other callbacksFramework Comparison
.app().app().app().app().ui()/.sidebar()/.server().ui()/.sidebar().ui().ui()+.init_app().df()/.sql()/.title().df()/.sql()/.title().df(state)/.sql(state)/.title(state).df(state)/.sql(state)/.title(state).reset()method.app().app()st.session_stategr.State(dict)dcc.Store(dict)Usage Examples
Installation
Each framework available as an optional extra:
Files Changed
Core infrastructure (~570 LOC):
_querychat_base.py- SharedQueryChatBaseclass_querychat_core.py-AppState, streaming utilities, type definitions_ui_assets.py- CSS/JS assets for clickable suggestions_querychat.py→_shiny.py,_querychat_module.py→_shiny_module.pyFramework integrations (~1130 LOC):
_streamlit.py(234 lines) - Session state integration, sidebar/ui methods_gradio.py(396 lines) -gr.Stateintegration,GradioBlocksWrapperfor 6.0+ compatibility_dash.py(504 lines) -dcc.Storeintegration, async callbacks,dash-ag-gridfor data display_dash_ui.py(226 lines) - Dash UI component buildersTesting (~1500+ LOC):
test_04_streamlit_apps.py,test_05_gradio_apps.py,test_06_dash_apps.pytest_base.py,test_state.py,test_frameworks.py.github/workflows/py-e2e-test.ymlDocumentation:
build-intro.qmd- Framework-agnostic introductionbuild-streamlit.qmd,build-gradio.qmd,build-dash.qmd- Framework guidesFor Reviewers
Key files to focus on:
_querychat_base.py- Core shared logic_querychat_core.py- State management architectureTesting locally:
Test Plan
make py-check-tests)make py-check-types)make py-check-format)make py-e2e-tests)make py-docs-preview)Generated with Claude Code