feat(jlisp): transform may return (df, sd_updates) tuple#744
Conversation
📦 TestPyPI package publishedpip install --index-strategy unsafe-best-match --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ buckaroo==0.13.5.dev25996399443or with uv: uv pip install --index-strategy unsafe-best-match --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ buckaroo==0.13.5.dev25996399443MCP server for Claude Codeclaude mcp add buckaroo-table -- uvx --from "buckaroo[mcp]==0.13.5.dev25996399443" --index-strategy unsafe-best-match --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ buckaroo-table📖 Docs preview🎨 Storybook preview |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bccc56c0a8
ℹ️ 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".
| if isinstance(result, tuple) and len(result) == 2 and isinstance(result[1], dict): | ||
| df, sd_updates = result | ||
| for col, kv in sd_updates.items(): | ||
| sd_accumulator.setdefault(col, {}).update(kv) |
There was a problem hiding this comment.
Preserve nested SD updates from earlier transforms
When two tuple-returning commands in the same jlisp run update the same column with different nested styling keys, this dict.update flattens them before handle_ops_and_clean gets a chance to call merge_sds. For example, if one command returns a column_config_override with a color rule and a later command returns a column_config_override with a tooltip, the later override replaces the whole nested dict, so the color metadata is silently lost even though merge_sds is designed to merge those nested overrides. Accumulate each partial SD with the same merge semantics used for final SDs.
Useful? React with 👍 / 👎.
bccc56c to
b67889e
Compare
0c079c2 to
1bdba1b
Compare
Lets a Command thread styling-relevant metadata alongside its df result, without a separate channel through the dataflow. The unpacking lives at the lisp level: configure_buckaroo registers an apply-result! primitive that, when a transform returns a 2-tuple ending in a dict, merges the second element into a sd dict bound in the lisp env and returns the bare df. autocleaning's wrap_set_df threads each form through this primitive before the enclosing (set! df ...), so existing single-return transforms continue to work unchanged. buckaroo_transform and _run_df_interpreter both take initial_sd as a required argument and return (df, sd). handle_ops_and_clean passes an empty initial_sd, receives op-contributed sd back, and merges into cleaning_sd. Call sites in command tests updated. Single-return transforms (all existing ones) are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1bdba1b to
905b42b
Compare
|
superseded by #755 |
Summary
Extends the jlisp interpreter contract so a Command's
transformcan return either a bare df or a 2-tuple(df, sd_updates). The optional second element is a partialSDType({col: {key: value}}) that gets merged intocleaning_sdafter the operation runs. This is the foundation that lets a Command thread styling-relevant metadata (e.g. a search term that becomes a highlight phrase downstream) without having to round-trip it through the dataframe.Design
_wrap_transforminbuckaroo/jlisp/configure_utils.pyinspects the return value: if it's a 2-tuple(df, dict)it accumulates the dict into a per-call sd_accumulator and returns the bare df to the rest of the interpreter (so existing call sites stay unchanged).buckaroo_transformruns, the accumulator is readable viabuckaroo_transform.get_last_sd_updates().sd_accumulator.clear()runs at the start of eachbuckaroo_transformcall so updates don't leak across invocations.No existing Command is updated in this PR — this is the pure contract change. The first consumer (polars Search → highlight) lands in the follow-up.
Test plan
pytest tests/unit/jlisp/ tests/unit/dataflow/— 134 pass