From 7cd1edd02cf62368404231c91c54751aa802387e Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 12:58:34 +0100 Subject: [PATCH 1/8] Skipping networks notebook test --- tests/notebooks/test_notebooks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/notebooks/test_notebooks.py b/tests/notebooks/test_notebooks.py index 5bd369390..e44be8975 100644 --- a/tests/notebooks/test_notebooks.py +++ b/tests/notebooks/test_notebooks.py @@ -7,7 +7,8 @@ _TEST_DIR = os.path.dirname(os.path.abspath(__file__)) PARENT_DIR = os.path.join(_TEST_DIR, "../..") -SKIP_LIST = ["Download", "Metocean_track_comparison_global", "Metrics_widget"] +SKIP_LIST = ["Download", "Metocean_track_comparison_global", "Metrics_widget", "Collection_systems_network"] +# We skip Collection_systems_network.ipynb since it uses Network.from_res1d() which uses pythonnet and, currently, it does not support python 3.14 def _process_notebook(notebook_filename, notebook_path="notebooks"): From 9718d47a08966ee188b42c264054fa4320953465 Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 13:08:27 +0100 Subject: [PATCH 2/8] Include explicit error to guard res1d with python 3.14 --- src/modelskill/network.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modelskill/network.py b/src/modelskill/network.py index ae3f492e0..184c27ee4 100644 --- a/src/modelskill/network.py +++ b/src/modelskill/network.py @@ -13,6 +13,8 @@ from __future__ import annotations +import sys + from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Sequence, overload, TYPE_CHECKING @@ -357,9 +359,13 @@ def from_res1d(cls, res: str | Path | Res1D) -> Network: >>> network = Network.from_res1d("model.res1d") >>> network = Network.from_res1d(Res1D("model.res1d")) """ + if sys.version_info >= (3, 14): + raise NotImplementedError(f"Current version of 'mikeio1d' requires python < 3.14 and {sys.version} is being used.") + from mikeio1d import Res1D as _Res1D from modelskill.model.adapters._res1d import Res1DReach + if isinstance(res, (str, Path)): path = Path(res) if path.suffix.lower() != ".res1d": From 60fe49bbeb52c1fa0e0d1f30e4d9dcc3a604f357 Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 13:08:44 +0100 Subject: [PATCH 3/8] Change workflow to build documentation with python 3.13 --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d0609d633..104d8b3e5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,7 +16,7 @@ jobs: - name: Set up uv uses: astral-sh/setup-uv@v6 with: - python-version: "3.14" + python-version: "3.13" enable-cache: true - name: Set up Quarto From a127fd136258691ffb374e44c568d5a6088b8363 Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 13:21:34 +0100 Subject: [PATCH 4/8] Add explanatory comment --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 104d8b3e5..b2d596187 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,7 +16,7 @@ jobs: - name: Set up uv uses: astral-sh/setup-uv@v6 with: - python-version: "3.13" + python-version: "3.13" # Need to use 3.13 for docs build due to pythonnet dependency not yet supporting 3.14 enable-cache: true - name: Set up Quarto From 68c6160c79565bf91fbdd5ed6d9d29b297091a1f Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 13:29:33 +0100 Subject: [PATCH 5/8] Adding simple test to open network from res1d --- tests/test_network.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_network.py b/tests/test_network.py index 90aec5583..2cd2ff1a0 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1,6 +1,7 @@ """Test network models and observations""" # ruff: noqa: E402 +import sys import pytest pytest.importorskip("networkx") @@ -434,3 +435,10 @@ def test_matching_workflow_multiple_nodes(self, sample_network, sample_node_data for comparer in comparer_collection: assert "Network_Model" in comparer.mod_names assert comparer.n_points > 0 + + +@pytest.mark.skipif(sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14") +def test_open_res1d(): + path_to_file = "./testdata/network.res1d" + network = Network.from_res1d(path_to_file) + assert network.graph.number_of_nodes() == 259 \ No newline at end of file From 8c537ca9e039eb528d9faac7249cee7058cc2357 Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 13:45:26 +0100 Subject: [PATCH 6/8] Fixing path --- tests/test_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_network.py b/tests/test_network.py index 2cd2ff1a0..6dc6e215f 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -439,6 +439,6 @@ def test_matching_workflow_multiple_nodes(self, sample_network, sample_node_data @pytest.mark.skipif(sys.version_info >= (3, 14), reason="mikeio1d requires Python < 3.14") def test_open_res1d(): - path_to_file = "./testdata/network.res1d" + path_to_file = "./tests/testdata/network.res1d" network = Network.from_res1d(path_to_file) assert network.graph.number_of_nodes() == 259 \ No newline at end of file From f1d03dccf9c919ac538f2d7b726f23118ffa35e2 Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 14:44:56 +0100 Subject: [PATCH 7/8] Improving robustness of res1d data renaming --- src/modelskill/model/adapters/_res1d.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/modelskill/model/adapters/_res1d.py b/src/modelskill/model/adapters/_res1d.py index 8dc0c5ad9..08f2c7cc1 100644 --- a/src/modelskill/model/adapters/_res1d.py +++ b/src/modelskill/model/adapters/_res1d.py @@ -12,16 +12,17 @@ def _simplify_res1d_colnames(node: ResultNode | ResultGridPoint) -> pd.DataFrame: # We remove suffixes and indexes so the columns contain only the quantity names + RES1D_NAME_SEP = ":" df = node.to_dataframe() - quantities = node.quantities renamer_dict = {} - for quantity in quantities: - relevant_columns = [col for col in df.columns if quantity in col] - if len(relevant_columns) != 1: + for quantity in node.quantities: + column_pairs = [(col, quantity) for col in df.columns if quantity in col.split(RES1D_NAME_SEP)] + if len(column_pairs) != 1: raise ValueError( - f"There must be exactly one column per quantity, found {relevant_columns}." + f"There must be exactly one column per quantity, found {column_pairs}." ) - renamer_dict[relevant_columns[0]] = quantity + old_name, new_name = column_pairs + renamer_dict[old_name] = new_name return df.rename(columns=renamer_dict).copy() From 5e3345ab4f2bc402005b2d3d2b19742e8cb459ae Mon Sep 17 00:00:00 2001 From: jpalm3r Date: Wed, 25 Mar 2026 14:51:07 +0100 Subject: [PATCH 8/8] fix --- src/modelskill/model/adapters/_res1d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modelskill/model/adapters/_res1d.py b/src/modelskill/model/adapters/_res1d.py index 08f2c7cc1..63efdf014 100644 --- a/src/modelskill/model/adapters/_res1d.py +++ b/src/modelskill/model/adapters/_res1d.py @@ -21,7 +21,7 @@ def _simplify_res1d_colnames(node: ResultNode | ResultGridPoint) -> pd.DataFrame raise ValueError( f"There must be exactly one column per quantity, found {column_pairs}." ) - old_name, new_name = column_pairs + old_name, new_name = column_pairs[0] renamer_dict[old_name] = new_name return df.rename(columns=renamer_dict).copy()