diff --git a/bindings/pyroot/pythonizations/test/CMakeLists.txt b/bindings/pyroot/pythonizations/test/CMakeLists.txt index eec078f5546fd..fa8f90b08e5ea 100644 --- a/bindings/pyroot/pythonizations/test/CMakeLists.txt +++ b/bindings/pyroot/pythonizations/test/CMakeLists.txt @@ -85,7 +85,8 @@ ROOT_ADD_PYUNITTEST(pyroot_pyz_decorator pythonization_decorator.py) # Miscellaneous small pythonizations grouped in a single file to avoid paying the # Python-startup + import-ROOT overhead once per tiny test: TClass::DynamicCast, -# TContext context manager, TComplex operators, TIter iteration and TGraph getters. +# TContext context manager, TComplex operators, TIter iteration, TGraph getters +# and TParameter arithmetic instantiations. ROOT_ADD_PYUNITTEST(pyroot_pyz_misc misc_pyz.py) # RVec and subclasses pythonizations diff --git a/bindings/pyroot/pythonizations/test/misc_pyz.py b/bindings/pyroot/pythonizations/test/misc_pyz.py index d732af025ba59..04fada64fc94c 100644 --- a/bindings/pyroot/pythonizations/test/misc_pyz.py +++ b/bindings/pyroot/pythonizations/test/misc_pyz.py @@ -372,5 +372,62 @@ def test_graphmultierrors(self): self.assertEqual(list(eyhigh), list(aeyh)) +class TParameterTemplateInstantiations(unittest.TestCase): + """ + Instantiating TParameter for a type without a dictionary (e.g. char) + from the interpreter used to fail with unresolved + TParameter::Class() and TParameter::Streamer(TBuffer&) symbols, + see https://github.com/root-project/root/issues/10724. Check that all + standard arithmetic types can be constructed, printed and serialized + from the interpreter. + """ + + # (type name, value passed to the constructor, value expected from GetVal()) + # cppyy maps the character types to Python str, so 42 comes back as "*" + instantiations = [ + ("bool", True, True), + ("char", 42, "*"), + ("signed char", 42, "*"), + ("unsigned char", 42, "*"), + ("short", 42, 42), + ("unsigned short", 42, 42), + ("int", 42, 42), + ("unsigned int", 42, 42), + ("long", 42, 42), + ("unsigned long", 42, 42), + ("long long", 42, 42), + ("unsigned long long", 42, 42), + ("float", 0.5, 0.5), + ("double", 0.5, 0.5), + ] + + def test_construct_and_print(self): + for typename, val, expected in self.instantiations: + with self.subTest(typename=typename): + param = ROOT.TParameter[typename]("p", val) + self.assertEqual(param.GetVal(), expected) + # Print and ls write to std::cout; exercise the code path + # (they used to be uncallable without arguments) + param.Print() + param.ls() + + def test_has_dictionary(self): + for typename, _, _ in self.instantiations: + with self.subTest(typename=typename): + tclass = ROOT.TClass.GetClass(f"TParameter<{typename}>") + self.assertIsNotNone(tclass) + self.assertTrue(tclass.HasDictionary()) + + def test_io_roundtrip(self): + for typename, val, expected in self.instantiations: + with self.subTest(typename=typename): + param = ROOT.TParameter[typename]("p", val) + memfile = ROOT.TMemFile("TParameterTemplateInstantiations.root", "recreate") + memfile.WriteObject(param, "p") + param_read = memfile.Get("p") + self.assertEqual(param_read.GetVal(), expected) + memfile.Close() + + if __name__ == '__main__': unittest.main() diff --git a/core/base/inc/LinkDef3.h b/core/base/inc/LinkDef3.h index 0ff51977efc32..cc8dc78bd7923 100644 --- a/core/base/inc/LinkDef3.h +++ b/core/base/inc/LinkDef3.h @@ -262,10 +262,18 @@ #pragma extra_include "Rtypes.h"; #pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; #pragma link C++ class TParameter+; #pragma link C++ class TParameter+; #pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; #pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; #pragma link C++ class TParameter+; +#pragma link C++ class TParameter+; #endif diff --git a/core/base/inc/TParameter.h b/core/base/inc/TParameter.h index a6a0edfd2dbf9..f52ae32b33d59 100644 --- a/core/base/inc/TParameter.h +++ b/core/base/inc/TParameter.h @@ -106,14 +106,14 @@ class TParameter : public TObject { return fName.CompareTo(obj->GetName()); } - void ls(Option_t *) const override + void ls(Option_t * = "") const override { // Print this parameter content TROOT::IndentLevel(); std::cout << "OBJ: " << IsA()->GetName() << "\t" << fName << " = " << fVal << std::endl; } - void Print(Option_t *) const override + void Print(Option_t * = "") const override { // Print this parameter content TROOT::IndentLevel();