Skip to content

Commit 9a90bd0

Browse files
authored
Merge branch 'master' into deprecate-per-dir-sconsign
2 parents 3d536f6 + 7c86b9f commit 9a90bd0

10 files changed

Lines changed: 111 additions & 77 deletions

File tree

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
6161
long function signature lines, and some linting-insipired cleanups.
6262
- Deprecated using signature-file-per-directory (aka old-style SConsign)
6363
via the SConsignFile(name=None) call.
64+
- Test framework: tweak module docstrings
6465

6566

6667
RELEASE 4.10.1 - Sun, 16 Nov 2025 10:51:57 -0700

RELEASE.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ IMPROVEMENTS
6363
- Additional small tweaks to Environment.py type hints, fold some overly
6464
long function signature lines, and some linting-insipired cleanups.
6565

66+
- Test framework: tweak module docstrings
67+
6668

6769
PACKAGING
6870
---------

testing/framework/TestCmd.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
# Copyright 2000-2024 Steven Knight
1+
# SPDX-License-Identifier: PSF-2.0
2+
#
3+
# Copyright 2000-2010 Steven Knight
4+
# Copyright The SCons Foundation
25
#
36
# This module is free software, and you may redistribute it and/or modify
47
# it under the same terms as Python itself, so long as this copyright message
@@ -22,19 +25,23 @@
2225
2326
The TestCmd module provides a framework for portable automated testing
2427
of executable commands and scripts (in any language, not just Python),
25-
especially commands and scripts that require file system interaction.
28+
particularly those that require file system interaction.
2629
27-
In addition to running tests and evaluating conditions, the TestCmd
28-
module manages and cleans up one or more temporary workspace
29-
directories, and provides methods for creating files and directories in
30-
those workspace directories from in-line data, here-documents), allowing
31-
tests to be completely self-contained.
30+
Beyond running tests and evaluating conditions, the TestCmd module manages
31+
temporary workspace directories, providing methods to create files and
32+
directories from inline data (here-documents) and from fixture files.
3233
33-
A TestCmd environment object is created via the usual invocation:
34+
Create a TestCmd environment object by instantiating the class:
3435
3536
import TestCmd
3637
test = TestCmd.TestCmd()
3738
39+
TestCmd is the bottom layer of an extensible stack. You will probably
40+
encounter it via derived classes such as the companion :class:`TestCommon`
41+
class, or, if used in the SCons project, via :class:`TestSCons` and
42+
other specializations, with the functionality implemented here provided
43+
via inheritance.
44+
3845
There are a bunch of keyword arguments available at instantiation:
3946
4047
test = TestCmd.TestCmd(
@@ -648,7 +655,7 @@ def match_re(
648655
def match_re_dotall(
649656
lines: str | list[str] | None = None,
650657
res: str | list[str] | None = None,
651-
) -> Match[str] | None:
658+
) -> re.Match[str] | None:
652659
"""Match function using regular expression match.
653660
654661
Unlike :math:`match_re`, the arguments are converted to strings (if necessary)

testing/framework/TestCommon.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
# SPDX-License-Identifier: PSF-2.0
2+
#
13
# Copyright 2000-2010 Steven Knight
4+
# Copyright The SCons Foundation
25
#
36
# This module is free software, and you may redistribute it and/or modify
47
# it under the same terms as Python itself, so long as this copyright message
@@ -27,12 +30,12 @@
2730
explicit checks unnecessary, making the test scripts themselves simpler
2831
to write and easier to read.
2932
30-
The TestCommon class is a subclass of the TestCmd class. In essence,
31-
TestCommon is a wrapper that handles common TestCmd error conditions in
32-
useful ways. You can use TestCommon directly, or subclass it for your
33-
program and add additional (or override) methods to tailor it to your
34-
program's specific needs. Alternatively, the TestCommon class serves
35-
as a useful example of how to define your own TestCmd subclass.
33+
The TestCommon class is a subclass of the :mod:`TestCmd:mod:` class.
34+
In essence, TestCommon` is a wrapper that handles common TestCmd` error
35+
conditions in useful ways. You can use TestCommon directly, or subclass
36+
it for your program and add additional (or override) methods to tailor
37+
it to your program's specific needs. Alternatively, the TestCommon class
38+
serves as a useful example of how to define your own TestCmd subclass.
3639
3740
As a subclass of TestCmd, TestCommon provides access to all of the
3841
variables and methods from the TestCmd module. Consequently, you can
@@ -771,7 +774,7 @@ def start(
771774
arguments=None,
772775
universal_newlines=None,
773776
**kw,
774-
):
777+
) -> Popen:
775778
"""
776779
Starts a program or script for the test environment, handling
777780
any exceptions.

testing/framework/TestRuntest.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
"""
2525
A testing framework for the runtest.py command used to invoke SCons tests.
2626
27-
A TestRuntest environment object is created via the usual invocation:
27+
Create a TestRuntest environment object by instantiating the class:
2828
29+
import TestRuntest
2930
test = TestRuntest()
3031
31-
TestRuntest is a subclass of TestCommon, which is in turn is a subclass
32-
of TestCmd), and hence has available all of the methods and attributes
33-
from those classes, as well as any overridden or additional methods or
34-
attributes defined in this subclass.
32+
test = TestRuntest()
33+
34+
TestRuntest is a subclass of :class:`TestCommon`, which is in turn is a
35+
subclass of :class:`TestCmd`, and hence has available all of the methods
36+
and attributes from those classes, as well as any overridden or additional
37+
methods or attributes defined in this subclass.
3538
"""
3639

3740
import os

testing/framework/TestSCons.py

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@
2424
"""
2525
A testing framework for the SCons software construction tool.
2626
27-
A TestSCons environment object is created via the usual invocation:
27+
Create a TestSCons environment object by instantiating the class:
2828
29-
test = TestSCons()
29+
import TestSCons
30+
test = TestSCons.TestSCons()
3031
31-
TestScons is a subclass of TestCommon, which in turn is a subclass
32-
of TestCmd), and hence has available all of the methods and attributes
33-
from those classes, as well as any overridden or additional methods or
34-
attributes defined in this subclass.
32+
:class:`TestScons' is a subclass of :class:`TestCommon,` which in turn
33+
is a subclass of :class:`TestCmd`, and hence has available all of the
34+
methods and attributes from those classes, as well as any overridden or
35+
additional methods or attributes defined in this subclass.
36+
37+
This class is further specialized for specific testing purposes in
38+
modules :mod:`TestSConsMSVS`, :mod:`TestSConsTar`, :mod:`TestSCons_time`,
39+
:mod:`TestSConsign` as well as in this file in :class:`TimeSCons`.
3540
"""
3641

3742
from __future__ import annotations
@@ -47,7 +52,7 @@
4752

4853
from SCons.Util import get_hash_format, get_current_hash_algorithm_used
4954
from TestCommon import *
50-
from TestCommon import __all__, _python_
55+
from TestCommon import __all__
5156

5257
# Some tests which verify that SCons has been packaged properly need to
5358
# look for specific version file names. Replicating the version number
@@ -146,7 +151,7 @@ def re_escape(str):
146151
# Helper functions that we use as a replacement to the default re.match
147152
# when searching for special strings in stdout/stderr.
148153
#
149-
def search_re(out, l):
154+
def search_re(out: str, l: str) -> int | None:
150155
"""Search the regular expression 'l' in the output 'out'
151156
and return the start index when successful.
152157
"""
@@ -157,7 +162,7 @@ def search_re(out, l):
157162
return None
158163

159164

160-
def search_re_in_list(out, l):
165+
def search_re_in_list(out: str, l: str) -> int | None:
161166
"""Search the regular expression 'l' in each line of
162167
the given string list 'out' and return the line's index
163168
when successful.
@@ -203,12 +208,20 @@ def deprecated_python_version(version=sys.version_info):
203208
deprecated_python_msg = ""
204209

205210

206-
def initialize_sconsflags(ignore_python_version):
207-
"""
208-
Add the --warn=no-python-version option to SCONSFLAGS for every
209-
command so test scripts don't have to filter out Python version
210-
deprecation warnings.
211-
Same for --warn=no-visual-c-missing.
211+
def initialize_sconsflags(ignore_python_version: bool) -> str | None:
212+
"""Set up SCONSFLAGS for every command.
213+
214+
Used so test scripts don't need to worry about unexpected warnings
215+
in their output.
216+
217+
``--warn=no-python-version`` is used to suppress Python version
218+
deprecation warnings while such are active.
219+
220+
``--warn=no-visual-c-missing`` is used so Windows systems which don't
221+
have Visual C++ installed don't get warnings about it.
222+
223+
Returns:
224+
the original ``SCONSFLAGS`` value, if any, so it can be restored
212225
"""
213226
save_sconsflags = os.environ.get('SCONSFLAGS')
214227
if save_sconsflags:
@@ -229,7 +242,8 @@ def initialize_sconsflags(ignore_python_version):
229242
return save_sconsflags
230243

231244

232-
def restore_sconsflags(sconsflags) -> None:
245+
def restore_sconsflags(sconsflags: str | None) -> None:
246+
"""Restore the original SCONSFLAGS value, if any."""
233247
if sconsflags is None:
234248
del os.environ['SCONSFLAGS']
235249
else:
@@ -249,18 +263,14 @@ def restore_sconsflags(sconsflags) -> None:
249263

250264

251265
class NoMatch(Exception):
252-
"""
253-
Exception for matchPart to indicate there was no match found in the passed logfile
254-
"""
266+
"""There was no match in the passed logfile."""
255267

256268
def __init__(self, p) -> None:
257269
self.pos = p
258270

259271

260272
def match_part_of_configlog(log, logfile, lastEnd, NoMatch=NoMatch):
261-
"""
262-
Match part of the logfile
263-
"""
273+
"""Match part of the logfile."""
264274
# print("Match:\n%s\n==============\n%s" % (log , logfile[lastEnd:]))
265275
m = re.match(log, logfile[lastEnd:])
266276
if not m:
@@ -368,8 +378,7 @@ def Environment(self, ENV=None, *args, **kw):
368378
return None
369379

370380
def detect(self, var, prog=None, ENV=None, norm=None):
371-
"""
372-
Return the detected path to a tool program.
381+
"""Return the detected path to a tool program.
373382
374383
Searches first the named construction variable, then
375384
the SCons path.
@@ -401,7 +410,7 @@ def detect(self, var, prog=None, ENV=None, norm=None):
401410

402411
return self.where_is(prog)
403412

404-
def detect_tool(self, tool, prog=None, ENV=None):
413+
def detect_tool(self, tool, prog=None, ENV=None) -> bool:
405414
"""
406415
Given a tool (i.e., tool specification that would be passed
407416
to the "tools=" parameter of Environment()) and a program that
@@ -410,12 +419,11 @@ def detect_tool(self, tool, prog=None, ENV=None):
410419
411420
By default, prog is set to the value passed into the tools parameter.
412421
"""
413-
414422
if not prog:
415423
prog = tool
416424
env = self.Environment(ENV, tools=[tool])
417425
if env is None:
418-
return None
426+
return False
419427
return env.Detect([prog])
420428

421429
def where_is(self, prog, path=None, pathext=None):
@@ -476,8 +484,9 @@ def wrap_stdout(
476484
)
477485

478486
def run(self, *args, **kw) -> None:
479-
"""
480-
Set up SCONSFLAGS for every command so test scripts don't need
487+
"""Run a command.
488+
489+
Sets up ``SCONSFLAGS`` first so test scripts don't need
481490
to worry about unexpected warnings in their output.
482491
"""
483492
sconsflags = initialize_sconsflags(self.ignore_python_version)
@@ -1810,9 +1819,8 @@ def venv_path():
18101819

18111820
return (python, incpath, libpath, libname + _lib)
18121821

1813-
def start(self, *args, **kw):
1814-
"""
1815-
Starts SCons in the test environment.
1822+
def start(self, *args, **kw) -> Popen:
1823+
"""Starts SCons in the test environment.
18161824
18171825
This method exists to tell Test{Cmd,Common} that we're going to
18181826
use standard input without forcing every .start() call in the

testing/framework/TestSConsMSVS.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@
2424
"""
2525
A testing framework for the SCons software construction tool.
2626
27-
A TestSConsMSVS environment object is created via the usual invocation:
27+
Create a TestSConsMSVS environment object by instantiating the class:
2828
29+
import TestSConsMSVS
2930
test = TestSConsMSVS()
3031
31-
TestSConsMSVS is a subsclass of TestSCons, which is in turn a subclass
32-
of TestCommon, which is in turn is a subclass of TestCmd), and hence
33-
has available all of the methods and attributes from those classes,
34-
as well as any overridden or additional methods or attributes defined
35-
in this subclass.
32+
TestSConsMSVS is a subsclass of :class:`TestSCons`, which is a subclass of
33+
:class:`TestCommon`, which is in turn is a subclass of :class:`TestCmd`,
34+
and hence has available all of the methods and attributes from those
35+
classes, as well as any overridden or additional methods or attributes
36+
defined in this subclass.
3637
"""
3738

3839
import os

testing/framework/TestSConsTar.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@
2424
"""
2525
A testing framework for the SCons software construction tool.
2626
27-
A TestSConsTar environment object is created via the usual invocation:
27+
Create a TestSConsTar environment object by instantiating the class:
2828
29+
import TestSConsTar
2930
test = TestSConsTar()
3031
31-
TestSConsTar is a subsclass of TestSCons, which is in turn a subclass
32-
of TestCommon, which is in turn is a subclass of TestCmd), and hence
33-
has available all of the methods and attributes from those classes,
34-
as well as any overridden or additional methods or attributes defined
35-
in this subclass.
32+
TestSConsTar is a subsclass of :class:`TestSCons`, which is in turn
33+
a subclass of :class:`TestCommon`, which is in turn is a subclass
34+
of :class:`TestCmd`, and hence has available all of the methods and
35+
attributes from those classes, as well as any overridden or additional
36+
methods or attributes defined in this subclass.
37+
38+
This module exists to provide support for using ``tar`` on Windows,
39+
where the state is a bit unpredictable.
3640
"""
3741

3842
import os
@@ -69,6 +73,9 @@
6973
# tar.exe --version (GH windows-2025):
7074
# bsdtar 3.7.7 - libarchive 3.7.7 zlib/1.2.13.1-motley liblzma/5.4.3 bz2lib/1.0.8 libzstd/1.5.5
7175

76+
# Later versions may support even more, e.g;
77+
# bsdtar 3.8.4 - libarchive 3.8.4 zlib/1.2.13.1-motley liblzma/5.8.1 bz2lib/1.0.8 libzstd/1.5.7 cng/2.0 libb2/bundles
78+
7279
def _is_windows_system_tar(tar):
7380

7481
if not tar:

testing/framework/TestSCons_time.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@
2424
"""
2525
A testing framework for the scons-time.py script
2626
27-
A TestSCons_time environment object is created via the usual invocation:
27+
Create a TestSCons_time environment object by instantiating the class:
2828
29+
import TestSCons_time
2930
test = TestSCons_time()
3031
31-
TestSCons_time is a subclass of TestCommon, which is in turn is a subclass
32-
of TestCmd), and hence has available all of the methods and attributes
33-
from those classes, as well as any overridden or additional methods or
34-
attributes defined in this subclass.
32+
TestSCons_time is a subclass of :class:`TestCommon`, which is in turn a
33+
subclass of :class:`TestCmd`, and hence has available all of the methods
34+
and attributes from those classes, as well as any overridden or additional
35+
methods or attributes defined in this subclass.
3536
"""
3637

3738
import os

testing/framework/TestSConsign.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@
2222
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2323

2424
"""
25-
A testing framework for the "sconsign" script tool.
25+
A testing framework for the "sconsign" tool.
2626
27-
A TestSConsign environment object is created via the usual invocation:
27+
Create a TestSConsign environment object by instantiating the class:
2828
29+
import TestSConsign
2930
test = TestSConsign()
3031
31-
TestSconsign is a subclass of TestSCons, which is a subclass of
32-
TestCommon, which is in turn is a subclass of TestCmd), and hence
33-
has available all of the methods and attributes from those classes,
34-
as well as any overridden or additional methods or attributes defined
35-
in this subclass.
32+
TestSConsign is a subsclass of :class:`TestSCons`, which is a subclass of
33+
:class:`TestCommon`, which is in turn is a subclass of :class:`TestCmd`,
34+
and hence has available all of the methods and attributes from those
35+
classes, as well as any overridden or additional methods or attributes
36+
defined in this subclass.
3637
"""
3738

3839
import os

0 commit comments

Comments
 (0)