Skip to content

Commit

Permalink
Merge branch 'master' into maint/py313-re
Browse files Browse the repository at this point in the history
  • Loading branch information
bdbaddog authored Mar 22, 2024
2 parents 43c6529 + 9beb493 commit 9c97705
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
- Updated Value Node docs and tests.
- Python 3.13 compat: re.sub deprecated count, flags as positional args,
caused update-release-info test to fail.
- Dump() with json format selected now recognizes additional compound types
(UserDict and UserList), which improves the detail of the display.
json output is also sorted, to match the default display.


RELEASE 4.7.0 - Sun, 17 Mar 2024 17:22:20 -0700
Expand Down
5 changes: 3 additions & 2 deletions RELEASE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ DEPRECATED FUNCTIONALITY
CHANGED/ENHANCED EXISTING FUNCTIONALITY
---------------------------------------

- List modifications to existing features, where the previous behavior
wouldn't actually be considered a bug
- Dump() with json format selected now recognizes additional compound types
(UserDict and UserList), which improves the detail of the display.
json output is also sorted, to match the default display.

FIXES
-----
Expand Down
61 changes: 37 additions & 24 deletions SCons/Environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
import sys
import re
import shlex
from collections import UserDict, deque
from collections import UserDict, UserList, deque
from subprocess import PIPE, DEVNULL
from typing import Optional
from typing import Optional, Sequence

import SCons.Action
import SCons.Builder
Expand Down Expand Up @@ -1687,17 +1687,23 @@ def Dictionary(self, *args):
return dlist


def Dump(self, key=None, format: str='pretty'):
""" Return construction variables serialized to a string.
def Dump(self, key: Optional[str] = None, format: str = 'pretty') -> str:
""" Returns a dump 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
``<function foo at 0x123456>`` or ``<<non-serializable: function>>``.
Args:
key (optional): if None, format the whole dict of variables.
Else format the value of `key` (Default value = None)
format (str, optional): specify the format to serialize to.
`"pretty"` generates a pretty-printed string,
`"json"` a JSON-formatted string.
(Default value = `"pretty"`)
key: if ``None``, format the whole dict of variables,
else format just the value of *key*.
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.
"""
if key:
cvars = self.Dictionary(key)
Expand All @@ -1707,9 +1713,9 @@ def Dump(self, key=None, format: str='pretty'):
fmt = format.lower()

if fmt == 'pretty':
import pprint
pp = pprint.PrettyPrinter(indent=2)
import pprint # pylint: disable=import-outside-toplevel

pp = pprint.PrettyPrinter(indent=2)
# TODO: pprint doesn't do a nice job on path-style values
# if the paths contain spaces (i.e. Windows), because the
# algorithm tries to break lines on spaces, while breaking
Expand All @@ -1718,26 +1724,33 @@ def Dump(self, key=None, format: str='pretty'):
return pp.pformat(cvars)

elif fmt == 'json':
import json
def non_serializable(obj):
return '<<non-serializable: %s>>' % type(obj).__qualname__
return json.dumps(cvars, indent=4, default=non_serializable)
import json # pylint: disable=import-outside-toplevel

class DumpEncoder(json.JSONEncoder):
"""SCons special json Dump formatter."""
def default(self, obj):
if isinstance(obj, (UserList, UserDict)):
return obj.data
return f'<<non-serializable: {type(obj).__qualname__}>>'

return json.dumps(cvars, indent=4, cls=DumpEncoder, sort_keys=True)
else:
raise ValueError("Unsupported serialization format: %s." % fmt)


def FindIxes(self, paths, prefix, suffix):
"""Search a list of paths for something that matches the prefix and suffix.
def FindIxes(self, paths: Sequence[str], prefix: str, suffix: str) -> Optional[str]:
"""Search *paths* for a path that has *prefix* and *suffix*.
Args:
paths: the list of paths or nodes.
prefix: construction variable for the prefix.
suffix: construction variable for the suffix.
Returns on first match.
Returns: the matched path or None
Arguments:
paths: the list of paths or nodes.
prefix: construction variable for the prefix.
suffix: construction variable for the suffix.
Returns:
The matched path or ``None``
"""

suffix = self.subst('$'+suffix)
prefix = self.subst('$'+prefix)

Expand Down
3 changes: 2 additions & 1 deletion SCons/EnvironmentTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3182,7 +3182,8 @@ def test_Dump(self) -> None:
assert len(env.Dump()) > 200, env.Dump() # no args version

assert env.Dump('FOO', 'json') == '"foo"' # JSON key version
self.assertEqual(env.Dump('FOOFLAGS', 'json'), '"<<non-serializable: CLVar>>"')
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
Expand Down

0 comments on commit 9c97705

Please sign in to comment.