Skip to content

35 add streamlit UI#56

Merged
Asifdotexe merged 11 commits into
mainfrom
35-add-streamlit-ui
Jan 19, 2026
Merged

35 add streamlit UI#56
Asifdotexe merged 11 commits into
mainfrom
35-add-streamlit-ui

Conversation

@Asifdotexe

@Asifdotexe Asifdotexe commented Jan 19, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Launched a Streamlit web app for interactive data ingestion, preview, multi-step analysis (profile, uni/bi/multivariate) and downloadable report ZIP.
    • Added a light UI theme for improved visuals.
  • Documentation

    • Expanded README with “What is DORA?”, Web App & CLI usage, quick start, supported file formats, examples and demo content.
  • Chores

    • Bumped project version to 4.0.0.

✏️ Tip: You can customize this high-level summary in your review settings.

@Asifdotexe Asifdotexe self-assigned this Jan 19, 2026
@Asifdotexe Asifdotexe added the enhancement New feature or request label Jan 19, 2026
@Asifdotexe Asifdotexe linked an issue Jan 19, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Jan 19, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a new Streamlit-based web UI (app.py) with data ingestion, configurable multi-step analyses, report generation and ZIP download; a Streamlit theme config; README updates describing web and CLI usage; and a pyproject version bump adding Streamlit.

Changes

Cohort / File(s) Summary
Streamlit Web Application
app.py
New Streamlit application implementing session state, local upload & Kaggle ingestion, dataset preview, configurable execution of Profile/Univariate/Bivariate/Multivariate steps, report assembly (HTML) and ZIP export. Multiple new functions added for rendering, execution, and report generation.
Configuration
.streamlit/config.toml
New Streamlit theme config: theme.base = "light", theme.primaryColor = "#4ecdc4", theme.backgroundColor = "#F7FDFA", theme.secondaryBackgroundColor = "#E8F8F5", theme.textColor = "#262730".
Project Metadata
pyproject.toml
Version bumped to 4.0.0 and streamlit (>=1.53.0,<2.0.0) added to dependencies.
Documentation
README.md
Added Streamlit promo badge/link, dual usage narrative (Web App & CLI), quickstart instructions, supported file formats, interactive wizard description, example commands and demo imagery.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant StreamlitApp as Streamlit App
    participant DataLoader as Data Loader
    participant Analysis as Analysis Modules
    participant Report as Report Generator

    User->>StreamlitApp: Upload file or provide Kaggle ID
    StreamlitApp->>DataLoader: Load data (local or Kaggle)
    DataLoader-->>StreamlitApp: Return DataFrame
    StreamlitApp->>User: Display preview

    User->>StreamlitApp: Configure steps & target
    User->>StreamlitApp: Execute analysis

    StreamlitApp->>Analysis: Run Profile
    Analysis-->>StreamlitApp: Profile results

    StreamlitApp->>Analysis: Run Univariate
    Analysis-->>StreamlitApp: Univariate plots

    StreamlitApp->>Analysis: Run Bivariate
    Analysis-->>StreamlitApp: Bivariate plots

    StreamlitApp->>Analysis: Run Multivariate
    Analysis-->>StreamlitApp: Multivariate outputs

    StreamlitApp->>Report: Generate HTML report & ZIP
    Report-->>StreamlitApp: Report path & ZIP
    StreamlitApp->>User: Provide download link
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • 35 add streamlit UI #56 — Adds the same Streamlit UI, identical .streamlit/config.toml, README updates, pyproject.toml changes, and the same app.py additions.

Poem

🐰 A bright teal button, DORA wakes to play,
Files hop in, charts scatter light in array,
Profiles nibble truths, plots bound and zoom,
Reports bundle snug in a cozy room,
I thump with joy—data spring’s new day.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "35 add streamlit UI" clearly summarizes the main change: adding a Streamlit-based user interface to the DORA project, which is the primary focus of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@app.py`:
- Around line 359-361: Remove the duplicate assignment of profile_data from
report_data: there are two identical lines setting profile_data =
report_data["profile"]; keep a single assignment and delete the redundant one so
only one assignment to profile_data from report_data["profile"] remains (locate
the duplicate in the block referencing variables profile_data and report_data).
- Around line 138-142: Remove or hide debug output that exposes internal paths:
eliminate the calls that display dataset_id and file_path to end users (the
st.text("Dataset ID: ...") and st.write("Downloaded to: ...") lines) or guard
them behind a server-side debug flag/setting (e.g., DEBUG or app.config.debug)
before calling them; keep the KaggleHandler.download_dataset(dataset_id) call
and use file_path only internally for subsequent processing, not for direct UI
output unless the debug flag is enabled.
- Around line 161-163: The file uploader variable uploaded_file in app.py
currently allows "xls" but read_data in src/dora/data_loader.py does not support
.xls, causing a runtime ValueError; either remove "xls" from the
st.file_uploader type list to prevent users uploading unsupported files, or
modify the read_data function to handle ".xls" (add a branch for ".xls"
extension in read_data and call pandas.read_excel with an appropriate engine
such as xlrd, and ensure the project dependencies include that engine).

In `@README.md`:
- Around line 15-21: The README contains a broken placeholder link token
PLACEHOLDER_LINK in the "Try DORA Online?" anchor; update that anchor so it
either points to the actual Streamlit app URL (https://dora-eda.streamlit.app/)
or remove the duplicate text link entirely (leaving only the badge anchor).
Locate the anchor containing the text "Try DORA Online?" and replace
PLACEHOLDER_LINK with the real URL or delete the entire <strong><a
href="PLACEHOLDER_LINK">Try DORA Online?</a></strong> element to avoid the
broken link.
🧹 Nitpick comments (4)
app.py (4)

24-38: Consider cleanup for accumulated session directories.

Session-based output directories under output/ will accumulate over time, especially on Streamlit Cloud deployments. Consider implementing a cleanup mechanism (e.g., deleting directories older than a threshold) or using Python's tempfile.mkdtemp() for automatic cleanup.


204-208: Consider list unpacking syntax.

Per Ruff RUF005, prefer ["None", *list(st.session_state.df.columns)] over concatenation. This is a minor style improvement.

Proposed fix
     target_variable = st.sidebar.selectbox(
         "Target Variable (for Bivariate Analysis)",
-        options=["None"] + list(st.session_state.df.columns),
+        options=["None", *st.session_state.df.columns],
         index=0,
     )

288-291: Minor: Inconsistent indentation.

Lines 289 and 291 have extra leading space compared to surrounding code.

Proposed fix
         # Remove extension if present (simple check)
         if "." in raw_name:
-             safe_name = raw_name.rsplit(".", 1)[0]
+            safe_name = raw_name.rsplit(".", 1)[0]
         else:
-             safe_name = raw_name
+            safe_name = raw_name

521-524: Consider moving session state initialization to init_session_state.

analysis_complete and report_data are initialized here rather than in init_session_state(). For consistency and single responsibility, move these initializations to init_session_state().

Proposed fix in init_session_state

Add to init_session_state():

    if "analysis_complete" not in st.session_state:
        st.session_state.analysis_complete = False
    if "report_data" not in st.session_state:
        st.session_state.report_data = None

Then remove lines 521-524 from main().

Comment thread app.py Outdated
Comment thread app.py
Comment thread app.py Outdated
Comment thread README.md
@Asifdotexe Asifdotexe merged commit 2cee3ee into main Jan 19, 2026
1 check passed
@Asifdotexe Asifdotexe deleted the 35-add-streamlit-ui branch January 19, 2026 15:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app.py`:
- Around line 128-149: The current load_kaggle_data flow calls
KaggleHandler.download_dataset which can block because it uses IntPrompt.ask()
for CLI file selection; update load_kaggle_data to avoid interactive CLI prompts
by calling KaggleHandler.download_dataset with a non-interactive flag (e.g.,
auto_select=True) or by retrieving the file list via a new
KaggleHandler.list_dataset_files(dataset_id) and presenting choices to the user
with Streamlit UI (st.radio) and then passing the chosen filename into
KaggleHandler.download_dataset; ensure to keep the Kaggle URL handling
(KaggleHandler.is_kaggle_url and KaggleHandler.extract_dataset_id) and to set
st.session_state.df and st.session_state.input_source only after the
non-interactive download completes.
🧹 Nitpick comments (4)
app.py (4)

24-39: Consider adding session cleanup for old output directories.

Each session creates a new directory under output/ that persists indefinitely. For production deployments, consider implementing a cleanup mechanism (e.g., a scheduled job or cleanup on app startup for directories older than N hours) to prevent disk space exhaustion.


111-126: Consider cleaning up the temporary file after loading.

The uploaded file is saved to temp_path but never deleted after being read into the DataFrame. For large files, this doubles disk usage unnecessarily.

♻️ Proposed fix
     try:
         with open(temp_path, "wb") as f:
             f.write(uploaded_file.getbuffer())

         with st.spinner("Loading data..."):
             df = read_data(temp_path)
             st.session_state.df = df
             st.session_state.input_source = uploaded_file.name
             st.success(f"Successfully loaded '{uploaded_file.name}'")
+    finally:
+        # Clean up temp file after loading
+        if temp_path.exists():
+            temp_path.unlink()
-    except Exception as e:
-        st.error(f"Error loading file: {e}")

Note: You'd need to restructure to use try/except/finally or handle cleanup in both success and error paths.


201-205: Consider using list unpacking for cleaner syntax.

Per Ruff RUF005, prefer unpacking over concatenation for readability.

♻️ Proposed fix
     target_variable = st.sidebar.selectbox(
         "Target Variable (for Bivariate Analysis)",
-        options=["None"] + list(st.session_state.df.columns),
+        options=["None", *st.session_state.df.columns],
         index=0,
     )

502-536: Consider consolidating session state initialization.

The analysis_complete and report_data session state variables are lazily initialized in main() (lines 517-520), while other session state variables are initialized in init_session_state(). Moving all session state initialization to one place would improve maintainability.

♻️ Proposed fix in init_session_state
 def init_session_state():
     """Initialize session state variables."""
     if "session_id" not in st.session_state:
         st.session_state.session_id = str(uuid.uuid4())
     if "df" not in st.session_state:
         st.session_state.df = None
     if "output_dir" not in st.session_state:
         # Create a unique output directory for this session
         base_output = Path("output") / st.session_state.session_id
         base_output.mkdir(parents=True, exist_ok=True)
         st.session_state.output_dir = base_output
     if "input_source" not in st.session_state:
         st.session_state.input_source = None
     if "zip_path" not in st.session_state:
         st.session_state.zip_path = None
+    if "analysis_complete" not in st.session_state:
+        st.session_state.analysis_complete = False
+    if "report_data" not in st.session_state:
+        st.session_state.report_data = None

Then remove lines 517-520 from main().

Comment thread app.py
Comment on lines +128 to +149
def load_kaggle_data(kaggle_input):
"""Handle loading of Kaggle datasets."""
try:
with st.spinner("Connecting to Kaggle..."):
# Extract ID if it's a URL
if KaggleHandler.is_kaggle_url(kaggle_input):
dataset_id = KaggleHandler.extract_dataset_id(kaggle_input)
else:
dataset_id = kaggle_input

# Download using existing handler
file_path = KaggleHandler.download_dataset(dataset_id)

# Load data
df = read_data(file_path)
st.session_state.df = df
st.session_state.input_source = dataset_id
st.success(f"Successfully loaded data from '{dataset_id}'")

except Exception as e:
st.error(f"Error processing Kaggle dataset: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for IntPrompt.ask usage in the codebase
rg "IntPrompt\.ask" -A 3 -B 3

Repository: Asifdotexe/DORA

Length of output: 491


🏁 Script executed:

#!/bin/bash
# Find the KaggleHandler class and download_dataset method
fd "KaggleHandler" --type f -o find . -name "*kaggle*" -type f | head -20

Repository: Asifdotexe/DORA

Length of output: 186


🏁 Script executed:

#!/bin/bash
# Search for the KaggleHandler class definition
rg "class KaggleHandler" -A 50 | head -100

Repository: Asifdotexe/DORA

Length of output: 2905


🏁 Script executed:

#!/bin/bash
# Search for download_dataset method
rg "def download_dataset" -A 30 -B 2

Repository: Asifdotexe/DORA

Length of output: 1962


Interactive file selection in KaggleHandler.download_dataset will fail in Streamlit context.

When a Kaggle dataset contains multiple supported files, KaggleHandler.download_dataset uses IntPrompt.ask() for interactive CLI selection. This requires stdin input and will block indefinitely or error in the Streamlit web environment.

Consider one of these approaches:

  1. Select the first or largest file automatically in the UI context
  2. Display the file list in Streamlit and let the user choose via radio buttons
  3. Add a parameter to download_dataset to control selection behavior (e.g., auto-select first file when called from web context)
🧰 Tools
🪛 Ruff (0.14.13)

147-147: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In `@app.py` around lines 128 - 149, The current load_kaggle_data flow calls
KaggleHandler.download_dataset which can block because it uses IntPrompt.ask()
for CLI file selection; update load_kaggle_data to avoid interactive CLI prompts
by calling KaggleHandler.download_dataset with a non-interactive flag (e.g.,
auto_select=True) or by retrieving the file list via a new
KaggleHandler.list_dataset_files(dataset_id) and presenting choices to the user
with Streamlit UI (st.radio) and then passing the chosen filename into
KaggleHandler.download_dataset; ensure to keep the Kaggle URL handling
(KaggleHandler.is_kaggle_url and KaggleHandler.extract_dataset_id) and to set
st.session_state.df and st.session_state.input_source only after the
non-interactive download completes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

give DORA streamlit compatibility

1 participant