Skip to content

Improve the handling of multiple metric columns in datasets - #274

Open
jtuomist wants to merge 8 commits into
mainfrom
feature/multiple-metric-cols
Open

Improve the handling of multiple metric columns in datasets#274
jtuomist wants to merge 8 commits into
mainfrom
feature/multiple-metric-cols

Conversation

@jtuomist

Copy link
Copy Markdown
Contributor

Description

Claude's summary of the two cleanups, ready for review as a separate change from the longmont-dev deploy:

  1. PathsDataFrame.drop() (common/polars.py:180-205) — now pre-validates requested columns against self.columns before calling polars' drop(), raising Cannot drop non-existent column(s) X; available columns: Y, Z instead of polars' generic error. Purely additive (only changes the error message for calls that were already going to fail); tested manually against single/list/missing-column cases.

  2. Explicit multi-column dataset selection — new columns: list[str] field alongside the existing singular column: str, mutually exclusive (validated), across nodes/defs/node_defs.py (InputDatasetDef, DatasetPortSpec, plus a SelectColumnsDatasetTransformOp for the DB-spec pipeline), nodes/datasets.py (DatasetWithFilters, refactored _filter_and_process_df/_select_dataset_columns into a shared helper to keep ruff's complexity check happy), and nodes/spec_export.py (editor port-binding logic). When set, it whitelists those metric columns, drops rows where all of them are null, and drops any dimension column left entirely null afterward — generalizing the "empty dimensions get dropped automatically" behavior that today only applies to the singular column: case (this is exactly the gap that made the blank-Building energy class approach fail for benchmark_energy_use earlier).

Verified: ruff check/ruff format --check/mypy clean on all four touched files, pytest nodes/tests/test_model_editor.py nodes/tests/test_datasets.py nodes/tests/test_dataset_provenance.py nodes/tests/test_compare_dataset.py all pass, and a full pytest nodes/ run shows only pre-existing failures unrelated to this change (test_destructively_trim_db.py, a Django oauth2_provider app-registration error that reproduces in isolation with no code changes at all — an environment issue, not something introduced here).

Screenshots/Videos (if applicable)

Add screenshots or videos demonstrating the changes if applicable.

Related issue

E.g. Link to asana, sentry, slack thread etc.

Requirements, dependencies and related PRs

Describe or link possible requirements, dependencies and related PRs here

Additional Notes

Any additional information that reviewers should know about this PR.


✅ Pre-Merge Checklist

Type of Change

  • [ x] Set the PR's label to match the nature of this change

Testing

  • Built Unit tests (unit tests added/updated)
  • Built E2E tests (if applicable. E2E tests added/updated)
  • Authorization is tested (permissions and access controls verified)
  • Manually tested locally (functionality verified)
    Manual testing instructions
    If feature requires manual testing by reviewer, you can provide instructions here.

Internationalization & Accessibility

  • New strings are translatable (all user-facing text uses i18n)
  • Accessibility standards met (WCAG compliance, screen reader support)

Dependencies

  • Dependencies are merged (if applicable. If the change depends on other PRs e.g. kausal_common)

Screenshots/Videos (if applicable)

Add screenshots or videos demonstrating the changes if applicable.

Additional Notes

Any additional information that reviewers should know about this PR.

@kausal-code-coverage

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 44.11765% with 38 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
nodes/datasets.py 39.39% 18 Missing and 2 partials ⚠️
common/polars.py 45.45% 3 Missing and 3 partials ⚠️
nodes/defs/node_defs.py 73.33% 3 Missing and 1 partial ⚠️
nodes/metric.py 0.00% 4 Missing ⚠️
nodes/spec_export.py 20.00% 2 Missing and 2 partials ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #274      +/-   ##
==========================================
- Coverage   48.05%   48.04%   -0.01%     
==========================================
  Files         342      342              
  Lines       45386    45444      +58     
  Branches     6794     6808      +14     
==========================================
+ Hits        21809    21835      +26     
- Misses      21895    21921      +26     
- Partials     1682     1688       +6     
Flag Coverage Δ
e2e-tests 13.30% <19.11%> (+<0.01%) ⬆️
unittests 45.74% <32.35%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
nodes/defs/node_defs.py 88.51% <73.33%> (-1.04%) ⬇️
nodes/metric.py 49.68% <0.00%> (-0.32%) ⬇️
nodes/spec_export.py 44.79% <20.00%> (-0.08%) ⬇️
common/polars.py 49.41% <45.45%> (-0.09%) ⬇️
nodes/datasets.py 49.76% <39.39%> (-0.49%) ⬇️

Impacted file tree graph

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jtuomist
jtuomist requested review from bbliem and juyrjola July 27, 2026 04:29
@jtuomist jtuomist self-assigned this Jul 27, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8e6b285a5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread nodes/defs/node_defs.py
input_dataset: str | None = None
"""DVC dataset identifier override (when different from ``id``)."""
column: str | None = None
columns: list[str] | None = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject empty multi-column selections

When a configuration supplies columns: [], validation accepts it and to_transform_pipeline() emits an explicit select_columns operation, while _select_dataset_columns() tests the list by truthiness and therefore treats it as if columns were unset, returning the entire dataset. The editor export similarly treats the non-None empty list as explicit and creates no dataset ports, so runtime computation and the persisted graph disagree. Require at least one item or consistently test is not None.

Useful? React with 👍 / 👎.

Comment thread common/polars.py
Comment on lines +194 to +196
raise Exception(
'Cannot drop non-existent column(s) %s; available columns: %s' % (', '.join(missing), ', '.join(self.columns))
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve Polars' missing-column exception type

For a strict drop of a missing literal column, this now raises a generic Exception before Polars can raise its documented ColumnNotFoundError. Any caller that catches the Polars exception to distinguish a missing column from unrelated failures will no longer handle this case, despite the change being intended to improve only the error message. Raise pl.exceptions.ColumnNotFoundError with the enhanced text instead.

Useful? React with 👍 / 👎.

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.

1 participant