Skip to content

Added export pdf feature#620

Open
Ani665458 wants to merge 2 commits intoStructuredLabs:mainfrom
Ani665458:feature/export-pdf
Open

Added export pdf feature#620
Ani665458 wants to merge 2 commits intoStructuredLabs:mainfrom
Ani665458:feature/export-pdf

Conversation

@Ani665458
Copy link
Contributor

This PR introduces a new export CLI command to generate print-ready PDF reports from Preswald visualizations using Playwright. Key highlights include:

✅ Features:

  • New CLI command:

preswald export --format pdf --output output/report.pdf

Renders the current app and exports a snapshot to a PDF.

  • Headless export support:

Uses Playwright to navigate to the local app (http://localhost:8501 by default), waits for charts to render, and captures the full page to a PDF.

-Modular design:

Added preswald/utils/exporter.py to encapsulate export logic.

-Updated cli.py to wire up the new command.

Introduced preswald/utils/init.py with utility functions like logging.

-Graph rendering wait:

The export command includes a configurable delay to wait for Plotly charts and other async content to finish rendering.

  • Internal Changes:

Refactored utility imports and logging setup.

Improved error handling for Playwright export failures.

📦 Example usage:

preswald run # In one terminal
preswald export --format pdf --output app-report.pdf # In another

Copy link
Member

Choose a reason for hiding this comment

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

Let's keep all of this in utils.py for now, instead of creating a separate file. Once this change is in, then we can refactor

Copy link
Member

Choose a reason for hiding this comment

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

See above comment - this should also just go in utils.py - we can refactor afterwards

@Ani665458 Ani665458 force-pushed the feature/export-pdf branch from a4ebac4 to 299644f Compare April 10, 2025 12:51
Copy link
Member

@shivam-singhal shivam-singhal left a comment

Choose a reason for hiding this comment

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

@Ani665458 last nit - can you move the imports and also include playwright in the pyproject toml dependencies? it should look like below (because it is not a pure python wheel and can't be installed within pyodide)

"playwright>=1.50; platform_system != 'Emscripten'"

from typing import Optional

import toml
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
Copy link
Member

Choose a reason for hiding this comment

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

Since these dependencies are only used within the export_app_to_pdf function, they should only be imported within the function context.

# Wait for Plotly charts to fully render
try:
print("⏳ Waiting for Plotly chart containers...")
page.wait_for_selector("div.js-plotly-plot", timeout=40000)
Copy link
Collaborator

Choose a reason for hiding this comment

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

1/ what if there are not plotly charts declared?

print("⏳ Waiting for Plotly chart containers...")
page.wait_for_selector("div.js-plotly-plot", timeout=40000)

charts = page.query_selector_all("div.js-plotly-plot")
Copy link
Collaborator

Choose a reason for hiding this comment

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

1/ why special handling for charts?

print(f"🧪 Waiting for chart {i + 1} to render...")
chart.wait_for_selector("svg", timeout=30000)

page.wait_for_timeout(2000) # Extra safety buffer
Copy link
Collaborator

Choose a reason for hiding this comment

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

1/ the hardcoding of the timeout itself is very bad, diff machines with diff sys resources take diff amount of time to get the websocket data propagated and get rendered on the page, so we should not do this wait for

change this to:
1/ declare unique html id for each frontend component
2/ get the components declared by the user in the script and check whether all are rendered on the page

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants