summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2021-10-04 19:03:47 (GMT)
committerMats Wichmann <mats@linux.com>2021-10-07 22:56:15 (GMT)
commit9fde9654191ccc21873710143357c3ca580fe72b (patch)
tree76408922ef5dd74f6660128af02ac725db60de0f
parent43f775a78f1d78515654e72c1280b074fd4c1899 (diff)
downloadSCons-9fde9654191ccc21873710143357c3ca580fe72b.zip
SCons-9fde9654191ccc21873710143357c3ca580fe72b.tar.gz
SCons-9fde9654191ccc21873710143357c3ca580fe72b.tar.bz2
Tweak Variables incl. manpage, docstrings
* Added link anchors in variables-related funcs/methods, and link to them - these methods are not part of the generated link setup. * Clarified that vars set to defaults are not saved. * Updated docstrings in the Variables source (for API docs). * Added return-type annotations to Variables. * Fix for converter function possibly failing if it tries to access an environment. Fixes #2064. * Fixed up the behavior of aliases to variables, and added docu. Fixes #3869. * Fix PathIsDirCreate validator to catch permission problems. Fixes #2828 Signed-off-by: Mats Wichmann <mats@linux.com>
-rwxr-xr-xCHANGES.txt8
-rw-r--r--SCons/Variables/BoolVariable.py67
-rw-r--r--SCons/Variables/EnumVariable.py51
-rw-r--r--SCons/Variables/ListVariable.py74
-rw-r--r--SCons/Variables/PackageVariable.py81
-rw-r--r--SCons/Variables/PathVariable.py122
-rw-r--r--SCons/Variables/PathVariableTests.py16
-rw-r--r--SCons/Variables/VariablesTests.py96
-rw-r--r--SCons/Variables/__init__.py163
-rw-r--r--doc/man/scons.xml127
10 files changed, 453 insertions, 352 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 3e26ade..6a708e0 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -53,6 +53,14 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Added new sconsign filenames to skip_entry_list in Scanner/Dir.py
- Change SCons.Scanner.Base to ScannerBase. Old name kept as an alias
but is now unused in SCons itself.
+ - Call Variables option converter consistently - the converter should
+ have access to the env if it needs to (issue #2064).
+ - Fixed the variables Add() method to accept a tuple for the variable
+ name the same way AddVariables() does (issue #3869).
+ - The premade validator PathIsDirCreate for for PathVariable now catches
+ the case where the directory could not be created due to permission
+ problems, allowing a more helpful error to be emitted (issue #2828)
+
RELEASE 4.2.0 - Sat, 31 Jul 2021 18:12:46 -0700
diff --git a/SCons/Variables/BoolVariable.py b/SCons/Variables/BoolVariable.py
index 6d9ff72..b3c0dc4 100644
--- a/SCons/Variables/BoolVariable.py
+++ b/SCons/Variables/BoolVariable.py
@@ -21,7 +21,7 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Option type for true/false Variables.
+"""Variable type for true/false Variables.
Usage example::
@@ -32,51 +32,62 @@ Usage example::
...
"""
-__all__ = ['BoolVariable',]
+from typing import Tuple, Callable
import SCons.Errors
-__true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
-__false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
+__all__ = ['BoolVariable',]
+TRUE_STRINGS = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
+FALSE_STRINGS = ('n', 'no', 'false', 'f', '0', 'off', 'none')
-def _text2bool(val):
- """
- Converts strings to True/False depending on the 'truth' expressed by
- the string. If the string can't be converted, the original value
- will be returned.
- See '__true_strings' and '__false_strings' for values considered
- 'true' or 'false respectively.
+def _text2bool(val) -> bool:
+ """Converts strings to True/False.
- This is usable as 'converter' for SCons' Variables.
+ If *val* looks like it expresses a bool-like value, based on
+ the :data:`TRUE_STRINGS` and :data:`FALSE_STRINGS` tuples,
+ return the appropriate value.
+
+ This is usable as a converter function for SCons Variables.
+
+ Raises:
+ ValueError: if the string cannot be converted.
"""
+
lval = val.lower()
- if lval in __true_strings: return True
- if lval in __false_strings: return False
+ if lval in TRUE_STRINGS:
+ return True
+ if lval in FALSE_STRINGS:
+ return False
raise ValueError("Invalid value for boolean option: %s" % val)
-def _validator(key, val, env):
- """
- Validates the given value to be either '0' or '1'.
-
- This is usable as 'validator' for SCons' Variables.
+def _validator(key, val, env) -> None:
+ """Validates the given value to be either true or false.
+
+ This is usable as a validator function for SCons Variables.
+
+ Raises:
+ KeyError: if key is not set in env
+ UserError: if key does not validate.
"""
if not env[key] in (True, False):
raise SCons.Errors.UserError(
- 'Invalid value for boolean option %s: %s' % (key, env[key]))
+ 'Invalid value for boolean option %s: %s' % (key, env[key])
+ )
-def BoolVariable(key, help, default):
- """
- The input parameters describe a boolean option, thus they are
- returned with the correct converter and validator appended. The
- 'help' text will by appended by '(yes|no) to show the valid
- valued. The result is usable for input to opts.Add().
+def BoolVariable(key, help, default) -> Tuple[str, str, str, Callable, Callable]:
+ """Return a tuple describing a boolean SCons Variable.
+
+ The input parameters describe a boolean option. Returns a tuple
+ including the correct converter and validator.
+ The *help* text will have ``(yes|no)`` automatically appended to show the
+ valid values. The result is usable as input to :meth:`Add`.
"""
- return (key, '%s (yes|no)' % help, default,
- _validator, _text2bool)
+ help = '%s (yes|no)' % help
+ return (key, help, default, _validator, _text2bool)
# Local Variables:
# tab-width:4
diff --git a/SCons/Variables/EnumVariable.py b/SCons/Variables/EnumVariable.py
index 6e0a8c5..e39eb02 100644
--- a/SCons/Variables/EnumVariable.py
+++ b/SCons/Variables/EnumVariable.py
@@ -21,10 +21,9 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Option type for enumeration Variables.
+"""Variable type for enumeration Variables.
-This file defines the option type for SCons allowing only specified
-input-values.
+Enumeration variables allow selection of one from a specified set of values.
Usage example::
@@ -32,8 +31,8 @@ Usage example::
opts.Add(
EnumVariable(
'debug',
- 'debug output and symbols',
- 'no',
+ help='debug output and symbols',
+ default='no',
allowed_values=('yes', 'no', 'full'),
map={},
ignorecase=2,
@@ -44,48 +43,52 @@ Usage example::
...
"""
+from typing import Tuple, Callable
-__all__ = ['EnumVariable',]
+import SCons.Errors
+__all__ = ['EnumVariable',]
-import SCons.Errors
-def _validator(key, val, env, vals):
+def _validator(key, val, env, vals) -> None:
if val not in vals:
raise SCons.Errors.UserError(
'Invalid value for option %s: %s. Valid values are: %s' % (key, val, vals))
-def EnumVariable(key, help, default, allowed_values, map={}, ignorecase=0):
- """
+def EnumVariable(key, help, default, allowed_values, map={}, ignorecase=0) -> Tuple[str, str, str, Callable, Callable]:
+ """Return a tuple describing an enumaration SCons Variable.
+
The input parameters describe an option with only certain values
- allowed. They are returned with an appropriate converter and
- validator appended. The result is usable for input to
- Variables.Add().
+ allowed. Returns A tuple including an appropriate converter and
+ validator. The result is usable as input to :meth:`Add`.
- 'key' and 'default' are the values to be passed on to Variables.Add().
+ *key* and *default* are passed directly on to :meth:`Add`.
- 'help' will be appended by the allowed values automatically
+ *help* is the descriptive part of the help text,
+ and will have the allowed values automatically appended.
- 'allowed_values' is a list of strings, which are allowed as values
+ *allowed_values* is a list of strings, which are the allowed values
for this option.
- The 'map'-dictionary may be used for converting the input value
+ The *map*-dictionary may be used for converting the input value
into canonical values (e.g. for aliases).
- 'ignorecase' defines the behaviour of the validator:
+ The value of *ignorecase* defines the behaviour of the validator:
- If ignorecase == 0, the validator/converter are case-sensitive.
- If ignorecase == 1, the validator/converter are case-insensitive.
- If ignorecase == 2, the validator/converter is case-insensitive and the converted value will always be lower-case.
+ * 0: the validator/converter are case-sensitive.
+ * 1: the validator/converter are case-insensitive.
+ * 2: the validator/converter is case-insensitive and the
+ converted value will always be lower-case.
- The 'validator' tests whether the value is in the list of allowed values. The 'converter' converts input values
- according to the given 'map'-dictionary (unmapped input values are returned unchanged).
+ The *validator* tests whether the value is in the list of allowed values.
+ The *converter* converts input values according to the given
+ *map*-dictionary (unmapped input values are returned unchanged).
"""
help = '%s (%s)' % (help, '|'.join(allowed_values))
# define validator
- if ignorecase >= 1:
+ if ignorecase:
validator = lambda key, val, env: \
_validator(key, val.lower(), env, allowed_values)
else:
diff --git a/SCons/Variables/ListVariable.py b/SCons/Variables/ListVariable.py
index c615258..7bd6053 100644
--- a/SCons/Variables/ListVariable.py
+++ b/SCons/Variables/ListVariable.py
@@ -21,9 +21,7 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Option type for list Variables.
-
-This file defines the option type for SCons implementing 'lists'.
+"""Variable type for list Variables.
A 'list' option may either be 'all', 'none' or a list of names
separated by comma. After the option has been processed, the option
@@ -38,8 +36,8 @@ Usage example::
opts.Add(
ListVariable(
'shared',
- 'libraries to build as shared libraries',
- 'all',
+ help='libraries to build as shared libraries',
+ default='all',
elems=list_of_libs,
)
)
@@ -54,44 +52,55 @@ Usage example::
# Known Bug: This should behave like a Set-Type, but does not really,
# since elements can occur twice.
-__all__ = ['ListVariable',]
-
import collections
+from typing import Tuple, Callable
import SCons.Util
+__all__ = ['ListVariable',]
+
class _ListVariable(collections.UserList):
- def __init__(self, initlist=[], allowedElems=[]):
- collections.UserList.__init__(self, [_f for _f in initlist if _f])
+ def __init__(self, initlist=None, allowedElems=None):
+ if initlist is None:
+ initlist = []
+ if allowedElems is None:
+ allowedElems = []
+ super().__init__([_f for _f in initlist if _f])
self.allowedElems = sorted(allowedElems)
def __cmp__(self, other):
raise NotImplementedError
+
def __eq__(self, other):
raise NotImplementedError
+
def __ge__(self, other):
raise NotImplementedError
+
def __gt__(self, other):
raise NotImplementedError
+
def __le__(self, other):
raise NotImplementedError
+
def __lt__(self, other):
raise NotImplementedError
+
def __str__(self):
- if len(self) == 0:
+ if not len(self):
return 'none'
self.data.sort()
if self.data == self.allowedElems:
return 'all'
else:
return ','.join(self)
+
def prepare_to_store(self):
return self.__str__()
-def _converter(val, allowedElems, mapdict):
- """
- """
+def _converter(val, allowedElems, mapdict) -> _ListVariable:
+ """ """
if val == 'none':
val = []
elif val == 'all':
@@ -101,35 +110,40 @@ def _converter(val, allowedElems, mapdict):
val = [mapdict.get(v, v) for v in val]
notAllowed = [v for v in val if v not in allowedElems]
if notAllowed:
- raise ValueError("Invalid value(s) for option: %s" %
- ','.join(notAllowed))
+ raise ValueError(
+ "Invalid value(s) for option: %s" % ','.join(notAllowed)
+ )
return _ListVariable(val, allowedElems)
-## def _validator(key, val, env):
-## """
-## """
-## # todo: write validator for pgk list
-## return 1
+# def _validator(key, val, env) -> None:
+# """ """
+# # TODO: write validator for pgk list
+# pass
-def ListVariable(key, help, default, names, map={}):
- """
- The input parameters describe a 'package list' option, thus they
- are returned with the correct converter and validator appended. The
- result is usable for input to opts.Add() .
+def ListVariable(key, help, default, names, map={}) -> Tuple[str, str, str, None, Callable]:
+ """Return a tuple describing a list SCons Variable.
+
+ The input parameters describe a 'list' option. Returns
+ a tuple including the correct converter and validator.
+ The result is usable for input to :meth:`Add`.
+
+ *help* will have text appended indicating the legal values
+ (not including any extra names from *map*).
+
+ *map* can be used to map alternative names to the ones in *names* -
+ that is, a form of alias.
- A 'package list' option may either be 'all', 'none' or a list of
- package names (separated by space).
+ A 'list' option may either be 'all', 'none' or a list of
+ names (separated by commas).
"""
names_str = 'allowed names: %s' % ' '.join(names)
if SCons.Util.is_List(default):
default = ','.join(default)
help = '\n '.join(
(help, '(all|none|comma-separated list of names)', names_str))
- return (key, help, default,
- None, #_validator,
- lambda val: _converter(val, names, map))
+ return (key, help, default, None, lambda val: _converter(val, names, map))
# Local Variables:
# tab-width:4
diff --git a/SCons/Variables/PackageVariable.py b/SCons/Variables/PackageVariable.py
index d4dafd5..43ce99d 100644
--- a/SCons/Variables/PackageVariable.py
+++ b/SCons/Variables/PackageVariable.py
@@ -21,58 +21,58 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Option type for package Variables.
-
-This file defines the option type for SCons implementing 'package activation'.
+"""Variable type for package Variables.
To be used whenever a 'package' may be enabled/disabled and the
package path may be specified.
-Usage example:
-
- Examples:
- x11=no (disables X11 support)
- x11=yes (will search for the package installation dir)
- x11=/usr/local/X11 (will check this path for existence)
-
- To replace autoconf's --with-xxx=yyy ::
-
-
- opts = Variables()
- opts.Add(PackageVariable('x11',
- 'use X11 installed here (yes = search some places',
- 'yes'))
- ...
- if env['x11'] == True:
- dir = ... search X11 in some standard places ...
- env['x11'] = dir
- if env['x11']:
- ... build with x11 ...
+Given these options ::
+
+ x11=no (disables X11 support)
+ x11=yes (will search for the package installation dir)
+ x11=/usr/local/X11 (will check this path for existence)
+
+Can be used as a replacement for autoconf's ``--with-xxx=yyy`` ::
+
+ opts = Variables()
+ opts.Add(
+ PackageVariable(
+ key='x11',
+ help='use X11 installed here (yes = search some places)',
+ default='yes'
+ )
+ )
+ ...
+ if env['x11'] == True:
+ dir = ... # search X11 in some standard places ...
+ env['x11'] = dir
+ if env['x11']:
+ ... # build with x11 ...
"""
-__all__ = ['PackageVariable',]
+from typing import Tuple, Callable
import SCons.Errors
+__all__ = ['PackageVariable',]
+
__enable_strings = ('1', 'yes', 'true', 'on', 'enable', 'search')
__disable_strings = ('0', 'no', 'false', 'off', 'disable')
-def _converter(val):
- """
- """
+def _converter(val) -> bool:
+ """ """
lval = val.lower()
if lval in __enable_strings: return True
if lval in __disable_strings: return False
- #raise ValueError("Invalid value for boolean option: %s" % val)
return val
-def _validator(key, val, env, searchfunc):
+def _validator(key, val, env, searchfunc) -> None:
+ """ """
# NB: searchfunc is currently undocumented and unsupported
- """
- """
# TODO write validator, check for path
import os
+
if env[key] is True:
if searchfunc:
env[key] = searchfunc(key, val)
@@ -81,20 +81,21 @@ def _validator(key, val, env, searchfunc):
'Path does not exist for option %s: %s' % (key, val))
-def PackageVariable(key, help, default, searchfunc=None):
- # NB: searchfunc is currently undocumented and unsupported
- """
- The input parameters describe a 'package list' option, thus they
- are returned with the correct converter and validator appended. The
- result is usable for input to opts.Add() .
+def PackageVariable(key, help, default, searchfunc=None) -> Tuple[str, str, str, Callable, Callable]:
+ """Return a tuple describing a package list SCons Variable.
- A 'package list' option may either be 'all', 'none' or a list of
- package names (separated by space).
+ The input parameters describe a 'package list' option. Returns
+ a tuple including the correct converter and validator appended.
+ The result is usable as input to :meth:`Add` .
+
+ A 'package list' option may either be 'all', 'none' or a pathname
+ string. This information is appended to *help*.
"""
+ # NB: searchfunc is currently undocumented and unsupported
help = '\n '.join(
(help, '( yes | no | /path/to/%s )' % key))
return (key, help, default,
- lambda k, v, e: _validator(k,v,e,searchfunc),
+ lambda k, v, e: _validator(k, v, e, searchfunc),
_converter)
# Local Variables:
diff --git a/SCons/Variables/PathVariable.py b/SCons/Variables/PathVariable.py
index 081872b..383c1f9 100644
--- a/SCons/Variables/PathVariable.py
+++ b/SCons/Variables/PathVariable.py
@@ -21,64 +21,74 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Option type for path Variables.
+"""Variable type for path Variables.
-This file defines an option type for SCons implementing path settings.
-
-To be used whenever a user-specified path override should be allowed.
+To be used whenever a user-specified path override setting should be allowed.
Arguments to PathVariable are:
- option-name = name of this option on the command line (e.g. "prefix")
- option-help = help string for option
- option-dflt = default value for this option
- validator = [optional] validator for option value. Predefined are:
- PathAccept -- accepts any path setting; no validation
- PathIsDir -- path must be an existing directory
- PathIsDirCreate -- path must be a dir; will create
- PathIsFile -- path must be a file
- PathExists -- path must exist (any type) [default]
-
- The validator is a function that is called and which should return
+ * *key* - name of this option on the command line (e.g. "prefix")
+ * *help* - help string for option
+ * *dflt* - default value for this option
+ * *validator* - [optional] validator for option value. Predefined are:
+
+ * *PathAccept* - accepts any path setting; no validation
+ * *PathIsDir* - path must be an existing directory
+ * *PathIsDirCreate* - path must be a dir; will create
+ * *PathIsFile* - path must be a file
+ * *PathExists* - path must exist (any type) [default]
+
+ The *validator* is a function that is called and which should return
True or False to indicate if the path is valid. The arguments
- to the validator function are: (key, val, env). The key is the
- name of the option, the val is the path specified for the option,
- and the env is the env to which the Options have been added.
+ to the validator function are: (*key*, *val*, *env*). *key* is the
+ name of the option, *val* is the path specified for the option,
+ and *env* is the environment to which the Options have been added.
Usage example::
- Examples:
- prefix=/usr/local
-
- opts = Variables()
-
- opts = Variables()
- opts.Add(PathVariable('qtdir',
- 'where the root of Qt is installed',
- qtdir, PathIsDir))
- opts.Add(PathVariable('qt_includes',
- 'where the Qt includes are installed',
- '$qtdir/includes', PathIsDirCreate))
- opts.Add(PathVariable('qt_libraries',
- 'where the Qt library is installed',
- '$qtdir/lib'))
+ opts = Variables()
+ opts.Add(
+ PathVariable(
+ 'qtdir',
+ help='where the root of Qt is installed',
+ default=qtdir,
+ validator=PathIsDir,
+ )
+ )
+ opts.Add(
+ PathVariable(
+ 'qt_includes',
+ help='where the Qt includes are installed',
+ default='$qtdir/includes',
+ validator=PathIsDirCreate,
+ )
+ )
+ opts.Add(
+ PathVariable(
+ 'qt_libraries',
+ help='where the Qt library is installed',
+ default='$qtdir/lib',
+ )
+ )
"""
-__all__ = ['PathVariable',]
import os
import os.path
+from typing import Tuple, Callable
import SCons.Errors
+__all__ = ['PathVariable',]
+
class _PathVariableClass:
@staticmethod
- def PathAccept(key, val, env):
+ def PathAccept(key, val, env) -> None:
"""Accepts any path, no checking done."""
pass
-
+
@staticmethod
- def PathIsDir(key, val, env):
+ def PathIsDir(key, val, env) -> None:
"""Validator to check if Path is a directory."""
if not os.path.isdir(val):
if os.path.isfile(val):
@@ -88,17 +98,20 @@ class _PathVariableClass:
raise SCons.Errors.UserError(m % (key, val))
@staticmethod
- def PathIsDirCreate(key, val, env):
+ def PathIsDirCreate(key, val, env) -> None:
"""Validator to check if Path is a directory,
creating it if it does not exist."""
- if os.path.isfile(val):
+ try:
+ os.makedirs(val, exist_ok=True)
+ except FileExistsError:
m = 'Path for option %s is a file, not a directory: %s'
raise SCons.Errors.UserError(m % (key, val))
- if not os.path.isdir(val):
- os.makedirs(val)
+ except PermissionError:
+ m = 'Path for option %s could not be created: %s'
+ raise SCons.Errors.UserError(m % (key, val))
@staticmethod
- def PathIsFile(key, val, env):
+ def PathIsFile(key, val, env) -> None:
"""Validator to check if Path is a file"""
if not os.path.isfile(val):
if os.path.isdir(val):
@@ -108,32 +121,33 @@ class _PathVariableClass:
raise SCons.Errors.UserError(m % (key, val))
@staticmethod
- def PathExists(key, val, env):
+ def PathExists(key, val, env) -> None:
"""Validator to check if Path exists"""
if not os.path.exists(val):
m = 'Path for option %s does not exist: %s'
raise SCons.Errors.UserError(m % (key, val))
- def __call__(self, key, help, default, validator=None):
- """
- The input parameters describe a 'path list' option, thus they
- are returned with the correct converter and validator appended. The
- result is usable for input to opts.Add() .
+ def __call__(self, key, help, default, validator=None) -> Tuple[str, str, str, Callable, None]:
+ """Return a tuple describing a path list SCons Variable.
- The 'default' option specifies the default path to use if the
+ The input parameters describe a 'path list' option. Returns
+ a tuple with the correct converter and validator appended. The
+ result is usable for input to :meth:`Add`.
+
+ The *default* option specifies the default path to use if the
user does not specify an override with this option.
- validator is a validator, see this file for examples
+ *validator* is a validator, see this file for examples
"""
if validator is None:
validator = self.PathExists
if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
- return (key, '%s ( /path/to/%s )' % (help, key[0]), default,
- validator, None)
+ helpmsg = '%s ( /path/to/%s )' % (help, key[0])
else:
- return (key, '%s ( /path/to/%s )' % (help, key), default,
- validator, None)
+ helpmsg = '%s ( /path/to/%s )' % (help, key)
+ return (key, helpmsg, default, validator, None)
+
PathVariable = _PathVariableClass()
diff --git a/SCons/Variables/PathVariableTests.py b/SCons/Variables/PathVariableTests.py
index 6e3a70b..a9aa8f0 100644
--- a/SCons/Variables/PathVariableTests.py
+++ b/SCons/Variables/PathVariableTests.py
@@ -96,8 +96,8 @@ class PathVariableTestCase(unittest.TestCase):
o.validator('X', dne, {})
except SCons.Errors.UserError as e:
assert str(e) == 'Directory path for option X does not exist: %s' % dne, e
- except:
- raise Exception("did not catch expected UserError")
+ except Exception as e:
+ raise Exception("did not catch expected UserError") from e
def test_PathIsDirCreate(self):
"""Test the PathIsDirCreate validator"""
@@ -121,8 +121,16 @@ class PathVariableTestCase(unittest.TestCase):
o.validator('X', f, {})
except SCons.Errors.UserError as e:
assert str(e) == 'Path for option X is a file, not a directory: %s' % f, e
- except:
- raise Exception("did not catch expected UserError")
+ except Exception as e:
+ raise Exception("did not catch expected UserError") from e
+
+ f = '/yyy/zzz' # this not exists and should fail to create
+ try:
+ o.validator('X', f, {})
+ except SCons.Errors.UserError as e:
+ assert str(e) == 'Path for option X could not be created: %s' % f, e
+ except Exception as e:
+ raise Exception("did not catch expected UserError") from e
def test_PathIsFile(self):
"""Test the PathIsFile validator"""
diff --git a/SCons/Variables/VariablesTests.py b/SCons/Variables/VariablesTests.py
index 8def19e..4672cdd 100644
--- a/SCons/Variables/VariablesTests.py
+++ b/SCons/Variables/VariablesTests.py
@@ -46,7 +46,7 @@ class Environment:
def check(key, value, env):
assert int(value) == 6 * 9, "key %s = %s" % (key, repr(value))
-
+
# Check saved option file by executing and comparing against
# the expected dictionary
def checkSave(file, expected):
@@ -138,7 +138,7 @@ class VariablesTestCase(unittest.TestCase):
test = TestSCons.TestSCons()
file = test.workpath('custom.py')
opts = SCons.Variables.Variables(file)
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"42",
@@ -159,7 +159,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=54')
opts = SCons.Variables.Variables(file)
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"42",
@@ -187,7 +187,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=42')
opts = SCons.Variables.Variables(file)
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"10",
@@ -208,7 +208,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=10')
opts = SCons.Variables.Variables(file)
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"12",
@@ -229,7 +229,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=10')
opts = SCons.Variables.Variables(file)
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"12",
@@ -247,7 +247,7 @@ class VariablesTestCase(unittest.TestCase):
test = TestSCons.TestSCons()
file = test.workpath('custom.py')
opts = SCons.Variables.Variables(file)
-
+
opts.Add('ANSWER',
help='THE answer to THE question',
converter=str)
@@ -282,9 +282,9 @@ class VariablesTestCase(unittest.TestCase):
nopts = SCons.Variables.Variables()
# Ensure that both attributes are initialized to
- # an empty list and dict, respectively.
+ # an empty list and dict, respectively.
assert len(nopts.files) == 0
- assert len(nopts.args) == 0
+ assert len(nopts.args) == 0
def test_args(self):
"""Test updating an Environment with arguments overridden"""
@@ -295,7 +295,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=42')
opts = SCons.Variables.Variables(file, {'ANSWER':54})
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"42",
@@ -315,7 +315,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=54')
opts = SCons.Variables.Variables(file, {'ANSWER':42})
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"54",
@@ -332,7 +332,7 @@ class VariablesTestCase(unittest.TestCase):
file = test.workpath('custom.py')
test.write('custom.py', 'ANSWER=54')
opts = SCons.Variables.Variables(file, {'ANSWER':54})
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"54",
@@ -354,7 +354,7 @@ class VariablesTestCase(unittest.TestCase):
if val in [1, 'y']: val = 1
if val in [0, 'n']: val = 0
return val
-
+
# test saving out empty file
opts.Add('OPT_VAL',
'An option to test',
@@ -400,11 +400,11 @@ class VariablesTestCase(unittest.TestCase):
self.x = x
def __str__(self):
return self.x
-
+
test = TestSCons.TestSCons()
cache_file = test.workpath('cached.options')
opts = SCons.Variables.Variables()
-
+
opts.Add('THIS_USED_TO_BREAK',
'An option to test',
"Default")
@@ -412,11 +412,11 @@ class VariablesTestCase(unittest.TestCase):
opts.Add('THIS_ALSO_BROKE',
'An option to test',
"Default2")
-
+
opts.Add('THIS_SHOULD_WORK',
'An option to test',
Foo('bar'))
-
+
env = Environment()
opts.Update(env, { 'THIS_USED_TO_BREAK' : "Single'Quotes'In'String",
'THIS_ALSO_BROKE' : "\\Escape\nSequences\t",
@@ -502,7 +502,10 @@ A: a - alpha test
assert text == expectAlpha, text
textBackwards = opts.GenerateHelpText(env, sort=lambda x, y: cmp(y, x))
- assert textBackwards == expectBackwards, "Expected:\n%s\nGot:\n%s\n"%(textBackwards, expectBackwards)
+ assert textBackwards == expectBackwards, "Expected:\n%s\nGot:\n%s\n" % (
+ textBackwards,
+ expectBackwards,
+ )
def test_FormatVariableHelpText(self):
"""Test generating custom format help text"""
@@ -550,7 +553,7 @@ B 42 54 b - alpha test ['B']
"""
text = opts.GenerateHelpText(env, sort=cmp)
assert text == expectAlpha, text
-
+
def test_Aliases(self):
"""Test option aliases"""
# test alias as a tuple
@@ -560,17 +563,17 @@ B 42 54 b - alpha test ['B']
'THE answer to THE question',
"42"),
)
-
+
env = Environment()
opts.Update(env, {'ANSWER' : 'answer'})
-
+
assert 'ANSWER' in env
-
+
env = Environment()
opts.Update(env, {'ANSWERALIAS' : 'answer'})
-
+
assert 'ANSWER' in env and 'ANSWERALIAS' not in env
-
+
# test alias as a list
opts = SCons.Variables.Variables()
opts.AddVariables(
@@ -578,17 +581,16 @@ B 42 54 b - alpha test ['B']
'THE answer to THE question',
"42"),
)
-
+
env = Environment()
opts.Update(env, {'ANSWER' : 'answer'})
-
+
assert 'ANSWER' in env
-
+
env = Environment()
opts.Update(env, {'ANSWERALIAS' : 'answer'})
-
- assert 'ANSWER' in env and 'ANSWERALIAS' not in env
+ assert 'ANSWER' in env and 'ANSWERALIAS' not in env
class UnknownVariablesTestCase(unittest.TestCase):
@@ -596,7 +598,7 @@ class UnknownVariablesTestCase(unittest.TestCase):
def test_unknown(self):
"""Test the UnknownVariables() method"""
opts = SCons.Variables.Variables()
-
+
opts.Add('ANSWER',
'THE answer to THE question',
"42")
@@ -612,38 +614,38 @@ class UnknownVariablesTestCase(unittest.TestCase):
r = opts.UnknownVariables()
assert r == {'UNKNOWN' : 'unknown'}, r
assert env['ANSWER'] == 'answer', env['ANSWER']
-
+
def test_AddOptionUpdatesUnknown(self):
"""Test updating of the 'unknown' dict"""
opts = SCons.Variables.Variables()
-
+
opts.Add('A',
'A test variable',
"1")
-
+
args = {
'A' : 'a',
'ADDEDLATER' : 'notaddedyet',
}
-
+
env = Environment()
opts.Update(env,args)
-
+
r = opts.UnknownVariables()
assert r == {'ADDEDLATER' : 'notaddedyet'}, r
assert env['A'] == 'a', env['A']
-
+
opts.Add('ADDEDLATER',
'An option not present initially',
"1")
-
+
args = {
'A' : 'a',
'ADDEDLATER' : 'added',
}
-
+
opts.Update(env, args)
-
+
r = opts.UnknownVariables()
assert len(r) == 0, r
assert env['ADDEDLATER'] == 'added', env['ADDEDLATER']
@@ -651,33 +653,33 @@ class UnknownVariablesTestCase(unittest.TestCase):
def test_AddOptionWithAliasUpdatesUnknown(self):
"""Test updating of the 'unknown' dict (with aliases)"""
opts = SCons.Variables.Variables()
-
+
opts.Add('A',
'A test variable',
"1")
-
+
args = {
'A' : 'a',
'ADDEDLATERALIAS' : 'notaddedyet',
}
-
+
env = Environment()
opts.Update(env,args)
-
+
r = opts.UnknownVariables()
assert r == {'ADDEDLATERALIAS' : 'notaddedyet'}, r
assert env['A'] == 'a', env['A']
-
+
opts.AddVariables(
(('ADDEDLATER', 'ADDEDLATERALIAS'),
'An option not present initially',
"1"),
)
-
+
args['ADDEDLATERALIAS'] = 'added'
-
+
opts.Update(env, args)
-
+
r = opts.UnknownVariables()
assert len(r) == 0, r
assert env['ADDEDLATER'] == 'added', env['ADDEDLATER']
diff --git a/SCons/Variables/__init__.py b/SCons/Variables/__init__.py
index 4a30a91..9c8bdca 100644
--- a/SCons/Variables/__init__.py
+++ b/SCons/Variables/__init__.py
@@ -44,7 +44,7 @@ class Variables:
Holds all the options, updates the environment with the variables,
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:
files (optional): List of option configuration files to load
@@ -64,7 +64,7 @@ class Variables:
self.args = args
if not SCons.Util.is_List(files):
if files:
- files = [ files ]
+ files = [files,]
else:
files = []
self.files = files
@@ -77,20 +77,23 @@ class Variables:
if not Variables.instance:
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:
pass
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.
if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
- option.key = key[0]
- option.aliases = key[1:]
+ option.key = key[0]
+ option.aliases = list(key[1:])
else:
- option.key = key
- option.aliases = [ key ]
+ option.key = key
+ # TODO: normalize to not include key in aliases. Currently breaks tests.
+ option.aliases = [key,]
+ if not SCons.Environment.is_valid_construction_var(option.key):
+ raise SCons.Errors.UserError("Illegal Variables key `%s'" % str(option.key))
option.help = help
option.default = default
option.validator = validator
@@ -100,43 +103,42 @@ class Variables:
# options might be added after the 'unknown' dict has been set up,
# 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:
del self.unknown[alias]
- def keys(self):
- """
- Returns the keywords for the options
- """
+ def keys(self) -> list:
+ """Returns the keywords for the options."""
return [o.key for o in self.options]
- def Add(self, key, help="", default=None, validator=None, converter=None, **kw):
- r"""Add an option.
+ def Add(self, key, *args, **kwargs) -> None:
+ r""" Add an option.
Args:
- key: the name of the variable, or a list or tuple of arguments
- help: optional help text for the options (Default value = "")
- 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)
- \*\*kw: keyword args, unused.
+ key: the name of the variable, or a 5-tuple (or list).
+ If a tuple, and there are no additional arguments,
+ the tuple is unpacked into help, default, validator, converter.
+ If there are additional arguments, the first word of the tuple
+ is taken as the key, and the remainder as aliases.
+ \*args: optional positional arguments
+ help: optional help text for the options (Default value = "")
+ 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):
- self._do_add(*key)
- return
-
- 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))
+ if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
+ if not (len(args) or len(kwargs)):
+ return self._do_add(*key)
- self._do_add(key, help, default, validator, converter)
+ return self._do_add(key, *args, **kwargs)
- def AddVariables(self, *optlist):
- """
- Add a list of options.
+ def AddVariables(self, *optlist) -> None:
+ """ Add a list of options.
Each list element is a tuple/list of arguments to be passed on
to the underlying method for adding options.
@@ -154,12 +156,13 @@ class Variables:
for o in optlist:
self._do_add(*o)
+ def Update(self, env, args=None) -> None:
+ """ Update an environment with the option variables.
- def Update(self, env, args=None):
- """
- 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 = {}
@@ -192,7 +195,7 @@ class Variables:
for arg, value in args.items():
added = False
for option in self.options:
- if arg in list(option.aliases) + [ option.key ]:
+ if arg in option.aliases + [option.key,]:
values[option.key] = value
added = True
if not added:
@@ -206,7 +209,7 @@ class Variables:
except KeyError:
pass
- # Call the convert functions:
+ # apply converters
for option in self.options:
if option.converter and option.key in values:
value = env.subst('${%s}'%option.key)
@@ -219,36 +222,39 @@ class Variables:
raise SCons.Errors.UserError('Error converting option: %s\n%s'%(option.key, x))
- # Finally validate the values:
+ # apply validators
for option in self.options:
if option.validator and option.key in values:
option.validator(option.key, env.subst('${%s}'%option.key), env)
- def UnknownVariables(self):
- """
- Returns any options in the specified arguments lists that
- were not known, declared options in this object.
+ def UnknownVariables(self) -> dict:
+ """ Returns unknown variables.
+
+ Identifies options that were not known, declared options in this object.
"""
return self.unknown
- def Save(self, filename, env):
- """
- Saves all the options in the given file. This file can
- then be used to load the options next run. This can be used
- to create an option cache file.
+ def Save(self, filename, env) -> None:
+ """ Save the options to a file.
+
+ Saves all the options which have non-default settings
+ 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
- env - the environment get the option values from
+ Args:
+ filename: Name of the file to save into
+ env: the environment get the option values from
"""
# Create the file and write out the header
try:
- fh = open(filename, 'w')
-
- try:
+ with open(filename, 'w') as fh:
# Make an assignment in the file for each option
# 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:
try:
value = env[option.key]
@@ -268,55 +274,58 @@ class Variables:
defaultVal = env.subst(SCons.Util.to_String(option.default))
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(defaultVal):
fh.write('%s = %s\n' % (option.key, repr(value)))
except KeyError:
pass
- finally:
- fh.close()
-
except IOError as x:
raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x))
- def GenerateHelpText(self, env, sort=None):
- """
- Generate the help text for the options.
+ def GenerateHelpText(self, env, sort=None) -> str:
+ """ Generate the help text for the options.
- env - an environment that is used to get the current values
- of the options.
- cmp - Either a function as follows: The specific sort function should take two arguments and return -1, 0 or 1
- or a boolean to indicate if it should be sorted.
+ Args:
+ env: an environment that is used to get the current values
+ of the options.
+ cmp: Either a comparison function used for sorting
+ (must take two arguments and return -1, 0 or 1)
+ or a boolean to indicate if it should be sorted.
"""
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.key, y.key)))
elif sort is True:
options = sorted(self.options, key=lambda x: x.key)
else:
options = self.options
- def format(opt, self=self, env=env):
+ def format_opt(opt, self=self, env=env) -> str:
if opt.key in env:
actual = env.subst('${%s}' % opt.key)
else:
actual = None
return self.FormatVariableHelpText(env, opt.key, opt.help, opt.default, 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)
- format = '\n%s: %s\n default: %s\n actual: %s\n'
- format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n'
+ fmt = '\n%s: %s\n default: %s\n actual: %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=None) -> str:
+ if aliases is None:
+ aliases = []
# Don't display the key name itself as an alias.
aliases = [a for a in aliases if a != key]
- if len(aliases)==0:
- return self.format % (key, help, default, actual)
+ if aliases:
+ return self.aliasfmt % (key, help, default, actual, aliases)
else:
- return self.format_ % (key, help, default, actual, aliases)
+ return self.fmt % (key, help, default, actual)
# Local Variables:
# tab-width:4
diff --git a/doc/man/scons.xml b/doc/man/scons.xml
index 214f38a..d38c6b7 100644
--- a/doc/man/scons.xml
+++ b/doc/man/scons.xml
@@ -4429,11 +4429,11 @@ from various sources, often from the command line:</para>
call the &Variables; function:</para>
<variablelist>
- <varlistentry>
+ <varlistentry id="v-Variables">
<term><function>Variables</function>([<parameter>files, [args]]</parameter>)</term>
<listitem>
<para>If <parameter>files</parameter> is a file or
-list of files, those are executed as Python scripts,
+list of files, they are executed as Python scripts,
and the values of (global) Python variables set in
those files are added as &consvars; in the &DefEnv;.
If no files are specified,
@@ -4460,10 +4460,14 @@ CC = 'my_cc'
is specified, it is a dictionary of
values that will override anything read from
<parameter>files</parameter>.
-This is primarily intended to pass the
+The primary use is to pass the
&ARGUMENTS; dictionary that holds variables
-specified on the command line.
-Example:</para>
+specified on the command line,
+allowing you to indicate that if a setting appears
+on both the command line and in the file(s),
+the command line setting takes precedence.
+However, any dictionary can be passed.
+Examples:</para>
<programlisting language="python">
vars = Variables('custom.py')
@@ -4492,36 +4496,59 @@ pre-defined &consvars; that your project will make use of
<para>Variables objects have the following methods:</para>
<variablelist>
- <varlistentry>
+ <varlistentry id="v-Add">
<term><replaceable>vars</replaceable>.<function>Add</function>(<parameter>key, [help, default, validator, converter]</parameter>)</term>
<listitem>
<para>Add a customizable &consvar; to the Variables object.
<parameter>key</parameter>
-is the name of the variable.
+is either the name of the variable,
+or a tuple (or list), in which case
+the first item in the tuple is taken as the variable name,
+and any remaining values are considered aliases for the variable.
<parameter>help</parameter>
-is the help text for the variable.
+is the help text for the variable
+(default empty string).
<parameter>default</parameter>
-is the default value of the variable;
-if the default value is
+is the default value of the variable
+(default <constant>None</constant>).
+If <parameter>default</parameter> is
<constant>None</constant>
-and there is no explicit value specified,
+and a value is not specified,
the &consvar; will not
be added to the &consenv;.
-If set, <parameter>validator</parameter>
-is called to validate the value of the variable.
-A function supplied as a validator shall accept
-arguments: <parameter>key</parameter>,
-<parameter>value</parameter>, and <parameter>env</parameter>.
-The recommended way to handle an invalid value is
-to raise an exception (see example below).
-If set, <parameter>converter</parameter>
-is called to convert the value before putting it in the environment, and
-should take either a value, or the value and environment, as parameters.
+</para>
+<para>
+As a special case, if <parameter>key</parameter>
+is a tuple (or list) and is the <emphasis>only</emphasis>
+argument, the tuple is unpacked into the five parameters
+listed above left to right, with any missing members filled with
+the respecitive default values. This form allows <function>Add</function>
+to consume a tuple emitted by the convenience functions
+<link linkend='v-BoolVariable'><function>BoolVariable</function></link>,
+<link linkend='v-EnumVariable'><function>EnumVariable</function></link>,
+<link linkend='v-ListVariable'><function>ListVariable</function></link>,
+<link linkend='v-PackageVariable'><function>PackageVariable</function></link>
+and
+<link linkend='v-PathVariable'><function>PathVariable</function></link>.
+</para>
+<para>
+If the optional <parameter>validator</parameter> is supplied,
+it is called to validate the value of the variable.
+A function supplied as a validator must accept
+three arguments: <parameter>key</parameter>,
+<parameter>value</parameter> and <parameter>env</parameter>,
+and should raise an exception with a helpful error message
+if <parameter>value</parameter> is invalid.
+No return value is expected from the validator.
+</para>
+<para>
+If the optional <parameter>converter</parameter> is supplied,
+it is called to convert the value before putting it in the environment,
+and should take either a value
+or a value and environment as parameters.
The converter function must return a value,
-which will be converted into a string
-before being validated by the
-<parameter>validator</parameter>
-(if any)
+which will be converted into a string and be passed to the
+<parameter>validator</parameter> (if any)
and then added to the &consenv;.</para>
<para>Examples:</para>
@@ -4538,11 +4565,11 @@ vars.Add('COLOR', validator=valid_color)
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-AddVariables">
<term><replaceable>vars</replaceable>.<function>AddVariables</function>(<parameter>args</parameter>)</term>
<listitem>
<para>A convenience method that adds
-multiple customizable &consvars;
+one or more customizable &consvars;
to a Variables object in one call;
equivalent to calling &Add; multiple times.
The <parameter>args</parameter>
@@ -4551,10 +4578,10 @@ that contain the arguments
for an individual call to the &Add; method.
Since tuples are not Python mappings,
the arguments cannot use the keyword form,
-but rather are positional arguments as documented
-for &Add;: a required name, the rest optional
-but must be in the specified in order if used.
-
+but rather are positional arguments as documented for
+<link linkend='v-Add'><function>Add</function></link>:
+a required name, the other four optional,
+but must be in the specified order if used.
</para>
<programlisting language="python">
@@ -4568,18 +4595,18 @@ opt.AddVariables(
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-Update">
<term><replaceable>vars</replaceable>.<function>Update</function>(<parameter>env, [args]</parameter>)</term>
<listitem>
<para>Update a &consenv;
<parameter>env</parameter>
-with the customized &consvars; .
+with the customized &consvars;.
Any specified variables that are not
configured for the Variables object
will be saved and may be
retrieved using the
-&UnknownVariables;
-method, below.</para>
+<link linkend='v-UnknownVariables'>&UnknownVariables;</link>
+method.</para>
<para>Normally this method is not called directly,
but rather invoked indirectly by passing the Variables object to
@@ -4592,7 +4619,7 @@ env = Environment(variables=vars)
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-UnknownVariables">
<term><replaceable>vars</replaceable>.<function>UnknownVariables</function>()</term>
<listitem>
<para>Returns a dictionary containing any
@@ -4611,14 +4638,17 @@ for key, value in vars.UnknownVariables():
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-Save">
<term><replaceable>vars</replaceable>.<function>Save</function>(<parameter>filename, env</parameter>)</term>
<listitem>
<para>Save the currently set variables into a script file named
-by <parameter>filename</parameter>
-that can be used on the next invocation to automatically load the current
-settings. This method combined with the Variables method can be used to
-support caching of variables between runs.</para>
+by <parameter>filename</parameter>. Only variables that are
+set to non-default values are saved.
+You can load these saved settings on a subsequent run
+by passing <parameter>filename</parameter> to the
+<link linkend='v-Variables'>&Variables;</link> function,
+providing a way to cache particular settings for reuse.
+</para>
<programlisting language="python">
env = Environment()
@@ -4631,7 +4661,7 @@ vars.Save('variables.cache', env)
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-GenerateHelpText">
<term><replaceable>vars</replaceable>.<function>GenerateHelpText</function>(<parameter>env, [sort]</parameter>)</term>
<listitem>
<para>Generate help text documenting the customizable construction
@@ -4663,7 +4693,7 @@ Help(vars.GenerateHelpText(env, sort=cmp))
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-FormatVariableHelpText">
<term><replaceable>vars</replaceable>.<function>FormatVariableHelpText</function>(<parameter>env, opt, help, default, actual</parameter>)</term>
<listitem>
<para>Returns a formatted string
@@ -4685,6 +4715,7 @@ string if you want the entries separated.</para>
def my_format(env, opt, help, default, actual):
fmt = "\n%s: default=%s actual=%s (%s)\n"
return fmt % (opt, default, actual, help)
+
vars.FormatVariableHelpText = my_format
</programlisting>
</listitem>
@@ -4701,7 +4732,7 @@ Each of these return a tuple ready to be passed to
the &Add; or &AddVariables; method:</para>
<variablelist>
- <varlistentry>
+ <varlistentry id="v-BoolVariable">
<term><function>BoolVariable</function>(<parameter>key, help, default</parameter>)</term>
<listitem>
<para>Returns a tuple of arguments
@@ -4736,7 +4767,7 @@ as false.</para>
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-EnumVariable">
<term><function>EnumVariable</function>(<parameter>key, help, default, allowed_values, [map, ignorecase]</parameter>)</term>
<listitem>
<para>Returns a tuple of arguments
@@ -4785,7 +4816,7 @@ converted to lower case.</para>
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-ListVariable">
<term><function>ListVariable</function>(<parameter>key, help, default, names, [map]</parameter>)</term>
<listitem>
<para>Returns a tuple of arguments
@@ -4824,7 +4855,7 @@ reflected in the generated help message). </para>
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-PackageVariable">
<term><function>PackageVariable</function>(<parameter>key, help, default</parameter>)</term>
<listitem>
<para>Returns a tuple of arguments
@@ -4864,7 +4895,7 @@ to disable use of the specified option.</para>
</listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="v-PathVariable">
<term><function>PathVariable</function>(<parameter>key, help, default, [validator]</parameter>)</term>
<listitem>
<para>Returns a tuple of arguments