From 30ed2f0feb338cb30207f1ff7784280e26ab17de Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Sat, 6 Jan 2024 10:46:19 +0100 Subject: [PATCH] Fix `SwigPtrView.__getattr__` (#2259) `hasattr` didn't work with SwigPtrView, because calling `__getattr__` for a missing attribute resulted in a KeyError via `__missing__`. However, hasattr expects an attribute error in that case. Fixed. Added tests. --- python/sdist/amici/numpy.py | 5 ++++- python/tests/test_swig_interface.py | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/numpy.py index 93b04603be..b259aca2a0 100644 --- a/python/sdist/amici/numpy.py +++ b/python/sdist/amici/numpy.py @@ -80,7 +80,10 @@ def __getattr__(self, item) -> Union[np.ndarray, float]: :returns: value """ - return self.__getitem__(item) + try: + return self.__getitem__(item) + except KeyError as e: + raise AttributeError(item) from e def __init__(self, swigptr): """ diff --git a/python/tests/test_swig_interface.py b/python/tests/test_swig_interface.py index 3eabafd49b..ffec95b77b 100644 --- a/python/tests/test_swig_interface.py +++ b/python/tests/test_swig_interface.py @@ -6,6 +6,8 @@ import copy import numbers +import pytest + import amici import numpy as np @@ -500,3 +502,26 @@ def test_model_is_deepcopyable(pysb_example_presimulation_module): assert model1.t0() == model2.t0() model2.setT0(100 + model2.t0()) assert model1.t0() != model2.t0() + + +def test_rdataview(sbml_example_presimulation_module): + """Test some SwigPtrView functionality via ReturnDataView.""" + model_module = sbml_example_presimulation_module + model = model_module.getModel() + rdata = amici.runAmiciSimulation(model, model.getSolver()) + assert isinstance(rdata, amici.ReturnDataView) + + # fields are accessible via dot notation and [] operator, + # __contains__ and __getattr__ are implemented correctly + with pytest.raises(AttributeError): + _ = rdata.nonexisting_attribute + + with pytest.raises(KeyError): + _ = rdata["nonexisting_attribute"] + + assert not hasattr(rdata, "nonexisting_attribute") + assert "x" in rdata + assert rdata.x == rdata["x"] + + # field names are included by dir() + assert "x" in dir(rdata)