Skip to content

Commit ad29bd7

Browse files
authored
Merge pull request SCons#4572 from mwichmann/env/dump-multi
Enhancement: Dump() takes multiple args now
2 parents b4260a7 + cfe50b5 commit ad29bd7

File tree

5 files changed

+112
-49
lines changed

5 files changed

+112
-49
lines changed

CHANGES.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
1818
will benefit from `TypeGuard`/`TypeIs`, to produce intellisense similar
1919
to using `isinstance` directly.
2020

21+
From Mats Wichmann:
22+
- env.Dump() now considers the "key" positional argument to be a varargs
23+
type (zero, one or many). However called, it returns a serialized
24+
result that looks like a dict. Previously, only one "key" was
25+
accepted. and unlike the zero-args case, it was be serialized
26+
to a string containing the value without the key. For example, if
27+
"print(repr(env.Dump('CC'))" previously returned "'gcc'", it will now
28+
return "{'CC': 'gcc'}".
29+
2130

2231
RELEASE 4.8.0 - Sun, 07 Jul 2024 17:22:20 -0700
2332

RELEASE.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,15 @@ DEPRECATED FUNCTIONALITY
2626
CHANGED/ENHANCED EXISTING FUNCTIONALITY
2727
---------------------------------------
2828

29-
- List modifications to existing features, where the previous behavior
30-
wouldn't actually be considered a bug
29+
- env.Dump() previously accepted a single optional "key" argument.
30+
It now accepts any number of optional "key" arguments; any supplied
31+
keys will be serialized with their values in a Python dict style.
32+
As a result there is a small change in behavior: if a *single* key
33+
argument is given, where it previously would return a string containing
34+
just the value, now it will return a string that looks like a dictionary
35+
including the key. For example, from "'gcc'" to "{'CC': 'gcc'}".
36+
This should not have any impact as the result of calling Dump is
37+
intended for diagnostic output, not for use by other interfaces.
3138

3239
FIXES
3340
-----
@@ -38,8 +45,8 @@ IMPROVEMENTS
3845
------------
3946

4047
- List improvements that wouldn't be visible to the user in the
41-
documentation: performance improvements (describe the circumstances
42-
under which they would be observed), or major code cleanups
48+
documentation: performance improvements (describe the circumstances
49+
under which they would be observed), or major code cleanups
4350

4451
PACKAGING
4552
---------

SCons/Environment.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,28 +1694,37 @@ def Dictionary(self, *args):
16941694
return dlist
16951695

16961696

1697-
def Dump(self, key: Optional[str] = None, format: str = 'pretty') -> str:
1698-
""" Returns a dump of serialized construction variables.
1697+
def Dump(self, *key: str, format: str = 'pretty') -> str:
1698+
"""Return string of serialized construction variables.
16991699
1700-
The display formats are intended for humaan readers when
1701-
debugging - none of the supported formats produce a result that
1702-
SCons itself can directly make use of. Objects that cannot
1703-
directly be represented get a placeholder like
1704-
``<function foo at 0x123456>`` or ``<<non-serializable: function>>``.
1700+
Produces a "pretty" output of a dictionary of selected
1701+
construction variables, or all of them. The display *format* is
1702+
selectable. The result is intended for human consumption (e.g,
1703+
to print), mainly when debugging. Objects that cannot directly be
1704+
represented get a placeholder like ``<function foo at 0x123456>``
1705+
(pretty-print) or ``<<non-serializable: function>>`` (JSON).
17051706
17061707
Args:
1707-
key: if ``None``, format the whole dict of variables,
1708-
else format just the value of *key*.
1708+
key: if omitted, format the whole dict of variables,
1709+
else format *key*(s) with the corresponding values.
17091710
format: specify the format to serialize to. ``"pretty"`` generates
17101711
a pretty-printed string, ``"json"`` a JSON-formatted string.
17111712
17121713
Raises:
17131714
ValueError: *format* is not a recognized serialization format.
1715+
1716+
.. versionchanged:: NEXT_VERSION
1717+
*key* is no longer limited to a single construction variable name.
1718+
If *key* is supplied, a formatted dictionary is generated like the
1719+
no-arg case - previously a single *key* displayed just the value.
17141720
"""
1715-
if key:
1716-
cvars = self.Dictionary(key)
1717-
else:
1721+
if not key:
17181722
cvars = self.Dictionary()
1723+
elif len(key) == 1:
1724+
dkey = key[0]
1725+
cvars = {dkey: self[dkey]}
1726+
else:
1727+
cvars = dict(zip(key, self.Dictionary(*key)))
17191728

17201729
fmt = format.lower()
17211730

@@ -1735,14 +1744,15 @@ def Dump(self, key: Optional[str] = None, format: str = 'pretty') -> str:
17351744

17361745
class DumpEncoder(json.JSONEncoder):
17371746
"""SCons special json Dump formatter."""
1747+
17381748
def default(self, obj):
17391749
if isinstance(obj, (UserList, UserDict)):
17401750
return obj.data
17411751
return f'<<non-serializable: {type(obj).__qualname__}>>'
17421752

17431753
return json.dumps(cvars, indent=4, cls=DumpEncoder, sort_keys=True)
1744-
else:
1745-
raise ValueError("Unsupported serialization format: %s." % fmt)
1754+
1755+
raise ValueError("Unsupported serialization format: %s." % fmt)
17461756

17471757

17481758
def FindIxes(self, paths: Sequence[str], prefix: str, suffix: str) -> Optional[str]:

SCons/Environment.xml

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,56 +1692,74 @@ for more information.
16921692

16931693
<scons_function name="Dump">
16941694
<arguments signature="env">
1695-
([key], [format])
1695+
([key, ...], [format=])
16961696
</arguments>
16971697
<summary>
16981698
<para>
1699-
Serializes &consvars; to a string.
1699+
Serializes &consvars; from the current &consenv;
1700+
to a string.
17001701
The method supports the following formats specified by
1701-
<parameter>format</parameter>:
1702+
<parameter>format</parameter>,
1703+
which must be used a a keyword argument:
1704+
</para>
17021705
<variablelist>
17031706
<varlistentry>
17041707
<term><literal>pretty</literal></term>
17051708
<listitem>
17061709
<para>
1707-
Returns a pretty printed representation of the environment (if
1708-
<parameter>format</parameter>
1709-
is not specified, this is the default).
1710+
Returns a pretty-printed representation of the variables
1711+
(this is the default).
1712+
The variables will be presented in &Python; dict form.
17101713
</para>
17111714
</listitem>
17121715
</varlistentry>
17131716
<varlistentry>
17141717
<term><literal>json</literal></term>
17151718
<listitem>
17161719
<para>
1717-
Returns a JSON-formatted string representation of the environment.
1720+
Returns a JSON-formatted string representation of the variables.
1721+
The variables will be presented as a JSON object literal,
1722+
the JSON equivalent of a &Python; dict.
17181723
</para>
17191724
</listitem>
17201725
</varlistentry>
17211726
</variablelist>
17221727

1723-
If <varname>key</varname> is
1724-
<constant>None</constant> (the default) the entire
1725-
dictionary of &consvars; is serialized.
1726-
If supplied, it is taken as the name of a &consvar;
1727-
whose value is serialized.
1728+
<para>
1729+
If no <varname>key</varname> is supplied,
1730+
all the &consvars; are serialized.
1731+
If one or more keys are supplied,
1732+
only those keys and their values are serialized.
1733+
</para>
1734+
1735+
<para>
1736+
<emphasis>Changed in NEXT_VERSION</emphasis>:
1737+
More than one <parameter>key</parameter> can be specified.
1738+
The returned string always looks like a dict (or JSON equivalent);
1739+
previously a single key serialized only the value,
1740+
not the key with the value.
17281741
</para>
17291742

17301743
<para>
17311744
This SConstruct:
17321745
</para>
17331746

17341747
<example_commands>
1735-
env=Environment()
1748+
env = Environment()
17361749
print(env.Dump('CCCOM'))
1750+
print(env.Dump('CC', 'CCFLAGS', format='json'))
17371751
</example_commands>
17381752

17391753
<para>
1740-
will print:
1754+
will print something like:
17411755
</para>
17421756

17431757
<example_commands>
1744-
'$CC -c -o $TARGET $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES'
1758+
{'CCCOM': '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'}
1759+
{
1760+
"CC": "gcc",
1761+
"CCFLAGS": []
1762+
}
17451763
</example_commands>
17461764

17471765
<para>
@@ -1754,7 +1772,7 @@ print(env.Dump())
17541772
</example_commands>
17551773

17561774
<para>
1757-
will print:
1775+
will print something like:
17581776
</para>
17591777
<example_commands>
17601778
{ 'AR': 'ar',
@@ -1765,6 +1783,7 @@ will print:
17651783
'ASFLAGS': [],
17661784
...
17671785
</example_commands>
1786+
17681787
</summary>
17691788
</scons_function>
17701789

SCons/EnvironmentTests.py

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,24 +3176,42 @@ def test_NoClean(self) -> None:
31763176

31773177
def test_Dump(self) -> None:
31783178
"""Test the Dump() method"""
3179-
31803179
env = self.TestEnvironment(FOO='foo', FOOFLAGS=CLVar('--bar --baz'))
3181-
assert env.Dump('FOO') == "'foo'", env.Dump('FOO')
3182-
assert len(env.Dump()) > 200, env.Dump() # no args version
31833180

3184-
assert env.Dump('FOO', 'json') == '"foo"' # JSON key version
3185-
expect = """[\n "--bar",\n "--baz"\n]"""
3186-
self.assertEqual(env.Dump('FOOFLAGS', 'json'), expect)
3187-
import json
3188-
env_dict = json.loads(env.Dump(format = 'json'))
3189-
assert env_dict['FOO'] == 'foo' # full JSON version
3181+
# changed in NEXT_VERSION: single arg now displays as a dict,
3182+
# not a bare value; more than one arg is allowed.
3183+
with self.subTest(): # one-arg version
3184+
self.assertEqual(env.Dump('FOO'), "{'FOO': 'foo'}")
3185+
3186+
with self.subTest(): # multi-arg version
3187+
expect = "{'FOO': 'foo', 'FOOFLAGS': ['--bar', '--baz']}"
3188+
self.assertEqual(env.Dump('FOO', 'FOOFLAGS'), expect)
3189+
3190+
with self.subTest(): # no-arg version
3191+
self.assertGreater(len(env.Dump()), 200)
3192+
3193+
with self.subTest(): # one-arg JSON version, simple value
3194+
expect = '{\n "FOO": "foo"\n}'
3195+
self.assertEqual(env.Dump('FOO', format='json'), expect)
3196+
3197+
with self.subTest(): # one-arg JSON version, list value
3198+
expect = '{\n "FOOFLAGS": [\n "--bar",\n "--baz"\n ]\n}'
3199+
self.assertEqual(env.Dump('FOOFLAGS', format='json'), expect)
3200+
3201+
with self.subTest(): # multi--arg JSON version, list value
3202+
expect = '{\n "FOO": "foo",\n "FOOFLAGS": [\n "--bar",\n "--baz"\n ]\n}'
3203+
self.assertEqual(env.Dump('FOO', 'FOOFLAGS', format='json'), expect)
3204+
3205+
with self.subTest(): # full JSON version
3206+
import json
3207+
env_dict = json.loads(env.Dump(format='json'))
3208+
self.assertEqual(env_dict['FOO'], 'foo')
3209+
3210+
with self.subTest(): # unsupported format type
3211+
with self.assertRaises(ValueError) as cm:
3212+
env.Dump(format='markdown')
3213+
self.assertEqual(str(cm.exception), "Unsupported serialization format: markdown.")
31903214

3191-
try:
3192-
env.Dump(format = 'markdown')
3193-
except ValueError as e:
3194-
assert str(e) == "Unsupported serialization format: markdown."
3195-
else:
3196-
self.fail("Did not catch expected ValueError.")
31973215

31983216
def test_Environment(self) -> None:
31993217
"""Test the Environment() method"""

0 commit comments

Comments
 (0)