Skip to content

Commit 758bd26

Browse files
authored
Merge branch 'master' into doc/doctools
2 parents 125a1ac + 122b1b5 commit 758bd26

File tree

16 files changed

+73
-31
lines changed

16 files changed

+73
-31
lines changed

CHANGES.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
3131
turning the introductory comment in bin/SConsExamples into a docstring
3232
that can be rendered by Sphinx, and updating that text. The rest is
3333
minor fiddling like switching to f-strings small doc changes.
34+
- Fix a couple of unit tests to not fail with Python 3.14. These involve
35+
bytecode and error message contents, and there was no problem with
36+
SCons itself using 3.14 in its current (just-before-freeze) state.
37+
- Replace use of old conditional expression idioms with the official
38+
one from PEP 308 introduced in Python 2.5 (2006). The idiom being
39+
replaced (using and/or) is regarded as error prone.
3440

3541

3642
RELEASE 4.9.1 - Thu, 27 Mar 2025 11:40:20 -0700

RELEASE.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY
3131

3232
- Nodes are now treated as PathLike objects.
3333

34+
- Replace use of old conditional expression idioms with the official
35+
one from PEP 308 introduced in Python 2.5 (2006). The idiom being
36+
replaced (using and/or) is regarded as error prone.
37+
3438
FIXES
3539
-----
3640

@@ -64,6 +68,10 @@ DEVELOPMENT
6468
- runtest.py once again finds "external" tests, such as the tests for
6569
tools in scons-contrib. An earlier rework had broken this. Fixes #4699.
6670

71+
- Fix a couple of unit tests to not fail with Python 3.14. These involve
72+
expectations for bytecode and error message contents; there was no problem
73+
with SCons itself using 3.14 in its current (just-before-freeze) state.
74+
6775
Thanks to the following contributors listed below for their contributions to this release.
6876
==========================================================================================
6977
.. code-block:: text

SCons/ActionTests.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,7 @@ def LocalFunc() -> None:
15521552
(3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
15531553
(3, 12): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00y\x00),(),()'),
15541554
(3, 13): bytearray(b'0, 0, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1555+
(3, 14): bytearray(b'0, 0, 0, 0,(),(),(\x80\x00P\x00"\x00),(),()'),
15551556
}
15561557

15571558
meth_matches = [
@@ -1732,6 +1733,7 @@ def LocalFunc() -> None:
17321733
(3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
17331734
(3, 12): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00y\x00),(),()'),
17341735
(3, 13): bytearray(b'0, 0, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1736+
(3, 14): bytearray(b'0, 0, 0, 0,(),(),(\x80\x00P\x00"\x00),(),()'),
17351737

17361738
}
17371739

@@ -1743,6 +1745,7 @@ def LocalFunc() -> None:
17431745
(3, 11): bytearray(b'1, 1, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
17441746
(3, 12): bytearray(b'1, 1, 0, 0,(),(),(\x97\x00y\x00),(),()'),
17451747
(3, 13): bytearray(b'1, 1, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1748+
(3, 14): bytearray(b'1, 1, 0, 0,(),(),(\x80\x00P\x00"\x00),(),()'),
17461749
}
17471750

17481751
def factory(act, **kw):
@@ -1983,6 +1986,7 @@ def LocalFunc() -> None:
19831986
(3, 11): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
19841987
(3, 12): bytearray(b'0, 0, 0, 0,(),(),(\x97\x00y\x00),(),()'),
19851988
(3, 13): bytearray(b'0, 0, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1989+
(3, 14): bytearray(b'0, 0, 0, 0,(),(),(\x80\x00P\x00"\x00),(),()'),
19861990
}
19871991

19881992
meth_matches = [
@@ -2045,6 +2049,7 @@ def LocalFunc() -> None:
20452049
(3, 11): b'\x97\x00d\x00S\x00',
20462050
(3, 12): b'\x97\x00y\x00',
20472051
(3, 13): b'\x95\x00g\x00',
2052+
(3, 14): b'\x80\x00P\x00"\x00',
20482053
}
20492054

20502055
with self.subTest():
@@ -2250,6 +2255,7 @@ def func1(a, b, c):
22502255
(3, 11): (bytearray(b'3, 3, 0, 0,(),(),(\x97\x00|\x00S\x00),(),()'),),
22512256
(3, 12): (bytearray(b'3, 3, 0, 0,(),(),(\x97\x00|\x00S\x00),(),()'),),
22522257
(3, 13): (bytearray(b'3, 3, 0, 0,(),(),(\x95\x00U\x00$\x00),(),()'),),
2258+
(3, 14): (bytearray(b'3, 3, 0, 0,(),(),(\x80\x00R\x00"\x00),(),()'),),
22532259
}
22542260

22552261
c = SCons.Action._function_contents(func1)
@@ -2288,9 +2294,13 @@ def test_object_contents(self) -> None:
22882294
(3, 13): bytearray(
22892295
b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x95\x00S\x01U\x00l\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x02U\x00l\x01\x00\x00\x00\x00\x00\x00\x00\x00g\x00),(),(),2, 2, 0, 0,(),(),(\x95\x00g\x00),(),()}}{{{a=a,b=b}}}"
22902296
),
2297+
(3, 14): bytearray(
2298+
b'{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x80\x00P\x00R\x00j\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x01R\x00j\x01\x00\x00\x00\x00\x00\x00\x00\x00P\x02"\x00),(),(),2, 2, 0, 0,(),(),(\x80\x00P\x00"\x00),(),()}}{{{a=a,b=b}}}'
2299+
),
22912300
}
22922301

2293-
self.assertEqual(c, expected[sys.version_info[:2]])
2302+
# self.assertEqual(c, expected[sys.version_info[:2]])
2303+
assert c == expected[sys.version_info[:2]], c
22942304

22952305
def test_code_contents(self) -> None:
22962306
"""Test that Action._code_contents works"""
@@ -2321,6 +2331,9 @@ def test_code_contents(self) -> None:
23212331
(3, 13): bytearray(
23222332
b'0, 0, 0, 0,(Hello, World!),(print),(\x95\x00\\\x00"\x00S\x005\x01\x00\x00\x00\x00\x00\x00 \x00g\x01)'
23232333
),
2334+
(3, 14): bytearray(
2335+
b'0, 0, 0, 0,(Hello, World!),(print),(\x80\x00Y\x00 \x00P\x002\x01\x00\x00\x00\x00\x00\x00\x1e\x00P\x01"\x00)'
2336+
),
23242337
}
23252338

23262339
self.assertEqual(c, expected[sys.version_info[:2]])

SCons/Builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ def set_src_suffix(self, src_suffix) -> None:
701701
src_suffix = []
702702
elif not SCons.Util.is_List(src_suffix):
703703
src_suffix = [ src_suffix ]
704-
self.src_suffix = [callable(suf) and suf or self.adjust_suffix(suf) for suf in src_suffix]
704+
self.src_suffix = [suf if callable(suf) else self.adjust_suffix(suf) for suf in src_suffix]
705705

706706
def get_src_suffix(self, env):
707707
"""Get the first src_suffix in the list of src_suffixes."""

SCons/Script/Main.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,19 +465,28 @@ def __init__(self, derived: bool=False, prune: bool=False, status: bool=False, s
465465
self.prune = prune
466466
self.status = status
467467
self.sLineDraw = sLineDraw
468+
468469
def get_all_children(self, node):
469470
return node.all_children()
471+
470472
def get_derived_children(self, node):
471473
children = node.all_children(None)
472474
return [x for x in children if x.has_builder()]
475+
473476
def display(self, t) -> None:
474477
if self.derived:
475478
func = self.get_derived_children
476479
else:
477480
func = self.get_all_children
478-
s = self.status and 2 or 0
479-
SCons.Util.print_tree(t, func, prune=self.prune, showtags=s, lastChild=True, singleLineDraw=self.sLineDraw)
480-
481+
s = 2 if self.status else 0
482+
SCons.Util.print_tree(
483+
t,
484+
func,
485+
prune=self.prune,
486+
showtags=s,
487+
lastChild=True,
488+
singleLineDraw=self.sLineDraw,
489+
)
481490

482491
def python_version_string():
483492
return sys.version.split()[0]

SCons/Taskmaster/TaskmasterTests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,7 @@ def test_exception(self) -> None:
11611161
"integer division or modulo",
11621162
"integer division or modulo by zero",
11631163
"integer division by zero", # PyPy2
1164+
"division by zero", # Python 3.14+
11641165
]
11651166
assert str(exc_value) in exception_values, exc_value
11661167

SCons/Tool/linkCommon/SharedLibrary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def setup_shared_lib_logic(env) -> None:
202202

203203
# Note this is gnu style
204204
env["SHLIBSONAMEFLAGS"] = "-Wl,-soname=$_SHLIBSONAME"
205-
env["_SHLIBVERSION"] = "${SHLIBVERSION and '.'+SHLIBVERSION or ''}"
205+
env["_SHLIBVERSION"] = "${'.' + SHLIBVERSION if SHLIBVERSION else ''}"
206206
env["_SHLIBVERSIONFLAGS"] = "$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME"
207207

208208
env["SHLIBEMITTER"] = [lib_emitter, shlib_symlink_emitter]

SCons/Tool/msvc.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ def msvc_set_PCHPDBFLAGS(env) -> None:
7272
if env.get('MSVC_VERSION',False):
7373
maj, min = msvc_version_to_maj_min(env['MSVC_VERSION'])
7474
if maj < 8:
75-
env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}'])
75+
env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${"/Yd" if PDB else ""}'])
7676
else:
7777
env['PCHPDBFLAGS'] = ''
7878
else:
7979
# Default if we can't determine which version of MSVC we're using
80-
env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}'])
80+
env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${"/Yd" if PDB else ""}'])
8181

8282

8383
def pch_emitter(target, source, env):
@@ -143,7 +143,7 @@ def gen_ccpchflags(env, target, source, for_signature):
143143
pch_node = get_pch_node(env, target, source)
144144
if not pch_node:
145145
return ''
146-
146+
147147
return SCons.Util.CLVar(["/Yu$PCHSTOP", "/Fp%s" % pch_node])
148148

149149
pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR')
@@ -256,7 +256,7 @@ def generate(env) -> None:
256256
static_obj.add_emitter(suffix, static_object_emitter)
257257
shared_obj.add_emitter(suffix, shared_object_emitter)
258258

259-
env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Z7") or ""}'])
259+
env['CCPDBFLAGS'] = SCons.Util.CLVar(['${"/Z7" if PDB else ""}'])
260260
env['CCPCHFLAGS'] = gen_ccpchflags
261261
env['_MSVC_OUTPUT_FLAG'] = msvc_output_flag
262262
env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS'

bin/scons-diff.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,10 @@ def simple_diff(a, b, fromfile='', tofile='',
9090
output like the simple, unadorned 'diff" command.
9191
"""
9292
sm = difflib.SequenceMatcher(None, a, b)
93+
9394
def comma(x1, x2):
94-
return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2)
95+
return x1 + 1 == str(x2) if x2 else '%s,%s' % (x1 + 1, x2)
96+
9597
result = []
9698
for op, a1, a2, b1, b2 in sm.get_opcodes():
9799
if op == 'delete':

bin/update-release-info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def set_new_date(self):
173173
Mon, 05 Jun 2010 21:17:15 -0700
174174
NEW DATE WILL BE INSERTED HERE
175175
"""
176-
min = (time.daylight and time.altzone or time.timezone) // 60
176+
min = (time.altzone if time.daylight else time.timezone) // 60
177177
hr = min // 60
178178
min = -(min % 60 + hr * 100)
179179
self.new_date = (time.strftime('%a, %d %b %Y %X', self.release_date + (0, 0, 0))

site_scons/BuildCommandLine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def set_date(self):
104104
NEW DATE WILL BE INSERTED HERE
105105
"""
106106

107-
min = (time.daylight and time.altzone or time.timezone) // 60
107+
min = (time.altzone if time.daylight else time.timezone) // 60
108108
hr = min // 60
109109
min = -(min % 60 + hr * 100)
110110
# TODO: is it better to take the date of last rev? Externally:

test/Actions/function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def foo(b=b):
122122
def runtest(arguments, expectedOutFile, expectedRebuild=True, stderr=""):
123123
test.run(
124124
arguments=arguments,
125-
stdout=expectedRebuild and rebuildstr or nobuildstr,
125+
stdout=rebuildstr if expectedRebuild else nobuildstr,
126126
stderr="",
127127
)
128128

test/SPAWN.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
ofp.write(ifp.read())
4343
""")
4444

45-
test.write('SConstruct', """
45+
test.write('SConstruct', """\
4646
import subprocess
4747
import sys
4848
@@ -56,16 +56,19 @@ def my_spawn2(sh, escape, cmd, args, env):
5656
cp = subprocess.run(s, shell=True)
5757
return cp.returncode
5858
59-
env = Environment(MY_SPAWN1 = my_spawn1,
60-
MY_SPAWN2 = my_spawn2,
61-
COMMAND = r'%(_python_)s cat.py $TARGET $SOURCES')
62-
env1 = env.Clone(SPAWN = my_spawn1)
59+
DefaultEnvironment()
60+
env = Environment(
61+
MY_SPAWN1=my_spawn1,
62+
MY_SPAWN2=my_spawn2,
63+
COMMAND=r'%(_python_)s cat.py $TARGET $SOURCES',
64+
)
65+
env1 = env.Clone(SPAWN=my_spawn1)
6366
env1.Command('file1.out', 'file1.in', '$COMMAND')
6467
65-
env2 = env.Clone(SPAWN = '$MY_SPAWN2')
68+
env2 = env.Clone(SPAWN='$MY_SPAWN2')
6669
env2.Command('file2.out', 'file2.in', '$COMMAND')
6770
68-
env3 = env.Clone(SPAWN = '${USE_TWO and MY_SPAWN2 or MY_SPAWN1}')
71+
env3 = env.Clone(SPAWN='${MY_SPAWN2 if USE_TWO else MY_SPAWN1}')
6972
env3.Command('file3.out', 'file3.in', '$COMMAND', USE_TWO=0)
7073
env3.Command('file4.out', 'file4.in', '$COMMAND', USE_TWO=1)
7174
""" % locals())

test/option/help-options.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
lines = stdout.split('\n')
5555
lines = [x for x in lines if x[:3] == ' -']
5656
lines = [x[3:] for x in lines]
57-
lines = [x[0] == '-' and x[1:] or x for x in lines]
57+
lines = [x[1:] if x.startswith('-') else x for x in lines]
5858
options = [x.split()[0] for x in lines]
59-
options = [x[-1] == ',' and x[:-1] or x for x in options]
59+
options = [x[:-1] if x.endswith(',') else x for x in options]
6060
lowered = [x.lower() for x in options]
6161
ordered = sorted(lowered)
6262
if lowered != ordered:
@@ -65,7 +65,7 @@
6565
test.fail_test()
6666

6767
test.pass_test()
68-
68+
6969

7070
# Local Variables:
7171
# tab-width:4

testing/framework/TestCmd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ def simple_diff(
699699
sm = difflib.SequenceMatcher(None, a, b)
700700

701701
def comma(x1, x2):
702-
return x1 + 1 == x2 and str(x2) or f'{x1 + 1},{x2}'
702+
return str(x2) if x1 + 1 == x2 else f'{x1 + 1},{x2}'
703703

704704
for op, a1, a2, b1, b2 in sm.get_opcodes():
705705
if op == 'delete':

testing/framework/TestCommon.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def must_be_writable(self, *files) -> None:
321321
them. Exits FAILED if any of the files does not exist or is
322322
not writable.
323323
"""
324-
flist = [is_List(x) and os.path.join(*x) or x for x in files]
324+
flist = [os.path.join(*x) if is_List(x) else x for x in files]
325325
existing, missing = separate_files(flist)
326326
unwritable = [x for x in existing if not is_writable(x)]
327327
if missing:
@@ -531,7 +531,7 @@ def must_exist(self, *files, message: str = "") -> None:
531531
pathname will be constructed by concatenating them. Exits FAILED
532532
if any of the files does not exist.
533533
"""
534-
flist = [is_List(x) and os.path.join(*x) or x for x in files]
534+
flist = [os.path.join(*x) if is_List(x) else x for x in files]
535535
missing = [x for x in flist if not os.path.exists(x) and not os.path.islink(x)]
536536
if missing:
537537
print("Missing files: `%s'" % "', `".join(missing))
@@ -550,7 +550,7 @@ def must_exist_one_of(self, files, message: str = "") -> None:
550550
if is_List(x) or is_Tuple(x):
551551
xpath = os.path.join(*x)
552552
else:
553-
xpath = is_Sequence(x) and os.path.join(x) or x
553+
xpath = os.path.join(x) if is_Sequence(x) else x
554554
if glob.glob(xpath):
555555
return
556556
missing.append(xpath)
@@ -669,7 +669,7 @@ def must_not_exist(self, *files) -> None:
669669
which case the pathname will be constructed by concatenating them.
670670
Exits FAILED if any of the files exists.
671671
"""
672-
flist = [is_List(x) and os.path.join(*x) or x for x in files]
672+
flist = [os.path.join(*x) if is_List(x) else x for x in files]
673673
existing = [x for x in flist if os.path.exists(x) or os.path.islink(x)]
674674
if existing:
675675
print("Unexpected files exist: `%s'" % "', `".join(existing))
@@ -688,7 +688,7 @@ def must_not_exist_any_of(self, files) -> None:
688688
if is_List(x) or is_Tuple(x):
689689
xpath = os.path.join(*x)
690690
else:
691-
xpath = is_Sequence(x) and os.path.join(x) or x
691+
xpath = os.path.join(x) if is_Sequence(x) else x
692692
if glob.glob(xpath):
693693
existing.append(xpath)
694694
if existing:
@@ -719,7 +719,7 @@ def must_not_be_writable(self, *files) -> None:
719719
them. Exits FAILED if any of the files does not exist or is
720720
writable.
721721
"""
722-
flist = [is_List(x) and os.path.join(*x) or x for x in files]
722+
flist = [os.path.join(*x) if is_List(x) else x for x in files]
723723
existing, missing = separate_files(flist)
724724
writable = [file for file in existing if is_writable(file)]
725725
if missing:

0 commit comments

Comments
 (0)