Skip to content

Fix network save/load, tz-mismatch, and node-filter bugs found in 1.4.0 beta testing#681

Open
jpalm3r wants to merge 10 commits into
mainfrom
beta_test_found_bugs
Open

Fix network save/load, tz-mismatch, and node-filter bugs found in 1.4.0 beta testing#681
jpalm3r wants to merge 10 commits into
mainfrom
beta_test_found_bugs

Conversation

@jpalm3r

@jpalm3r jpalm3r commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three bugs found by a test user evaluating the network functionality ahead of the 1.4.0 release, each fixed test-first (failing regression test committed before the fix):

Test plan

  • uv run ruff check src
  • uv run mypy src/ --config-file pyproject.toml
  • uv run pytest --disable-warnings (full suite)
  • uv run pytest src/modelskill/metrics.py --doctest-modules
  • Each fix has a dedicated regression test that failed before the fix and passes after

🤖 Generated with Claude Code

jpalm3r and others added 8 commits July 24, 2026 15:24
Topology-only nodes store an empty DataFrame (not None), so the existing
`is not None` check never dropped them. Concatenating an empty RangeIndex
frame alongside real DatetimeIndex frames degraded the result index to
object dtype, which later failed the "time must be datetime" assertion in
ms.match(). Also skip empty frames so the DatetimeIndex is preserved.

Fixes #676

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ComparerCollection.save()/load() doesn't support the NODE geometry
type: Comparer.load() has no "node" branch and falls into
NotImplementedError("Unknown gtype: node").

Refs gh #677
Comparer.save() only flattened raw_mod_data into the netcdf for
gtype == "point", so node comparers silently dropped their raw model
data on save. Extend the check to also cover "node".

Part of gh #677
load() dispatched "track" / "vertical" / "point" and raised
NotImplementedError for anything else, so a node comparer's netcdf
could never be loaded back. Reconstruct NodeModelResult from the
flattened _raw_* variables, mirroring the existing point branch, using
the node coordinate carried along on each variable.

Fixes gh #677
ms.match() raises a bare pandas TypeError ("Cannot compare tz-naive
and tz-aware datetime-like objects") when the observation and model
result disagree on timezone-awareness, with no ModelSkill-specific
context about what went wrong.

Refs gh #678
No timezone handling existed anywhere in modelskill, so a mismatch
between a tz-aware and tz-naive time index only surfaced as a bare
pandas TypeError deep inside observation.trim(), with no indication
of what went wrong. Validate tz-awareness compatibility between the
observation and each model result before trimming, and raise a
ValueError naming both sides.

Fixes gh #678
mypy inferred ts's type from its first assignment (NodeModelResult),
flagging the later PointModelResult assignment as incompatible.

Part of gh #677
@jpalm3r
jpalm3r requested a review from ecomodeller as a code owner July 24, 2026 14:10
Copilot AI review requested due to automatic review settings July 24, 2026 14:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes three regressions found during 1.4.0 beta testing in the network matching and persistence workflow, improving robustness of node-filtered networks, node-geometry save/load, and timezone mismatch error reporting in ms.match().

Changes:

  • Prevent Network._build_dataframe() from concatenating empty node DataFrames (which degraded the time index to object dtype) by filtering out empty frames.
  • Add an explicit timezone-awareness compatibility check in _match_space_time() that raises a clear ValueError when obs/model timezones disagree.
  • Extend Comparer.save()/Comparer.load() to support gtype == "node" the same way as "point" for raw model data round-tripping, with regression tests.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/test_network.py Adds regression coverage ensuring node-filtered networks preserve a DatetimeIndex time coordinate.
tests/test_match.py Adds regression test asserting a clear ValueError on tz-aware vs tz-naive mismatch.
tests/test_comparercollection.py Adds a node-geometry save/load round-trip regression test for raw model data.
src/modelskill/network.py Filters out empty per-node frames before concat to avoid time index dtype corruption.
src/modelskill/matching.py Introduces _check_timezone_compatibility() and calls it before trimming/alignment.
src/modelskill/comparison/_comparison.py Enables node-geometry raw model data flattening on save and reconstruction on load.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings July 24, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/modelskill/matching.py Outdated
…s earlier

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 24, 2026 14:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

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

Labels

None yet

Projects

None yet

2 participants