Skip to content

feat: support tsam v4 (cluster_counts rename, ClusterConfig.weights removal)#105

Merged
FBumann merged 1 commit into
mainfrom
feat/tsam-v4-compat
Jul 23, 2026
Merged

feat: support tsam v4 (cluster_counts rename, ClusterConfig.weights removal)#105
FBumann merged 1 commit into
mainfrom
feat/tsam-v4-compat

Conversation

@FBumann

@FBumann FBumann commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Makes the wrapper ready for the upcoming tsam v4 (develop-v4, 4.0.0) while staying green on the currently released tsam 3.4.x.

I installed develop-v4 and ran our full suite against it — every failure traced to just two v4 API breaks:

  1. AggregationResult.cluster_weightscluster_counts. The values were always occurrence counts, not weights, so tsam renamed the attribute.
    • We read counts from tsam via a small version-compat accessor (_cluster_counts: new name, fall back to old).
    • We forward our own public attribute to cluster_counts and keep cluster_weights as a deprecated property alias (FutureWarning).
  2. ClusterConfig.weights removed (constructing ClusterConfig(weights=...) now raises TypeError on v4). Our deprecation validator reads the field via getattr(..., "weights", None), so it is a no-op on v4 instead of AttributeError-ing.

Everything else the migration guide flags (removed TimeSeriesAggregation / LegacyAPIWarning / MIN_WEIGHT, verbose representation names, column-order change) — we don't touch, and roundtrip/reconstruction tests confirm it.

Changes

  • _result.py — rename public field cluster_weightscluster_counts; add deprecated cluster_weights alias property.
  • _core.py / _clustering.py_cluster_counts() compat shim; update all three AggregationResult(...) construction sites (incl. the slice-merge path); make the ClusterConfig.weights validator v4-safe.
  • Tests — rename references to cluster_counts; add a deprecated-alias test; relax the ClusterConfig.weights rejection test to accept v4's TypeError.
  • Docs/notebooks — cluster_weightscluster_counts.

Verification

tsam 3.4.1 (pinned) tsam develop-v4
pytest 542 passed, 4 skipped 542 passed, 4 skipped

ruff check, ruff format, mypy --strict all clean.

Notes

  • Floor stays tsam>=3.4.0 — the code now works on both v3.4.x and v4, and v4 isn't released yet, so bumping would break installs today.
  • Prerequisite for the extremes work in feat(extremes): count-stable clustering and transferable replace #104: those preserve_n_clusters / extreme_replacements feature-detection hooks can only be exercised end-to-end once the wrapper runs on v4. (Note develop-v4 does not yet carry tsam #414, so those flags still no-op there.)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Aggregation results now expose per-cluster occurrence totals through cluster_counts.
    • Cluster counts are supported across sliced and multi-dimensional results.
  • Bug Fixes

    • Improved compatibility across supported tsam versions.
  • Documentation

    • Updated guides, examples, and data-model documentation to use cluster_counts.
  • Deprecations

    • cluster_weights remains available as a deprecated alias and now issues a warning when accessed.

…emoval)

Port the wrapper to run on both released tsam 3.4.x and the upcoming
v4 (develop-v4). Two v4 API breaks are the entire delta:

- AggregationResult.cluster_weights -> cluster_counts. Read from tsam
  via a version-compat accessor (new name, fall back to old). Forward
  our own public attribute to cluster_counts and keep cluster_weights
  as a deprecated alias emitting FutureWarning.
- ClusterConfig.weights removed (constructing it raises TypeError on
  v4). The deprecation validator now reads the field via getattr so it
  is a no-op on v4 instead of raising AttributeError.

Verified: full suite passes on both tsam 3.4.1 and develop-v4. Floor
stays tsam>=3.4.0 (v4 unreleased; dual-version support).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The aggregation result API now uses cluster_counts as the canonical per-cluster output, with cluster_weights retained as a deprecated alias. Construction, slicing, concatenation, tsam-version compatibility, tests, and documentation are updated accordingly.

Changes

Cluster Counts Migration

Layer / File(s) Summary
Aggregation result contract
src/tsam_xarray/_result.py
AggregationResult now exposes cluster_counts, derives n_clusters from it, slices it in views, and warns when the deprecated cluster_weights alias is accessed.
Aggregation construction and compatibility
src/tsam_xarray/_core.py, src/tsam_xarray/_clustering.py
Aggregation paths populate and concatenate cluster_counts; tsam field-name fallback and deprecated ClusterConfig.weights validation are updated.
Validation and documentation updates
test/*, docs/*
Tests and examples use cluster_counts, verify the deprecated alias, and update the data-model diagram and notebook output examples.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: tsam v4 compatibility, the cluster_counts rename, and ClusterConfig.weights deprecation handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tsam-v4-compat

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.

@FBumann
FBumann merged commit 6cd9f5d into main Jul 23, 2026
9 of 10 checks passed

@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: 2

🧹 Nitpick comments (1)
test/test_parametrized.py (1)

302-307: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the stale test name.

The body now validates cluster_counts, but test_cluster_occurrences_matches_weights still reports the old contract. Rename it to test_cluster_occurrences_matches_counts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_parametrized.py` around lines 302 - 307, Rename the test method
test_cluster_occurrences_matches_weights to
test_cluster_occurrences_matches_counts, leaving its implementation and
assertions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/examples/getting-started.ipynb`:
- Around line 110-111: Complete the cluster_weights-to-cluster_counts
terminology migration: in docs/examples/getting-started.ipynb lines 110-111,
rename the displayed “weights” label and the to_dataframe column to “count” or
“cluster_counts”; in docs/examples/multi-dim.ipynb line 118, rename the “weight”
column similarly; and in test/test_parametrized.py lines 302-307, rename
test_cluster_occurrences_matches_weights to a count-oriented name.

In `@src/tsam_xarray/_result.py`:
- Around line 115-133: Complete the Google-style docstrings at
src/tsam_xarray/_result.py lines 115-133 by adding Returns sections for
cluster_weights and n_clusters; at src/tsam_xarray/_core.py lines 22-33, add
Args and Returns sections for _cluster_counts; and at src/tsam_xarray/_core.py
lines 195-201, add Args and Raises sections for
_validate_no_cluster_config_weights, documenting each parameter, return value,
and raised exception accurately.

---

Nitpick comments:
In `@test/test_parametrized.py`:
- Around line 302-307: Rename the test method
test_cluster_occurrences_matches_weights to
test_cluster_occurrences_matches_counts, leaving its implementation and
assertions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 473aa3dc-3cbc-4f16-9642-a67d8b0b914b

📥 Commits

Reviewing files that changed from the base of the PR and between c49fd82 and 1121de6.

📒 Files selected for processing (9)
  • docs/data-model.md
  • docs/examples/getting-started.ipynb
  • docs/examples/multi-dim.ipynb
  • docs/index.md
  • src/tsam_xarray/_clustering.py
  • src/tsam_xarray/_core.py
  • src/tsam_xarray/_result.py
  • test/test_aggregate.py
  • test/test_parametrized.py

Comment on lines 110 to +111
"print(\"Cluster weights (days each represents):\")\n",
"result.cluster_weights.to_dataframe(\"weight\")"
"result.cluster_counts.to_dataframe(\"weight\")"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Finish the cluster_weightscluster_counts terminology migration. The changed code uses counts, but user-facing notebook output and a test name still expose the deprecated “weights” wording.

  • docs/examples/getting-started.ipynb#L110-L111: rename the label and .to_dataframe() column from weight to count or cluster_counts.
  • docs/examples/multi-dim.ipynb#L118-L118: rename the .to_dataframe("weight") column.
  • test/test_parametrized.py#L302-L307: rename test_cluster_occurrences_matches_weights to a count-oriented name.
📍 Affects 3 files
  • docs/examples/getting-started.ipynb#L110-L111 (this comment)
  • docs/examples/multi-dim.ipynb#L118-L118
  • test/test_parametrized.py#L302-L307
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/getting-started.ipynb` around lines 110 - 111, Complete the
cluster_weights-to-cluster_counts terminology migration: in
docs/examples/getting-started.ipynb lines 110-111, rename the displayed
“weights” label and the to_dataframe column to “count” or “cluster_counts”; in
docs/examples/multi-dim.ipynb line 118, rename the “weight” column similarly;
and in test/test_parametrized.py lines 302-307, rename
test_cluster_occurrences_matches_weights to a count-oriented name.

Comment on lines +115 to +133
@property
def cluster_weights(self) -> xr.DataArray:
"""Deprecated alias for `cluster_counts`.

Renamed to match tsam v4, where the values are occurrence counts
rather than weights. Will be removed in a future release.
"""
warnings.warn(
"AggregationResult.cluster_weights is deprecated; use "
"cluster_counts instead.",
FutureWarning,
stacklevel=2,
)
return self.cluster_counts

@property
def n_clusters(self) -> int:
"""Number of cluster representative clusters."""
return int(self.cluster_weights.sizes[self.dim_names.cluster])
return int(self.cluster_counts.sizes[self.dim_names.cluster])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Complete the changed docstrings with the required Google-style sections. The same documentation-contract gap appears across the changed source files.

  • src/tsam_xarray/_result.py#L115-L133: add Returns: sections for cluster_weights and n_clusters.
  • src/tsam_xarray/_core.py#L22-L33: add Args: and Returns: for _cluster_counts.
  • src/tsam_xarray/_core.py#L195-L201: add Args: and Raises: for _validate_no_cluster_config_weights.

As per coding guidelines, src/**/*.py docstrings must use Google-style sections where applicable.

📍 Affects 2 files
  • src/tsam_xarray/_result.py#L115-L133 (this comment)
  • src/tsam_xarray/_core.py#L22-L33
  • src/tsam_xarray/_core.py#L195-L201
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tsam_xarray/_result.py` around lines 115 - 133, Complete the Google-style
docstrings at src/tsam_xarray/_result.py lines 115-133 by adding Returns
sections for cluster_weights and n_clusters; at src/tsam_xarray/_core.py lines
22-33, add Args and Returns sections for _cluster_counts; and at
src/tsam_xarray/_core.py lines 195-201, add Args and Raises sections for
_validate_no_cluster_config_weights, documenting each parameter, return value,
and raised exception accurately.

Source: Coding guidelines

FBumann added a commit that referenced this pull request Jul 23, 2026
Follow-up to #105. Rename the leftover user-facing "weight" labels and
column names to "count", and the matching test, so nothing displays the
old term:

- getting-started.ipynb: "Cluster weights" print label and the
  to_dataframe("weight") column -> "count".
- multi-dim.ipynb: prose "Cluster weights" and to_dataframe("weight")
  column -> "count".
- test_parametrized: test_cluster_occurrences_matches_weights ->
  ..._matches_counts.

Skipped the reviewer's docstring-section suggestions (Returns on the
cluster_weights/n_clusters properties; Args/Returns/Raises on
_cluster_counts and _validate_no_cluster_config_weights): the codebase
convention is prose one-liners for trivial properties and private
helpers, with structured sections only on the public aggregate() and
public methods that take real parameters. Adding them would break that
local consistency.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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