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

Fixes issue where command line ignored if YAML exists #62

Closed
wants to merge 8 commits into from

Conversation

maxvonhippel
Copy link
Contributor

This PR fixes the issue identified by @sishijing (#61) where if you try to use both command line args and a YAML file the command line args are ignored. It prioritizes command line args over YAML, so if you set a value in both YAML and the command line, the command line value will be the one used. This makes sense to me since if you set a value explicitly in the command line it seems likely that is the value you want and you probably just forgot to remove the other value from the YAML.

I also set the default values for prior means and starting carbonicity to 0.38 per @tedvh's request in the Settings.cpp ternaries. I am not sure how best to set these in the actual cluster definition. They appear to be right already in the included default YAML file, and reading Cluster.cpp and Cluster.hpp, I don't see a clear way to set these defaults in their original definition. That said, if you have a suggestion for where to look, let me know and I'll give it a shot.

… Cleaned up code accordingly and tested. Removed compiled code. Not sure how to add binaries to a .gitignore but I think it would be a good idea to do so.
Signed-off-by: Max von Hippel <maxvonhippel1996@gmail.com>
Signed-off-by: Max von Hippel <maxvonhippel1996@gmail.com>
Signed-off-by: Max von Hippel <maxvonhippel1996@gmail.com>
Signed-off-by: Max von Hippel <maxvonhippel1996@gmail.com>
@tedvh
Copy link
Collaborator

tedvh commented Jan 6, 2017 via email

Signed-off-by: Max von Hippel <maxvonhippel1996@gmail.com>
@argiopetech
Copy link
Owner

The problem this is supposed to fix (#61) is solved by 324669b.

@argiopetech argiopetech closed this Jan 7, 2017
@maxvonhippel
Copy link
Contributor Author

Thanks @argiopetech . That said, do you disagree that we should have the ternaries like in this commit? Because right now (as I said in my comments above) the command line args are ignored if the same argument appears in the YAML, and it seems like the command line should be prioritized over the YAML.

@tedvh
Copy link
Collaborator

tedvh commented Jan 7, 2017 via email

@argiopetech
Copy link
Owner

We actually have a much cleaner method of handling this already in the code. You'll note that every call to fromYaml happens in a code block something like the below (taken directly from singlePopMcmc/mpiMcmc.cpp):

        settings.fromCLI (argc, argv);

        if (!settings.files.config.empty())
        {
            settings.fromYaml (settings.files.config);
        }
        else
        {
            settings.fromYaml ("base9.yaml");
        }

        settings.fromCLI (argc, argv);

The first call to fromCLI loads the --config parameter which may specify a YAML file, along with doing some short-circuit exiting for things like the --version flag. If the YAML file is provided we use that, if not there's a default of base9.yaml. Running fromYAML overrides all non-CLI-only commands, so we then have to call fromCLI again to override the YAML defaults.

@argiopetech
Copy link
Owner

argiopetech commented Jan 7, 2017

I do think that this could be encapsulated into one function

void Settings::loadSettings(int argc, char* argv[], const std::string& defaultFile="base9.yaml")
{
    fromCLI (argc, argv);

    if (!files.config.empty())
    {
        fromYaml (files.config);
    }
    else
    {
        fromYaml (defaultFile);
    }

    fromCLI (argc, argv);
}

so we could just call settings.loadSettings(argc, argv) in the various applications while maintaining the functionality to have a different default YAML files for a specific application (e.g., settings.loadSettings(argc, argv, "singlePopMcmc.yaml").

The only reason it isn't this way already is because it was implemented piece by piece historically (CLI functionality came after YAML files), and it hasn't been broken since then (so I haven't changed it).

@argiopetech
Copy link
Owner

argiopetech commented Jan 7, 2017

I forgot to ask when this came up what ternaries are.

Ternaries are the if/then/else format formatted as such:

<conditional> ? <do if true> : <do if false>

which is equivalent to

if (<conditional>)
{
    <do if true>;
}
else
{
    <do if false>;
}

It's just a shortcut, but if overused or poorly formatted they can become very hard to read. I prefer to reserve them for conditional assignment, and I use them to this end several places in the code for brevity. As such, I have no issues with the way @maxvonhippel has used them here.

The goal was to have command-line args supercede anything in the yaml file.

This has been the case since the CLI functionality was implemented. The only reason it wasn't working for Shijing was that one of the command line flags he was using wasn't recognized because I had failed to implement it.

@argiopetech
Copy link
Owner

I went ahead and implemented the Settings::loadSettings() function and integrated it into all applications in 3dfadaa.

@maxvonhippel
Copy link
Contributor Author

You're right that's infinitely more elegant. Definitely feel foolish now for writing a billion ternary statements when I could have just switched the order of the settings.

@maxvonhippel
Copy link
Contributor Author

That said, we should change the getOrRequest behavior so that it checks YAML, checks

@tedvh
Copy link
Collaborator

tedvh commented Jan 7, 2017 via email

@maxvonhippel
Copy link
Contributor Author

Sorry, on my iPhone. So it checks YAML, then command line, then asks for anything that's missing. Rather than YAML, ask for missing stuff, then command line.

@argiopetech
Copy link
Owner

You're right that's infinitely more elegant. Definitely feel foolish now for writing a billion ternary statements when I could have just switched the order of the settings.

No worries, a big part of that was reliant on my latency... Apologies again. Had I gotten to you before the code we could have nipped this in the bud.

That said, we should change the getOrRequest behavior so that it ... checks YAML, then command line, then asks for anything that's missing. Rather than YAML, ask for missing stuff, then command line.

Ted may be a better person to ask than me on this one. I'm of the opinion that the getOrRequest functionality is for cases where we (the code maintainers) have updated the YAML specification but the end user has not updated their local YAML file. The case where an end user has overridden a required YAML setting from the command line without updating their YAML file should never happen. Adding logic to handle this potential edge case seems excessive to me.

@tedvh
Copy link
Collaborator

tedvh commented Jan 7, 2017 via email

@argiopetech
Copy link
Owner

I'm not sure what you (Elliot) mean by "The case where an end user has overridden a required YAML setting from the command line without updating their YAML file should never happen". If you mean that I might specify a parameter in the YAML file, but then run BASE9 with a different value for that same parameter from the command line, that will indeed happen. I do that when I want to run the same data set through BASE9 N times with different parameters and just have a script do this with changing command line arguments.

I mean that if I add a new parameter foo to the YAML file without telling you, and you therefore run BASE9 without updating your YAML file, it should ask you for a value for foo via Max's getOrRequest. There should very seldom be a case where you don't have foo in your YAML file but have used the theoretical --foo flag, such that Max's getOrRequest would trigger, but the value you specify to getOrRequest would then be overridden by the --foo flag you passed at the command line.

Basically, if that last thing were ever to happen, it's probably a sign that you have used an old version of your YAML file.

This also raises an interesting issue. Can we easily let users know that their yaml file is out of date? In the case you mention, Elliot, where BASE9 wants a parameter that isn't even listed in the yaml file, would there be an easy way to recognize that and throw a warning? Not a stop, just a warning?

That's pretty much what Max's code does now, in that it allows you to enter a value for that missing parameter and continue.

@tedvh
Copy link
Collaborator

tedvh commented Jan 7, 2017 via email

@argiopetech
Copy link
Owner

Done with 3106da6. The updated verbage for getOrRequest is:

No value was found in the YAML file for parameter 'pi'.
Please enter your desired value for this parameter: 3.1415

Notably, I've added the clarification for YAML, removes the newline after the colon (I tend to prefer same-line input unless the text line is very long), and uses cerr instead of cout to avoid potential issues with flushing.

@tedvh
Copy link
Collaborator

tedvh commented Jan 7, 2017 via email

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.

None yet

3 participants