__init__.py (scons-4.2.0) | : | __init__.py (SCons-4.3.0) | ||
---|---|---|---|---|
skipping to change at line 46 | skipping to change at line 46 | |||
from .EnumVariable import EnumVariable # okay | from .EnumVariable import EnumVariable # okay | |||
from .ListVariable import ListVariable # naja | from .ListVariable import ListVariable # naja | |||
from .PackageVariable import PackageVariable # naja | from .PackageVariable import PackageVariable # naja | |||
from .PathVariable import PathVariable # okay | from .PathVariable import PathVariable # okay | |||
class Variables: | class Variables: | |||
""" | """ | |||
Holds all the options, updates the environment with the variables, | Holds all the options, updates the environment with the variables, | |||
and renders the help text. | and renders the help text. | |||
If is_global is True, this is a singleton, create only once. | If *is_global* is true, this is a singleton, create only once. | |||
Args: | Args: | |||
files (optional): List of option configuration files to load | files (optional): List of option configuration files to load | |||
(backward compatibility). If a single string is passed it is | (backward compatibility). If a single string is passed it is | |||
automatically placed in a file list (Default value = None) | automatically placed in a file list (Default value = None) | |||
args (optional): dictionary to override values set from *files*. | args (optional): dictionary to override values set from *files*. | |||
(Default value = None) | (Default value = None) | |||
is_global (optional): global instance? (Default value = True) | is_global (optional): global instance? (Default value = True) | |||
""" | """ | |||
instance = None | instance = None | |||
def __init__(self, files=None, args=None, is_global=True): | def __init__(self, files=None, args=None, is_global=True): | |||
if args is None: | if args is None: | |||
args = {} | args = {} | |||
self.options = [] | self.options = [] | |||
self.args = args | self.args = args | |||
if not SCons.Util.is_List(files): | if not SCons.Util.is_List(files): | |||
if files: | if files: | |||
files = [ files ] | files = [files,] | |||
else: | else: | |||
files = [] | files = [] | |||
self.files = files | self.files = files | |||
self.unknown = {} | self.unknown = {} | |||
# create the singleton instance | # create the singleton instance | |||
if is_global: | if is_global: | |||
self = Variables.instance | self = Variables.instance | |||
if not Variables.instance: | if not Variables.instance: | |||
Variables.instance=self | Variables.instance=self | |||
def _do_add(self, key, help="", default=None, validator=None, converter=None ): | def _do_add(self, key, help="", default=None, validator=None, converter=None , **kwargs) -> None: | |||
class Variable: | class Variable: | |||
pass | pass | |||
option = Variable() | option = Variable() | |||
# if we get a list or a tuple, we take the first element as the | # If we get a list or a tuple, we take the first element as the | |||
# option key and store the remaining in aliases. | # option key and store the remaining in aliases. | |||
if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): | if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): | |||
option.key = key[0] | option.key = key[0] | |||
option.aliases = key[1:] | option.aliases = list(key[1:]) | |||
else: | else: | |||
option.key = key | option.key = key | |||
option.aliases = [ key ] | # TODO: normalize to not include key in aliases. Currently breaks te | |||
sts. | ||||
option.aliases = [key,] | ||||
if not SCons.Environment.is_valid_construction_var(option.key): | ||||
raise SCons.Errors.UserError("Illegal Variables key `%s'" % str(opti | ||||
on.key)) | ||||
option.help = help | option.help = help | |||
option.default = default | option.default = default | |||
option.validator = validator | option.validator = validator | |||
option.converter = converter | option.converter = converter | |||
self.options.append(option) | self.options.append(option) | |||
# options might be added after the 'unknown' dict has been set up, | # options might be added after the 'unknown' dict has been set up, | |||
# so we remove the key and all its aliases from that dict | # so we remove the key and all its aliases from that dict | |||
for alias in list(option.aliases) + [ option.key ]: | for alias in option.aliases + [option.key,]: | |||
if alias in self.unknown: | if alias in self.unknown: | |||
del self.unknown[alias] | del self.unknown[alias] | |||
def keys(self): | def keys(self) -> list: | |||
""" | """Returns the keywords for the options.""" | |||
Returns the keywords for the options | ||||
""" | ||||
return [o.key for o in self.options] | return [o.key for o in self.options] | |||
def Add(self, key, help="", default=None, validator=None, converter=None, ** | def Add(self, key, *args, **kwargs) -> None: | |||
kw): | r""" Add an option. | |||
r"""Add an option. | ||||
Args: | Args: | |||
key: the name of the variable, or a list or tuple of arguments | key: the name of the variable, or a 5-tuple (or list). | |||
help: optional help text for the options (Default value = "") | If a tuple, and there are no additional arguments, | |||
default: optional default value for option (Default value = None) | the tuple is unpacked into help, default, validator, converter. | |||
validator: optional function called to validate the option's value | If there are additional arguments, the first word of the tuple | |||
(Default value = None) | is taken as the key, and the remainder as aliases. | |||
converter: optional function to be called to convert the option's | \*args: optional positional arguments | |||
value before putting it in the environment. (Default value = None) | help: optional help text for the options (Default value = "") | |||
\*\*kw: keyword args, unused. | default: optional default value for option (Default value = None) | |||
validator: optional function called to validate the option's value | ||||
(Default value = None) | ||||
converter: optional function to be called to convert the option's | ||||
value before putting it in the environment. (Default value = None) | ||||
\*\*kwargs: keyword args, can be the arguments from \*args or | ||||
arbitrary kwargs used by a variable itself | ||||
""" | """ | |||
if SCons.Util.is_List(key) or isinstance(key, tuple): | if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): | |||
self._do_add(*key) | if not (len(args) or len(kwargs)): | |||
return | return self._do_add(*key) | |||
if not SCons.Util.is_String(key) or \ | ||||
not SCons.Environment.is_valid_construction_var(key): | ||||
raise SCons.Errors.UserError("Illegal Variables.Add() key `%s'" | ||||
% str(key)) | ||||
self._do_add(key, help, default, validator, converter) | return self._do_add(key, *args, **kwargs) | |||
def AddVariables(self, *optlist): | def AddVariables(self, *optlist) -> None: | |||
""" | """ Add a list of options. | |||
Add a list of options. | ||||
Each list element is a tuple/list of arguments to be passed on | Each list element is a tuple/list of arguments to be passed on | |||
to the underlying method for adding options. | to the underlying method for adding options. | |||
Example:: | Example:: | |||
opt.AddVariables( | opt.AddVariables( | |||
('debug', '', 0), | ('debug', '', 0), | |||
('CC', 'The C compiler'), | ('CC', 'The C compiler'), | |||
('VALIDATE', 'An option for testing validation', 'notset', valid ator, None), | ('VALIDATE', 'An option for testing validation', 'notset', valid ator, None), | |||
) | ) | |||
""" | """ | |||
for o in optlist: | for o in optlist: | |||
self._do_add(*o) | self._do_add(*o) | |||
def Update(self, env, args=None): | def Update(self, env, args=None) -> None: | |||
""" | """ Update an environment with the option variables. | |||
Update an environment with the option variables. | ||||
env - the environment to update. | Args: | |||
env: the environment to update. | ||||
args: [optional] a dictionary of keys and values to update | ||||
in *env*. If omitted, uses the variables from the commandline. | ||||
""" | """ | |||
values = {} | values = {} | |||
# first set the defaults: | # first set the defaults: | |||
for option in self.options: | for option in self.options: | |||
if option.default is not None: | if option.default is not None: | |||
values[option.key] = option.default | values[option.key] = option.default | |||
# next set the value specified in the options file | # next set the value specified in the options file | |||
skipping to change at line 193 | skipping to change at line 197 | |||
del sys.path[0] | del sys.path[0] | |||
del values['__name__'] | del values['__name__'] | |||
# set the values specified on the command line | # set the values specified on the command line | |||
if args is None: | if args is None: | |||
args = self.args | args = self.args | |||
for arg, value in args.items(): | for arg, value in args.items(): | |||
added = False | added = False | |||
for option in self.options: | for option in self.options: | |||
if arg in list(option.aliases) + [ option.key ]: | if arg in option.aliases + [option.key,]: | |||
values[option.key] = value | values[option.key] = value | |||
added = True | added = True | |||
if not added: | if not added: | |||
self.unknown[arg] = value | self.unknown[arg] = value | |||
# put the variables in the environment: | # put the variables in the environment: | |||
# (don't copy over variables that are not declared as options) | # (don't copy over variables that are not declared as options) | |||
for option in self.options: | for option in self.options: | |||
try: | try: | |||
env[option.key] = values[option.key] | env[option.key] = values[option.key] | |||
except KeyError: | except KeyError: | |||
pass | pass | |||
# Call the convert functions: | # apply converters | |||
for option in self.options: | for option in self.options: | |||
if option.converter and option.key in values: | if option.converter and option.key in values: | |||
value = env.subst('${%s}'%option.key) | value = env.subst('${%s}'%option.key) | |||
try: | try: | |||
try: | try: | |||
env[option.key] = option.converter(value) | env[option.key] = option.converter(value) | |||
except TypeError: | except TypeError: | |||
env[option.key] = option.converter(value, env) | env[option.key] = option.converter(value, env) | |||
except ValueError as x: | except ValueError as x: | |||
raise SCons.Errors.UserError('Error converting option: %s\n% s'%(option.key, x)) | raise SCons.Errors.UserError('Error converting option: %s\n% s'%(option.key, x)) | |||
# Finally validate the values: | # apply validators | |||
for option in self.options: | for option in self.options: | |||
if option.validator and option.key in values: | if option.validator and option.key in values: | |||
option.validator(option.key, env.subst('${%s}'%option.key), env) | option.validator(option.key, env.subst('${%s}'%option.key), env) | |||
def UnknownVariables(self): | def UnknownVariables(self) -> dict: | |||
""" | """ Returns unknown variables. | |||
Returns any options in the specified arguments lists that | ||||
were not known, declared options in this object. | Identifies options that were not known, declared options in this object. | |||
""" | """ | |||
return self.unknown | return self.unknown | |||
def Save(self, filename, env): | def Save(self, filename, env) -> None: | |||
""" | """ Save the options to a file. | |||
Saves all the options in the given file. This file can | ||||
then be used to load the options next run. This can be used | Saves all the options which have non-default settings | |||
to create an option cache file. | to the given file as Python expressions. This file can | |||
then be used to load the options for a subsequent run. | ||||
This can be used to create an option cache file. | ||||
filename - Name of the file to save into | Args: | |||
env - the environment get the option values from | filename: Name of the file to save into | |||
env: the environment get the option values from | ||||
""" | """ | |||
# Create the file and write out the header | # Create the file and write out the header | |||
try: | try: | |||
fh = open(filename, 'w') | with open(filename, 'w') as fh: | |||
try: | ||||
# Make an assignment in the file for each option | # Make an assignment in the file for each option | |||
# within the environment that was assigned a value | # within the environment that was assigned a value | |||
# other than the default. | # other than the default. We don't want to save the | |||
# ones set to default: in case the SConscript settings | ||||
# change you would then pick up old defaults. | ||||
for option in self.options: | for option in self.options: | |||
try: | try: | |||
value = env[option.key] | value = env[option.key] | |||
try: | try: | |||
prepare = value.prepare_to_store | prepare = value.prepare_to_store | |||
except AttributeError: | except AttributeError: | |||
try: | try: | |||
eval(repr(value)) | eval(repr(value)) | |||
except KeyboardInterrupt: | except KeyboardInterrupt: | |||
raise | raise | |||
except: | except: | |||
# Convert stuff that has a repr() that | # Convert stuff that has a repr() that | |||
# cannot be evaluated into a string | # cannot be evaluated into a string | |||
value = SCons.Util.to_String(value) | value = SCons.Util.to_String(value) | |||
else: | else: | |||
value = prepare() | value = prepare() | |||
defaultVal = env.subst(SCons.Util.to_String(option.defau lt)) | defaultVal = env.subst(SCons.Util.to_String(option.defau lt)) | |||
if option.converter: | if option.converter: | |||
defaultVal = option.converter(defaultVal) | try: | |||
defaultVal = option.converter(defaultVal) | ||||
except TypeError: | ||||
defaultVal = option.converter(defaultVal, env) | ||||
if str(env.subst('${%s}' % option.key)) != str(defaultVa l): | if str(env.subst('${%s}' % option.key)) != str(defaultVa l): | |||
fh.write('%s = %s\n' % (option.key, repr(value))) | fh.write('%s = %s\n' % (option.key, repr(value))) | |||
except KeyError: | except KeyError: | |||
pass | pass | |||
finally: | ||||
fh.close() | ||||
except IOError as x: | except IOError as x: | |||
raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) | raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) | |||
def GenerateHelpText(self, env, sort=None): | def GenerateHelpText(self, env, sort=None) -> str: | |||
""" | """ Generate the help text for the options. | |||
Generate the help text for the options. | ||||
env - an environment that is used to get the current values | Args: | |||
of the options. | env: an environment that is used to get the current values | |||
cmp - Either a function as follows: The specific sort function should ta | of the options. | |||
ke two arguments and return -1, 0 or 1 | cmp: Either a comparison function used for sorting | |||
or a boolean to indicate if it should be sorted. | (must take two arguments and return -1, 0 or 1) | |||
or a boolean to indicate if it should be sorted. | ||||
""" | """ | |||
if callable(sort): | if callable(sort): | |||
options = sorted(self.options, key=cmp_to_key(lambda x,y: sort(x.key ,y.key))) | options = sorted(self.options, key=cmp_to_key(lambda x, y: sort(x.ke y, y.key))) | |||
elif sort is True: | elif sort is True: | |||
options = sorted(self.options, key=lambda x: x.key) | options = sorted(self.options, key=lambda x: x.key) | |||
else: | else: | |||
options = self.options | options = self.options | |||
def format(opt, self=self, env=env): | def format_opt(opt, self=self, env=env) -> str: | |||
if opt.key in env: | if opt.key in env: | |||
actual = env.subst('${%s}' % opt.key) | actual = env.subst('${%s}' % opt.key) | |||
else: | else: | |||
actual = None | actual = None | |||
return self.FormatVariableHelpText(env, opt.key, opt.help, opt.defau lt, actual, opt.aliases) | return self.FormatVariableHelpText(env, opt.key, opt.help, opt.defau lt, actual, opt.aliases) | |||
lines = [_f for _f in map(format, options) if _f] | ||||
lines = [_f for _f in map(format_opt, options) if _f] | ||||
return ''.join(lines) | return ''.join(lines) | |||
format = '\n%s: %s\n default: %s\n actual: %s\n' | fmt = '\n%s: %s\n default: %s\n actual: %s\n' | |||
format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' | aliasfmt = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' | |||
def FormatVariableHelpText(self, env, key, help, default, actual, aliases=[] | def FormatVariableHelpText(self, env, key, help, default, actual, aliases=No | |||
): | ne) -> str: | |||
if aliases is None: | ||||
aliases = [] | ||||
# Don't display the key name itself as an alias. | # Don't display the key name itself as an alias. | |||
aliases = [a for a in aliases if a != key] | aliases = [a for a in aliases if a != key] | |||
if len(aliases)==0: | if aliases: | |||
return self.format % (key, help, default, actual) | return self.aliasfmt % (key, help, default, actual, aliases) | |||
else: | else: | |||
return self.format_ % (key, help, default, actual, aliases) | return self.fmt % (key, help, default, actual) | |||
# Local Variables: | # Local Variables: | |||
# tab-width:4 | # tab-width:4 | |||
# indent-tabs-mode:nil | # indent-tabs-mode:nil | |||
# End: | # End: | |||
# vim: set expandtab tabstop=4 shiftwidth=4: | # vim: set expandtab tabstop=4 shiftwidth=4: | |||
End of changes. 35 change blocks. | ||||
80 lines changed or deleted | 89 lines changed or added |