From 79070cb1858849c3933434838f46c45238c8aac3 Mon Sep 17 00:00:00 2001 From: Barthelemy Date: Tue, 14 Oct 2025 09:06:40 +0200 Subject: [PATCH 1/3] [QC-1297] CustomParameters support for nested configuration --- .../include/QualityControl/CustomParameters.h | 24 +++++- Framework/src/CustomParameters.cxx | 23 +++++- Framework/test/testCustomParameters.cxx | 80 +++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/Framework/include/QualityControl/CustomParameters.h b/Framework/include/QualityControl/CustomParameters.h index 6373c246e7..dd1020ed2e 100644 --- a/Framework/include/QualityControl/CustomParameters.h +++ b/Framework/include/QualityControl/CustomParameters.h @@ -108,12 +108,34 @@ class CustomParameters /** * Return the optional value for the given key, runType and beamType. * If no key is found for the runType and the Beamtype, the fallback is to substitute with "default", first for beamType then for runType. - * Empty is only returned if the key could not be found in any combination of the provided run and beam types with "default". * @param key + * Empty is only returned if the key could not be found in any combination of the provided run and beam types with "default". + * @param key * @param activity * @return an optional with the value for the given key and for the given activity. */ std::optional atOptional(const std::string& key, const Activity& activity) const; + /** + * Return the ptree representation of the optional value for the given key, runType and beamType. + * If no key is found for the runType and the Beamtype, the fallback is to substitute with "default", first for beamType then for runType. + * Empty is only returned if the key could not be found in any combination of the provided run and beam types with "default". + * @param key + * @param runType + * @param beamType + * @return an optional with the ptree representation of the value for the given key, runType and beamType or empty if not found. + */ + std::optional getOptionalPtree(const std::string& key, const std::string& runType = "default", const std::string& beamType = "default") const; + + /** + * Return the ptree representation of the optional value for the given key, runType and beamType. + * If no key is found for the runType and the Beamtype, the fallback is to substitute with "default", first for beamType then for runType. + * Empty is only returned if the key could not be found in any combination of the provided run and beam types with "default". + * @param key + * @param activity + * @return an optional with the ptree representation of the value for the given key, runType and beamType or empty if not found. + */ + std::optional getOptionalPtree(const std::string& key, const Activity& activity) const; + /** * Return the value for the given key, runType and beamType (the two latter optional). If it does not exist, returns the default value if provided or an empty string. * @param key diff --git a/Framework/src/CustomParameters.cxx b/Framework/src/CustomParameters.cxx index e32c528f9e..6cb363c127 100644 --- a/Framework/src/CustomParameters.cxx +++ b/Framework/src/CustomParameters.cxx @@ -10,11 +10,11 @@ // or submit itself to any jurisdiction. #include "QualityControl/CustomParameters.h" -#include #include #include #include #include +#include namespace o2::quality_control::core { @@ -96,6 +96,27 @@ std::optional CustomParameters::atOptional(const std::string& key, return atOptional(key, activity.mType, activity.mBeamType); } +std::optional CustomParameters::getOptionalPtree(const std::string& key, const std::string& runType , const std::string& beamType ) const +{ + std::optional result = std::nullopt; + + // get the text and make it a ptree + auto text = atOptional(key, runType, beamType); + if (text.has_value()) { + std::stringstream listingAsStringStream{ text.value() }; + boost::property_tree::ptree pt; + boost::property_tree::read_json(listingAsStringStream, pt); + result = pt; + } + + return result; +} + +std::optional CustomParameters::getOptionalPtree(const std::string& key, const Activity& activity) const +{ + return getOptionalPtree(key, activity.mType, activity.mBeamType); +} + std::string CustomParameters::atOrDefaultValue(const std::string& key, std::string defaultValue, const std::string& runType, const std::string& beamType) const { try { diff --git a/Framework/test/testCustomParameters.cxx b/Framework/test/testCustomParameters.cxx index 70678488c2..7ffd4f7ef0 100644 --- a/Framework/test/testCustomParameters.cxx +++ b/Framework/test/testCustomParameters.cxx @@ -265,3 +265,83 @@ TEST_CASE("test_getAllDefaults") auto result = cp.getAllDefaults(); CHECK(result.size() == 0); } + +TEST_CASE("test_getOptionalPtree") +{ + CustomParameters cp; + cp.set("key", R""""( +[ + { + "name": "mean_of_histogram", + "title": "Mean trend of the example histogram", + "graphAxisLabel": "Mean X:time", + "graphYRange": "0:10000", + "graphs" : [ + { + "name": "mean_trend", + "title": "mean trend", + "varexp": "example.mean:time", + "selection": "", + "option": "*L PLC PMC" + }, { + "name": "mean_trend_1000", + "title": "mean trend + 1000", + "varexp": "example.mean + 1000:time", + "selection": "", + "option": "* PMC", + "graphErrors": "1:200" + } + ] + }, + { + "name": "histogram_of_means", + "title": "Distribution of mean values in the example histogram", + "graphs" : [{ + "varexp": "example.mean", + "selection": "", + "option": "" + }] + }, + { + "name": "correlation_mean_stddev", + "title": "Correlation between the mean and stddev of the example histogram", + "graphs" : [{ + "varexp": "example.mean:example.stddev", + "selection": "", + "option": "*" + }] + }, + { + "name": "correlation_stddev_entries", + "title": "Correlation between the stddev and entries of the example histogram", + "graphAxisLabel": "stddev:entries", + "graphs" : [{ + "varexp": "example.stddev:example.entries", + "selection": "", + "option": "*" + }] + }, + { + "name": "example_quality", + "title": "Trend of the example histogram's quality", + "graphs" : [{ + "varexp": "QcCheck.name:time", + "selection": "", + "option": "*" + }] + } + ] + )""""); + auto pt = cp.getOptionalPtree("key"); + + std::size_t number_plots = std::distance(pt->begin(), pt->end()); + CHECK(number_plots == 5); + + auto first_plot = pt->begin()->second; + CHECK(first_plot.get("name") == "mean_of_histogram"); + auto graphs = first_plot.get_child("graphs"); + CHECK(graphs.size() == 2); + + auto last_plot = std::prev(pt->end())->second; + CHECK(last_plot.get("name") == "example_quality"); +} \ No newline at end of file From 0898190147255ed51e141ea29c0e87827cab722a Mon Sep 17 00:00:00 2001 From: Barthelemy Date: Tue, 14 Oct 2025 09:22:04 +0200 Subject: [PATCH 2/3] fix the case where it is not parsable. --- Framework/src/CustomParameters.cxx | 6 +++- Framework/test/testCustomParameters.cxx | 38 +++++++++++-------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Framework/src/CustomParameters.cxx b/Framework/src/CustomParameters.cxx index 6cb363c127..2d8f2ba6f5 100644 --- a/Framework/src/CustomParameters.cxx +++ b/Framework/src/CustomParameters.cxx @@ -105,7 +105,11 @@ std::optional CustomParameters::getOptionalPtree(co if (text.has_value()) { std::stringstream listingAsStringStream{ text.value() }; boost::property_tree::ptree pt; - boost::property_tree::read_json(listingAsStringStream, pt); + try { + boost::property_tree::read_json(listingAsStringStream, pt); + } catch (const boost::property_tree::json_parser::json_parser_error& e) { + return result; + } result = pt; } diff --git a/Framework/test/testCustomParameters.cxx b/Framework/test/testCustomParameters.cxx index 7ffd4f7ef0..5d7eccfec7 100644 --- a/Framework/test/testCustomParameters.cxx +++ b/Framework/test/testCustomParameters.cxx @@ -269,7 +269,7 @@ TEST_CASE("test_getAllDefaults") TEST_CASE("test_getOptionalPtree") { CustomParameters cp; - cp.set("key", R""""( + std::string content = R""""( [ { "name": "mean_of_histogram", @@ -302,25 +302,6 @@ TEST_CASE("test_getOptionalPtree") "option": "" }] }, - { - "name": "correlation_mean_stddev", - "title": "Correlation between the mean and stddev of the example histogram", - "graphs" : [{ - "varexp": "example.mean:example.stddev", - "selection": "", - "option": "*" - }] - }, - { - "name": "correlation_stddev_entries", - "title": "Correlation between the stddev and entries of the example histogram", - "graphAxisLabel": "stddev:entries", - "graphs" : [{ - "varexp": "example.stddev:example.entries", - "selection": "", - "option": "*" - }] - }, { "name": "example_quality", "title": "Trend of the example histogram's quality", @@ -331,11 +312,13 @@ TEST_CASE("test_getOptionalPtree") }] } ] - )""""); + )""""; + cp.set("key", content); auto pt = cp.getOptionalPtree("key"); + CHECK(pt.has_value()); std::size_t number_plots = std::distance(pt->begin(), pt->end()); - CHECK(number_plots == 5); + CHECK(number_plots == 3); auto first_plot = pt->begin()->second; CHECK(first_plot.get("name") == "mean_of_histogram"); @@ -344,4 +327,15 @@ TEST_CASE("test_getOptionalPtree") auto last_plot = std::prev(pt->end())->second; CHECK(last_plot.get("name") == "example_quality"); + + // test for failure + CustomParameters cp2; + cp2.set("key", "blabla"); + auto pt2 = cp2.getOptionalPtree("key"); + CHECK(!pt2.has_value()); + + // try to get it as text + auto text = cp.atOptional("key"); + CHECK(text.has_value()); + CHECK(text == content); } \ No newline at end of file From 46ba1047f7cdd62bc2e415dab85b90ba7a308ec7 Mon Sep 17 00:00:00 2001 From: Piotr Konopka Date: Wed, 22 Oct 2025 13:57:15 +0200 Subject: [PATCH 3/3] clang-format --- .../include/QualityControl/CustomParameters.h | 14 +++++++------- Framework/src/CustomParameters.cxx | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Framework/include/QualityControl/CustomParameters.h b/Framework/include/QualityControl/CustomParameters.h index dd1020ed2e..bb0d251903 100644 --- a/Framework/include/QualityControl/CustomParameters.h +++ b/Framework/include/QualityControl/CustomParameters.h @@ -127,13 +127,13 @@ class CustomParameters std::optional getOptionalPtree(const std::string& key, const std::string& runType = "default", const std::string& beamType = "default") const; /** - * Return the ptree representation of the optional value for the given key, runType and beamType. - * If no key is found for the runType and the Beamtype, the fallback is to substitute with "default", first for beamType then for runType. - * Empty is only returned if the key could not be found in any combination of the provided run and beam types with "default". - * @param key - * @param activity - * @return an optional with the ptree representation of the value for the given key, runType and beamType or empty if not found. - */ + * Return the ptree representation of the optional value for the given key, runType and beamType. + * If no key is found for the runType and the Beamtype, the fallback is to substitute with "default", first for beamType then for runType. + * Empty is only returned if the key could not be found in any combination of the provided run and beam types with "default". + * @param key + * @param activity + * @return an optional with the ptree representation of the value for the given key, runType and beamType or empty if not found. + */ std::optional getOptionalPtree(const std::string& key, const Activity& activity) const; /** diff --git a/Framework/src/CustomParameters.cxx b/Framework/src/CustomParameters.cxx index 2d8f2ba6f5..d4cb044770 100644 --- a/Framework/src/CustomParameters.cxx +++ b/Framework/src/CustomParameters.cxx @@ -96,7 +96,7 @@ std::optional CustomParameters::atOptional(const std::string& key, return atOptional(key, activity.mType, activity.mBeamType); } -std::optional CustomParameters::getOptionalPtree(const std::string& key, const std::string& runType , const std::string& beamType ) const +std::optional CustomParameters::getOptionalPtree(const std::string& key, const std::string& runType, const std::string& beamType) const { std::optional result = std::nullopt;