Fix network save/load, tz-mismatch, and node-filter bugs found in 1.4.0 beta testing - #681
Open
jpalm3r wants to merge 3 commits into
Open
Fix network save/load, tz-mismatch, and node-filter bugs found in 1.4.0 beta testing#681jpalm3r wants to merge 3 commits into
jpalm3r wants to merge 3 commits into
Conversation
Contributor
There was a problem hiding this comment.
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 toobjectdtype) by filtering out empty frames. - Add an explicit timezone-awareness compatibility check in
_match_space_time()that raises a clearValueErrorwhen obs/model timezones disagree. - Extend
Comparer.save()/Comparer.load()to supportgtype == "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.
This was referenced Jul 31, 2026
Merged
jpalm3r
force-pushed
the
beta_test_found_bugs
branch
from
August 4, 2026 13:52
85fc301 to
0ed112e
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 23 changed files in this pull request and generated no new comments.
Suppressed comments (2)
tests/test_network.py:624
- This test name and body no longer align: it says "from_res1d" and "empty_nodes_and_reaches", but it calls Network.from_mike() with non-empty nodes and duplicates the datetime-index assertions already covered by test_nodes_filtered_network_keeps_datetime_index(). Consider removing this redundant test (empty nodes/reaches is already covered below by test_from_mike_empty_nodes_and_reaches_keeps_topology_and_empty_outputs).
def test_from_res1d_empty_nodes_and_reaches_keeps_topology_and_empty_outputs():
path_to_file = "./tests/testdata/network.res1d"
network = Network.from_mike(path_to_file, nodes=["108", "101"], reaches=[])
assert isinstance(network._df.index, pd.DatetimeIndex)
src/modelskill/network.py:425
- The PR description focuses on three bug fixes (#676–#678), but this change also introduces a public API shift:
Network.from_res1dis removed and replaced byNetwork.from_mikeplus a newNetwork.from_epanet(with companion file handling). Please either (a) update the PR description to explicitly call out this API change and its migration path, or (b) consider adding a compatibility shim (e.g.,from_res1d = from_mike) if any released version could have external callers depending on the old name.
def from_mike(
cls,
res: str | Path | Res1D,
*,
nodes: str | list[str] | None = None,
reaches: str | list[str] | None = None,
) -> Network:
Matching a tz-aware observation against a tz-naive model result (or the reverse) failed deep inside pandas with a bare TypeError. Check awareness up front and name both sides in the message. Fixes gh #678. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Raw model data was only round-tripped for the "point" gtype, so a node Comparer came back without it and the reconstructed series were plain PointModelResults. Handle "node" alongside "point" and rebuild each series as a NodeModelResult. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A node carrying an empty frame still contributed a column block, which gave the concatenated result a non-datetime index. Treat empty data the same as missing data. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jpalm3r
force-pushed
the
beta_test_found_bugs
branch
from
August 11, 2026 09:54
e6e2002 to
2d017ee
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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):
Network._build_dataframedegraded the time index toobjectdtype for nodes-filtered networks, because topology-only nodes store an emptyDataFrame(notNone), so theis not Nonefilter never dropped them beforepd.concat. Now also filters out empty frames.Comparer.save()/load()didn't support thenodegeometry type:save()only flattened raw model data forpoint, andload()raisedNotImplementedErrorfornode. Both now handlenodethe same way they already handlepoint.ms.match()raised a bare pandasTypeErrorwith no context when the observation and model result disagreed on timezone-awareness._match_space_timenow checks tz compatibility up front and raises a clearValueErrornaming both sides.Test plan
uv run ruff check srcuv run mypy src/ --config-file pyproject.tomluv run pytest --disable-warnings(full suite)uv run pytest src/modelskill/metrics.py --doctest-modules🤖 Generated with Claude Code