diff options
author | Mats Wichmann <mats@linux.com> | 2024-11-12 14:35:10 (GMT) |
---|---|---|
committer | Mats Wichmann <mats@linux.com> | 2024-11-12 15:10:40 (GMT) |
commit | c8ebf8ee8393e3471083920ea07387a30aa6ced1 (patch) | |
tree | 31076b6059df2117720836daf6984ff8a20046a1 | |
parent | b4d72c716aa98d3cefcf9fcb358429b08ac58114 (diff) | |
download | SCons-c8ebf8ee8393e3471083920ea07387a30aa6ced1.zip SCons-c8ebf8ee8393e3471083920ea07387a30aa6ced1.tar.gz SCons-c8ebf8ee8393e3471083920ea07387a30aa6ced1.tar.bz2 |
Add as_dict flag to env.Dictionary
The Dictionary method now has an as_dict flag. If true, Dictionary
always returns a dict. The default remains to return different
types depending on whether zero (a dict of construction vars),
one (that construction var's value), or multiple (a list of construction
var values) arguments are given
Fixes #4631
Signed-off-by: Mats Wichmann <mats@linux.com>
-rw-r--r-- | CHANGES.txt | 4 | ||||
-rw-r--r-- | RELEASE.txt | 4 | ||||
-rw-r--r-- | SCons/Environment.py | 58 | ||||
-rw-r--r-- | SCons/Environment.xml | 71 | ||||
-rw-r--r-- | SCons/EnvironmentTests.py | 20 |
5 files changed, 100 insertions, 57 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index b75f856..7d6ef00 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -134,6 +134,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Add a tag to each CacheDir to let systems ignore backing it up (per https://bford.info/cachedir/). Update the way a CacheDir is created, since it now has to create two files. + - The Dictionary method now has an as_dict flag. If true, Dictionary + always returns a dict. The default remains to return different + types depending on whether zero, one, or multiple construction + variable names are given. RELEASE 4.8.1 - Tue, 03 Sep 2024 17:22:20 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index 2cb6638..e71f535 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -70,6 +70,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY (per https://bford.info/cachedir/). Update the way a CacheDir is created, since it now has to create two files. +- The Dictionary method now has an as_dict flag. If true, Dictionary + always returns a dict. The default remains to return different + types depending on whether zero, one, or multiple construction + FIXES ----- diff --git a/SCons/Environment.py b/SCons/Environment.py index ad50456..0c14468 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -537,7 +537,7 @@ class SubstitutionEnvironment: Special note: methods here and in actual child classes might be called via proxy from an :class:`OverrideEnvironment`, which isn't in the - Python inheritance chain. Take care that methods called with a *self* + class inheritance chain. Take care that methods called with a *self* that's really an ``OverrideEnvironment`` don't make bad assumptions. """ @@ -1708,23 +1708,33 @@ class Base(SubstitutionEnvironment): return None - def Dictionary(self, *args: str): + def Dictionary(self, *args: str, as_dict: bool = False): """Return construction variables from an environment. Args: - args (optional): variable names to look up + args (optional): construction variable names to select. + If omitted, all variables are selected and returned + as a dict. + as_dict: if true, and *args* is supplied, return the + variables and their values in a dict. If false + (the default), return a single value as a scalar, + or multiple values in a list. Returns: - If *args* omitted, the dictionary of all construction variables. - If one arg, the corresponding value is returned. - If more than one arg, a list of values is returned. + A dictionary of construction variables, or a single value + or list of values. Raises: KeyError: if any of *args* is not in the construction environment. + + .. versionchanged:: NEXT_RELEASE + Added the *as_dict* keyword arg to specify always returning a dict. """ if not args: return self._dict - dlist = [self._dict[x] for x in args] + if as_dict: + return {key: self._dict[key] for key in args} + dlist = [self._dict[key] for key in args] if len(dlist) == 1: return dlist[0] return dlist @@ -1754,13 +1764,10 @@ class Base(SubstitutionEnvironment): If *key* is supplied, a formatted dictionary is generated like the no-arg case - previously a single *key* displayed just the value. """ - if not key: - cvars = self.Dictionary() - elif len(key) == 1: - dkey = key[0] - cvars = {dkey: self[dkey]} + if len(key): + cvars = self.Dictionary(*key, as_dict=True) else: - cvars = dict(zip(key, self.Dictionary(*key))) + cvars = self.Dictionary() fmt = format.lower() @@ -2716,28 +2723,29 @@ class OverrideEnvironment(Base): return False return key in self.__dict__['__subject'] - def Dictionary(self, *args): + def Dictionary(self, *args, as_dict: bool = False): """Return construction variables from an environment. - Returns all the visible variables, or just those in *args* if - specified. Obtains a Dictionary view of the subject env, then layers - the overrrides on top, after which any any deleted items are removed. - - Returns: - Like :meth:`Base.Dictionary`, returns a dict if *args* is - omitted; a single value if there is one arg; else a list of values. + Behavior is as described for :class:`SubstitutionEnvironment.Dictionary` + but understanda about the override. Raises: - KeyError: if any of *args* is not visible in the construction environment. + KeyError: if any of *args* is not in the construction environment. + + .. versionchanged: NEXT_RELEASE + Added the *as_dict* keyword arg to always return a dict. """ - d = self.__dict__['__subject'].Dictionary().copy() + d = {} + d.update(self.__dict__['__subject']) d.update(self.__dict__['overrides']) d = {k: v for k, v in d.items() if k not in self.__dict__['__deleted']} if not args: return d - dlist = [d[x] for x in args] + if as_dict: + return {key: d[key] for key in args} + dlist = [d[key] for key in args] if len(dlist) == 1: - dlist = dlist[0] + return dlist[0] return dlist def items(self): diff --git a/SCons/Environment.xml b/SCons/Environment.xml index 403d6b8..bc4c3b7 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -1624,16 +1624,22 @@ but will not include any such extension in the return value. <scons_function name="Dictionary"> <arguments signature="env"> -([vars]) +([var, ...], [as_dict=]) </arguments> <summary> <para> -Returns a dictionary object -containing the &consvars; in the &consenv;. -If there are any arguments specified, -the values of the specified &consvars; -are returned as a string (if one -argument) or as a list of strings. +Return an object containing &consvars; from +<parameter>env</parameter>. +If <parameter>var</parameter> is omitted, +all the &consvars; with their values +are returned in a <type>dict</type>. +If <parameter>var</parameter> is specified, +and <parameter>as_dict</parameter> is true, +the specified &consvars; are returned in a <type>dict</type>; +otherwise (the default, for backwards compatibility), +values only are returned, +as a scalar if one <parameter>var</parameter> is given, +or as a list if multiples. </para> <para> @@ -1648,8 +1654,8 @@ cc_values = env.Dictionary('CC', 'CCFLAGS', 'CCCOM') <note><para> The object returned by &f-link-env-Dictionary; should be treated as a read-only view into the &consvars;. -Some &consvars; have special internal handling, -and making changes through the &f-env-Dictionary; object can bypass +Some &consvars; require special internal handling, +and modifying them through the &f-env-Dictionary; object can bypass that handling and cause data inconsistencies. The primary use of &f-env-Dictionary; is for diagnostic purposes - it is used widely by test cases specifically because @@ -1657,6 +1663,11 @@ it bypasses the special handling so that behavior can be verified. </para></note> +<para> +<emphasis>Changed in NEXT_RELEASE</emphasis>: +<parameter>as_dict</parameter> added. +</para> + </summary> </scons_function> @@ -1702,24 +1713,30 @@ for more information. <scons_function name="Dump"> <arguments signature="env"> -([key, ...], [format=]) +([var, ...], [format=TYPE]) </arguments> <summary> <para> -Serializes &consvars; from the current &consenv; -to a string. -The method supports the following formats specified by -<parameter>format</parameter>, -which must be used a a keyword argument: +Serialize &consvars; from <parameter>env</parameter> to a string. +If <varname>var</varname> is omitted, +all the &consvars; are serialized. +If one or more <varname>var</varname> values are supplied, +only those variables and their values are serialized. +</para> + +<para> +The optional <parameter>format</parameter> string +selects the serialization format: </para> <variablelist> <varlistentry> <term><literal>pretty</literal></term> <listitem> <para> -Returns a pretty-printed representation of the variables +Returns a pretty-printed representation +of the &consvars; - the result will look like a +&Python; <type>dict</type> (this is the default). -The variables will be presented in &Python; dict form. </para> </listitem> </varlistentry> @@ -1727,31 +1744,25 @@ The variables will be presented in &Python; dict form. <term><literal>json</literal></term> <listitem> <para> -Returns a JSON-formatted string representation of the variables. +Returns a JSON-formatted representation of the variables. The variables will be presented as a JSON object literal, -the JSON equivalent of a &Python; dict. +the JSON equivalent of a &Python; <type>dict</type>.. </para> </listitem> </varlistentry> </variablelist> <para> -If no <varname>key</varname> is supplied, -all the &consvars; are serialized. -If one or more keys are supplied, -only those keys and their values are serialized. -</para> - -<para> <emphasis>Changed in NEXT_RELEASE</emphasis>: More than one <parameter>key</parameter> can be specified. -The returned string always looks like a dict (or JSON equivalent); +The returned string always looks like a <type>dict</type> +(or equivalent in other formats); previously a single key serialized only the value, not the key with the value. </para> <para> -This SConstruct: +Examples: this &SConstruct; </para> <example_commands> @@ -1773,7 +1784,7 @@ will print something like: </example_commands> <para> -While this SConstruct: +While this &SConstruct;: </para> <example_commands> @@ -2022,7 +2033,7 @@ FindSourceFiles('src') </example_commands> <para> -As you can see build support files (SConstruct in the above example) +As you can see build support files (&SConstruct; in the above example) will also be returned by this function. </para> </summary> diff --git a/SCons/EnvironmentTests.py b/SCons/EnvironmentTests.py index 62238c7..22b9074 100644 --- a/SCons/EnvironmentTests.py +++ b/SCons/EnvironmentTests.py @@ -1832,8 +1832,10 @@ def exists(env): assert env['CCC1'] == 'c1', env['CCC1'] assert env['CCC2'] == ['c2'], env['CCC2'] assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1'] - assert env['LL1'] == [env.Literal('a literal'), \ - env.Literal('b literal')], env['LL1'] + assert env['LL1'] == [ + env.Literal('a literal'), + env.Literal('b literal'), + ], env['LL1'] assert env['LL2'] == [ env.Literal('c literal'), env.Literal('b literal'), @@ -2135,6 +2137,13 @@ def generate(env): xxx, zzz = env.Dictionary('XXX', 'ZZZ') assert xxx == 'x' assert zzz == 'z' + # added in NEXT_RELEASE: as_dict flag + with self.subTest(): + expect = {'XXX': 'x'} + self.assertEqual(env.Dictionary('XXX', as_dict=True), expect) + with self.subTest(): + expect = {'XXX': 'x', 'YYY': 'y'} + self.assertEqual(env.Dictionary('XXX', 'YYY', as_dict=True), expect) assert 'BUILDERS' in env.Dictionary() assert 'CC' in env.Dictionary() assert 'CCFLAGS' in env.Dictionary() @@ -3927,6 +3936,13 @@ class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture): xxx, yyy = env2.Dictionary('XXX', 'YYY') assert xxx == 'x2', xxx assert yyy == 'y', yyy + # added in NEXT_VERSION: as_dict flag + with self.subTest(): + expect = {'XXX': 'x3'} + self.assertEqual(env3.Dictionary('XXX', as_dict=True), expect) + with self.subTest(): + expect = {'XXX': 'x2', 'YYY': 'y'} + self.assertEqual(env2.Dictionary('XXX', 'YYY', as_dict=True), expect) # test deletion in top override del env3['XXX'] |