From 7ddeb166c05a68ebea9b4976373694337614c5ae Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 23 Mar 2023 09:28:54 -0600 Subject: yacc tool updates The yacc tool now recognizes the bison syntax of using --header, --defines and --graph options in YACCFLAGS without supplying an option argument. Note that byacc doesn't allow leaving off the option argument, and would error out in such cases. Fixes #4326 The yacc tool now recognizes -H as a partial synonym for --header. It only works in the no-option-argument form - giving an option argument will likely break things. Fixes #4327 Tests are expanded to cover these. The graph file name (-g) is now generated relative to the requested target file name, not to the source name, to match actual current behavior. This is rare case - only kicks in if target explicitly requested with a different base name than source - in this case SCons would emit a different name than bison produces. Unlikely to affect any real usage - you would have to set up the condition described, and additionally use the graph file as a source for some other build target. The default file suffix for graph files is set to .gv, which is current for Bison as of 3.8. The previous suffix for Bison, dating back to 2.4, was .dot, which is still the suffix byacc uses. Docs updated to better describe when you need to set this. The former default, .vcg, has not been used since 2006. Documentation updated for the two header suffix construction variables to better describe (I hope) what these mean and when to set them. Other doc updates as well. Signed-off-by: Mats Wichmann --- CHANGES.txt | 9 +++ SCons/Tool/Tool.xml | 26 +++++-- SCons/Tool/yacc.py | 35 ++++++---- SCons/Tool/yacc.xml | 92 +++++++++++++------------ test/YACC/BISONFLAGS.py | 49 ++++++++++++- test/YACC/YACCFLAGS-fixture/myyacc.py | 125 ++++++++++++++++++++++------------ test/YACC/YACCFLAGS.py | 2 +- 7 files changed, 230 insertions(+), 108 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d4ad973..2977fa8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -23,6 +23,15 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER calls dunder method __call__. Invoke instance directly." - Python 3.9 dropped the alias base64.decodestring, deprecated since 3.1. Only used in msvs.py. Use base64.decodebytes instead. + - The yacc tool now understands the bison behavior of --header, + --defines and --graph being called without option-argument as being + synonyms for -d (first two) and -g. -H also recognized as a synonym + for -d. Default value for $YACCVCGFILESUFFIX changed to '.gv' + to match current bison default (since bison 3.8). The graph file name + (-g) is now generated relative to the requested target file name, + not to the source file name, to match actual current behavior (only + affects if target explicitly requested with a different base name + than source). Docs updated. Fixes #4326 and #4327. RELEASE 4.5.2 - Sun, 21 Mar 2023 14:08:29 -0700 diff --git a/SCons/Tool/Tool.xml b/SCons/Tool/Tool.xml index de71efb..d25d7a5 100644 --- a/SCons/Tool/Tool.xml +++ b/SCons/Tool/Tool.xml @@ -37,10 +37,19 @@ Example: # builds foo.c -env.CFile(target = 'foo.c', source = 'foo.l') +env.CFile(target='foo.c', source='foo.l') + # builds bar.c -env.CFile(target = 'bar', source = 'bar.y') +env.CFile(target='bar', source='bar.y') + + +Note that for yacc files, +the output file name is derived from target, +or from the source file name if a target is not specified; +the traditional yacc default name +y.tab.c is not used. + @@ -59,10 +68,19 @@ Example: # builds foo.cc -env.CXXFile(target = 'foo.cc', source = 'foo.ll') +env.CXXFile(target='foo.cc', source='foo.ll') + # builds bar.cc -env.CXXFile(target = 'bar', source = 'bar.yy') +env.CXXFile(target='bar', source='bar.yy') + + +Note that for yacc files, +the output file name is derived from target, +or from the source file name if a target is not specified; +the traditional yacc default name +y.tab.cc is not used. + diff --git a/SCons/Tool/yacc.py b/SCons/Tool/yacc.py index 67ecd86..d408e62 100644 --- a/SCons/Tool/yacc.py +++ b/SCons/Tool/yacc.py @@ -23,8 +23,11 @@ """Tool-specific initialization for yacc. -This tool should support multiple yacc implementations, -but is in actuality biased towards GNU Bison. +This tool should support multiple yacc implementations, but is in actuality +biased towards GNU Bison. In particular, it forces the output file name (thus +avoiding the default convention of y.tab.c or foo.tab.c), so the tool *must* +support the -o option, which pure POSIX yacc does not. byacc should be okay +as an alternative to bison. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() @@ -64,15 +67,17 @@ def _yaccEmitter(target, source, env, ysuf, hsuf) -> tuple: target = [targetBase + ".m"] # the extension is ".m". # If -d is specified on the command line, yacc will emit a .h - # or .hpp file with the same name as the .c or .cpp output file. - if '-d' in flags: + # or .hpp file with the same base name as the .c or .cpp output file. + # if '-d' in flags: # add bison options -H, --header, --defines (obsolete) + if "-d" in flags or "-H" in flags or "--header" in flags or "--defines" in flags: target.append(targetBase + env.subst(hsuf, target=target, source=source)) - # If -g is specified on the command line, yacc will emit a .vcg - # file with the same base name as the .y, .yacc, .ym or .yy file. - if "-g" in flags: - base, ext = os.path.splitext(to_String(source[0])) - target.append(base + env.subst("$YACCVCGFILESUFFIX")) + # If -g is specified on the command line, yacc will emit a graph + # file with the same base name as the .c or .cpp output file. + # TODO: should this be handled like -v? i.e. a side effect, not target + # if "-g" in flags: # add bison option --graph + if "-g" in flags or "--graph" in flags: + target.append(targetBase + env.subst("$YACCVCGFILESUFFIX")) # If -v is specified yacc will create the output debug file # which is not really source for any process, but should @@ -82,11 +87,13 @@ def _yaccEmitter(target, source, env, ysuf, hsuf) -> tuple: env.Clean(target[0], targetBase + '.output') # With --defines and --graph, the file to write is defined by the option - # argument. Extract this and include in the list of targets. - # NOTE: a filename passed to the command this way is not modified by SCons, - # and so will be interpreted relative to the project top directory at - # execution time, while the name added to the target list will be + # argument, if present (the no-option-argument cases were caught above). + # Extract this and include in the list of targets. + # NOTE: a filename passed to the command this way is not modified by + # SCons, and so will be interpreted relative to the project top directory + # at execution time, while the name added to the target list will be # interpreted relative to the SConscript directory - a possible mismatch. + # Better to use YACC_HEADER_FILE and YACC_GRAPH_FILE to pass these. # # These are GNU bison-only options. # Since bison 3.8, --header is the preferred name over --defines @@ -185,7 +192,7 @@ def generate(env) -> None: env['YACCCOM'] = '$YACC $YACCFLAGS $_YACC_HEADER $_YACC_GRAPH -o $TARGET $SOURCES' env['YACCHFILESUFFIX'] = '.h' env['YACCHXXFILESUFFIX'] = '.hpp' - env['YACCVCGFILESUFFIX'] = '.vcg' + env['YACCVCGFILESUFFIX'] = '.gv' env['_YACC_HEADER'] = '${YACC_HEADER_FILE and "--header=" + str(YACC_HEADER_FILE)}' env['_YACC_GRAPH'] = '${YACC_GRAPH_FILE and "--graph=" + str(YACC_GRAPH_FILE)}' diff --git a/SCons/Tool/yacc.xml b/SCons/Tool/yacc.xml index 9ccc4e6..cf466a2 100644 --- a/SCons/Tool/yacc.xml +++ b/SCons/Tool/yacc.xml @@ -115,6 +115,7 @@ with the suffix defined by &cv-link-YACCHFILESUFFIX; if the yacc source file ends in a .y suffix, or a file with the suffix defined by &cv-link-YACCHXXFILESUFFIX; if the yacc source file ends in a .yy suffix. +The header will have the same base name as the requested target. @@ -131,22 +132,31 @@ with the suffix .output. Also recognized are GNU &bison; options - and its deprecated synonym -, + +(and its deprecated synonym ), which is similar to -but the output filename is named by the option argument; -and , +but gives the option to explicitly name the output header file +through an option argument; +and , which is similar to -but the output filename is named by the option argument. +but gives the option to explicitly name the output graph file +through an option argument. +The file suffixes described for + and above +are not applied if these are used in the option=argument form. Note that files specified by and may not be properly handled -by &SCons; in all situations. Consider using -&cv-link-YACC_HEADER_FILE; and &cv-link-YACC_GRAPH_FILE; instead. +by &SCons; in all situations, and using those in &cv-YACCFLAGS; +should be considered legacy support only. +Consider using &cv-link-YACC_HEADER_FILE; +and &cv-link-YACC_GRAPH_FILE; instead +if the files need to be explicitly named +(new in version 4.4.0). @@ -159,6 +169,7 @@ Will be emitted as a command-line option. Use this in preference to including in &cv-link-YACCFLAGS; directly. +New in version 4.4.0. @@ -171,6 +182,7 @@ Will be emitted as a command-line option. Use this in preference to including in &cv-link-YACCFLAGS; directly. +New in version 4.4.0. @@ -179,14 +191,13 @@ command-line option. Use this in preference to including The suffix of the C header file generated by the parser generator -when the - -option is used. -Note that setting this variable does not cause -the parser generator to generate a header -file with the specified suffix, -it exists to allow you to specify -what suffix the parser generator will use of its own accord. +when the option +(or without an option-argument) +is used in &cv-link-YACCFLAGS;. +Note that setting this variable informs &SCons; +how to construct the header filename for tracking purposes, +it does not affect the actual generated filename. +Set this to match what your parser generator produces. The default value is .h. @@ -198,22 +209,14 @@ The default value is The suffix of the C++ header file generated by the parser generator -when the - -option is used. -Note that setting this variable does not cause -the parser generator to generate a header -file with the specified suffix, -it exists to allow you to specify -what suffix the parser generator will use of its own accord. -The default value is -.hpp, -except on Mac OS X, -where the default is -${TARGET.suffix}.h. -because the default &bison; parser generator just -appends .h -to the name of the generated C++ file. +when the option +(or without an option-argument) +is used in &cv-link-YACCFLAGS;. +Note that setting this variable informs &SCons; +how to construct the header filename for tracking purposes, +it does not affect the actual generated filename. +Set this to match what your parser generator produces. +The default value is .hpp. @@ -222,17 +225,22 @@ to the name of the generated C++ file. The suffix of the file -containing the VCG grammar automaton definition -when the - -option is used. -Note that setting this variable does not cause -the parser generator to generate a VCG -file with the specified suffix, -it exists to allow you to specify -what suffix the parser generator will use of its own accord. -The default value is -.vcg. +containing a graph of the grammar automaton +when the option +(or without an option-argument) +is used in &cv-link-YACCFLAGS;. +Note that setting this variable informs &SCons; +how to construct the graph filename for tracking purposes, +it does not affect the actual generated filename. +Various yacc tools have emitted various formats +at different times. +Set this to match what your parser generator produces. +The default value is .gv. + + +Changed in version 4.X.Y: the default value +changed from .vcg (&bison; stopped generating +.vcg output with version 2.4, in 2006). diff --git a/test/YACC/BISONFLAGS.py b/test/YACC/BISONFLAGS.py index cae673d..9b8cf03 100644 --- a/test/YACC/BISONFLAGS.py +++ b/test/YACC/BISONFLAGS.py @@ -47,12 +47,13 @@ test = TestSCons.TestSCons() test.subdir('sub1') test.subdir('sub2') +test.subdir('sub3') test.dir_fixture('YACCFLAGS-fixture') test.write('SConstruct', """\ DefaultEnvironment(tools=[]) -SConscript(dirs=['sub1', 'sub2']) +SConscript(dirs=['sub1', 'sub2', 'sub3']) """) # this SConscript is for the options-in-flags version @@ -90,8 +91,50 @@ env.CFile( """ % locals()) test.write(['sub2', 'aaa.y'], "aaa.y\nYACCFLAGS\n") +# this SConscript is to try various other flag combos +test.write(['sub3', 'SConscript'], """\ +import sys + +env = Environment( + YACC=r'%(_python_)s myyacc.py', + YACCFLAGS='-x --header=header.h --graph=graph.g', + tools=['yacc', '%(linker)s', '%(compiler)s'], +) + +def check(targets, expected): + t = [str(target) for target in targets] + assert t == expected, t + +targs1 = env.CFile('trg1', source='aaa.y', YACCFLAGS='-d') +check(targs1, ['trg1.c', 'trg1.h']) + +targs2 = env.CXXFile('trg2', source='aaa.yy', YACCFLAGS='-d') +check(targs2, ['trg2.cc', 'trg2.hpp']) + +targs3 = env.CFile('trg3', source='aaa.y', YACCFLAGS='--defines=zot.q') +check(targs3, ['trg3.c', 'zot.q']) + +targs4 = env.CFile('trg4', source='aaa.y', YACCFLAGS='--header') +check(targs4, ['trg4.c', 'trg4.h']) + +targs5 = env.CFile('trg5', source='aaa.y', YACCFLAGS='-H') +check(targs5, ['trg5.c', 'trg5.h']) + +targs6 = env.CFile('trg6', source='aaa.y', YACCFLAGS='-g') +check(targs6, ['trg6.c', 'trg6.gv']) + +targs7 = env.CFile('trg7', source='aaa.y', YACCFLAGS='-g -H') +check(targs7, ['trg7.c', 'trg7.h', 'trg7.gv']) + +targs8 = env.CFile('trg8', source='aaa.y', YACCFLAGS='--graph --header') +check(targs8, ['trg8.c', 'trg8.h', 'trg8.gv']) +""" % locals()) + +test.write(['sub3', 'aaa.y'], "aaa.y\nYACCFLAGS\n") +test.write(['sub3', 'aaa.yy'], "aaa.yy\nYACCFLAGS\n") + test.run('.', stderr=None) -test.must_match(['sub1', 'aaa.c'], "aaa.y\n -x --header=header.h --graph=graph.g\n") +test.must_match(['sub1', 'aaa.c'], "aaa.y\n-x --header=header.h --graph=graph.g\n") # NOTE: this behavior is "wrong" but we're keeping it for compat: # the generated files should go into 'sub1', not the topdir. @@ -109,7 +152,7 @@ test.must_match(['graph.g'], 'yacc graph\n') sub2 = Path('sub2') headerfile = sub2 / 'header.h' graphfile = sub2 / 'graph.g' -yaccflags = f"aaa.y\n -x --header={headerfile} --graph={graphfile}\n" +yaccflags = f"aaa.y\n-x --header={headerfile} --graph={graphfile}\n" test.must_match(['sub2', 'aaa.c'], yaccflags) test.must_match(['sub2', 'header.h'], 'yacc header\n') test.must_match(['sub2', 'graph.g'], 'yacc graph\n') diff --git a/test/YACC/YACCFLAGS-fixture/myyacc.py b/test/YACC/YACCFLAGS-fixture/myyacc.py index 3bc1375..8b793a1 100644 --- a/test/YACC/YACCFLAGS-fixture/myyacc.py +++ b/test/YACC/YACCFLAGS-fixture/myyacc.py @@ -1,65 +1,102 @@ -import getopt +#!/usr/bin/python +# +# SPDX-License-Identifier: MIT +# +# Copyright The SCons Foundation + +""" +Mock yacc/bison command for testing yacc tool with options +""" + +import argparse +import os import sys from pathlib import Path -def make_side_effect(path, text): +# Sentinels to make sure we pick the defaults +HEADER_DEFAULT = "_header_compute" +GRAPH_DEFAULT = "_graph_compute" +REPORT_DEFAULT = "_report_compute" + + +def make_side_effect(path, text, outfile): + if path == HEADER_DEFAULT: + file, ext = os.path.splitext(outfile) + if ext in [".y", ".yacc"]: + path = file + ".h" + elif ext in [".ym"]: + path = file + ".h.m" + elif ext in [".yy"]: + path = file + ".hpp" + else: # just guess + path = file + ".h" + if path == GRAPH_DEFAULT: + path = os.path.splitext(outfile)[0] + ".gv" + if path == REPORT_DEFAULT: + path = os.path.splitext(outfile)[0] + ".output" + p = Path(path) - if str(p.parent) != '.': + if str(p.parent) != ".": p.parent.mkdir(parents=True, exist_ok=True) with p.open(mode="wb") as f: f.write(text) def fake_yacc(): - make_header = None - make_graph = None + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("-g", "--graph", nargs="?", const=GRAPH_DEFAULT) + parser.add_argument("-d", dest="graph", action="store_const", const=HEADER_DEFAULT) + parser.add_argument("-v", "--verbose", action="store_const", const=REPORT_DEFAULT) + parser.add_argument("-x", action="store_true") # accept, do nothing + parser.add_argument("-H", "--header", "--defines", nargs="?", const=HEADER_DEFAULT) + parser.add_argument("-o", "--output", dest="out", required=True) + parser.add_argument("-I", dest="i_arguments", default=[], action="append") + parser.add_argument("files", nargs="+") + args = parser.parse_args() + # print(f"DEBUG: {args}") - longopts = ["defines=", "header=", "graph="] - cmd_opts, args = getopt.getopt(sys.argv[1:], 'o:I:x', longopts) - opt_string = '' - i_arguments = '' - - for opt, arg in cmd_opts: - if opt == '-o': - out = arg - elif opt == '-I': - i_arguments = f'{i_arguments} {arg}' - elif opt in ('--defines', '--header'): - make_header = arg - opt_string = f'{opt_string} {opt}={arg}' - elif opt == '--graph': - make_graph = arg - opt_string = f'{opt_string} {opt}={arg}' + # Synthesize "opt_string", which, when this script used getopt, was + # collected in the arg processing loop - from some arguments. The tests + # expect this to be subbed in for YACCFLAGS in making the output file. + opt_list = [] + skip = False + for arg in sys.argv[1:]: + if skip: + skip = False + elif arg == "-o": + skip = True + elif arg.startswith("-I"): + pass else: - opt_string = f'{opt_string} {opt}' + opt_list.append(arg) + # The original didn't use the file argument(s) so we have to get rid of. + for file in args.files: + if file in opt_list: + opt_list.remove(file) + opt_string = " ".join(opt_list) + + # Now we need to do something similar for i_arguments, which is easier + i_arguments = " ".join(args.i_arguments) - with open(out, 'wb') as ofp: - for a in args: - with open(a, 'rb') as ifp: + with open(args.out, "wb") as ofp: + for file in args.files: + with open(file, "rb") as ifp: contents = ifp.read() - contents = contents.replace(b'YACCFLAGS', opt_string.encode()) - contents = contents.replace(b'YACC', b'myyacc.py') - contents = contents.replace(b'I_ARGS', i_arguments.encode()) + contents = contents.replace(b"YACCFLAGS", opt_string.encode()) + contents = contents.replace(b"YACC", b"myyacc.py") + contents = contents.replace(b"I_ARGS", i_arguments.encode()) ofp.write(contents) - # Extra bits: - if make_header: - make_side_effect(make_header, b"yacc header\n") - if make_graph: - make_side_effect(make_graph, b"yacc graph\n") + # Make extra output files + if args.header: + make_side_effect(args.header, b"yacc header\n", args.out) + if args.graph: + make_side_effect(args.graph, b"yacc graph\n", args.out) + if args.verbose: + make_side_effect(args.verbose, b"yacc debug\n", args.out) -if __name__ == '__main__': +if __name__ == "__main__": fake_yacc() sys.exit(0) - -# If -d is specified on the command line, yacc will emit a .h -# or .hpp file with the same name as the .c or .cpp output file. - -# If -g is specified on the command line, yacc will emit a .vcg -# file with the same base name as the .y, .yacc, .ym or .yy file. - -# If -v is specified yacc will create the output debug file -# which is not really source for any process, but should -# be noted and also be cleaned (issue #2558) diff --git a/test/YACC/YACCFLAGS.py b/test/YACC/YACCFLAGS.py index 1f3ad78..7a07072 100644 --- a/test/YACC/YACCFLAGS.py +++ b/test/YACC/YACCFLAGS.py @@ -56,7 +56,7 @@ env.CFile(target='out/aaa', source='in/aaa.y') test.write(['in', 'aaa.y'], "aaa.y\nYACCFLAGS\nI_ARGS\n") test.run('.', stderr=None) -test.must_match(['out', 'aaa.c'], "aaa.y\n -x\n out in\n") +test.must_match(['out', 'aaa.c'], "aaa.y\n-x\nout in\n") test.pass_test() -- cgit v0.12 From 2ef22690e2c81db7e82b0526bc935854e4e85e8e Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sat, 6 May 2023 08:00:27 -0600 Subject: yacc changes: add RELEASE, drop doc note Per review requests Signed-off-by: Mats Wichmann --- RELEASE.txt | 9 ++++++--- SCons/Tool/Tool.xml | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/RELEASE.txt b/RELEASE.txt index c2244f2..e475755 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -26,13 +26,16 @@ DEPRECATED FUNCTIONALITY CHANGED/ENHANCED EXISTING FUNCTIONALITY --------------------------------------- -- List modifications to existing features, where the previous behavior - wouldn't actually be considered a bug +- The yacc tool now understands the bison behavior of --header, --defines + and --graph being called without an option-argument as being synonyms + for -d (first two) and -g. -H also recognized as a synonym for -d. + Default value for $YACCVCGFILESUFFIX changed to '.gv' to match + current bison default (since bison 3.8). Set this variable to '.dot' + if using byacc. FIXES ----- - - Fixed: when using the mingw tool, if an msys2 Python is used (os.sep is '/' rather than the Windows default '\'), certain Configure checks could fail due to the construction of the path to run the compiled check. diff --git a/SCons/Tool/Tool.xml b/SCons/Tool/Tool.xml index d25d7a5..086d989 100644 --- a/SCons/Tool/Tool.xml +++ b/SCons/Tool/Tool.xml @@ -43,13 +43,13 @@ env.CFile(target='foo.c', source='foo.l') env.CFile(target='bar', source='bar.y') - + -- cgit v0.12 From e327282f5086730fc045d99c5efbc7a2be0839b4 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Mon, 8 May 2023 09:23:46 -0600 Subject: Fixup usage of new mock yacc tool When the mock tool was revised to use argparse instead of getopt, it stumbled across the problem that argparse apparently doesn't deal with a single-letter option and its option-argument not having a space between them until Python 3.8 - 3.6 and 3.7 failed the test. Change to use the space in the test/mock tool. Signed-off-by: Mats Wichmann --- test/YACC/YACCFLAGS-fixture/myyacc.py | 2 +- test/YACC/YACCFLAGS.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/YACC/YACCFLAGS-fixture/myyacc.py b/test/YACC/YACCFLAGS-fixture/myyacc.py index 8b793a1..7461501 100644 --- a/test/YACC/YACCFLAGS-fixture/myyacc.py +++ b/test/YACC/YACCFLAGS-fixture/myyacc.py @@ -67,7 +67,7 @@ def fake_yacc(): elif arg == "-o": skip = True elif arg.startswith("-I"): - pass + skip = True else: opt_list.append(arg) # The original didn't use the file argument(s) so we have to get rid of. diff --git a/test/YACC/YACCFLAGS.py b/test/YACC/YACCFLAGS.py index 7a07072..f7a3cfb 100644 --- a/test/YACC/YACCFLAGS.py +++ b/test/YACC/YACCFLAGS.py @@ -48,7 +48,7 @@ test.write('SConstruct', """ DefaultEnvironment(tools=[]) env = Environment( YACC=r'%(_python_)s myyacc.py', - YACCFLAGS='-x -I${TARGET.dir} -I${SOURCE.dir}', + YACCFLAGS='-x -I ${TARGET.dir} -I ${SOURCE.dir}', tools=['yacc', '%(linker)s', '%(compiler)s'], ) env.CFile(target='out/aaa', source='in/aaa.y') -- cgit v0.12 From 34d0aedbec2df177264c023c554c2f5cbb966ccc Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Mon, 8 May 2023 12:20:08 -0600 Subject: yacc tool: further doc tweak [skip appveyor] Signed-off-by: Mats Wichmann --- SCons/Tool/yacc.py | 2 +- SCons/Tool/yacc.xml | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/SCons/Tool/yacc.py b/SCons/Tool/yacc.py index d408e62..9751742 100644 --- a/SCons/Tool/yacc.py +++ b/SCons/Tool/yacc.py @@ -53,7 +53,7 @@ YaccAction = SCons.Action.Action("$YACCCOM", "$YACCCOMSTR") if sys.platform == 'win32': BINS = ['bison', 'yacc', 'win_bison'] else: - BINS = ["bison", "yacc"] + BINS = ["bison", "yacc", "byacc"] # for byacc, yacc is normally a link def _yaccEmitter(target, source, env, ysuf, hsuf) -> tuple: diff --git a/SCons/Tool/yacc.xml b/SCons/Tool/yacc.xml index cf466a2..cc70adb 100644 --- a/SCons/Tool/yacc.xml +++ b/SCons/Tool/yacc.xml @@ -48,7 +48,7 @@ See its __doc__ string for a discussion of the format. -Sets construction variables for the &yacc; parse generator. +Sets construction variables for the &yacc; parser generator. @@ -109,13 +109,19 @@ and adds those to the target list. -If a option is present, +If the option is present in &cv-YACCFLAGS; &scons; assumes that the call will also create a header file with the suffix defined by &cv-link-YACCHFILESUFFIX; if the yacc source file ends in a .y suffix, or a file with the suffix defined by &cv-link-YACCHXXFILESUFFIX; if the yacc source file ends in a .yy suffix. The header will have the same base name as the requested target. +This is only correct if the executable is bison +(or win_bison). +If using Berkeley yacc (byacc), +y.tab.h is always written - +avoid the in this case and +use &cv-link-YACC_HEADER_FILE; instead. -- cgit v0.12 From 201be7ebc3e65094b189ff82d75cfef3fb695321 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 9 May 2023 08:45:34 -0600 Subject: yacc tool: comment out other doc note A review request suggested removing the note in CFile/CXXFile tool doc on yacc filenames. I removed only the CFile one, this does the CXXFile one as well. Signed-off-by: Mats Wichmann --- SCons/Tool/Tool.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SCons/Tool/Tool.xml b/SCons/Tool/Tool.xml index 086d989..25e4625 100644 --- a/SCons/Tool/Tool.xml +++ b/SCons/Tool/Tool.xml @@ -74,13 +74,13 @@ env.CXXFile(target='foo.cc', source='foo.ll') env.CXXFile(target='bar', source='bar.yy') - + -- cgit v0.12 From 157c5f8354abc5ed247c84c424cdc5e171729021 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 17 May 2023 20:59:16 -0700 Subject: added YACC_GRAPH_FILE_SUFFIX to represent it's the graph file and not be tied to the suffix string. It will respect the previous value if it's not set. Added test for such --- CHANGES.txt | 4 +- RELEASE.txt | 5 +- SCons/Tool/yacc.py | 9 ++-- SCons/Tool/yacc.xml | 15 ++++++ test/YACC/YACC_GRAPH_FILE_SUFFIX.py | 96 +++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 test/YACC/YACC_GRAPH_FILE_SUFFIX.py diff --git a/CHANGES.txt b/CHANGES.txt index 2977fa8..367a498 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -23,10 +23,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER calls dunder method __call__. Invoke instance directly." - Python 3.9 dropped the alias base64.decodestring, deprecated since 3.1. Only used in msvs.py. Use base64.decodebytes instead. + - Obsoleted YACCVCGFILESUFFIX, it's being replaced by YACC_GRAPH_FILE_SUFFIX. + If YACC_GRAPH_FILE_SUFFIX is not set, it will respect YACCVCGFILESUFFIX. - The yacc tool now understands the bison behavior of --header, --defines and --graph being called without option-argument as being synonyms for -d (first two) and -g. -H also recognized as a synonym - for -d. Default value for $YACCVCGFILESUFFIX changed to '.gv' + for -d. Default value for $YACC_GRAPH_FILE_SUFFIX changed to '.gv' to match current bison default (since bison 3.8). The graph file name (-g) is now generated relative to the requested target file name, not to the source file name, to match actual current behavior (only diff --git a/RELEASE.txt b/RELEASE.txt index e475755..095a85c 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -25,11 +25,12 @@ DEPRECATED FUNCTIONALITY CHANGED/ENHANCED EXISTING FUNCTIONALITY --------------------------------------- - +- Obsoleted YACCVCGFILESUFFIX, it's being replaced by YACC_GRAPH_FILE_SUFFIX. + If YACC_GRAPH_FILE_SUFFIX is not set, it will respect YACCVCGFILESUFFIX. - The yacc tool now understands the bison behavior of --header, --defines and --graph being called without an option-argument as being synonyms for -d (first two) and -g. -H also recognized as a synonym for -d. - Default value for $YACCVCGFILESUFFIX changed to '.gv' to match + Default value for $YACC_GRAPH_FILE_SUFFIX changed to '.gv' to match current bison default (since bison 3.8). Set this variable to '.dot' if using byacc. diff --git a/SCons/Tool/yacc.py b/SCons/Tool/yacc.py index 9751742..7a4ddfc 100644 --- a/SCons/Tool/yacc.py +++ b/SCons/Tool/yacc.py @@ -68,16 +68,18 @@ def _yaccEmitter(target, source, env, ysuf, hsuf) -> tuple: # If -d is specified on the command line, yacc will emit a .h # or .hpp file with the same base name as the .c or .cpp output file. - # if '-d' in flags: # add bison options -H, --header, --defines (obsolete) + # if '-d' in flags: + # or bison options -H, --header, --defines (obsolete) if "-d" in flags or "-H" in flags or "--header" in flags or "--defines" in flags: target.append(targetBase + env.subst(hsuf, target=target, source=source)) # If -g is specified on the command line, yacc will emit a graph # file with the same base name as the .c or .cpp output file. # TODO: should this be handled like -v? i.e. a side effect, not target - # if "-g" in flags: # add bison option --graph + # if "-g" in flags: + # or bison option --graph if "-g" in flags or "--graph" in flags: - target.append(targetBase + env.subst("$YACCVCGFILESUFFIX")) + target.append(targetBase + env.subst("$YACC_GRAPH_FILE_SUFFIX")) # If -v is specified yacc will create the output debug file # which is not really source for any process, but should @@ -193,6 +195,7 @@ def generate(env) -> None: env['YACCHFILESUFFIX'] = '.h' env['YACCHXXFILESUFFIX'] = '.hpp' env['YACCVCGFILESUFFIX'] = '.gv' + env['YACC_GRAPH_FILE_SUFFIX'] = '$YACCVCGFILESUFFIX' env['_YACC_HEADER'] = '${YACC_HEADER_FILE and "--header=" + str(YACC_HEADER_FILE)}' env['_YACC_GRAPH'] = '${YACC_GRAPH_FILE and "--graph=" + str(YACC_GRAPH_FILE)}' diff --git a/SCons/Tool/yacc.xml b/SCons/Tool/yacc.xml index cc70adb..3d4fa33 100644 --- a/SCons/Tool/yacc.xml +++ b/SCons/Tool/yacc.xml @@ -58,6 +58,7 @@ Sets construction variables for the &yacc; parser generator. YACCHFILESUFFIX YACCHXXFILESUFFIX YACCVCGFILESUFFIX +YACC_GRAPH_FILE_SUFFIX YACCCOMSTR @@ -230,6 +231,20 @@ The default value is .hpp. +Obsoleted. Use &cv-link-ACC_GRAPH_FILE_SUFFIX;. + + +Changed in version 4.X.Y + + + + + + + +Previously specified by &cv-link-YACCVCGFILESUFFIX;. + + The suffix of the file containing a graph of the grammar automaton when the option diff --git a/test/YACC/YACC_GRAPH_FILE_SUFFIX.py b/test/YACC/YACC_GRAPH_FILE_SUFFIX.py new file mode 100644 index 0000000..58e7628 --- /dev/null +++ b/test/YACC/YACC_GRAPH_FILE_SUFFIX.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# +# MIT License +# +# Copyright The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" +Test setting the YACC_GRAPH_FILE_SUFFIX variable. +Also that if both YACCVCGFILESUFFIX and YACC_GRAPH_FILE_SUFFIX are set, +then YACCVCGFILESUFFIX will be ignored. +""" + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +test.write('myyacc.py', """\ +import getopt +import os.path +import sys + +vcg = None +opts, args = getopt.getopt(sys.argv[1:], 'go:') +for o, a in opts: + if o == '-g': + vcg = 1 + elif o == '-o': + outfile = open(a, 'wb') +for f in args: + with open(f, 'rb') as infile: + for l in [l for l in infile.readlines() if l != b'/*yacc*/\\n']: + outfile.write(l) +outfile.close() +if vcg: + base, ext = os.path.splitext(args[0]) + with open(base + '.graph_suffix', 'wb') as outfile: + outfile.write((" ".join(sys.argv) + '\\n').encode()) +sys.exit(0) +""") + +test.write('SConstruct', """ +DefaultEnvironment(tools=[]) +env = Environment( + tools=['default', 'yacc'], + YACC=r'%(_python_)s myyacc.py', + YACCVCGFILESUFFIX='.vcg_obsolete', + YACC_GRAPH_FILE_SUFFIX='.graph_suffix', +) +env.CXXFile(target='aaa', source='aaa.yy') +env.CXXFile(target='bbb', source='bbb.yy', YACCFLAGS='-g') +""" % locals()) + +test.write('aaa.yy', "aaa.yy\n/*yacc*/\n") +test.write('bbb.yy', "bbb.yy\n/*yacc*/\n") + +test.run(arguments='.') + +test.must_match('aaa.cc', "aaa.yy\n") +test.must_not_exist('aaa.vcg') +test.must_not_exist('aaa.graph_suffix') + +test.must_match('bbb.cc', "bbb.yy\n") +test.must_not_exist('bbb.vcg') +test.must_not_exist('bbb.vcg_obsolete') +test.must_contain('bbb.graph_suffix', "myyacc.py -g -o bbb.cc bbb.yy\n") + +test.up_to_date(arguments='.') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: -- cgit v0.12 From dc7407bb002b20c781e1d40b6678d1df7f2818fc Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 19 May 2023 08:24:11 -0600 Subject: Fix doc typo referencing YACC_GRAPH_FILE_SUFFIX [skip appveyor] Signed-off-by: Mats Wichmann --- CHANGES.txt | 6 ++++-- SCons/Tool/yacc.xml | 15 +++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index dfdba44..f99e8ac 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,6 +9,10 @@ NOTE: 4.3.0 now requires Python 3.6.0 and above. Python 3.5.x is no longer suppo RELEASE VERSION/DATE TO BE FILLED IN LATER + From William Deegan: + - Obsoleted YACCVCGFILESUFFIX, being replaced by YACC_GRAPH_FILE_SUFFIX. + If YACC_GRAPH_FILE_SUFFIX is not set, it will respect YACCVCGFILESUFFIX. + From Mats Wichmann - C scanner's dictifyCPPDEFINES routine did not understand the possible combinations of CPPDEFINES - not aware of a "name=value" string either @@ -32,8 +36,6 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER not to the source file name, to match actual current behavior (only affects if target explicitly requested with a different base name than source). Docs updated. Fixes #4326 and #4327. - Obsoleted YACCVCGFILESUFFIX, being replaced by YACC_GRAPH_FILE_SUFFIX. - If YACC_GRAPH_FILE_SUFFIX is not set, it will respect YACCVCGFILESUFFIX. - SCons test runner now uses pathlib to normalize and compare paths to test files. - Minor doc fixes: signature of Alias() now matches implementation diff --git a/SCons/Tool/yacc.xml b/SCons/Tool/yacc.xml index 3d4fa33..82725db 100644 --- a/SCons/Tool/yacc.xml +++ b/SCons/Tool/yacc.xml @@ -231,10 +231,14 @@ The default value is .hpp. -Obsoleted. Use &cv-link-ACC_GRAPH_FILE_SUFFIX;. +Obsoleted. Use &cv-link-YACC_GRAPH_FILE_SUFFIX; instead. +The value is used only if &cv-YACC_GRAPH_FILE_SUFFIX; is not set. +The default value is .gv. -Changed in version 4.X.Y +Changed in version 4.X.Y: deprecated. The default value +changed from .vcg (&bison; stopped generating +.vcg output with version 2.4, in 2006). @@ -256,13 +260,8 @@ it does not affect the actual generated filename. Various yacc tools have emitted various formats at different times. Set this to match what your parser generator produces. -The default value is .gv. - - -Changed in version 4.X.Y: the default value -changed from .vcg (&bison; stopped generating -.vcg output with version 2.4, in 2006). +New in version 4.X.Y. -- cgit v0.12 From cb4d8c9016441047758c8b1f0c0f9ef945d48873 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 23 May 2023 10:08:09 -0600 Subject: Followon to PR #4348: more bool fixes Manually fixed up some things related to bool, e.g. simple functions which just did "return 1" were interpreted by the tool as returning int, when bool was really the intent. Functions/methods named like "is*", "has*", "exists", "rexists" (and others) are now pretty consistently marked as returning bool. A couple of minor alignments of branched definitions, and a couple of docstring adjustments made. If Tools which had old heading style were touched, they got the new style. Signed-off-by: Mats Wichmann --- CHANGES.txt | 5 +++ RELEASE.txt | 1 + SCons/ActionTests.py | 6 +-- SCons/Builder.py | 6 +-- SCons/BuilderTests.py | 6 +-- SCons/CacheDir.py | 7 +++- SCons/Debug.py | 4 +- SCons/Defaults.py | 4 +- SCons/Environment.py | 20 ++++------ SCons/ExecutorTests.py | 6 +-- SCons/Node/Alias.py | 8 ++-- SCons/Node/FS.py | 76 ++++++++++++++++++------------------- SCons/Node/NodeTests.py | 7 ++-- SCons/Node/Python.py | 4 +- SCons/Node/__init__.py | 63 +++++++++++++++--------------- SCons/SConf.py | 13 ++++--- SCons/SConfTests.py | 12 +++--- SCons/Scanner/JavaTests.py | 4 +- SCons/Scanner/ProgTests.py | 8 ++-- SCons/Scanner/ScannerTests.py | 45 +++++++++++----------- SCons/Subst.py | 16 ++++---- SCons/SubstTests.py | 41 ++++++++++---------- SCons/Taskmaster/TaskmasterTests.py | 22 +++++------ SCons/Tool/DCommon.py | 8 ++-- SCons/Tool/JavaCommon.py | 4 +- SCons/Tool/MSCommon/MSVC/Util.py | 6 +-- SCons/Tool/MSCommon/common.py | 7 ++-- SCons/Tool/cxx.py | 28 +++++++------- SCons/Tool/cyglink.py | 4 +- SCons/Tool/default.py | 25 +++++------- SCons/Tool/docbook/__init__.py | 27 ++++++------- SCons/Tool/dvi.py | 18 ++++----- SCons/Tool/filesystem.py | 24 +++++------- SCons/Tool/install.py | 4 +- SCons/Tool/javac.py | 10 ++--- SCons/Tool/linkCommon/__init__.py | 2 +- SCons/Tool/msvsTests.py | 27 +++++++------ SCons/Tool/ninja/Utils.py | 6 +-- SCons/Tool/packaging/__init__.py | 4 +- SCons/Tool/packaging/msi.py | 25 ++++++------ SCons/Tool/packaging/rpm.py | 14 ++----- SCons/Tool/pdf.py | 23 +++++------ SCons/Tool/rmic.py | 25 +++++------- SCons/Tool/textfile.py | 45 ++++++++++------------ SCons/UtilTests.py | 36 +++++++++--------- SCons/cppTests.py | 2 +- 46 files changed, 358 insertions(+), 400 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d292d84..fc51163 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -24,6 +24,11 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER add missed versionadded indicator. - Added some typing annotations generated by a tool, to eliminate manual work in future on things which are safe for the tool to produce. + Then manually fixed up some things related to bool that the tool did + not handly idealls. For example, simple functions which just did + "return 1" were interpreted by the tool as returning int, when bool + was really the intent. Functions/methods named like "is_*", "has_*", + "exists" are now pretty consistently marked as "-> bool". - Simplify some code due to pylint observation: "C2801: Unnecessarily calls dunder method __call__. Invoke instance directly." - Python 3.9 dropped the alias base64.decodestring, deprecated since 3.1. diff --git a/RELEASE.txt b/RELEASE.txt index bd4be6b..bb0ca0f 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -79,6 +79,7 @@ DEVELOPMENT reflect its usage. Derived _ActionAction inherits the ABC, so it now declares (actually raises NotImplementedError) two methods it doesn't use so it can be instantiated by unittests and others. +- Added more type annotations to internal routines. Thanks to the following contributors listed below for their contributions to this release. ========================================================================================== diff --git a/SCons/ActionTests.py b/SCons/ActionTests.py index 533a007..07fa297 100644 --- a/SCons/ActionTests.py +++ b/SCons/ActionTests.py @@ -109,7 +109,7 @@ class CmdStringHolder: self.data = str(cmd) self.literal = literal - def is_literal(self): + def is_literal(self) -> bool: return self.literal def escape(self, escape_func): @@ -1265,8 +1265,8 @@ class CommandActionTestCase(unittest.TestCase): def escape(self, escape_func): return escape_func(self.data) - def is_literal(self) -> int: - return 1 + def is_literal(self) -> bool: + return True a = SCons.Action.CommandAction(["xyzzy"]) e = Environment(SPAWN=func) diff --git a/SCons/Builder.py b/SCons/Builder.py index bdedc3a..a11524e 100644 --- a/SCons/Builder.py +++ b/SCons/Builder.py @@ -385,10 +385,10 @@ class BuilderBase: emitter = None, multi: int = 0, env = None, - single_source: int = 0, + single_source: bool = False, name = None, chdir = _null, - is_explicit: int = 1, + is_explicit: bool = True, src_builder = None, ensure_suffix: bool = False, **overrides) -> None: @@ -889,7 +889,7 @@ class CompositeBuilder(SCons.Util.Proxy): self.cmdgen.add_action(suffix, action) self.set_src_suffix(self.cmdgen.src_suffixes()) -def is_a_Builder(obj): +def is_a_Builder(obj) -> bool: """"Returns True if the specified obj is one of our Builder classes. The test is complicated a bit by the fact that CompositeBuilder diff --git a/SCons/BuilderTests.py b/SCons/BuilderTests.py index 3ba5285..379d18b 100644 --- a/SCons/BuilderTests.py +++ b/SCons/BuilderTests.py @@ -170,15 +170,15 @@ class MyNode_without_target_from_source: return self.builder is not None def set_explicit(self, is_explicit) -> None: self.is_explicit = is_explicit - def has_explicit_builder(self): + def has_explicit_builder(self) -> bool: return self.is_explicit - def env_set(self, env, safe: int=0) -> None: + def env_set(self, env, safe: bool=False) -> None: self.env = env def add_source(self, source) -> None: self.sources.extend(source) def scanner_key(self): return self.name - def is_derived(self): + def is_derived(self) -> bool: return self.has_builder() def generate_build_env(self, env): return env diff --git a/SCons/CacheDir.py b/SCons/CacheDir.py index 12f1d54..a063849 100644 --- a/SCons/CacheDir.py +++ b/SCons/CacheDir.py @@ -67,7 +67,7 @@ def CacheRetrieveFunc(target, source, env) -> int: fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) return 0 -def CacheRetrieveString(target, source, env): +def CacheRetrieveString(target, source, env) -> None: t = target[0] fs = t.fs cd = env.get_CacheDir() @@ -271,7 +271,10 @@ class CacheDir: return cachedir, os.path.join(cachedir, sig) def retrieve(self, node) -> bool: - """ + """Retrieve a node from cache. + + Returns True if a successful retrieval resulted. + This method is called from multiple threads in a parallel build, so only do thread safe stuff here. Do thread unsafe stuff in built(). diff --git a/SCons/Debug.py b/SCons/Debug.py index 000ebd5..615eb4f 100644 --- a/SCons/Debug.py +++ b/SCons/Debug.py @@ -92,7 +92,7 @@ def dumpLoggedInstances(classes, file=sys.stdout) -> None: if sys.platform[:5] == "linux": # Linux doesn't actually support memory usage stats from getrusage(). - def memory(): + def memory() -> int: with open('/proc/self/stat') as f: mstr = f.read() mstr = mstr.split()[22] @@ -111,7 +111,7 @@ else: def memory() -> int: return 0 else: - def memory(): + def memory() -> int: res = resource.getrusage(resource.RUSAGE_SELF) return res[4] diff --git a/SCons/Defaults.py b/SCons/Defaults.py index 15041a5..39fdd5b 100644 --- a/SCons/Defaults.py +++ b/SCons/Defaults.py @@ -95,7 +95,7 @@ def DefaultEnvironment(*args, **kw): # going into a shared library are, in fact, shared. def StaticObjectEmitter(target, source, env): for tgt in target: - tgt.attributes.shared = None + tgt.attributes.shared = False return target, source @@ -112,7 +112,7 @@ def SharedFlagChecker(source, target, env): try: shared = src.attributes.shared except AttributeError: - shared = None + shared = False if not shared: raise SCons.Errors.UserError( "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])) diff --git a/SCons/Environment.py b/SCons/Environment.py index 2f1dcaf..4e5601e 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -507,17 +507,13 @@ class BuilderDict(UserDict): self.__setitem__(i, v) - _is_valid_var = re.compile(r'[_a-zA-Z]\w*$') -def is_valid_construction_var(varstr): - """Return if the specified string is a legitimate construction - variable. - """ +def is_valid_construction_var(varstr) -> bool: + """Return True if *varstr* is a legitimate construction variable.""" return _is_valid_var.match(varstr) - class SubstitutionEnvironment: """Base class for different flavors of construction environments. @@ -1602,21 +1598,21 @@ class Base(SubstitutionEnvironment): if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone') return clone - def _changed_build(self, dependency, target, prev_ni, repo_node=None): + def _changed_build(self, dependency, target, prev_ni, repo_node=None) -> bool: if dependency.changed_state(target, prev_ni, repo_node): - return 1 + return True return self.decide_source(dependency, target, prev_ni, repo_node) - def _changed_content(self, dependency, target, prev_ni, repo_node=None): + def _changed_content(self, dependency, target, prev_ni, repo_node=None) -> bool: return dependency.changed_content(target, prev_ni, repo_node) - def _changed_timestamp_then_content(self, dependency, target, prev_ni, repo_node=None): + def _changed_timestamp_then_content(self, dependency, target, prev_ni, repo_node=None) -> bool: return dependency.changed_timestamp_then_content(target, prev_ni, repo_node) - def _changed_timestamp_newer(self, dependency, target, prev_ni, repo_node=None): + def _changed_timestamp_newer(self, dependency, target, prev_ni, repo_node=None) -> bool: return dependency.changed_timestamp_newer(target, prev_ni, repo_node) - def _changed_timestamp_match(self, dependency, target, prev_ni, repo_node=None): + def _changed_timestamp_match(self, dependency, target, prev_ni, repo_node=None) -> bool: return dependency.changed_timestamp_match(target, prev_ni, repo_node) def Decider(self, function): diff --git a/SCons/ExecutorTests.py b/SCons/ExecutorTests.py index 24df8e7..7e5df14 100644 --- a/SCons/ExecutorTests.py +++ b/SCons/ExecutorTests.py @@ -49,7 +49,7 @@ class MyAction: return ' '.join(['GENSTRING'] + list(map(str, self.actions)) + target + source) def get_contents(self, target, source, env): return b' '.join( - [SCons.Util.to_bytes(aa) for aa in self.actions] + + [SCons.Util.to_bytes(aa) for aa in self.actions] + [SCons.Util.to_bytes(tt) for tt in target] + [SCons.Util.to_bytes(ss) for ss in source] ) @@ -99,7 +99,7 @@ class MyNode: def disambiguate(self): return self - def is_up_to_date(self): + def is_up_to_date(self) -> bool: return self.up_to_date class MyScanner: @@ -264,7 +264,7 @@ class ExecutorTestCase(unittest.TestCase): be = x.get_build_env() assert be['e'] == 1, be['e'] - + x.cleanup() x.env = MyEnvironment(eee=1) diff --git a/SCons/Node/Alias.py b/SCons/Node/Alias.py index 55c4795..f36a4ec 100644 --- a/SCons/Node/Alias.py +++ b/SCons/Node/Alias.py @@ -87,7 +87,7 @@ class AliasNodeInfo(SCons.Node.NodeInfoBase): for key, value in state.items(): if key not in ('__weakref__',): setattr(self, key, value) - + class AliasBuildInfo(SCons.Node.BuildInfoBase): __slots__ = () @@ -103,7 +103,7 @@ class Alias(SCons.Node.Node): self.name = name self.changed_since_last_build = 1 self.store_info = 0 - + def str_for_display(self): return '"' + self.__str__() + '"' @@ -116,11 +116,11 @@ class Alias(SCons.Node.Node): really_build = SCons.Node.Node.build is_up_to_date = SCons.Node.Node.children_are_up_to_date - def is_under(self, dir) -> int: + def is_under(self, dir) -> bool: # Make Alias nodes get built regardless of # what directory scons was run from. Alias nodes # are outside the filesystem: - return 1 + return True def get_contents(self): """The contents of an alias is the concatenation diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index 58b8a5c..e6255c4 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -762,30 +762,30 @@ class Base(SCons.Node.Node): else: return None - def isdir(self): + def isdir(self) -> bool: st = self.stat() return st is not None and stat.S_ISDIR(st.st_mode) - def isfile(self): + def isfile(self) -> bool: st = self.stat() return st is not None and stat.S_ISREG(st.st_mode) if hasattr(os, 'symlink'): - def islink(self): + def islink(self) -> bool: st = self.lstat() return st is not None and stat.S_ISLNK(st.st_mode) else: def islink(self) -> bool: return False # no symlinks - def is_under(self, dir): + def is_under(self, dir) -> bool: if self is dir: - return 1 + return True else: return self.dir.is_under(dir) def set_local(self) -> None: - self._local = 1 + self._local = True def srcnode(self): """If this node is in a build path, return the node @@ -1144,10 +1144,10 @@ class LocalFS: def getsize(self, path): return os.path.getsize(path) - def isdir(self, path): + def isdir(self, path) -> bool: return os.path.isdir(path) - def isfile(self, path): + def isfile(self, path) -> bool: return os.path.isfile(path) def link(self, src, dst): @@ -1185,7 +1185,7 @@ class LocalFS: if hasattr(os, 'symlink'): - def islink(self, path): + def islink(self, path) -> bool: return os.path.islink(path) else: @@ -1914,16 +1914,15 @@ class Dir(Base): def do_duplicate(self, src) -> None: pass - def is_up_to_date(self) -> int: - """If any child is not up-to-date, then this directory isn't, - either.""" + def is_up_to_date(self) -> bool: + """If any child is not up-to-date, then this directory isn't, either.""" if self.builder is not MkdirBuilder and not self.exists(): - return 0 + return False up_to_date = SCons.Node.up_to_date for kid in self.children(): if kid.get_state() > up_to_date: - return 0 - return 1 + return False + return True def rdir(self): if not self.exists(): @@ -2474,11 +2473,8 @@ class RootDir(Dir): def entry_tpath(self, name): return self._tpath + name - def is_under(self, dir) -> int: - if self is dir: - return 1 - else: - return 0 + def is_under(self, dir) -> bool: + return True if self is dir else False def up(self): return None @@ -2713,7 +2709,7 @@ class File(Base): """Turn a file system node into a File object.""" self.scanner_paths = {} if not hasattr(self, '_local'): - self._local = 0 + self._local = False if not hasattr(self, 'released_target_info'): self.released_target_info = False @@ -3018,19 +3014,19 @@ class File(Base): if self.exists(): self.get_build_env().get_CacheDir().push(self) - def retrieve_from_cache(self): + def retrieve_from_cache(self) -> bool: """Try to retrieve the node's content from a cache This method is called from multiple threads in a parallel build, so only do thread safe stuff here. Do thread unsafe stuff in built(). - Returns true if the node was successfully retrieved. + Returns True if the node was successfully retrieved. """ if self.nocache: - return None + return False if not self.is_derived(): - return None + return False return self.get_build_env().get_CacheDir().retrieve(self) def visited(self) -> None: @@ -3310,7 +3306,7 @@ class File(Base): self.scanner_paths = None - def changed(self, node=None, allowcache: bool=False): + def changed(self, node=None, allowcache: bool=False) -> bool: """ Returns if the node is up-to-date with respect to the BuildInfo stored last time it was built. @@ -3332,14 +3328,14 @@ class File(Base): self._memo['changed'] = has_changed return has_changed - def changed_content(self, target, prev_ni, repo_node=None): + def changed_content(self, target, prev_ni, repo_node=None) -> bool: cur_csig = self.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: - return 1 + return True - def changed_state(self, target, prev_ni, repo_node=None): + def changed_state(self, target, prev_ni, repo_node=None) -> bool: return self.state != SCons.Node.up_to_date @@ -3466,7 +3462,7 @@ class File(Base): return df - def changed_timestamp_then_content(self, target, prev_ni, node=None): + def changed_timestamp_then_content(self, target, prev_ni, node=None) -> bool: """ Used when decider for file is Timestamp-MD5 @@ -3527,13 +3523,13 @@ class File(Base): return False return self.changed_content(target, new_prev_ni) - def changed_timestamp_newer(self, target, prev_ni, repo_node=None): + def changed_timestamp_newer(self, target, prev_ni, repo_node=None) -> bool: try: return self.get_timestamp() > target.get_timestamp() except AttributeError: - return 1 + return True - def changed_timestamp_match(self, target, prev_ni, repo_node=None): + def changed_timestamp_match(self, target, prev_ni, repo_node=None) -> bool: """ Return True if the timestamps don't match or if there is no previous timestamp :param target: @@ -3543,13 +3539,13 @@ class File(Base): try: return self.get_timestamp() != prev_ni.timestamp except AttributeError: - return 1 + return True - def is_up_to_date(self): - """Check for whether the Node is current - In all cases self is the target we're checking to see if it's up to date - """ + def is_up_to_date(self) -> bool: + """Check for whether the Node is current. + In all cases self is the target we're checking to see if it's up to date + """ T = 0 if T: Trace('is_up_to_date(%s):' % self) if not self.exists(): @@ -3570,10 +3566,10 @@ class File(Base): raise e SCons.Node.store_info_map[self.store_info](self) if T: Trace(' 1\n') - return 1 + return True self.changed() if T: Trace(' None\n') - return None + return False else: r = self.changed() if T: Trace(' self.exists(): %s\n' % r) diff --git a/SCons/Node/NodeTests.py b/SCons/Node/NodeTests.py index e7c9e9a..42fae01 100644 --- a/SCons/Node/NodeTests.py +++ b/SCons/Node/NodeTests.py @@ -137,7 +137,7 @@ class Environment: return [] class Builder: - def __init__(self, env=None, is_explicit: int=1) -> None: + def __init__(self, env=None, is_explicit: bool=True) -> None: if env is None: env = Environment() self.env = env self.overrides = {} @@ -542,10 +542,9 @@ class NodeTestCase(unittest.TestCase): assert m is None, m def test_is_up_to_date(self) -> None: - """Test the default is_up_to_date() method - """ + """Test the default is_up_to_date() method.""" node = SCons.Node.Node() - assert node.is_up_to_date() is None + assert not node.is_up_to_date() def test_children_are_up_to_date(self) -> None: """Test the children_are_up_to_date() method used by subclasses diff --git a/SCons/Node/Python.py b/SCons/Node/Python.py index 008787a..2f285b4 100644 --- a/SCons/Node/Python.py +++ b/SCons/Node/Python.py @@ -117,11 +117,11 @@ class Value(SCons.Node.Node): is_up_to_date = SCons.Node.Node.children_are_up_to_date - def is_under(self, dir) -> int: + def is_under(self, dir) -> bool: # Make Value nodes get built regardless of # what directory scons was run from. Value nodes # are outside the filesystem: - return 1 + return True def write(self, built_value) -> None: """Set the value of the node.""" diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index 81ff2ff..9a8398f 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -109,7 +109,7 @@ interactive = False def is_derived_none(node): raise NotImplementedError -def is_derived_node(node): +def is_derived_node(node) -> bool: """ Returns true if this node is derived (i.e. built). """ @@ -118,16 +118,16 @@ def is_derived_node(node): _is_derived_map = {0 : is_derived_none, 1 : is_derived_node} -def exists_none(node): +def exists_none(node) -> bool: raise NotImplementedError -def exists_always(node) -> int: - return 1 +def exists_always(node) -> bool: + return True def exists_base(node) -> bool: return node.stat() is not None -def exists_entry(node): +def exists_entry(node) -> bool: """Return if the Entry exists. Check the file system to see what we should turn into first. Assume a file if there's no directory.""" @@ -135,7 +135,7 @@ def exists_entry(node): return _exists_map[node._func_exists](node) -def exists_file(node): +def exists_file(node) -> bool: # Duplicate from source path if we are set up to do this. if node.duplicate and not node.is_derived() and not node.linked: src = node.srcnode() @@ -245,7 +245,7 @@ _target_from_source_map = {0 : target_from_source_none, # # First, the single decider functions # -def changed_since_last_build_node(node, target, prev_ni, repo_node=None): +def changed_since_last_build_node(node, target, prev_ni, repo_node=None) -> bool: """ Must be overridden in a specific subclass to return True if this @@ -266,37 +266,37 @@ def changed_since_last_build_node(node, target, prev_ni, repo_node=None): raise NotImplementedError -def changed_since_last_build_alias(node, target, prev_ni, repo_node=None): +def changed_since_last_build_alias(node, target, prev_ni, repo_node=None) -> bool: cur_csig = node.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: - return 1 + return True -def changed_since_last_build_entry(node, target, prev_ni, repo_node=None): +def changed_since_last_build_entry(node, target, prev_ni, repo_node=None) -> bool: node.disambiguate() return _decider_map[node.changed_since_last_build](node, target, prev_ni, repo_node) -def changed_since_last_build_state_changed(node, target, prev_ni, repo_node=None): +def changed_since_last_build_state_changed(node, target, prev_ni, repo_node=None) -> bool: return node.state != SCons.Node.up_to_date -def decide_source(node, target, prev_ni, repo_node=None): +def decide_source(node, target, prev_ni, repo_node=None) -> bool: return target.get_build_env().decide_source(node, target, prev_ni, repo_node) -def decide_target(node, target, prev_ni, repo_node=None): +def decide_target(node, target, prev_ni, repo_node=None) -> bool: return target.get_build_env().decide_target(node, target, prev_ni, repo_node) -def changed_since_last_build_python(node, target, prev_ni, repo_node=None): +def changed_since_last_build_python(node, target, prev_ni, repo_node=None) -> bool: cur_csig = node.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: - return 1 + return True # @@ -681,7 +681,7 @@ class Node(object, metaclass=NoSlotsPyPy): """ pass - def retrieve_from_cache(self) -> int: + def retrieve_from_cache(self) -> bool: """Try to retrieve the node's content from a cache This method is called from multiple threads in a parallel build, @@ -690,7 +690,7 @@ class Node(object, metaclass=NoSlotsPyPy): Returns true if the node was successfully retrieved. """ - return 0 + return False # # Taskmaster interface subsystem @@ -757,7 +757,7 @@ class Node(object, metaclass=NoSlotsPyPy): e.node = self raise - def built(self): + def built(self) -> None: """Called just after this node is successfully built.""" # Clear the implicit dependency caches of any Nodes @@ -783,7 +783,6 @@ class Node(object, metaclass=NoSlotsPyPy): except AttributeError: pass - self.clear() if self.pseudo: @@ -900,8 +899,8 @@ class Node(object, metaclass=NoSlotsPyPy): def set_explicit(self, is_explicit) -> None: self.is_explicit = is_explicit - def has_explicit_builder(self): - """Return whether this Node has an explicit builder + def has_explicit_builder(self) -> bool: + """Return whether this Node has an explicit builder. This allows an internal Builder created by SCons to be marked non-explicit, so that it can be overridden by an explicit @@ -910,8 +909,8 @@ class Node(object, metaclass=NoSlotsPyPy): try: return self.is_explicit except AttributeError: - self.is_explicit = None - return self.is_explicit + self.is_explicit = False + return False def get_builder(self, default_builder=None): """Return the set builder, or a specified default value""" @@ -922,7 +921,7 @@ class Node(object, metaclass=NoSlotsPyPy): multiple_side_effect_has_builder = has_builder - def is_derived(self): + def is_derived(self) -> bool: """ Returns true if this node is derived (i.e. built). @@ -1119,7 +1118,7 @@ class Node(object, metaclass=NoSlotsPyPy): """ return scanner.select(self) - def env_set(self, env, safe: int=0) -> None: + def env_set(self, env, safe: bool=False) -> None: if safe and self.env: return self.env = env @@ -1250,7 +1249,7 @@ class Node(object, metaclass=NoSlotsPyPy): """Set the Node's always_build value.""" self.always_build = always_build - def exists(self): + def exists(self) -> bool: """Does this node exists?""" return _exists_map[self._func_exists](self) @@ -1512,12 +1511,12 @@ class Node(object, metaclass=NoSlotsPyPy): return result - def is_up_to_date(self): + def is_up_to_date(self) -> bool: """Default check for whether the Node is current: unknown Node subtypes are always out of date, so they will always get built.""" - return None + return False - def children_are_up_to_date(self): + def children_are_up_to_date(self) -> bool: """Alternate check for whether the Node is current: If all of our children were up-to-date, then this Node was up-to-date, too. @@ -1526,7 +1525,7 @@ class Node(object, metaclass=NoSlotsPyPy): # Allow the children to calculate their signatures. self.binfo = self.get_binfo() if self.always_build: - return None + return False state = 0 for kid in self.children(None): s = kid.get_state() @@ -1534,10 +1533,10 @@ class Node(object, metaclass=NoSlotsPyPy): state = s return (state == 0 or state == SCons.Node.up_to_date) - def is_literal(self) -> int: + def is_literal(self) -> bool: """Always pass the string representation of a Node to the command interpreter literally.""" - return 1 + return True def render_include_tree(self): """ diff --git a/SCons/SConf.py b/SCons/SConf.py index 128644f..e522c8b 100644 --- a/SCons/SConf.py +++ b/SCons/SConf.py @@ -39,6 +39,7 @@ import os import re import sys import traceback +from typing import Tuple import SCons.Action import SCons.Builder @@ -265,12 +266,12 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask): sys.excepthook(*self.exc_info()) return SCons.Taskmaster.Task.failed(self) - def collect_node_states(self): + def collect_node_states(self) -> Tuple[bool, bool, bool]: # returns (is_up_to_date, cached_error, cachable) - # where is_up_to_date is 1, if the node(s) are up_to_date - # cached_error is 1, if the node(s) are up_to_date, but the - # build will fail - # cachable is 0, if some nodes are not in our cache + # where is_up_to_date is True if the node(s) are up_to_date + # cached_error is True if the node(s) are up_to_date, but the + # build will fail + # cachable is False if some nodes are not in our cache T = 0 changed = False cached_error = False @@ -311,7 +312,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask): if cache_mode == CACHE and not cachable: raise ConfigureCacheError(self.targets[0]) elif cache_mode == FORCE: - is_up_to_date = 0 + is_up_to_date = False if cached_error and is_up_to_date: self.display("Building \"%s\" failed in a previous run and all " diff --git a/SCons/SConfTests.py b/SCons/SConfTests.py index 96ba926..2903ba6 100644 --- a/SCons/SConfTests.py +++ b/SCons/SConfTests.py @@ -185,8 +185,8 @@ class SConfTestCase(unittest.TestCase): self.attributes = Attrs() def disambiguate(self): return self - def has_builder(self) -> int: - return 1 + def has_builder(self) -> bool: + return True def add_pre_action(self, *actions) -> None: pass def add_post_action(self, *actions) -> None: @@ -203,14 +203,14 @@ class SConfTestCase(unittest.TestCase): pass def clear(self) -> None: pass - def is_up_to_date(self): - return None + def is_up_to_date(self) -> bool: + return False def prepare(self) -> None: pass def push_to_cache(self) -> None: pass - def retrieve_from_cache(self) -> int: - return 0 + def retrieve_from_cache(self) -> bool: + return False def build(self, **kw) -> None: return def built(self) -> None: diff --git a/SCons/Scanner/JavaTests.py b/SCons/Scanner/JavaTests.py index 38a4bdb..0a3c759 100644 --- a/SCons/Scanner/JavaTests.py +++ b/SCons/Scanner/JavaTests.py @@ -96,8 +96,8 @@ class DummyNode: def __init__(self, name) -> None: self.name = name - def rexists(self) -> int: - return 1 + def rexists(self) -> bool: + return True def __str__(self) -> str: return self.name diff --git a/SCons/Scanner/ProgTests.py b/SCons/Scanner/ProgTests.py index 2798ab6..37eb48a 100644 --- a/SCons/Scanner/ProgTests.py +++ b/SCons/Scanner/ProgTests.py @@ -89,11 +89,11 @@ class DummyEnvironment: class DummyNode: def __init__(self, name) -> None: self.name = name - def rexists(self) -> int: - return 1 + def rexists(self) -> bool: + return True def __str__(self) -> str: return self.name - + def deps_match(deps, libs): deps=sorted(map(str, deps)) libs.sort() @@ -195,7 +195,7 @@ class ProgramScannerTestCase7(unittest.TestCase): class ProgramScannerTestCase8(unittest.TestCase): def runTest(self) -> None: - + n1 = DummyNode('n1') env = DummyEnvironment(LIBPATH=[ test.workpath("dir") ], LIBS=[n1], diff --git a/SCons/Scanner/ScannerTests.py b/SCons/Scanner/ScannerTests.py index 1fbbb62..a777ba5 100644 --- a/SCons/Scanner/ScannerTests.py +++ b/SCons/Scanner/ScannerTests.py @@ -124,8 +124,8 @@ class ScannerBaseTestCase(unittest.TestCase): self.key = key def scanner_key(self): return self.key - def rexists(self) -> int: - return 1 + def rexists(self) -> bool: + return True def func(self, filename, env, target, *args): self.filename = filename @@ -343,13 +343,14 @@ class ScannerBaseTestCase(unittest.TestCase): assert s == 'xyzzy', s class SelectorTestCase(unittest.TestCase): + class skey_node: def __init__(self, key) -> None: self.key = key def scanner_key(self): return self.key - def rexists(self) -> int: - return 1 + def rexists(self) -> bool: + return True def test___init__(self) -> None: """Test creation of Scanner.Selector object""" @@ -407,28 +408,28 @@ class CurrentTestCase(unittest.TestCase): self.called_has_builder = None self.called_is_up_to_date = None self.func_called = None - def rexists(self) -> int: - return 1 + def rexists(self) -> bool: + return True class HasNoBuilder(MyNode): - def has_builder(self): - self.called_has_builder = 1 - return None + def has_builder(self) -> bool: + self.called_has_builder = True + return False class IsNotCurrent(MyNode): - def has_builder(self) -> int: - self.called_has_builder = 1 - return 1 - def is_up_to_date(self): - self.called_is_up_to_date = 1 - return None + def has_builder(self) -> bool: + self.called_has_builder = True + return True + def is_up_to_date(self) -> bool: + self.called_is_up_to_date = True + return False class IsCurrent(MyNode): - def has_builder(self) -> int: - self.called_has_builder = 1 - return 1 - def is_up_to_date(self) -> int: - self.called_is_up_to_date = 1 - return 1 + def has_builder(self) -> bool: + self.called_has_builder = True + return True + def is_up_to_date(self) -> bool: + self.called_is_up_to_date = True + return True def func(node, env, path): - node.func_called = 1 + node.func_called = True return [] env = DummyEnvironment() s = Current(func) diff --git a/SCons/Subst.py b/SCons/Subst.py index 8e6d22e..4046ca6 100644 --- a/SCons/Subst.py +++ b/SCons/Subst.py @@ -71,8 +71,8 @@ class Literal: def for_signature(self): return self.lstr - def is_literal(self) -> int: - return 1 + def is_literal(self) -> bool: + return True def __eq__(self, other): if not isinstance(other, Literal): @@ -113,8 +113,8 @@ class SpecialAttrWrapper: def for_signature(self): return self.forsig - def is_literal(self) -> int: - return 1 + def is_literal(self) -> bool: + return True def quote_spaces(arg): """Generic function for putting double quotes around any string that @@ -135,7 +135,7 @@ class CmdStringHolder(collections.UserString): super().__init__(cmd) self.literal = literal - def is_literal(self): + def is_literal(self) -> bool: return self.literal def escape(self, escape_func, quote_func=quote_spaces): @@ -417,7 +417,7 @@ class StringSubber: return list(map(func, s)) elif callable(s): - # SCons has the unusual Null class where any __getattr__ call returns it's self, + # SCons has the unusual Null class where any __getattr__ call returns it's self, # which does not work the signature module, and the Null class returns an empty # string if called on, so we make an exception in this condition for Null class # Also allow callables where the only non default valued args match the expected defaults @@ -594,7 +594,7 @@ class ListSubber(collections.UserList): self.substitute(a, lvars, 1) self.next_word() elif callable(s): - # SCons has the unusual Null class where any __getattr__ call returns it's self, + # SCons has the unusual Null class where any __getattr__ call returns it's self, # which does not work the signature module, and the Null class returns an empty # string if called on, so we make an exception in this condition for Null class # Also allow callables where the only non default valued args match the expected defaults @@ -894,7 +894,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv The companion scons_subst() function (above) handles basic substitutions within strings, so see that function instead if that's what you're looking for. - """ + """ if conv is None: conv = _strconv[mode] diff --git a/SCons/SubstTests.py b/SCons/SubstTests.py index dead458..12929c6 100644 --- a/SCons/SubstTests.py +++ b/SCons/SubstTests.py @@ -40,8 +40,8 @@ class DummyNode: self.name = os.path.normpath(name) def __str__(self) -> str: return self.name - def is_literal(self) -> int: - return 1 + def is_literal(self) -> bool: + return True def rfile(self): return self def get_subst_proxy(self): @@ -136,8 +136,8 @@ class SubstTestCase(unittest.TestCase): self.literal = literal def __str__(self) -> str: return self.literal - def is_literal(self) -> int: - return 1 + def is_literal(self) -> bool: + return True class TestCallable: def __init__(self, value) -> None: @@ -1200,24 +1200,25 @@ class quote_spaces_TestCase(unittest.TestCase): def __init__(self, name, children=[]) -> None: self.children = children self.name = name + def __str__(self) -> str: return self.name - def exists(self) -> int: - return 1 - def rexists(self) -> int: - return 1 - def has_builder(self) -> int: - return 1 - def has_explicit_builder(self) -> int: - return 1 - def side_effect(self) -> int: - return 1 - def precious(self) -> int: - return 1 - def always_build(self) -> int: - return 1 - def current(self) -> int: - return 1 + def exists(self) -> bool: + return True + def rexists(self) -> bool: + return True + def has_builder(self) -> bool: + return True + def has_explicit_builder(self) -> bool: + return True + def side_effect(self) -> bool: + return True + def precious(self) -> bool: + return True + def always_build(self) -> bool: + return True + def current(self) -> bool: + return True class LiteralTestCase(unittest.TestCase): def test_Literal(self) -> None: diff --git a/SCons/Taskmaster/TaskmasterTests.py b/SCons/Taskmaster/TaskmasterTests.py index 83b7ea9..0dd91f1 100644 --- a/SCons/Taskmaster/TaskmasterTests.py +++ b/SCons/Taskmaster/TaskmasterTests.py @@ -43,8 +43,8 @@ class Node: self.name = name self.kids = kids self.scans = scans - self.cached = 0 - self.scanned = 0 + self.cached = False + self.scanned = False self.scanner = None self.targets = [self] self.prerequisites = None @@ -61,7 +61,7 @@ class Node: self.ref_count = 0 self.waiting_parents = set() self.waiting_s_e = set() - self.side_effect = 0 + self.side_effect = False self.side_effects = [] self.alttargets = [] self.postprocessed = None @@ -75,7 +75,7 @@ class Node: def push_to_cache(self) -> None: pass - def retrieve_from_cache(self): + def retrieve_from_cache(self) -> bool: global cache_text if self.cached: cache_text.append(self.name + " retrieved") @@ -147,7 +147,7 @@ class Node: def has_builder(self) -> bool: return self.builder is not None - def is_derived(self): + def is_derived(self) -> bool: return self.has_builder or self.side_effect def alter_targets(self): @@ -160,7 +160,7 @@ class Node: def children(self): if not self.scanned: self.scan() - self.scanned = 1 + self.scanned = True return self.kids def scan(self) -> None: @@ -197,7 +197,7 @@ class Node: def store_bsig(self) -> None: pass - def is_up_to_date(self): + def is_up_to_date(self) -> bool: return self._current_val def __str__(self) -> str: @@ -447,7 +447,7 @@ class TaskmasterTestCase(unittest.TestCase): n3 = Node("n3") n4 = Node("n4", [n1, n2, n3]) n5 = Node("n5", [n4]) - n3.side_effect = 1 + n3.side_effect = True n1.side_effects = n2.side_effects = n3.side_effects = [n4] tm = SCons.Taskmaster.Taskmaster([n1, n2, n3, n4, n5]) t = tm.next_task() @@ -1001,7 +1001,7 @@ class TaskmasterTestCase(unittest.TestCase): cache_text = [] n5 = Node("n5") n6 = Node("n6") - n6.cached = 1 + n6.cached = True tm = SCons.Taskmaster.Taskmaster([n5]) t = tm.next_task() # This next line is moderately bogus. We're just reaching @@ -1019,8 +1019,8 @@ class TaskmasterTestCase(unittest.TestCase): cache_text = [] n7 = Node("n7") n8 = Node("n8") - n7.cached = 1 - n8.cached = 1 + n7.cached = True + n8.cached = True tm = SCons.Taskmaster.Taskmaster([n7]) t = tm.next_task() # This next line is moderately bogus. We're just reaching diff --git a/SCons/Tool/DCommon.py b/SCons/Tool/DCommon.py index a4f976d..7bdf6f5 100644 --- a/SCons/Tool/DCommon.py +++ b/SCons/Tool/DCommon.py @@ -32,15 +32,15 @@ Coded by Russel Winder (russel@winder.org.uk) import os.path -def isD(env, source) -> int: +def isD(env, source) -> bool: if not source: - return 0 + return False for s in source: if s.sources: ext = os.path.splitext(str(s.sources[0]))[1] if ext == '.d': - return 1 - return 0 + return True + return False def addDPATHToEnv(env, executable) -> None: diff --git a/SCons/Tool/JavaCommon.py b/SCons/Tool/JavaCommon.py index 96000d0..4a5a7c5 100644 --- a/SCons/Tool/JavaCommon.py +++ b/SCons/Tool/JavaCommon.py @@ -471,7 +471,7 @@ else: # Java-file parsing takes too long (although it shouldn't relative # to how long the Java compiler itself seems to take...). - def parse_java_file(fn): + def parse_java_file(fn, version=default_java_version): """ "Parse" a .java file. This actually just splits the file name, so the assumption here @@ -511,7 +511,7 @@ def get_java_install_dirs(platform, version=None) -> List[str]: extracts the next-to-last component, then trims it further if it had a complex name, like 'java-1.8.0-openjdk-1.8.0.312-1', to try and put it on a common footing with the more common style, - which looks like 'jdk-11.0.2'. + which looks like 'jdk-11.0.2'. This is certainly fragile, and if someone has a 9.0 it won't sort right since this will still be alphabetic, BUT 9.0 was diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py index 4b487da..f0e47e2 100644 --- a/SCons/Tool/MSCommon/MSVC/Util.py +++ b/SCons/Tool/MSCommon/MSVC/Util.py @@ -157,21 +157,21 @@ def get_msvc_version_prefix(version): # toolset version query utilities -def is_toolset_full(toolset_version): +def is_toolset_full(toolset_version) -> bool: rval = False if toolset_version: if re_toolset_full.match(toolset_version): rval = True return rval -def is_toolset_140(toolset_version): +def is_toolset_140(toolset_version) -> bool: rval = False if toolset_version: if re_toolset_140.match(toolset_version): rval = True return rval -def is_toolset_sxs(toolset_version): +def is_toolset_sxs(toolset_version) -> bool: rval = False if toolset_version: if re_toolset_sxs.match(toolset_version): diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py index 185ccdf..0cadc10 100644 --- a/SCons/Tool/MSCommon/common.py +++ b/SCons/Tool/MSCommon/common.py @@ -161,7 +161,7 @@ def write_script_env_cache(cache) -> None: _is_win64 = None -def is_win64(): +def is_win64() -> bool: """Return true if running on windows 64 bits. Works whether python itself runs in 64 bits or 32 bits.""" @@ -196,9 +196,8 @@ def read_reg(value, hkroot=SCons.Util.HKEY_LOCAL_MACHINE): return SCons.Util.RegGetValue(hkroot, value)[0] -def has_reg(value): - """Return True if the given key exists in HKEY_LOCAL_MACHINE, False - otherwise.""" +def has_reg(value) -> bool: + """Return True if the given key exists in HKEY_LOCAL_MACHINE.""" try: SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value) ret = True diff --git a/SCons/Tool/cxx.py b/SCons/Tool/cxx.py index bf4bcce..2cf3299 100644 --- a/SCons/Tool/cxx.py +++ b/SCons/Tool/cxx.py @@ -1,12 +1,6 @@ -"""SCons.Tool.c++ - -Tool-specific initialization for generic Posix C++ compilers. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. -""" - +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,7 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# + +"""Tool-specific initialization for generic Posix C++ compilers. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path @@ -39,16 +39,16 @@ CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++', '.mm'] if SCons.Util.case_sensitive_suffixes('.c', '.C'): CXXSuffixes.append('.C') -def iscplusplus(source) -> int: +def iscplusplus(source) -> bool: if not source: # Source might be None for unusual cases like SConf. - return 0 + return False for s in source: if s.sources: ext = os.path.splitext(str(s.sources[0]))[1] if ext in CXXSuffixes: - return 1 - return 0 + return True + return False def generate(env) -> None: """ diff --git a/SCons/Tool/cyglink.py b/SCons/Tool/cyglink.py index 0d1eb51..0925a3d 100644 --- a/SCons/Tool/cyglink.py +++ b/SCons/Tool/cyglink.py @@ -31,7 +31,7 @@ def cyglink_lib_emitter(target, source, env, **kw): import_lib = env.subst('$%s_IMPLIBNAME' % var_prefix, target=target, source=source) import_lib_target = env.fs.File(import_lib) - import_lib_target.attributes.shared = 1 + import_lib_target.attributes.shared = True target.append(import_lib_target) if verbose: @@ -41,7 +41,7 @@ def cyglink_lib_emitter(target, source, env, **kw): for tgt in target: if is_String(tgt): tgt = env.File(tgt) - tgt.attributes.shared = 1 + tgt.attributes.shared = True return target, source diff --git a/SCons/Tool/default.py b/SCons/Tool/default.py index 4b386e2..3ceefb1 100644 --- a/SCons/Tool/default.py +++ b/SCons/Tool/default.py @@ -1,15 +1,6 @@ -"""SCons.Tool.default - -Initialization with a default tool list. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -29,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Initialization with a default tool list. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import SCons.Tool @@ -40,8 +35,8 @@ def generate(env) -> None: for t in SCons.Tool.tool_list(env['PLATFORM'], env): SCons.Tool.Tool(t)(env) -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/docbook/__init__.py b/SCons/Tool/docbook/__init__.py index 3af1bdb..54f1883 100644 --- a/SCons/Tool/docbook/__init__.py +++ b/SCons/Tool/docbook/__init__.py @@ -1,16 +1,6 @@ - -"""SCons.Tool.docbook - -Tool-specific initialization for Docbook. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -30,7 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# + +"""Tool-specific initialization for Docbook. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os import glob @@ -43,7 +39,6 @@ import SCons.Script import SCons.Tool import SCons.Util - __debug_tool_location = False # Get full path to this script scriptpath = os.path.dirname(os.path.realpath(__file__)) @@ -839,5 +834,5 @@ def generate(env) -> None: env.AddMethod(DocbookXslt, "DocbookXslt") -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True diff --git a/SCons/Tool/dvi.py b/SCons/Tool/dvi.py index a395d2b..044f62c 100644 --- a/SCons/Tool/dvi.py +++ b/SCons/Tool/dvi.py @@ -1,11 +1,6 @@ -"""SCons.Tool.dvi - -Common DVI Builder definition for various other Tool modules that use it. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,10 @@ Common DVI Builder definition for various other Tool modules that use it. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +""" +Common DVI Builder definition for various other Tool modules that use it. +""" import SCons.Builder import SCons.Tool @@ -52,10 +48,10 @@ def generate(env) -> None: env['BUILDERS']['DVI'] = DVIBuilder -def exists(env) -> int: +def exists(env) -> bool: # This only puts a skeleton Builder in place, so if someone # references this Tool directly, it's always "available." - return 1 + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/filesystem.py b/SCons/Tool/filesystem.py index 9a977b5..d90f240 100644 --- a/SCons/Tool/filesystem.py +++ b/SCons/Tool/filesystem.py @@ -1,14 +1,6 @@ -"""SCons.Tool.filesystem - -Tool-specific initialization for the filesystem tools. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Tool-specific initialization for the filesystem tools. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import SCons from SCons.Tool.install import copyFunc @@ -88,8 +84,8 @@ def generate(env) -> None: env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"' -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/install.py b/SCons/Tool/install.py index 54fc090..5c98fb3 100644 --- a/SCons/Tool/install.py +++ b/SCons/Tool/install.py @@ -500,8 +500,8 @@ def generate(env) -> None: except KeyError: env['INSTALLVERSIONEDLIB'] = copyFuncVersionedLib -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/javac.py b/SCons/Tool/javac.py index 6353924..a805937 100644 --- a/SCons/Tool/javac.py +++ b/SCons/Tool/javac.py @@ -21,17 +21,13 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -"""SCons.Tool.javac - -Tool-specific initialization for javac. +"""Tool-specific initialization for javac. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. - """ - import os import os.path from collections import OrderedDict @@ -242,8 +238,8 @@ def generate(env) -> None: env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVAPROCESSORPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM','$JAVACCOMSTR')}" -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/linkCommon/__init__.py b/SCons/Tool/linkCommon/__init__.py index b8d7610..f0cf4fc 100644 --- a/SCons/Tool/linkCommon/__init__.py +++ b/SCons/Tool/linkCommon/__init__.py @@ -165,6 +165,6 @@ def lib_emitter(target, source, env, **kw): for tgt in target: if SCons.Util.is_String(tgt): tgt = env.File(tgt) - tgt.attributes.shared = 1 + tgt.attributes.shared = True return target, source diff --git a/SCons/Tool/msvsTests.py b/SCons/Tool/msvsTests.py index 9c369d1..dd708d0 100644 --- a/SCons/Tool/msvsTests.py +++ b/SCons/Tool/msvsTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,8 +20,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import sys @@ -577,8 +576,8 @@ def DummyQueryValue(key, value): # print "Query Value",key.name+"\\"+value,"=>",rv return rv -def DummyExists(path) -> int: - return 1 +def DummyExists(path) -> bool: + return True def DummyVsWhere(msvc_version, env): # not testing versions with vswhere, so return none @@ -642,12 +641,12 @@ class msvsTestCase(unittest.TestCase): assert not v1 or str(v1[0]) == self.highest_version, \ (v1, self.highest_version) assert len(v1) == self.number_of_versions, v1 - + def test_config_generation(self) -> None: """Test _DSPGenerator.__init__(...)""" if not self.highest_version : return - + # Initialize 'static' variables version_num, suite = msvs_parse_version(self.highest_version) if version_num >= 10.0: @@ -663,16 +662,16 @@ class msvsTestCase(unittest.TestCase): # Avoid any race conditions between the test cases when we test # actually writing the files. dspfile = 'test%s%s' % (hash(self), suffix) - + str_function_test = str(function_test.__init__) source = 'test.cpp' - + # Create the cmdargs test list list_variant = ['Debug|Win32','Release|Win32', 'Debug|x64', 'Release|x64'] - list_cmdargs = ['debug=True target_arch=32', + list_cmdargs = ['debug=True target_arch=32', 'debug=False target_arch=32', - 'debug=True target_arch=x64', + 'debug=True target_arch=x64', 'debug=False target_arch=x64'] list_cppdefines = [['_A', '_B', 'C'], ['_B', '_C_'], ['D'], []] list_cpppaths = [[r'C:\test1'], [r'C:\test1;C:\test2'], @@ -775,15 +774,15 @@ class msvsTestCase(unittest.TestCase): class _DummyEnv(DummyEnv): def subst(self, string, *args, **kwargs): return string - + env = _DummyEnv(param_dict) env['MSVSSCONSCRIPT'] = '' env['MSVS_VERSION'] = self.highest_version env['MSVSBUILDTARGET'] = 'target' - + # Call function to test genDSP = function_test(dspfile, source, env) - + # Check expected result self.assertListEqual(list(genDSP.configs.keys()), list(expected_configs.keys())) for key, v in genDSP.configs.items(): diff --git a/SCons/Tool/ninja/Utils.py b/SCons/Tool/ninja/Utils.py index eb09daf..7c85f62 100644 --- a/SCons/Tool/ninja/Utils.py +++ b/SCons/Tool/ninja/Utils.py @@ -59,11 +59,11 @@ def ninja_add_command_line_options() -> None: action="store_true", default=False, help='Allow scons to skip regeneration of the ninja file and restarting of the daemon. ' + - 'Care should be taken in cases where Glob is in use or SCons generated files are used in ' + + 'Care should be taken in cases where Glob is in use or SCons generated files are used in ' + 'command lines.') -def is_valid_dependent_node(node): +def is_valid_dependent_node(node) -> bool: """ Return True if node is not an alias or is an alias that has children @@ -76,7 +76,7 @@ def is_valid_dependent_node(node): are valid implicit dependencies. """ if isinstance(node, SCons.Node.Alias.Alias): - return node.children() + return bool(node.children()) return not node.get_env().get("NINJA_SKIP") diff --git a/SCons/Tool/packaging/__init__.py b/SCons/Tool/packaging/__init__.py index c8e530d..ea2f429 100644 --- a/SCons/Tool/packaging/__init__.py +++ b/SCons/Tool/packaging/__init__.py @@ -218,8 +218,8 @@ def generate(env) -> None: env['BUILDERS']['Tag'] = Tag -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True def options(opts) -> None: diff --git a/SCons/Tool/packaging/msi.py b/SCons/Tool/packaging/msi.py index a0bed8f..6746db8 100644 --- a/SCons/Tool/packaging/msi.py +++ b/SCons/Tool/packaging/msi.py @@ -1,11 +1,7 @@ -"""SCons.Tool.packaging.msi - -The msi packager. -""" - +# MIT License +# +# Copyright The SCons Foundation # -# __COPYRIGHT__ -# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -25,7 +21,7 @@ The msi packager. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""The msi packager.""" import os import SCons @@ -78,9 +74,8 @@ def convert_to_id(s, id_set): return id_set[id][s] -def is_dos_short_file_name(file): - """ Examine if the given file is in the 8.3 form. - """ +def is_dos_short_file_name(file) -> bool: + """Examine if the given file is in the 8.3 form.""" fname, ext = os.path.splitext(file) proper_ext = len(ext) == 0 or (2 <= len(ext) <= 4) # the ext contains the dot proper_fname = file.isupper() and len(fname) <= 8 @@ -88,9 +83,11 @@ def is_dos_short_file_name(file): return proper_ext and proper_fname def gen_dos_short_file_name(file, filename_set): - """ See http://support.microsoft.com/default.aspx?scid=kb;en-us;Q142982 + """Return a filename in the 8.3 form. + + See http://support.microsoft.com/default.aspx?scid=kb;en-us;Q142982 - These are no complete 8.3 dos short names. The ~ char is missing and + These are no complete 8.3 dos short names. The ~ char is missing and replaced with one character from the filename. WiX warns about such filenames, since a collision might occur. Google for "CNDL1014" for more information. @@ -298,7 +295,7 @@ def build_wxsfile_file_section(root, files, NAME, VERSION, VENDOR, filename_set, for d in dir_parts[:]: already_created = [c for c in Directory.childNodes if c.nodeName == 'Directory' - and c.attributes['LongName'].value == escape(d)] + and c.attributes['LongName'].value == escape(d)] if already_created: Directory = already_created[0] diff --git a/SCons/Tool/packaging/rpm.py b/SCons/Tool/packaging/rpm.py index a0c3172..03633db 100644 --- a/SCons/Tool/packaging/rpm.py +++ b/SCons/Tool/packaging/rpm.py @@ -1,10 +1,6 @@ -"""SCons.Tool.Packaging.rpm - -The rpm packager. -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,12 +21,10 @@ The rpm packager. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - +"""The rpm packager.""" import SCons.Builder import SCons.Tool.rpmutils - from SCons.Environment import OverrideEnvironment from SCons.Tool.packaging import stripinstallbuilder, src_targz from SCons.Errors import UserError @@ -324,7 +318,7 @@ class SimpleTagCompiler: def compile(self, values): """ Compiles the tagset and returns a str containing the result """ - def is_international(tag): + def is_international(tag) -> bool: return tag.endswith('_') def get_country_code(tag): diff --git a/SCons/Tool/pdf.py b/SCons/Tool/pdf.py index ddaaa8a..74b2449 100644 --- a/SCons/Tool/pdf.py +++ b/SCons/Tool/pdf.py @@ -1,12 +1,6 @@ -"""SCons.Tool.pdf - -Common PDF Builder definition for various other Tool modules that use it. -Add an explicit action to run epstopdf to convert .eps files to .pdf - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,9 +20,12 @@ Add an explicit action to run epstopdf to convert .eps files to .pdf # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Common PDF Builder definition. + +This is for various other Tool modules that use it. +Add an explicit action to run epstopdf to convert .eps files to .pdf +""" import SCons.Builder import SCons.Tool @@ -55,7 +52,7 @@ def generate(env) -> None: env['PDFPREFIX'] = '' env['PDFSUFFIX'] = '.pdf' -# put the epstopdf builder in this routine so we can add it after +# put the epstopdf builder in this routine so we can add it after # the pdftex builder so that one is the default for no source suffix def generate2(env) -> None: bld = env['BUILDERS']['PDF'] @@ -66,10 +63,10 @@ def generate2(env) -> None: env['EPSTOPDFFLAGS'] = SCons.Util.CLVar('') env['EPSTOPDFCOM'] = '$EPSTOPDF $EPSTOPDFFLAGS ${SOURCE} --outfile=${TARGET}' -def exists(env) -> int: +def exists(env) -> bool: # This only puts a skeleton Builder in place, so if someone # references this Tool directly, it's always "available." - return 1 + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/rmic.py b/SCons/Tool/rmic.py index 8523397..a5d8063 100644 --- a/SCons/Tool/rmic.py +++ b/SCons/Tool/rmic.py @@ -1,15 +1,6 @@ -"""SCons.Tool.rmic - -Tool-specific initialization for rmic. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -29,9 +20,13 @@ selection method. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Tool-specific initialization for rmic. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. +""" import os.path @@ -123,14 +118,14 @@ def generate(env) -> None: env['RMICCOM'] = '$RMIC $RMICFLAGS -d ${TARGET.attributes.java_lookupdir} -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}' env['JAVACLASSSUFFIX'] = '.class' -def exists(env) -> int: +def exists(env) -> bool: # As reported by Jan Nijtmans in issue #2730, the simple # return env.Detect('rmic') # doesn't always work during initialization. For now, we # stop trying to detect an executable (analogous to the # javac Builder). # TODO: Come up with a proper detect() routine...and enable it. - return 1 + return True # Local Variables: # tab-width:4 diff --git a/SCons/Tool/textfile.py b/SCons/Tool/textfile.py index 9d98644..f79f808 100644 --- a/SCons/Tool/textfile.py +++ b/SCons/Tool/textfile.py @@ -21,31 +21,28 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -""" -Textfile/Substfile builder for SCons. - - Create file 'target' which typically is a textfile. The 'source' - may be any combination of strings, Nodes, or lists of same. A - 'linesep' will be put between any part written and defaults to - os.linesep. - - The only difference between the Textfile builder and the Substfile - builder is that strings are converted to Value() nodes for the - former and File() nodes for the latter. To insert files in the - former or strings in the latter, wrap them in a File() or Value(), - respectively. - - The values of SUBST_DICT first have any construction variables - expanded (its keys are not expanded). If a value of SUBST_DICT is - a python callable function, it is called and the result is expanded - as the value. Values are substituted in a "random" order; if any - substitution could be further expanded by another substitution, it - is unpredictable whether the expansion will occur. +"""Textfile/Substfile builder for SCons. + +Create file 'target' which typically is a textfile. The 'source' +may be any combination of strings, Nodes, or lists of same. A +'linesep' will be put between any part written and defaults to +os.linesep. + +The only difference between the Textfile builder and the Substfile +builder is that strings are converted to Value() nodes for the +former and File() nodes for the latter. To insert files in the +former or strings in the latter, wrap them in a File() or Value(), +respectively. + +The values of SUBST_DICT first have any construction variables +expanded (its keys are not expanded). If a value of SUBST_DICT is +a python callable function, it is called and the result is expanded +as the value. Values are substituted in a "random" order; if any +substitution could be further expanded by another substitution, it +is unpredictable whether the expansion will occur. """ import SCons - - from SCons.Node import Node from SCons.Node.Python import Value from SCons.Util import is_String, is_Sequence, is_Dict, to_bytes @@ -192,8 +189,8 @@ def generate(env) -> None: env['FILE_ENCODING'] = env.get('FILE_ENCODING', 'utf-8') -def exists(env) -> int: - return 1 +def exists(env) -> bool: + return True # Local Variables: # tab-width:4 diff --git a/SCons/UtilTests.py b/SCons/UtilTests.py index 860724e..54cb658 100644 --- a/SCons/UtilTests.py +++ b/SCons/UtilTests.py @@ -119,32 +119,32 @@ class UtilTestCase(unittest.TestCase): def __str__(self) -> str: return self.name - def exists(self) -> int: - return 1 + def exists(self) -> bool: + return True - def rexists(self) -> int: - return 1 + def rexists(self) -> bool: + return True - def has_builder(self) -> int: - return 1 + def has_builder(self) -> bool: + return True - def has_explicit_builder(self) -> int: - return 1 + def has_explicit_builder(self) -> bool: + return True - def side_effect(self) -> int: - return 1 + def side_effect(self) -> bool: + return True - def precious(self) -> int: - return 1 + def precious(self) -> bool: + return True - def always_build(self) -> int: - return 1 + def always_build(self) -> bool: + return True - def is_up_to_date(self) -> int: - return 1 + def is_up_to_date(self) -> bool: + return True - def noclean(self) -> int: - return 1 + def noclean(self) -> bool: + return True def tree_case_1(self): """Fixture for the render_tree() and print_tree() tests.""" diff --git a/SCons/cppTests.py b/SCons/cppTests.py index 5f00d50..85f01b7 100644 --- a/SCons/cppTests.py +++ b/SCons/cppTests.py @@ -26,7 +26,7 @@ import unittest import TestUnit -import cpp +import SCons.cpp as cpp basic_input = """ -- cgit v0.12 From f2f997b6907e2f5bcf1c8553a5532b54aa6bdc71 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 18 Jun 2023 15:53:33 -0700 Subject: [ci skip] Fixed typo in CHANGES.txt --- CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index fc51163..57089dc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -25,7 +25,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Added some typing annotations generated by a tool, to eliminate manual work in future on things which are safe for the tool to produce. Then manually fixed up some things related to bool that the tool did - not handly idealls. For example, simple functions which just did + not handly ideally. For example, simple functions which just did "return 1" were interpreted by the tool as returning int, when bool was really the intent. Functions/methods named like "is_*", "has_*", "exists" are now pretty consistently marked as "-> bool". -- cgit v0.12 From 34552173661b13419cec50628604ad37b19856f2 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 18 Jun 2023 16:06:35 -0700 Subject: [ci skip] Added info on byacc difference to CHANGES.txt --- CHANGES.txt | 9 +++++---- RELEASE.txt | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 6276443..9bd0fbe 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -80,10 +80,11 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER --defines and --graph being called without option-argument as being synonyms for -d (first two) and -g. -H also recognized as a synonym for -d. Default value for $YACC_GRAPH_FILE_SUFFIX changed to '.gv' - to match current bison default (since bison 3.8). The graph file name - (-g) is now generated relative to the requested target file name, - not to the source file name, to match actual current behavior (only - affects if target explicitly requested with a different base name + to match current bison default (since bison 3.8). Set this variable + to '.dot' if using byacc. The graph file name (-g) is now generated + relative to the requested target file name, not to the source file + name, to match actual current behavior (only affects if target + explicitly requested with a different base name than source). Docs updated. Fixes #4326 and #4327. diff --git a/RELEASE.txt b/RELEASE.txt index 45a5f4b..ee27081 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -44,7 +44,7 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY for -d (first two) and -g. -H also recognized as a synonym for -d. Default value for $YACC_GRAPH_FILE_SUFFIX changed to '.gv' to match current bison default (since bison 3.8). Set this variable to '.dot' - if using byacc. + if using byacc. Fixes #4326 and #4327. FIXES ----- -- cgit v0.12 From 2d14859378bc9f099f115e3e816eaebebf29dd77 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 6 Jun 2023 06:46:56 -0600 Subject: maintenance: update/cleanup dblite module Signed-off-by: Mats Wichmann --- CHANGES.txt | 1 + RELEASE.txt | 1 + SCons/SConsign.py | 26 ++------ SCons/dblite.py | 190 +++++++++++++++++++++++++++++++++++------------------- 4 files changed, 132 insertions(+), 86 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 30218d3..a4d12a2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -91,6 +91,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER name, to match actual current behavior (only affects if target explicitly requested with a different base name than source). Docs updated. Fixes #4326 and #4327. + - Cleanud up dblite module (checker warnings, etc.). RELEASE 4.5.2 - Sun, 21 Mar 2023 14:08:29 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index ff15b25..a9132c4 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -88,6 +88,7 @@ DEVELOPMENT now declares (actually raises NotImplementedError) two methods it doesn't use so it can be instantiated by unittests and others. - Added more type annotations to internal routines. +- Cleanud up dblite module (checker warnings, etc.). Thanks to the following contributors listed below for their contributions to this release. ========================================================================================== diff --git a/SCons/SConsign.py b/SCons/SConsign.py index 860d40b..5d57af5 100644 --- a/SCons/SConsign.py +++ b/SCons/SConsign.py @@ -23,7 +23,7 @@ """Operations on signature database files (.sconsign). """ -import SCons.compat +import SCons.compat # pylint: disable=wrong-import-order import os import pickle @@ -69,11 +69,10 @@ def current_sconsign_filename(): # eg .sconsign_sha1, etc. if hash_format is None and current_hash_algorithm == 'md5': return ".sconsign" - else: - return ".sconsign_" + current_hash_algorithm + return ".sconsign_" + current_hash_algorithm def Get_DataBase(dir): - global DataBase, DB_Module, DB_Name + global DB_Name if DB_Name is None: DB_Name = current_sconsign_filename() @@ -117,8 +116,6 @@ normcase = os.path.normcase def write() -> None: - global sig_files - if print_time(): start_time = time.perf_counter() @@ -284,7 +281,6 @@ class DB(Base): self.set_entry = self.do_not_set_entry self.store_info = self.do_not_store_info - global sig_files sig_files.append(self) def write(self, sync: int=1) -> None: @@ -316,9 +312,7 @@ class DB(Base): class Dir(Base): def __init__(self, fp=None, dir=None) -> None: - """ - fp - file pointer to read entries from - """ + """fp - file pointer to read entries from.""" super().__init__() if not fp: @@ -335,13 +329,9 @@ class Dir(Base): class DirFile(Dir): - """ - Encapsulates reading and writing a per-directory .sconsign file. - """ + """Encapsulates reading and writing a per-directory .sconsign file.""" def __init__(self, dir) -> None: - """ - dir - the directory for the file - """ + """dir - the directory for the file.""" self.dir = dir self.sconsign = os.path.join(dir.get_internal_path(), current_sconsign_filename()) @@ -364,12 +354,10 @@ class DirFile(Dir): except AttributeError: pass - global sig_files sig_files.append(self) def write(self, sync: int=1) -> None: - """ - Write the .sconsign file to disk. + """Write the .sconsign file to disk. Try to write to a temporary file first, and rename it if we succeed. If we can't write to the temporary file, it's diff --git a/SCons/dblite.py b/SCons/dblite.py index dd05f66..e50b7f9 100644 --- a/SCons/dblite.py +++ b/SCons/dblite.py @@ -24,8 +24,13 @@ """ dblite.py module contributed by Ralf W. Grosse-Kunstleve. Extended for Unicode by Steven Knight. + +This is a very simple-minded "database" used for saved signature +information, with an interface modeled on the Python dbm database +interface module. """ +import io import os import pickle import shutil @@ -45,41 +50,59 @@ def corruption_warning(filename) -> None: """ print("Warning: Discarding corrupt database:", filename) -DBLITE_SUFFIX = '.dblite' -TMP_SUFFIX = '.tmp' +DBLITE_SUFFIX = ".dblite" +TMP_SUFFIX = ".tmp" -class dblite: - """ - Squirrel away references to the functions in various modules - that we'll use when our __del__() method calls our sync() method - during shutdown. We might get destroyed when Python is in the midst - of tearing down the different modules we import in an essentially - arbitrary order, and some of the various modules's global attributes - may already be wiped out from under us. - See the discussion at: - http://mail.python.org/pipermail/python-bugs-list/2003-March/016877.html +class _Dblite: + """Lightweight signature database class. + + Behaves like a dict when in memory, loads from a pickled disk + file on open and writes back out to it on close. + + Open the database file using a path derived from *file_base_name*. + The optional *flag* argument can be: + +---------+---------------------------------------------------+ + | Value | Meaning | + +=========+===================================================+ + | ``'r'`` | Open existing database for reading only (default) | + +---------+---------------------------------------------------+ + | ``'w'`` | Open existing database for reading and writing | + +---------+---------------------------------------------------+ + | ``'c'`` | Open database for reading and writing, creating | + | | it if it doesn't exist | + +---------+---------------------------------------------------+ + | ``'n'`` | Always create a new, empty database, open for | + | | reading and writing | + +---------+---------------------------------------------------+ + + The optional *mode* argument is the POSIX mode of the file, used only + when the database has to be created. It defaults to octal ``0o666``. """ - _open = open + # Because open() is defined at module level, overwriting builtin open + # in the scope of this module, we use io.open to avoid ambiguity. + _open = staticmethod(io.open) + + # we need to squirrel away references to functions from various modules + # that we'll use when sync() is called: this may happen at Python + # teardown time (we call it from our __del__), and the global module + # references themselves may already have been rebound to None. _pickle_dump = staticmethod(pickle.dump) _pickle_protocol = PICKLE_PROTOCOL - try: - _os_chown = os.chown + _os_chown = staticmethod(os.chown) except AttributeError: _os_chown = None - _os_replace = os.replace - _os_chmod = os.chmod - _shutil_copyfile = shutil.copyfile - _time_time = time.time + _os_replace = staticmethod(os.replace) + _os_chmod = staticmethod(os.chmod) + _shutil_copyfile = staticmethod(shutil.copyfile) + _time_time = staticmethod(time.time) - def __init__(self, file_base_name, flag, mode) -> None: - assert flag in (None, "r", "w", "c", "n") - if flag is None: - flag = "r" + def __init__(self, file_base_name, flag='r', mode=0o666) -> None: + assert flag in ("r", "w", "c", "n") base, ext = os.path.splitext(file_base_name) if ext == DBLITE_SUFFIX: @@ -95,7 +118,7 @@ class dblite: self._dict = {} self._needs_sync = False - if self._os_chown is not None and (os.geteuid() == 0 or os.getuid() == 0): + if self._os_chown is not None and 0 in (os.geteuid(), os.getegid()): # running as root; chown back to current owner/group when done try: statinfo = os.stat(self._file_name) @@ -111,30 +134,47 @@ class dblite: self._chgrp_to = -1 # don't chgrp if self._flag == "n": - with self._open(self._file_name, "wb", self._mode): - pass # just make sure it exists + with io.open(self._file_name, "wb", opener=self.opener): + return # just make sure it exists else: + # We only need the disk file to slurp in the data. Updates are + # handled on close, db is mainained only in memory until then. try: - f = self._open(self._file_name, "rb") - except IOError as e: + with io.open(self._file_name, "rb") as f: + p = f.read() + except OSError as e: + # an error for file not to exist, unless flag is create if self._flag != "c": raise e - with self._open(self._file_name, "wb", self._mode): - pass # just make sure it exists - else: - p = f.read() - f.close() - if len(p) > 0: - try: - self._dict = pickle.loads(p, encoding='bytes') - except (pickle.UnpicklingError, EOFError, KeyError): - # Note how we catch KeyErrors too here, which might happen - # when we don't have cPickle available (default pickle - # throws it). - if IGNORE_CORRUPT_DBFILES: - corruption_warning(self._file_name) - else: - raise + with io.open(self._file_name, "wb", opener=self.opener): + return # just make sure it exists + if len(p) > 0: + try: + self._dict = pickle.loads(p, encoding='bytes') + except ( + pickle.UnpicklingError, + # Python3 docs: + # Note that other exceptions may also be raised during + # unpickling, including (but not necessarily limited to) + # AttributeError, EOFError, ImportError, and IndexError. + AttributeError, + EOFError, + ImportError, + IndexError, + ): + if IGNORE_CORRUPT_DBFILES: + corruption_warning(self._file_name) + else: + raise + + def opener(self, path, flags): + """Database open helper when creation may be needed. + + The high-level Python open() function cannot specify a file mode + for creation. Using this as the opener with the saved mode lets + us do that. + """ + return os.open(path, flags, mode=self._mode) def close(self) -> None: if self._needs_sync: @@ -144,8 +184,15 @@ class dblite: self.close() def sync(self) -> None: + """Flush the database to disk. + + This routine *must* succeed, since the in-memory and on-disk + copies are out of sync as soon as we do anything that changes + the in-memory version. Thus, to be cautious, flush to a + temporary file and then move it over with some error handling. + """ self._check_writable() - with self._open(self._tmp_name, "wb", self._mode) as f: + with self._open(self._tmp_name, "wb", opener=self.opener) as f: self._pickle_dump(self._dict, f, self._pickle_protocol) try: @@ -162,7 +209,9 @@ class dblite: pass self._os_replace(self._tmp_name, self._file_name) - if self._os_chown is not None and self._chown_to > 0: # don't chown to root or -1 + if ( + self._os_chown is not None and self._chown_to > 0 + ): # don't chown to root or -1 try: self._os_chown(self._file_name, self._chown_to, self._chgrp_to) except OSError: @@ -171,13 +220,12 @@ class dblite: self._needs_sync = False if KEEP_ALL_FILES: self._shutil_copyfile( - self._file_name, - self._file_name + "_" + str(int(self._time_time())) + self._file_name, f"{self._file_name}_{int(self._time_time())}" ) def _check_writable(self): if self._flag == "r": - raise IOError("Read-only database: %s" % self._file_name) + raise OSError(f"Read-only database: {self._file_name}") def __getitem__(self, key): return self._dict[key] @@ -186,29 +234,37 @@ class dblite: self._check_writable() if not isinstance(key, str): - raise TypeError("key `%s' must be a string but is %s" % (key, type(key))) + raise TypeError(f"key `{key}' must be a string but is {type(key)}") if not isinstance(value, bytes): - raise TypeError("value `%s' must be a bytes but is %s" % (value, type(value))) + raise TypeError(f"value `{value}' must be bytes but is {type(value)}") self._dict[key] = value self._needs_sync = True + def __delitem__(self, key): + del self._dict[key] + def keys(self): - return list(self._dict.keys()) + return self._dict.keys() + + def items(self): + return self._dict.items() + + def values(self): + return self._dict.values() + + __iter__ = keys def __contains__(self, key) -> bool: return key in self._dict - def __iter__(self): - return iter(self._dict) - def __len__(self) -> int: return len(self._dict) -def open(file, flag=None, mode: int=0o666): - return dblite(file, flag, mode) +def open(file, flag="r", mode: int = 0o666): # pylint: disable=redefined-builtin + return _Dblite(file, flag, mode) def _exercise(): @@ -225,13 +281,13 @@ def _exercise(): assert db["bar"] == b"foo" db.sync() - db = open("tmp", "r") + db = open("tmp") assert len(db) == 2, len(db) assert db["foo"] == b"bar" assert db["bar"] == b"foo" try: db.sync() - except IOError as e: + except OSError as e: assert str(e) == "Read-only database: tmp.dblite" else: raise RuntimeError("IOError expected.") @@ -250,21 +306,21 @@ def _exercise(): try: db["list"] = [1, 2] except TypeError as e: - assert str(e) == "value `[1, 2]' must be a bytes but is ", str(e) + assert str(e) == "value `[1, 2]' must be bytes but is ", str(e) else: raise RuntimeError("TypeError exception expected") - db = open("tmp", "r") + db = open("tmp") assert len(db) == 3, len(db) db = open("tmp", "n") assert len(db) == 0, len(db) - dblite._open("tmp.dblite", "w") + _Dblite._open("tmp.dblite", "w") - db = open("tmp", "r") - dblite._open("tmp.dblite", "w").write("x") + db = open("tmp") + _Dblite._open("tmp.dblite", "w").write("x") try: - db = open("tmp", "r") + db = open("tmp") except pickle.UnpicklingError: pass else: @@ -272,12 +328,12 @@ def _exercise(): global IGNORE_CORRUPT_DBFILES IGNORE_CORRUPT_DBFILES = True - db = open("tmp", "r") + db = open("tmp") assert len(db) == 0, len(db) os.unlink("tmp.dblite") try: db = open("tmp", "w") - except IOError as e: + except OSError as e: assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e) else: raise RuntimeError("IOError expected.") -- cgit v0.12 From 9e116a99b7cd8fc4284400a38de9bc23ee63905a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 19 Jun 2023 17:12:22 -0700 Subject: [ci skip] fixed typo in CHANGES.txt/RELEASE.txt --- CHANGES.txt | 2 +- RELEASE.txt | 4 ++-- SCons/SConsign.py | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index a4d12a2..702b4ff 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -91,7 +91,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER name, to match actual current behavior (only affects if target explicitly requested with a different base name than source). Docs updated. Fixes #4326 and #4327. - - Cleanud up dblite module (checker warnings, etc.). + - Cleaned up dblite module (checker warnings, etc.). RELEASE 4.5.2 - Sun, 21 Mar 2023 14:08:29 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index a9132c4..331872e 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -88,10 +88,10 @@ DEVELOPMENT now declares (actually raises NotImplementedError) two methods it doesn't use so it can be instantiated by unittests and others. - Added more type annotations to internal routines. -- Cleanud up dblite module (checker warnings, etc.). +- Cleaned up dblite module (checker warnings, etc.). Thanks to the following contributors listed below for their contributions to this release. ========================================================================================== .. code-block:: text - git shortlog --no-merges -ns 4.0.1..HEAD + git shortlog --no-merges -ns 4.5.2..HEAD diff --git a/SCons/SConsign.py b/SCons/SConsign.py index 5d57af5..3d56304 100644 --- a/SCons/SConsign.py +++ b/SCons/SConsign.py @@ -112,6 +112,7 @@ def Reset() -> None: sig_files = [] DB_sync_list = [] + normcase = os.path.normcase -- cgit v0.12