From c027067c0dadc4b48b924eba8e190099e8970a5f Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 4 Jan 2024 19:22:48 +0100 Subject: [PATCH 1/3] Fix `SwigPtrView.__getattr__` `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. --- python/sdist/amici/numpy.py | 5 ++++- 1 file changed, 4 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): """ From d2dbac57f2f489d16120c9549e01e4ccb0914654 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Fri, 5 Jan 2024 09:30:28 +0100 Subject: [PATCH 2/3] test --- python/tests/test_swig_interface.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/python/tests/test_swig_interface.py b/python/tests/test_swig_interface.py index 3eabafd49b..41845c9d37 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,24 @@ 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 + + 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) From d7cc4abe802e4d9b2df5d59faff87f72f2519a13 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Fri, 5 Jan 2024 09:34:39 +0100 Subject: [PATCH 3/3] .. --- python/tests/test_swig_interface.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/tests/test_swig_interface.py b/python/tests/test_swig_interface.py index 41845c9d37..ffec95b77b 100644 --- a/python/tests/test_swig_interface.py +++ b/python/tests/test_swig_interface.py @@ -509,7 +509,6 @@ def test_rdataview(sbml_example_presimulation_module): 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, @@ -517,6 +516,9 @@ def test_rdataview(sbml_example_presimulation_module): 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"]