Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/config params #5

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from
Open

Feature/config params #5

wants to merge 20 commits into from

Conversation

antons-it
Copy link
Collaborator

Enable plugins to request parameters from config file
Note: Do not merge yet, PR is currently for discussion only

@FussyDuck
Copy link

FussyDuck commented Feb 18, 2025

CLA assistant check
All committers have signed the CLA.

@codecov-commenter
Copy link

codecov-commenter commented Feb 18, 2025

Codecov Report

Attention: Patch coverage is 66.85393% with 118 lines in your changes missing coverage. Please review.

Project coverage is 40.76%. Comparing base (0355966) to head (22565c6).

Files with missing lines Patch % Lines
examples/example3.F90 0.00% 38 Missing ⚠️
examples/example2.cc 0.00% 21 Missing ⚠️
examples/example1.F90 0.00% 9 Missing ⚠️
examples/example1.cc 0.00% 9 Missing ⚠️
examples/example3.cc 0.00% 9 Missing ⚠️
src/plume/data/ModelData.cc 0.00% 8 Missing ⚠️
examples/example2.F90 0.00% 7 Missing ⚠️
examples/plugin_bar.cc 0.00% 6 Missing ⚠️
examples/plugin_foo.cc 0.00% 3 Missing ⚠️
src/plume/Configurable.cc 85.71% 2 Missing ⚠️
... and 4 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop       #5      +/-   ##
===========================================
+ Coverage    36.59%   40.76%   +4.17%     
===========================================
  Files           44       53       +9     
  Lines         1585     1820     +235     
  Branches        67       93      +26     
===========================================
+ Hits           580      742     +162     
- Misses        1005     1078      +73     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@antons-it antons-it marked this pull request as draft February 23, 2025 16:27
@antons-it antons-it marked this pull request as ready for review February 28, 2025 07:58
@antons-it antons-it self-assigned this Feb 28, 2025
// 1) in this case, we can check that each contained plugin has a valid configuration
if (this->config().has("plugins")) {
try {
auto pconfigs = this->config().getSubConfigurations("plugins");
Copy link

@cducher cducher Mar 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are lookups methods on data types now in eckit, which could be used to avoid the try/catch group (see here) but I don't think there is a release that contains these changes at the moment. I am quite heavily using them as well, do you think we could ask for a release ? This would change to something like:

if (!this->config().isSubConfigurationList("plugins")) {
    throw eckit::BadValue("ManagerConfig: plugins must be a list of configurations", Here());
}

This way we can safely make the call to getSubConfigurations in the for loop. What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to the changes that introduce reflection, @cducher ? I thought they have been merged/released already...

if (group_satisfied) {
eckit::Log::info() << " ---> Parameter Group Accepted!" << std::endl;
for (const auto& param : params) {
if (std::find_if(allRequestedParams.begin(), allRequestedParams.end(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe that's where using a set or unordered_set would help keep things a bit simpler and more efficient since you're not interested in duplicates. Then you can recast it as a vector in your return. Since you're also not interested in the result of the insertion, this for loop can become:

for (const auto& param: params) {
    allRequestedParams.insert(param.getString("name"));
}

@@ -50,11 +54,14 @@ CheckedConfigurable::~CheckedConfigurable() {

}

bool CheckedConfigurable::isValid(const eckit::Configuration& config, const std::vector<std::string> essentialKeys, const eckit::Configuration& options) {
bool CheckedConfigurable::isValid(const eckit::Configuration& config,
const std::vector<std::string> essentialKeys,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know where these keys are coming from, but we may use a std::unordered_set<std::string> (https://en.cppreference.com/w/cpp/container/unordered_set) in general???

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, std::set (or std::unordered_set) seem to make more sense. Also, pass by const ref.

Copy link
Collaborator

@dsarmany dsarmany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this. It is thorough work. Many thanks especially for the tests and examples; they will be very useful.

See my comments. They are mostly about style, clarity and simplification.

class Negotiator {
public:

Negotiator();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define this as default or not at all (it will be synthetised).

* @param config_params
* @return PluginDecision
*/
PluginDecision negotiate(const Protocol& offers, const Protocol& requires, const std::vector<eckit::LocalConfiguration>& config_params);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a single constructor with a default third parameter?

// 1) Check requested parameters (from the plugin)
// if ANY one of these parameters is not offered, the plugin is rejected
eckit::Log::info() << "Requesting Parameters: [";
for (int i = 0; i < requested_params.size(); i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use range-based for loops or even an algorithm.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or you can keep the current way and do the printing a bit more elegantly by looping only up to size() -1 and print the last element in the same statement as the "]". That way, the ugly 'if' in the body of the for loop can be avoided.

CheckedConfigurable::CheckedConfigurable(const eckit::Configuration& config, const std::vector<std::string> essentialKeys, const eckit::Configuration& options) : Configurable{config} {
if (!isValid(config, essentialKeys, options)) {
CheckedConfigurable::CheckedConfigurable(const eckit::Configuration& config,
const std::vector<std::string> essentialKeys,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to pass these by const ref.

@@ -50,11 +54,14 @@ CheckedConfigurable::~CheckedConfigurable() {

}

bool CheckedConfigurable::isValid(const eckit::Configuration& config, const std::vector<std::string> essentialKeys, const eckit::Configuration& options) {
bool CheckedConfigurable::isValid(const eckit::Configuration& config,
const std::vector<std::string> essentialKeys,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, std::set (or std::unordered_set) seem to make more sense. Also, pass by const ref.

private:

// internal Plugin ptr
Plugin* pluginPtr_;

// store the plugin configuration
PluginConfig config_;

// internal PluginCore ptr
PluginCore* plugincorePtr_;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be a std::unique_ptr? Who owns this object?


CASE("test_manager_configuration") {

const char* mgr_configstr_valid = R"YAML({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would define this as an std::string here already, but no big deal obviously...

@@ -35,6 +35,20 @@ PluginCoreBar::PluginCoreBar(const eckit::Configuration& conf) : PluginCore(conf
PluginCoreBar::~PluginCoreBar() {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about destructors declaration/definition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants