scons icon indicating copy to clipboard operation
scons copied to clipboard

Check if option was set when default value is used

Open dmoody256 opened this issue 7 years ago • 6 comments

I sent this to the user mailing list and also wrote a stack overflow question: https://stackoverflow.com/questions/50396802/checking-if-arg-was-passed-when-default-is-set-with-python-optparse

In my case I am interested in num_jobs options, but this could apply to any option.

I want to determine if the option was set by the user even in the default case. So far I can only figure out how to do this by looking through the sys.argv, but considering that the option parser is already doing this, maybe it should save this information at the time it is parsing the args.

Since Scons already extends pythons optparse class, this should be pretty easy to add.

Here is how I did it by manually checking sys.argv:

###################################################
# Determine number of Jobs
# start by assuming num_jobs was not set
NUM_JOBS_SET = False
if GetOption("num_jobs") == 1:
    # if num_jobs is the default we need to check sys.argv
    # to see if the user happened to set the default
    for arg in sys.argv:
        if arg.startswith("-j") or arg.startswith("--jobs"):
            if arg == "-j" or arg == "--jobs":
                if(int(sys.argv[sys.argv.index(arg)+1]) == 1):
                    NUM_JOBS_SET = True
            else:
                if arg.startswith("-j"):
                    if(int(arg[2:]) == 1):
                        NUM_JOBS_SET = True
else:
    # user must have set something if it wasn't default
    NUM_JOBS_SET = True

# num_jobs wasn't specified so lets use the
# max number since the user doesn't seem to care
if not NUM_JOBS_SET:
    NUM_CPUS = get_num_cpus()
    print("Building with " + str(NUM_CPUS) + " parallel jobs")
    MAIN_ENV.SetOption("num_jobs", NUM_CPUS)
else:
    # user wants a certain number of jobs so do that
    print("Building with " + str(GetOption('num_jobs')) + " parallel jobs")

Here's how I did by using optparse:

###################################################
# Determine number of Jobs
# start by assuming num_jobs was not set
opts_no_defaults = optparse.Values()
parser = Parser(MAIN_ENV._get_major_minor_revision(SCons.__version__))
__, args = parser.parse_args(values=opts_no_defaults)
opts = optparse.Values(parser.get_default_values().__dict__)
opts._update_careful(opts_no_defaults.__dict__)

# num_jobs wasn't specificed so let use the
# max number since the user doesn't seem to care
if not hasattr(opts_no_defaults, parser.get_option('--jobs').dest):
    NUM_CPUS = get_num_cpus()
    ColorPrinter().InfoPrint("Building with " + str(NUM_CPUS) + " parallel jobs")
    MAIN_ENV.SetOption("num_jobs", NUM_CPUS)
else:
    # user wants a certain number of jobs so do that
    ColorPrinter().InfoPrint(
        "Building with " + str(GetOption('num_jobs')) + " parallel jobs")
  • Version of SCons: 3.0.1
  • Version of Python: any
  • Which python distribution if applicable: any
  • How you installed SCons: pip
  • What Platform are you on? Windows and Linux
  • Link to SCons Users thread discussing your issue: https://pairlist4.pair.net/pipermail/scons-users/2018-May/006946.html

dmoody256 avatar May 17 '18 20:05 dmoody256

Does the normal trick for this kind of thing work here? Make the default be None, and if the value is still None when processing, set the "real" default.

mwichmann avatar Jan 28 '19 15:01 mwichmann

SCons "knows" which source a value came from, since it walks through the list (cli param, SetOption, defaults from option definitions) in SConsValues.__getattr__, but it doesn't record or have a clean way to return that info. Maybe there's a way to solve that?

mwichmann avatar May 13 '21 16:05 mwichmann

I see there was a kind of solution in the linked StackOverflow article. Is there anything from that we can bring back to SCons itself? Or alternatively add as a recipe for someone else with the same need at https://scons-cookbook.readthedocs.io/en/latest ?

mwichmann avatar Jan 24 '22 22:01 mwichmann

Can't remember if this got mentioned somewhere else. How about creating an options object that holds the "real" defaults, and put dummy ones (some kind of sentinel) in the add_option calls; then add a processing step where if any options have the dummy default you fill them in from the defaults object - that way there's a difference between an option not set, and an option set by the user to the default value.

mwichmann avatar Jul 13 '22 14:07 mwichmann