diff --git a/python/ribasim/ribasim/input_base.py b/python/ribasim/ribasim/input_base.py
index d2b2b5f86..bae11f35a 100644
--- a/python/ribasim/ribasim/input_base.py
+++ b/python/ribasim/ribasim/input_base.py
@@ -316,6 +316,17 @@ def columns(cls) -> list[str]:
else:
return []
+ def __repr__(self) -> str:
+ # Make sure not to return just "None", because it gets extremely confusing
+ # when debugging.
+ return f"{self.tablename()}\n{self.df.__repr__()}"
+
+ def _repr_html_(self):
+ if self.df is None:
+ return self.__repr__()
+ else:
+ return f"
{self.tablename()}
" + self.df._repr_html_()
+
class SpatialTableModel(TableModel[TableT], Generic[TableT]):
@classmethod
@@ -394,3 +405,23 @@ def _save(self, directory: DirectoryPath, input_dir: DirectoryPath, **kwargs):
input_dir,
sort_keys=self._sort_keys.get("field", ["node_id"]),
)
+
+ def _repr_content(self) -> str:
+ """Generate a succinct overview of the content.
+
+ Skip "empty" attributes: when the dataframe of a TableModel is None.
+ """
+ content = []
+ for field in self.fields():
+ attr = getattr(self, field)
+ if isinstance(attr, TableModel):
+ if attr.df is not None:
+ content.append(field)
+ else:
+ content.append(field)
+ return ", ".join(content)
+
+ def __repr__(self) -> str:
+ content = self._repr_content()
+ typename = type(self).__name__
+ return f"{typename}({content})"
diff --git a/python/ribasim/ribasim/model.py b/python/ribasim/ribasim/model.py
index 86c8cf4a0..d51a21e48 100644
--- a/python/ribasim/ribasim/model.py
+++ b/python/ribasim/ribasim/model.py
@@ -38,7 +38,7 @@
)
from ribasim.geometry.edge import Edge
from ribasim.geometry.node import Node
-from ribasim.input_base import FileModel, NodeModel, TableModel, context_file_loading
+from ribasim.input_base import FileModel, NodeModel, context_file_loading
from ribasim.types import FilePath
@@ -206,20 +206,24 @@ def serialize_path(self, path: Path) -> str:
return str(path)
def __repr__(self) -> str:
- first = []
- second = []
+ """Generate a succinct overview of the Model content.
+
+ Skip "empty" NodeModel instances: when all dataframes are None.
+ """
+ content = ["ribasim.Model("]
+ INDENT = " "
for field in self.fields():
attr = getattr(self, field)
- if isinstance(attr, TableModel):
- second.append(f"{field}: {repr(attr)}")
+ if isinstance(attr, NodeModel):
+ attr_content = attr._repr_content()
+ typename = type(attr).__name__
+ if attr_content:
+ content.append(f"{INDENT}{field}={typename}({attr_content}),")
else:
- first.append(f"{field}={repr(attr)}")
- content = [""] + first + second
- return "\n".join(content)
+ content.append(f"{INDENT}{field}={repr(attr)},")
- def _repr_html(self):
- # Default to standard repr for now
- return self.__repr__()
+ content.append(")")
+ return "\n".join(content)
def _write_toml(self, directory: FilePath):
directory = Path(directory)
diff --git a/python/ribasim/tests/test_io.py b/python/ribasim/tests/test_io.py
index 129a01963..1d3335276 100644
--- a/python/ribasim/tests/test_io.py
+++ b/python/ribasim/tests/test_io.py
@@ -72,8 +72,13 @@ def test_repr():
)
pump_1 = Pump(static=static_data)
+ pump_2 = Pump()
- assert repr(pump_1) == "Pump(static=TableModel[PumpStaticSchema]())"
+ assert repr(pump_1) == "Pump(static)"
+ assert repr(pump_2) == "Pump()"
+ # Ensure _repr_html doesn't error
+ assert isinstance(pump_1.static._repr_html_(), str)
+ assert isinstance(pump_2.static._repr_html_(), str)
def test_extra_columns():
diff --git a/python/ribasim/tests/test_model.py b/python/ribasim/tests/test_model.py
index e8f5baa77..0138e1e12 100644
--- a/python/ribasim/tests/test_model.py
+++ b/python/ribasim/tests/test_model.py
@@ -9,7 +9,7 @@
def test_repr(basic):
representation = repr(basic).split("\n")
- assert representation[0] == ""
+ assert representation[0] == "ribasim.Model("
def test_solver():