diff options
author | William Deegan <bill@baddogconsulting.com> | 2024-11-14 05:17:03 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-14 05:17:03 (GMT) |
commit | c1ddbc7fa5e34ae6aba45104e6dfb39ebb08d3eb (patch) | |
tree | 31076b6059df2117720836daf6984ff8a20046a1 | |
parent | b4d72c716aa98d3cefcf9fcb358429b08ac58114 (diff) | |
parent | c8ebf8ee8393e3471083920ea07387a30aa6ced1 (diff) | |
download | SCons-c1ddbc7fa5e34ae6aba45104e6dfb39ebb08d3eb.zip SCons-c1ddbc7fa5e34ae6aba45104e6dfb39ebb08d3eb.tar.gz SCons-c1ddbc7fa5e34ae6aba45104e6dfb39ebb08d3eb.tar.bz2 |
Merge pull request #4633 from mwichmann/feature/Dictionary-dict
Add as_dict flag to env.Dictionary
-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'] |