summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2024-11-12 14:35:10 (GMT)
committerMats Wichmann <mats@linux.com>2024-11-12 15:10:40 (GMT)
commitc8ebf8ee8393e3471083920ea07387a30aa6ced1 (patch)
tree31076b6059df2117720836daf6984ff8a20046a1
parentb4d72c716aa98d3cefcf9fcb358429b08ac58114 (diff)
downloadSCons-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.txt4
-rw-r--r--RELEASE.txt4
-rw-r--r--SCons/Environment.py58
-rw-r--r--SCons/Environment.xml71
-rw-r--r--SCons/EnvironmentTests.py20
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']