From fa93df19d3b707661ecf0967aa8d2f4f6cebde84 Mon Sep 17 00:00:00 2001 From: Frank Winklmeier <frank.winklmeier@cern.ch> Date: Fri, 3 Nov 2023 15:41:11 +0100 Subject: [PATCH] GaudiConfig2: strict type checking for list properties Allow only `list` types to be assigned to `list` properties and extend test coverage. This brings GaudiConfig2 in line with the legacy configurables. I.e. the following now fails: ``` MyAlg.MyVecOfStrings = "abc" ``` --- GaudiConfiguration/python/GaudiConfig2/semantics.py | 7 ++++++- .../tests/python/test_mapping_semantics.py | 6 ++++++ .../tests/python/test_sequence_semantics.py | 6 ++++++ GaudiConfiguration/tests/python/test_serialization.py | 10 +++++----- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/GaudiConfiguration/python/GaudiConfig2/semantics.py b/GaudiConfiguration/python/GaudiConfig2/semantics.py index 70f78ecd3b..6729b2bb5f 100644 --- a/GaudiConfiguration/python/GaudiConfig2/semantics.py +++ b/GaudiConfiguration/python/GaudiConfig2/semantics.py @@ -148,7 +148,7 @@ class FloatSemantics(PropertySemantics): if not isinstance(value, Number): raise TypeError( - "number expected, got {!r} in assignemnt to {}".format(value, self.name) + "number expected, got {!r} in assignment to {}".format(value, self.name) ) return float(value) @@ -360,6 +360,10 @@ class SequenceSemantics(PropertySemantics): self.value_semantics.name = "{} element".format(self._name) def store(self, value): + if not isinstance(value, (list, _ListHelper)): + raise TypeError( + "list expected, got {!r} in assignment to {}".format(value, self.name) + ) new_value = _ListHelper(self.value_semantics) new_value.extend(value) return new_value @@ -494,6 +498,7 @@ class MappingSemantics(PropertySemantics): self.value_semantics.name = "{} value".format(self._name) def store(self, value): + # No explicit type checking as anything else than dict fails in update call new_value = _DictHelper(self.key_semantics, self.value_semantics) new_value.update(value) return new_value diff --git a/GaudiConfiguration/tests/python/test_mapping_semantics.py b/GaudiConfiguration/tests/python/test_mapping_semantics.py index 6dbbb40991..13228c6615 100644 --- a/GaudiConfiguration/tests/python/test_mapping_semantics.py +++ b/GaudiConfiguration/tests/python/test_mapping_semantics.py @@ -95,6 +95,12 @@ def test_access(): assert d.get("q", "Q") == "Q" +def test_assignment_bad_type(): + s = S.getSemanticsFor("std::map<std::string, std::string>") + with pytest.raises(AttributeError): + s.store([("a", 1), ("b", 2)]) + + def test_assignment_bad_value(): s = S.getSemanticsFor("std::map<std::string, std::string>") with pytest.raises(TypeError): diff --git a/GaudiConfiguration/tests/python/test_sequence_semantics.py b/GaudiConfiguration/tests/python/test_sequence_semantics.py index 50aea3703c..14b9c4ddc3 100644 --- a/GaudiConfiguration/tests/python/test_sequence_semantics.py +++ b/GaudiConfiguration/tests/python/test_sequence_semantics.py @@ -89,6 +89,12 @@ def test_assignment_bad(): with pytest.raises(TypeError): s.store(["a", "b", 1]) + with pytest.raises(TypeError): + s.store("ab") + + with pytest.raises(TypeError): + s.store(set("ab")) + def test_in_alg(): p = AlgWithVectors() diff --git a/GaudiConfiguration/tests/python/test_serialization.py b/GaudiConfiguration/tests/python/test_serialization.py index 621dd6d4ac..f8fab92f1c 100644 --- a/GaudiConfiguration/tests/python/test_serialization.py +++ b/GaudiConfiguration/tests/python/test_serialization.py @@ -1,5 +1,5 @@ ##################################################################################### -# (c) Copyright 1998-2020 CERN for the benefit of the LHCb and ATLAS collaborations # +# (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations # # # # This software is distributed under the terms of the Apache version 2 licence, # # copied verbatim in the file "LICENSE". # @@ -50,7 +50,7 @@ def test_repr(with_global_instances): assert t1.name == orig_name assert t1.Bool == t.Bool - p = AlgWithVectors(VS="abc") + p = AlgWithVectors(VS=list("abc")) q = eval(repr(p)) assert list(q.VS) == list("abc") assert repr(q) == repr(p) @@ -88,7 +88,7 @@ def test_pickle(with_global_instances): assert t1.name == orig_name assert t1.Bool == t.Bool - p = AlgWithVectors(VS="abc") + p = AlgWithVectors(VS=list("abc")) q = loads(dumps(p)) assert list(q.VS) == list("abc") assert dumps(q) == dumps(p) @@ -107,7 +107,7 @@ def test_pickle(with_global_instances): def test_full_serialization_repr(with_global_instances): MyAlg("Alg1", AnIntProp=1) SimpleOptsAlgTool("ToolA", parent=MyAlg("Alg2", AnIntProp=2)) - AlgWithVectors("AV", VS="abc") + AlgWithVectors("AV", VS=list("abc")) AlgWithMaps("AM", MSS={"a": "B"}) serial = repr(list(Configurable.instances.values())) @@ -122,7 +122,7 @@ def test_full_serialization_pickle(with_global_instances): MyAlg("Alg1", AnIntProp=1) SimpleOptsAlgTool("ToolA", parent=MyAlg("Alg2", AnIntProp=2)) - AlgWithVectors("AV", VS="abc") + AlgWithVectors("AV", VS=list("abc")) AlgWithMaps("AM", MSS={"a": "B"}) serial = dumps(list(Configurable.instances.values())) -- GitLab