From cfe50b5e406226aeaff4a0027a8fdd2b9634273a Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 12 Jul 2024 08:22:20 -0600 Subject: [PATCH] Enhancement: Dump() takes multiple args now env.Dump previously either printed the whole dict of construction variables (with no args), or a single value (with one variable name argument). Now it takes a varargs specifier so you can give any number of consvar names. All returned strings are now in dict form, including the single-arg case which previously just returned the value matching the key, not a dict with a key:value pair. This is a slight ABI change, but should not affect any actual scripts since the output is intended for human consumption, not for programmatic use - env.Dictionary() can be used to fetch construction vars for programmatic use (in fact, Dump is a consumer of Dictionary's output). Signed-off-by: Mats Wichmann --- CHANGES.txt | 9 +++++++++ RELEASE.txt | 15 ++++++++++---- SCons/Environment.py | 38 ++++++++++++++++++++++------------- SCons/Environment.xml | 51 ++++++++++++++++++++++++++++++++--------------- SCons/EnvironmentTests.py | 48 ++++++++++++++++++++++++++++++-------------- 5 files changed, 112 insertions(+), 49 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index dea43b8bb..44d8a9787 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -18,6 +18,15 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER will benefit from `TypeGuard`/`TypeIs`, to produce intellisense similar to using `isinstance` directly. + From Mats Wichmann: + - env.Dump() now considers the "key" positional argument to be a varargs + type (zero, one or many). However called, it returns a serialized + result that looks like a dict. Previously, only one "key" was + accepted. and unlike the zero-args case, it was be serialized + to a string containing the value without the key. For example, if + "print(repr(env.Dump('CC'))" previously returned "'gcc'", it will now + return "{'CC': 'gcc'}". + RELEASE 4.8.0 - Sun, 07 Jul 2024 17:22:20 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index 5845e560c..b29ecbd1a 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -26,8 +26,15 @@ DEPRECATED FUNCTIONALITY CHANGED/ENHANCED EXISTING FUNCTIONALITY --------------------------------------- -- List modifications to existing features, where the previous behavior - wouldn't actually be considered a bug +- env.Dump() previously accepted a single optional "key" argument. + It now accepts any number of optional "key" arguments; any supplied + keys will be serialized with their values in a Python dict style. + As a result there is a small change in behavior: if a *single* key + argument is given, where it previously would return a string containing + just the value, now it will return a string that looks like a dictionary + including the key. For example, from "'gcc'" to "{'CC': 'gcc'}". + This should not have any impact as the result of calling Dump is + intended for diagnostic output, not for use by other interfaces. FIXES ----- @@ -38,8 +45,8 @@ IMPROVEMENTS ------------ - List improvements that wouldn't be visible to the user in the - documentation: performance improvements (describe the circumstances - under which they would be observed), or major code cleanups +documentation: performance improvements (describe the circumstances +under which they would be observed), or major code cleanups PACKAGING --------- diff --git a/SCons/Environment.py b/SCons/Environment.py index 932245062..ac752c71a 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1694,28 +1694,37 @@ class Base(SubstitutionEnvironment): return dlist - def Dump(self, key: Optional[str] = None, format: str = 'pretty') -> str: - """ Returns a dump of serialized construction variables. + def Dump(self, *key: str, format: str = 'pretty') -> str: + """Return string of serialized construction variables. - The display formats are intended for humaan readers when - debugging - none of the supported formats produce a result that - SCons itself can directly make use of. Objects that cannot - directly be represented get a placeholder like - ```` or ``<>``. + Produces a "pretty" output of a dictionary of selected + construction variables, or all of them. The display *format* is + selectable. The result is intended for human consumption (e.g, + to print), mainly when debugging. Objects that cannot directly be + represented get a placeholder like ```` + (pretty-print) or ``<>`` (JSON). Args: - key: if ``None``, format the whole dict of variables, - else format just the value of *key*. + key: if omitted, format the whole dict of variables, + else format *key*(s) with the corresponding values. format: specify the format to serialize to. ``"pretty"`` generates a pretty-printed string, ``"json"`` a JSON-formatted string. Raises: ValueError: *format* is not a recognized serialization format. + + .. versionchanged:: NEXT_VERSION + *key* is no longer limited to a single construction variable name. + If *key* is supplied, a formatted dictionary is generated like the + no-arg case - previously a single *key* displayed just the value. """ - if key: - cvars = self.Dictionary(key) - else: + if not key: cvars = self.Dictionary() + elif len(key) == 1: + dkey = key[0] + cvars = {dkey: self[dkey]} + else: + cvars = dict(zip(key, self.Dictionary(*key))) fmt = format.lower() @@ -1735,14 +1744,15 @@ class Base(SubstitutionEnvironment): class DumpEncoder(json.JSONEncoder): """SCons special json Dump formatter.""" + def default(self, obj): if isinstance(obj, (UserList, UserDict)): return obj.data return f'<>' return json.dumps(cvars, indent=4, cls=DumpEncoder, sort_keys=True) - else: - raise ValueError("Unsupported serialization format: %s." % fmt) + + raise ValueError("Unsupported serialization format: %s." % fmt) def FindIxes(self, paths: Sequence[str], prefix: str, suffix: str) -> Optional[str]: diff --git a/SCons/Environment.xml b/SCons/Environment.xml index f489ca17f..ce73cad6a 100644 --- a/SCons/Environment.xml +++ b/SCons/Environment.xml @@ -1692,21 +1692,24 @@ for more information. -([key], [format]) +([key, ...], [format=]) -Serializes &consvars; to a string. +Serializes &consvars; from the current &consenv; +to a string. The method supports the following formats specified by -format: +format, +which must be used a a keyword argument: + pretty -Returns a pretty printed representation of the environment (if -format -is not specified, this is the default). +Returns a pretty-printed representation of the variables +(this is the default). +The variables will be presented in &Python; dict form. @@ -1714,17 +1717,27 @@ is not specified, this is the default). json -Returns a JSON-formatted string representation of the environment. +Returns a JSON-formatted string representation of the variables. +The variables will be presented as a JSON object literal, +the JSON equivalent of a &Python; dict. -If key is -None (the default) the entire -dictionary of &consvars; is serialized. -If supplied, it is taken as the name of a &consvar; -whose value is serialized. + +If no key is supplied, +all the &consvars; are serialized. +If one or more keys are supplied, +only those keys and their values are serialized. + + + +Changed in NEXT_VERSION: +More than one key can be specified. +The returned string always looks like a dict (or JSON equivalent); +previously a single key serialized only the value, +not the key with the value. @@ -1732,16 +1745,21 @@ This SConstruct: -env=Environment() +env = Environment() print(env.Dump('CCCOM')) +print(env.Dump('CC', 'CCFLAGS', format='json')) -will print: +will print something like: -'$CC -c -o $TARGET $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES' +{'CCCOM': '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'} +{ + "CC": "gcc", + "CCFLAGS": [] +} @@ -1754,7 +1772,7 @@ print(env.Dump()) -will print: +will print something like: { 'AR': 'ar', @@ -1765,6 +1783,7 @@ will print: 'ASFLAGS': [], ... + diff --git a/SCons/EnvironmentTests.py b/SCons/EnvironmentTests.py index 8d90d4d17..f171ac896 100644 --- a/SCons/EnvironmentTests.py +++ b/SCons/EnvironmentTests.py @@ -3176,24 +3176,42 @@ def generate(env): def test_Dump(self) -> None: """Test the Dump() method""" - env = self.TestEnvironment(FOO='foo', FOOFLAGS=CLVar('--bar --baz')) - assert env.Dump('FOO') == "'foo'", env.Dump('FOO') - assert len(env.Dump()) > 200, env.Dump() # no args version - assert env.Dump('FOO', 'json') == '"foo"' # JSON key version - expect = """[\n "--bar",\n "--baz"\n]""" - self.assertEqual(env.Dump('FOOFLAGS', 'json'), expect) - import json - env_dict = json.loads(env.Dump(format = 'json')) - assert env_dict['FOO'] == 'foo' # full JSON version + # changed in NEXT_VERSION: single arg now displays as a dict, + # not a bare value; more than one arg is allowed. + with self.subTest(): # one-arg version + self.assertEqual(env.Dump('FOO'), "{'FOO': 'foo'}") + + with self.subTest(): # multi-arg version + expect = "{'FOO': 'foo', 'FOOFLAGS': ['--bar', '--baz']}" + self.assertEqual(env.Dump('FOO', 'FOOFLAGS'), expect) + + with self.subTest(): # no-arg version + self.assertGreater(len(env.Dump()), 200) + + with self.subTest(): # one-arg JSON version, simple value + expect = '{\n "FOO": "foo"\n}' + self.assertEqual(env.Dump('FOO', format='json'), expect) + + with self.subTest(): # one-arg JSON version, list value + expect = '{\n "FOOFLAGS": [\n "--bar",\n "--baz"\n ]\n}' + self.assertEqual(env.Dump('FOOFLAGS', format='json'), expect) + + with self.subTest(): # multi--arg JSON version, list value + expect = '{\n "FOO": "foo",\n "FOOFLAGS": [\n "--bar",\n "--baz"\n ]\n}' + self.assertEqual(env.Dump('FOO', 'FOOFLAGS', format='json'), expect) + + with self.subTest(): # full JSON version + import json + env_dict = json.loads(env.Dump(format='json')) + self.assertEqual(env_dict['FOO'], 'foo') + + with self.subTest(): # unsupported format type + with self.assertRaises(ValueError) as cm: + env.Dump(format='markdown') + self.assertEqual(str(cm.exception), "Unsupported serialization format: markdown.") - try: - env.Dump(format = 'markdown') - except ValueError as e: - assert str(e) == "Unsupported serialization format: markdown." - else: - self.fail("Did not catch expected ValueError.") def test_Environment(self) -> None: """Test the Environment() method""" -- 2.11.4.GIT