feat: add --save-results option to preview command#333
Conversation
Greptile SummaryThis PR adds a
|
| Filename | Overview |
|---|---|
| packages/data-designer-config/src/data_designer/config/utils/constants.py | Adds DEFAULT_DISPLAY_WIDTH = 110 constant. Clean, minimal change. |
| packages/data-designer-config/src/data_designer/config/utils/visualization.py | Adds save-to-file support (save_path, theme, display_width params), HTML post-processing with viewport/dark-mode injection, and fixes an UnboundLocalError bug by moving num_records before the try block. Well-structured with good separation of concerns. |
| packages/data-designer-config/tests/config/utils/test_visualization.py | Comprehensive test coverage for new save functionality, HTML post-processing, SVG output, invalid extensions, and the UnboundLocalError bug fix. Has known test naming issue (testapply_ instead of test_apply_) noted in prior review. |
| packages/data-designer/src/data_designer/cli/commands/preview.py | Adds --save-results, --artifact-path, --theme, and --display-width CLI options. Clean delegation to GenerationController.run_preview(). |
| packages/data-designer/src/data_designer/cli/controllers/generation_controller.py | Orchestrates save-results workflow: timestamped directory creation, dataset parquet export, report HTML, per-record HTML save, and pager generation. OSError handling with typer.Exit(code=1). One potential issue with --display-width help text being ambiguous about scope. |
| packages/data-designer/src/data_designer/cli/utils/sample_records_pager.py | New file generating a self-contained HTML pager for browsing sample records via iframe. Properly escapes directory names with html.escape(), uses json.dumps() for record file list, and includes keyboard/button navigation. Well-structured dark-themed UI. |
| packages/data-designer/tests/cli/commands/test_preview_command.py | Collapsed three similar tests into a single parametrized test covering all new CLI options. Clean improvement. |
| packages/data-designer/tests/cli/controllers/test_generation_controller.py | Thorough tests for save-results workflow: directory structure, default artifact path, analysis presence/absence, OSError handling, and non-OSError propagation. Well-structured mock setup. |
| packages/data-designer/tests/cli/utils/test_sample_records_pager.py | Good coverage for pager generation: zero/single/multiple records, XSS-safe title escaping, valid JSON records array, and counter element presence. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["preview_command()"] --> B["GenerationController.run_preview()"]
B --> C["Generate preview dataset"]
C --> D{Interactive?}
D -->|Yes| E["_browse_records_interactively()"]
D -->|No| F["_display_all_records()"]
E --> G["display_sample_record(index=i)"]
F --> G
G --> H{analysis present?}
H -->|Yes| I["analysis.to_report() → console"]
H -->|No| J{--save-results?}
I --> J
J -->|No| K["Print success"]
J -->|Yes| L["Create timestamped directory"]
L --> M["Save report.html"]
L --> N["Save dataset.parquet"]
L --> O["Save record_i.html per record"]
O --> P["apply_html_post_processing()"]
P --> Q["create_sample_records_pager()"]
Q --> R["Write sample_records_browser.html"]
R --> K
Last reviewed commit: 52245b7
packages/data-designer-config/tests/config/utils/test_visualization.py
Outdated
Show resolved
Hide resolved
packages/data-designer/src/data_designer/cli/controllers/generation_controller.py
Show resolved
Hide resolved
Allow saving rendered sample records as HTML or SVG files via an optional save_path parameter on both the standalone function and the WithRecordSamplerMixin method.
Replace the single-file --save-report option with --save-results, which saves all preview artifacts (dataset parquet, analysis report HTML, and per-record sample HTMLs) into a timestamped directory under the artifact path. Add error handling around the save block, improve timestamp precision to microseconds, and expand test coverage for the new behavior.
- Split try/except in generation_controller so report display errors don't produce misleading "failed to save" messages when not saving - Add browser HTML path to save success output for discoverability - Remove 5 unused CSS variables from pager theme constants - Add "N of M" record counter to pager toolbar - Add theme/display_width assertions to all preview_command tests - Add dedicated test for custom theme and display_width passthrough - Add tests for record counter and CSS variable cleanup
- Fix critical bug: analysis report now displays to console even when --save-results is active (was silently dropped via pass statement) - Fix latent UnboundLocalError in display_sample_record when index is out of bounds (num_records computed before try block) - Eliminate duplicated dark CSS between constant and theme listener script - Simplify sample_records_pager: remove dual-theme system, postMessage bridge, and responsive media queries; restore GitHub link; reorder toolbar to put prev/next buttons on the far left - Narrow except Exception to except OSError in save-results path - Use case-insensitive extension check and lambda-based re.sub - Collapse redundant preview command delegation tests into parametrize - Add missing type annotations and remove tautological assertions
_THEME_LISTENER_SCRIPT and _SAMPLE_RECORD_DARK_CSS_INLINE became orphaned after the pager simplification removed the postMessage bridge. This removes both constants, drops the injection line, switches the idempotency guard to the viewport meta tag, and cleans up related test assertions.
67c8ef6 to
ad4c9b2
Compare
packages/data-designer/src/data_designer/cli/utils/sample_records_pager.py
Show resolved
Hide resolved
packages/data-designer-config/tests/config/utils/test_visualization.py
Outdated
Show resolved
Hide resolved
packages/data-designer/src/data_designer/cli/commands/preview.py
Outdated
Show resolved
Hide resolved
packages/data-designer/src/data_designer/cli/utils/sample_records_pager.py
Show resolved
Hide resolved
…post_processing public
packages/data-designer-config/tests/config/utils/test_visualization.py
Outdated
Show resolved
Hide resolved
…ation.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
| display_width: int = typer.Option( | ||
| DEFAULT_DISPLAY_WIDTH, | ||
| "--display-width", | ||
| help="Width of the rendered record output in characters.", | ||
| min=40, | ||
| ), |
There was a problem hiding this comment.
--display-width silently ignored without --save-results
The --display-width option is accepted regardless of whether --save-results is passed, but it has no effect on the console display path. In visualization.py, when save_path is None, the module-level console object is used with its own default width, and display_width is ignored.
A user running data-designer preview config.yaml --display-width 80 (without --save-results) would expect narrower output but get no change.
Consider either:
- Applying
display_widthto the console output path as well, or - Adding a note to the help text that this only applies with
--save-results:
| display_width: int = typer.Option( | |
| DEFAULT_DISPLAY_WIDTH, | |
| "--display-width", | |
| help="Width of the rendered record output in characters.", | |
| min=40, | |
| ), | |
| display_width: int = typer.Option( | |
| DEFAULT_DISPLAY_WIDTH, | |
| "--display-width", | |
| help="Width of the rendered record output in characters. Only applies when --save-results is used.", | |
| min=40, | |
| ), |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/data-designer/src/data_designer/cli/commands/preview.py
Line: 49-54
Comment:
**`--display-width` silently ignored without `--save-results`**
The `--display-width` option is accepted regardless of whether `--save-results` is passed, but it has no effect on the console display path. In `visualization.py`, when `save_path is None`, the module-level `console` object is used with its own default width, and `display_width` is ignored.
A user running `data-designer preview config.yaml --display-width 80` (without `--save-results`) would expect narrower output but get no change.
Consider either:
1. Applying `display_width` to the console output path as well, or
2. Adding a note to the help text that this only applies with `--save-results`:
```suggestion
display_width: int = typer.Option(
DEFAULT_DISPLAY_WIDTH,
"--display-width",
help="Width of the rendered record output in characters. Only applies when --save-results is used.",
min=40,
),
```
How can I resolve this? If you propose a fix, please make it concise.| <title>{title}</title> | ||
| <style> | ||
| :root {{ | ||
| color-scheme: dark; |
There was a problem hiding this comment.
the pager shell is hardcoded dark, so if someone passes --theme light they get white-background records sitting inside the dark pager frame — looks a bit odd. might be worth threading the theme through to _build_pager_html too, or at least a note in the help text
There was a problem hiding this comment.
nice catch! that was intentional, but now that you call it out, i think you are right 🤦♂️
| @@ -622,3 +647,53 @@ def _get_field_constraints(field: dict, schema: dict) -> str: | |||
| constraints.append(f"allowed: {', '.join(enum_values.keys())}") | |||
|
|
|||
There was a problem hiding this comment.
this flips the background to dark blue but Rich's default markup colors (greens, reds, dim text) were designed for white. they're not broken, but some of them feel a bit washed out on the dark bg. the dracula code blocks look great since that theme was made for dark — just something to keep an eye on if you want to polish the dark mode later
There was a problem hiding this comment.
Good callout! For sure would be a good idea to iterate once more folks have seen it on their screen
| results.dataset.to_parquet(results_dir / "dataset.parquet") | ||
|
|
||
| sample_records_dir = results_dir / "sample_records" | ||
| sample_records_dir.mkdir(parents=True, exist_ok=True) |
There was a problem hiding this comment.
looks like when --save-results is used, records and the report might get printed to the terminal twice? the display happens above (lines 69-76), and then this save block calls display_sample_record and to_report again with save_path — but those internally use Console(record=True) which still writes to stdout on top of saving to file. haven't tested it end-to-end with the full pipeline so not 100% sure, but might be worth a quick check
| help="Width of the rendered record output in characters.", | ||
| min=40, | ||
| ), | ||
| ) -> None: |
There was a problem hiding this comment.
minor: --theme help text says it only applies with --save-results, but --display-width doesn't mention that — it also only affects saved files (console display uses terminal width). might be worth adding the same note for consistency, or maybe a shared "Save Options" section in the help output if typer supports that
| """Test that display_sample_record saves HTML with dark-mode style block injected.""" | ||
| sample_record = {"code": "print('hello world')", "code_validation_result": validation_output} | ||
| record_series = pd.Series(sample_record) | ||
| save_path = tmp_path / "output.html" |
There was a problem hiding this comment.
nit: the sample_record + pd.Series setup is repeated in 5 tests (save_html, save_svg, save_invalid_extension, save_path_none_default, svg_no_dark_mode). could be a fixture:
@pytest.fixture
def record_series(validation_output: dict) -> pd.Series:
return pd.Series({"code": "print('hello world')", "code_validation_result": validation_output})
📋 Summary
Add
--save-resultsflag to thedata-designer previewCLI command, enabling users to persist preview artifacts (dataset parquet, analysis report HTML, and per-record sample HTML files) to disk with a built-in browser pager for navigating sample records.🔄 Changes
✨ Added
sample_records_pager.py— Generates a single-page HTML pager (sample_records_browser.html) for navigating saved sample records via iframe with prev/next, dropdown jump, and keyboard navigation--save-results,--artifact-path,--theme, and--display-widthCLI options onpreviewcommandsave_path,theme, anddisplay_widthparameters ondisplay_sample_record()andWithRecordSamplerMixin.display_sample_record()🔧 Changed
generation_controller.py—run_preview()now orchestrates saving dataset parquet, analysis report, sample record HTMLs, and the pager when--save-resultsis activevisualization.py—display_sample_record()supports saving to HTML/SVG via Rich's recording consoleconvert_to_row_elementandpad_console_element🔍 Attention Areas
visualization.py— HTML post-processing uses regex to inject CSS before</head>. Uses a lambda replacement to avoid backslash interpretation issues.generation_controller.py— Save-results block creates a timestamped directory structure. CatchesOSErrorspecifically (not broadException).sample_records_pager.py— New file (~270 lines) generating a self-contained HTML pager via f-string template.🤖 Generated with AI