From 1bdca141aaffd784827f62657c95e61f39fe1eb3 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 30 Jul 2023 07:48:57 -0600 Subject: Add ability to save "local" help only An additional keyword argument, "local_only", is now recorgnized by Help(). If true, and "append" is True, then only project-defined help messages are saved into the help text. That is, save help added by calls to AddOption, but not SCons' own help, which is added a different way. Fixes #2356 Fixes #3686 Signed-off-by: Mats Wichmann --- CHANGES.txt | 4 ++ RELEASE.txt | 4 ++ SCons/Script/Main.py | 9 +++-- SCons/Script/SConsOptions.py | 61 ++++++++++++++++++++++++++--- SCons/Script/SConscript.py | 21 ++++++++-- SCons/Script/SConscript.xml | 39 ++++++++++++------- SCons/Script/__init__.py | 31 ++++++++------- doc/user/output.xml | 56 +++++++++++---------------- test/Help.py | 91 ++++++++++++++++++++++++++++++-------------- 9 files changed, 217 insertions(+), 99 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index db96df0..d2c074d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -131,6 +131,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - More tweaking of test framework overview (which is duplicated onto the website, but not in the regular documentation section). - Extend range of recognized Java versions to 20. + - The Help() function now takes an additional keyword argument + keep_local, which if combined with the append argument direct + help from only AddOption ("project local") calls to be kept in the + help message, not SCons' own option help. From Jonathon Reinhart: - Fix another instance of `int main()` in CheckLib() causing failures diff --git a/RELEASE.txt b/RELEASE.txt index f72a2a6..22be0f5 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -60,6 +60,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY architecture combination. For example, when using VS2022 on arm64, the arm64 native tools are only installed for the 14.3x toolsets. - Extend range of recognized Java versions to 20. +- The Help() function now takes an additional keyword argument keep_local. + On first call to Help(), if both append and keep_local are True, + the help from project AddOption calls is kept in the help message, + but not SCons' own option help. FIXES ----- diff --git a/SCons/Script/Main.py b/SCons/Script/Main.py index 361b4b2..5ccb197 100644 --- a/SCons/Script/Main.py +++ b/SCons/Script/Main.py @@ -564,10 +564,11 @@ def ValidateOptions(throw_exception: bool=False) -> None: OptionsParser.preserve_unknown_options = False OptionsParser.parse_args(OptionsParser.largs, OptionsParser.values) -def PrintHelp(file=None) -> None: - OptionsParser.print_help(file=file) - - +def PrintHelp(file=None, local_only: bool = False) -> None: + if local_only: + OptionsParser.print_local_option_help(file=file) + else: + OptionsParser.print_help(file=file) # utility functions diff --git a/SCons/Script/SConsOptions.py b/SCons/Script/SConsOptions.py index d2893ba..e799716 100644 --- a/SCons/Script/SConsOptions.py +++ b/SCons/Script/SConsOptions.py @@ -271,8 +271,7 @@ class SConsOption(optparse.Option): class SConsOptionGroup(optparse.OptionGroup): - """ - A subclass for SCons-specific option groups. + """A subclass for SCons-specific option groups. The only difference between this and the base class is that we print the group's help text flush left, underneath their own title but @@ -288,7 +287,8 @@ class SConsOptionGroup(optparse.OptionGroup): formatter.dedent() result = formatter.format_heading(self.title) formatter.indent() - result = result + optparse.OptionContainer.format_help(self, formatter) + # bypass OptionGroup format_help and call up to its parent + result += optparse.OptionContainer.format_help(self, formatter) return result @@ -474,7 +474,6 @@ class SConsOptionParser(optparse.OptionParser): self.local_option_group = group result = group.add_option(*args, **kw) - if result: # The option was added successfully. We now have to add the # default value to our object that holds the default values @@ -489,6 +488,40 @@ class SConsOptionParser(optparse.OptionParser): return result + def format_local_option_help(self, formatter=None, file=None): + """Return the help for the project-level ("local") options. + + .. versionadded:: 4.6.0 + """ + if formatter is None: + formatter = self.formatter + try: + group = self.local_option_group + except AttributeError: + return "" + + formatter.store_local_option_strings(self, group) + for opt in group.option_list: + strings = formatter.format_option_strings(opt) + formatter.option_strings[opt] = strings + + # defeat our own cleverness, which starts out by dedenting + formatter.indent() + local_help = group.format_help(formatter) + formatter.dedent() + return local_help + + def print_local_option_help(self, file=None): + """Print help for just project-defined options. + + Writes to *file* (default stdout). + + .. versionadded:: 4.6.0 + """ + if file is None: + file = sys.stdout + file.write(self.format_local_option_help()) + class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): def format_usage(self, usage) -> str: @@ -504,7 +537,7 @@ class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): """ if heading == 'Options': heading = "SCons Options" - return optparse.IndentedHelpFormatter.format_heading(self, heading) + return super().format_heading(heading) def format_option(self, option): """ Customized option formatter. @@ -577,6 +610,24 @@ class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): result.append("\n") return "".join(result) + def store_local_option_strings(self, parser, group): + """Local-only version of store_option_strings. + + We need to replicate this so the formatter will be set up + properly if we didn't go through the "normal" store_option_strings + + .. versionadded:: 4.6.0 + """ + self.indent() + max_len = 0 + for opt in group.option_list: + strings = self.format_option_strings(opt) + self.option_strings[opt] = strings + max_len = max(max_len, len(strings) + self.current_indent) + self.dedent() + self.help_position = min(max_len + 2, self.max_help_position) + self.help_width = max(self.width - self.help_position, 11) + def Parser(version): """Returns a parser object initialized with the standard SCons options. diff --git a/SCons/Script/SConscript.py b/SCons/Script/SConscript.py index c0b556c..66ce5b6 100644 --- a/SCons/Script/SConscript.py +++ b/SCons/Script/SConscript.py @@ -145,7 +145,7 @@ def Return(*vars, **kw): stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) -def handle_missing_SConscript(f, must_exist=None): +def handle_missing_SConscript(f: str, must_exist=None) -> None: """Take appropriate action on missing file in SConscript() call. Print a warning or raise an exception on missing file, unless @@ -528,10 +528,25 @@ class SConsEnvironment(SCons.Environment.Base): name = self.subst(name) return SCons.Script.Main.GetOption(name) + def Help(self, text, append: bool = False, keep_local: bool = False) -> None: + """Update the help text. - def Help(self, text, append: bool=False) -> None: + The previous help text has *text* appended to it, except on the + first call. On first call, the values of *append* and *keep_local* + are considered to determine what is appended to. + + Arguments: + text: string to add to the help text. + append: on first call, if true, keep the existing help text + (default False). + keep_local: on first call, if true and *append* is also true, + keep only the help text from AddOption calls. + + .. versionchanged:: 4.6.0 + The *keep_local* parameter was added. + """ text = self.subst(text, raw=1) - SCons.Script.HelpFunction(text, append=append) + SCons.Script.HelpFunction(text, append=append, keep_local=keep_local) def Import(self, *vars): try: diff --git a/SCons/Script/SConscript.xml b/SCons/Script/SConscript.xml index 7a4bc29..b984f7d 100644 --- a/SCons/Script/SConscript.xml +++ b/SCons/Script/SConscript.xml @@ -238,29 +238,42 @@ file is found. -(text, append=False) +(text, append=False, local_only=False) -Specifies a local help message to be printed if the - -argument is given to -&scons;. -Subsequent calls to -&f-Help; -append text to the previously -defined local help text. +Adds text to the help message shown when +&scons; is called with the + or +argument. -For the first call to &f-Help; only, +On the first call to &f-Help;, if append is False -(the default) -any local help message generated through -&f-link-AddOption; calls is replaced. +(the default), any existing help text is discarded. +The default help text is the help for the &scons; +command itself plus help collected from any +project-local &f-link-AddOption; calls. +This is the help printed if &f-Help; has never been called. If append is True, text is appended to the existing help text. +If local_only is also True +(the default is False), +the project-local help from &f-AddOption; calls is preserved +in the help message but the &scons; command help is not. + + +Subsequent calls to +&f-Help; ignore the keyword arguments +append and +local_only +and always append to the existing help text. + +Changed in 4.6.0: added local_only. + + diff --git a/SCons/Script/__init__.py b/SCons/Script/__init__.py index e398ecf..6811e57 100644 --- a/SCons/Script/__init__.py +++ b/SCons/Script/__init__.py @@ -100,7 +100,6 @@ main = Main.main BuildTask = Main.BuildTask CleanTask = Main.CleanTask QuestionTask = Main.QuestionTask -#PrintHelp = Main.PrintHelp #SConscriptSettableOptions = Main.SConscriptSettableOptions AddOption = Main.AddOption @@ -248,31 +247,37 @@ def _Set_Default_Targets(env, tlist) -> None: BUILD_TARGETS._add_Default(nodes) _build_plus_default._add_Default(nodes) -# + help_text = None -def HelpFunction(text, append: bool=False) -> None: + +def HelpFunction(text, append: bool = False, keep_local: bool = False) -> None: + """The implementaion of the the ``Help`` method. + + See :meth:`~SCons.Script.SConscript.Help`. + + .. versionchanged:: 4.6.0 + The *keep_local* parameter was added. + """ global help_text if help_text is None: if append: - s = StringIO() - PrintHelp(s) - help_text = s.getvalue() - s.close() + with StringIO() as s: + PrintHelp(s, local_only=keep_local) + help_text = s.getvalue() else: help_text = "" - help_text= help_text + text + help_text += text -# # Will be non-zero if we are reading an SConscript file. -sconscript_reading = 0 +sconscript_reading: int = 0 -_no_missing_sconscript = False -_warn_missing_sconscript_deprecated = True +_no_missing_sconscript: bool = False +_warn_missing_sconscript_deprecated: bool = True -def set_missing_sconscript_error(flag: int=1): +def set_missing_sconscript_error(flag: bool = True) -> bool: """Set behavior on missing file in SConscript() call. Returns: diff --git a/doc/user/output.xml b/doc/user/output.xml index cf6571c..3831088 100644 --- a/doc/user/output.xml +++ b/doc/user/output.xml @@ -1,4 +1,10 @@ + + %scons; @@ -19,31 +25,6 @@ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd"> Controlling Build Output - - A key aspect of creating a usable build configuration @@ -67,7 +48,7 @@ users some help that describes the specific targets, build options, etc., that can be used for your build. - &SCons; provides the &Help; function + &SCons; provides the &f-link-Help; function to allow you to specify this help text: @@ -83,7 +64,7 @@ Type: 'scons program' to build the production program, - Optionally, one can specify the append flag: + Optionally, you can specify the append flag: @@ -107,7 +88,7 @@ Type: 'scons program' to build the production program, When the &SConstruct; or &SConscript; files - contain such a call to the &Help; function, + contain a call to the &Help; function, the specified help text will be displayed in response to the &SCons; option: @@ -120,11 +101,12 @@ Type: 'scons program' to build the production program, The &SConscript; files may contain - multiple calls to the &Help; function, + multiple calls to the &f-link-Help; function, in which case the specified text(s) will be concatenated when displayed. - This allows you to split up the - help text across multiple &SConscript; files. + This allows you to define bits of help text together with + the corresponding feature, even if speread + across multiple &SConscript; files. In this situation, the order in which the &SConscript; files are called will determine the order in which the &Help; functions are called, @@ -135,8 +117,16 @@ Type: 'scons program' to build the production program, - When used with &AddOption; Help("text", append=False) will clobber any help output associated with AddOption(). - To preserve the help output from AddOption(), set append=True. + Calling Help("text") will clobber + any help output associated with &f-link-AddOption; calls. + To preserve the help output from &AddOption;, + add the append=True keyword argument. + This also preserves the help for the &scons; command itself. + To preserve only the &AddOption; help, + also add the local_only=True keyword argument. + (This only matters the first time you call &Append;, + on any subsequent calls the text you passed is added + to the existing help text). diff --git a/test/Help.py b/test/Help.py index 95f57ad..a090d42 100644 --- a/test/Help.py +++ b/test/Help.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -20,9 +22,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 TestSCons @@ -85,47 +84,46 @@ test.run(arguments = '-h', stdout = expect) # Bug #2831 - append flag to Help doesn't wipe out addoptions and variables used together test.write('SConstruct', r""" -AddOption('--debugging', - dest='debugging', - action='store_true', - default=False, - metavar='BDEBUGGING', - help='Compile with debugging symbols') +AddOption( + '--debugging', + dest='debugging', + action='store_true', + default=False, + metavar='BDEBUGGING', + help='Compile with debugging symbols', +) vars = Variables() -vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', - ['python'])) - +vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', ['python'])) +DefaultEnvironment(tools=[]) env = Environment() - -Help(vars.GenerateHelpText(env),append=True) +Help(vars.GenerateHelpText(env), append=True) """) expect = ".*--debugging.*Compile with debugging symbols.*buildmod: List of modules to build.*" - test.run(arguments = '-h', stdout = expect, match=TestSCons.match_re_dotall) - # Bug 2831 # This test checks to verify that append=False doesn't include anything # but the expected help for the specified Variable() test.write('SConstruct', r""" - -AddOption('--debugging', - dest='debugging', - action='store_true', - default=False, - metavar='BDEBUGGING', - help='Compile with debugging symbols') +AddOption( + '--debugging', + dest='debugging', + action='store_true', + default=False, + metavar='BDEBUGGING', + help='Compile with debugging symbols', +) vars = Variables() -vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', - ['python'])) +vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', ['python'])) +DefaultEnvironment(tools=[]) env = Environment() -Help(vars.GenerateHelpText(env),append=False) +Help(vars.GenerateHelpText(env), append=False) """) expect = """\ @@ -141,8 +139,45 @@ buildmod: List of modules to build Use scons -H for help about SCons built-in command-line options. """ -test.run(arguments = '-h', stdout = expect) +test.run(arguments='-h', stdout=expect) + +# Enhancement: keep_local flag saves the AddOption help, +# but not SCons' own help. +test.write('SConstruct', r""" +AddOption( + '--debugging', + dest='debugging', + action='store_true', + default=False, + metavar='BDEBUGGING', + help='Compile with debugging symbols', +) + +vars = Variables() +vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', ['python'])) + +DefaultEnvironment(tools=[]) +env = Environment() + +Help(vars.GenerateHelpText(env), append=True, keep_local=True) +""") + +expect = """\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +Local Options: + --debugging Compile with debugging symbols + +buildmod: List of modules to build + (all|none|comma-separated list of names) + allowed names: python + default: none + actual: None + +Use scons -H for help about SCons built-in command-line options. +""" +test.run(arguments='-h', stdout=expect) test.pass_test() -- cgit v0.12 From 70b64467bf91b6a1ea1224f43de4d4f416d94799 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 1 Aug 2023 15:24:16 -0600 Subject: Further tweak user guide Help description [skip appveyor] Signed-off-by: Mats Wichmann --- doc/user/output.xml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/user/output.xml b/doc/user/output.xml index 3831088..7a63540 100644 --- a/doc/user/output.xml +++ b/doc/user/output.xml @@ -104,8 +104,8 @@ Type: 'scons program' to build the production program, multiple calls to the &f-link-Help; function, in which case the specified text(s) will be concatenated when displayed. - This allows you to define bits of help text together with - the corresponding feature, even if speread + This allows you to define fragments of help text together with + the corresponding feature, even if spread across multiple &SConscript; files. In this situation, the order in which the &SConscript; files are called @@ -117,11 +117,13 @@ Type: 'scons program' to build the production program, - Calling Help("text") will clobber - any help output associated with &f-link-AddOption; calls. - To preserve the help output from &AddOption;, - add the append=True keyword argument. - This also preserves the help for the &scons; command itself. + Calling Help("text") overwrites + the help text that otherwise would be collected from any + command-line options defined in &f-link-AddOption; calls. + To preserve the &AddOption; help text, + add the append=True keyword argument + when calling Help. + This also preserves the option help for the &scons; command itself. To preserve only the &AddOption; help, also add the local_only=True keyword argument. (This only matters the first time you call &Append;, -- cgit v0.12 From f3d1936c34333b8b535269a007a5598e93029bc0 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 4 Aug 2023 08:37:28 -0600 Subject: "Modernize" to Python 3.6 via tool $ pyupgrade --py36-plus $( --- CHANGES.txt | 2 ++ SCons/Action.py | 4 +-- SCons/CacheDir.py | 4 +-- SCons/Environment.py | 4 +-- SCons/Executor.py | 4 +-- SCons/Memoize.py | 2 +- SCons/Node/FS.py | 16 ++++++------ SCons/Node/__init__.py | 4 +-- SCons/Platform/darwin.py | 2 +- SCons/Platform/win32.py | 10 ++++---- SCons/SConsign.py | 12 ++++----- SCons/Scanner/C.py | 4 +-- SCons/Scanner/Dir.py | 2 +- SCons/Script/Interactive.py | 2 +- SCons/Script/Main.py | 6 ++--- SCons/Taskmaster/__init__.py | 4 +-- SCons/Tool/JavaCommon.py | 2 +- SCons/Tool/MSCommon/MSVC/Config.py | 4 +-- SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 24 +++++++++--------- SCons/Tool/MSCommon/MSVC/Util.py | 6 ++--- SCons/Tool/MSCommon/MSVC/WinSDK.py | 2 +- SCons/Tool/MSCommon/common.py | 6 ++--- SCons/Tool/MSCommon/sdk.py | 2 +- SCons/Tool/MSCommon/vc.py | 26 ++++++++++---------- SCons/Tool/PharLapCommon.py | 2 +- SCons/Tool/cyglink.py | 4 +-- SCons/Tool/dmd.py | 2 +- SCons/Tool/docbook/__init__.py | 6 ++--- SCons/Tool/gdc.py | 2 +- SCons/Tool/hpcxx.py | 2 +- SCons/Tool/hplink.py | 2 +- SCons/Tool/install.py | 4 +-- SCons/Tool/intelc.py | 2 +- SCons/Tool/ldc.py | 2 +- SCons/Tool/linkCommon/__init__.py | 2 +- SCons/Tool/linkloc.py | 4 +-- SCons/Tool/msvs.py | 30 +++++++++++------------ SCons/Tool/ninja/Methods.py | 2 +- SCons/Tool/ninja/NinjaState.py | 2 +- SCons/Tool/ninja/Utils.py | 6 ++--- SCons/Tool/ninja/__init__.py | 5 ++-- SCons/Tool/ninja/ninja_scons_daemon.py | 2 +- SCons/Tool/rpmutils.py | 4 +-- SCons/Tool/suncxx.py | 8 +++--- SCons/Tool/sunlink.py | 2 +- SCons/Tool/swig.py | 2 +- SCons/Tool/tex.py | 10 ++++---- SCons/Tool/textfile.py | 2 +- SCons/Util/types.py | 2 +- SCons/Utilities/ConfigureCache.py | 2 +- SCons/Utilities/sconsign.py | 10 ++++---- SCons/Variables/__init__.py | 4 +-- SCons/compat/__init__.py | 2 +- SCons/compat/win32.py | 4 +-- doc/sphinx/conf.py | 1 - site_scons/SConsRevision.py | 2 +- site_scons/soe_utils.py | 4 +-- test/D/SharedObjects/Common/common.py | 4 +-- test/D/di/Image/SConstruct_template | 2 -- test/Docbook/basedir/slideshtml/image/xsltver.py | 2 +- test/Docbook/basic/slideshtml/image/xsltver.py | 2 +- test/Docbook/rootname/slideshtml/image/xsltver.py | 2 +- test/Fortran/F90FLAGS.py | 8 +++--- test/MSVS/CPPPATH-Dirs.py | 8 +++--- test/MSVS/common-prefix.py | 8 +++--- test/MSVS/runfile.py | 8 +++--- test/Parallel/failed-build/fixture/teststate.py | 2 +- test/Removed/SourceSignatures/Old/no-csigs.py | 8 +++--- test/Scanner/unicode.py | 15 ++++++------ test/Subst/fixture/SConstruct.callable_exception | 2 +- test/VariantDir/no-execute.py | 8 +++--- test/fixture/mycompile.py | 2 +- test/gettext/MOFiles/UserExamples.py | 8 +++--- test/packaging/option--package-type.py | 1 - test/packaging/rpm/internationalization.py | 3 --- test/scons-time/run/option/outdir.py | 8 +++--- test/special-filenames.py | 11 ++++----- testing/framework/TestCmd.py | 6 ++--- testing/framework/TestSCons.py | 2 +- testing/framework/TestUnit/__init__.py | 1 - 80 files changed, 195 insertions(+), 220 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index db96df0..7d4e1da 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -131,6 +131,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - More tweaking of test framework overview (which is duplicated onto the website, but not in the regular documentation section). - Extend range of recognized Java versions to 20. + - A little more code "modernization", done via "pypgrade" tool set + to "3.6 and above" setting. From Jonathon Reinhart: - Fix another instance of `int main()` in CheckLib() causing failures diff --git a/SCons/Action.py b/SCons/Action.py index 8748985..ec0a2b6 100644 --- a/SCons/Action.py +++ b/SCons/Action.py @@ -249,7 +249,7 @@ def _code_contents(code, docstring=None) -> bytearray: # The code contents depends on the number of local variables # but not their actual names. - contents = bytearray("{}, {}".format(code.co_argcount, len(code.co_varnames)), 'utf-8') + contents = bytearray(f"{code.co_argcount}, {len(code.co_varnames)}", 'utf-8') contents.extend(b", ") contents.extend(bytearray(str(len(code.co_cellvars)), 'utf-8')) @@ -847,7 +847,7 @@ def _subproc(scons_env, cmd, error: str='ignore', **kw): try: pobj = subprocess.Popen(cmd, **kw) - except EnvironmentError as e: + except OSError as e: if error == 'raise': raise # return a dummy Popen instance that only returns error class dummyPopen: diff --git a/SCons/CacheDir.py b/SCons/CacheDir.py index a063849..7ac2049 100644 --- a/SCons/CacheDir.py +++ b/SCons/CacheDir.py @@ -118,7 +118,7 @@ def CachePushFunc(target, source, env): cd.copy_to_cache(env, t.get_internal_path(), tempfile) fs.rename(tempfile, cachefile) - except EnvironmentError: + except OSError: # It's possible someone else tried writing the file at the # same time we did, or else that there was some problem like # the CacheDir being on a separate file system that's full. @@ -233,7 +233,7 @@ class CacheDir: os.chmod(dst, st | stat.S_IWRITE) return result except AttributeError as ex: - raise EnvironmentError from ex + raise OSError from ex @property def hit_ratio(self) -> float: diff --git a/SCons/Environment.py b/SCons/Environment.py index 4e5601e..04f9496 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1773,9 +1773,9 @@ class Base(SubstitutionEnvironment): """ filename = self.subst(filename) try: - with open(filename, 'r') as fp: + with open(filename) as fp: lines = LogicalLines(fp).readlines() - except IOError: + except OSError: if must_exist: raise return diff --git a/SCons/Executor.py b/SCons/Executor.py index 153b010..02be2c9 100644 --- a/SCons/Executor.py +++ b/SCons/Executor.py @@ -145,7 +145,7 @@ _execute_str_map = {0 : execute_null_str, 1 : execute_actions_str} -class Executor(object, metaclass=NoSlotsPyPy): +class Executor(metaclass=NoSlotsPyPy): """A class for controlling instances of executing an action. This largely exists to hold a single association of an action, @@ -576,7 +576,7 @@ def get_NullEnvironment(): nullenv = NullEnvironment() return nullenv -class Null(object, metaclass=NoSlotsPyPy): +class Null(metaclass=NoSlotsPyPy): """A null Executor, with a null build Environment, that does nothing when the rest of the methods call it. diff --git a/SCons/Memoize.py b/SCons/Memoize.py index c594348..42e52c4 100644 --- a/SCons/Memoize.py +++ b/SCons/Memoize.py @@ -121,7 +121,7 @@ class Counter: def key(self): return self.cls_name+'.'+self.method_name def display(self) -> None: - print(" {:7d} hits {:7d} misses {}()".format(self.hit, self.miss, self.key())) + print(f" {self.hit:7d} hits {self.miss:7d} misses {self.key()}()") def __eq__(self, other): try: return self.key() == other.key() diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index e6255c4..151a925 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -308,7 +308,7 @@ def LinkFunc(target, source, env) -> int: try: func(fs, src, dest) break - except (IOError, OSError): + except OSError: # An OSError indicates something happened like a permissions # problem or an attempt to symlink across file-system # boundaries. An IOError indicates something like the file @@ -2778,7 +2778,7 @@ class File(Base): fname = self.rfile().get_abspath() try: cs = hash_file_signature(fname, chunksize=File.hash_chunksize) - except EnvironmentError as e: + except OSError as e: if not e.filename: e.filename = fname raise @@ -2935,7 +2935,7 @@ class File(Base): try: sconsign_entry = self.dir.sconsign().get_entry(self.name) - except (KeyError, EnvironmentError): + except (KeyError, OSError): import SCons.SConsign sconsign_entry = SCons.SConsign.SConsignEntry() sconsign_entry.binfo = self.new_binfo() @@ -3146,7 +3146,7 @@ class File(Base): def _rmv_existing(self): self.clear_memoized_values() if SCons.Node.print_duplicate: - print("dup: removing existing target {}".format(self)) + print(f"dup: removing existing target {self}") e = Unlink(self, [], None) if isinstance(e, SCons.Errors.BuildError): raise e @@ -3174,7 +3174,7 @@ class File(Base): try: self._createDir() except SCons.Errors.StopError as drive: - raise SCons.Errors.StopError("No drive `{}' for target `{}'.".format(drive, self)) + raise SCons.Errors.StopError(f"No drive `{drive}' for target `{self}'.") # # @@ -3190,11 +3190,11 @@ class File(Base): def do_duplicate(self, src): self._createDir() if SCons.Node.print_duplicate: - print("dup: relinking variant '{}' from '{}'".format(self, src)) + print(f"dup: relinking variant '{self}' from '{src}'") Unlink(self, None, None) e = Link(self, src, None) if isinstance(e, SCons.Errors.BuildError): - raise SCons.Errors.StopError("Cannot duplicate `{}' in `{}': {}.".format(src.get_internal_path(), self.dir._path, e.errstr)) + raise SCons.Errors.StopError(f"Cannot duplicate `{src.get_internal_path()}' in `{self.dir._path}': {e.errstr}.") self.linked = 1 # The Link() action may or may not have actually # created the file, depending on whether the -n @@ -3260,7 +3260,7 @@ class File(Base): contents = self.get_contents() else: csig = self.get_content_hash() - except IOError: + except OSError: # This can happen if there's actually a directory on-disk, # which can be the case if they've disabled disk checks, # or if an action with a File target actually happens to diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index 9a8398f..3da4faf 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -212,7 +212,7 @@ def get_contents_file(node): try: with open(fname, "rb") as fp: contents = fp.read() - except EnvironmentError as e: + except OSError as e: if not e.filename: e.filename = fname raise @@ -501,7 +501,7 @@ class BuildInfoBase: setattr(self, key, value) -class Node(object, metaclass=NoSlotsPyPy): +class Node(metaclass=NoSlotsPyPy): """The base Node class, for entities that we know how to build, or use to build other Nodes. """ diff --git a/SCons/Platform/darwin.py b/SCons/Platform/darwin.py index f17968b..381b542 100644 --- a/SCons/Platform/darwin.py +++ b/SCons/Platform/darwin.py @@ -54,7 +54,7 @@ def generate(env) -> None: for file in filelist: if os.path.isfile(file): - with open(file, 'r') as f: + with open(file) as f: lines = f.readlines() for line in lines: if line: diff --git a/SCons/Platform/win32.py b/SCons/Platform/win32.py index 275a5d4..160cb98 100644 --- a/SCons/Platform/win32.py +++ b/SCons/Platform/win32.py @@ -166,18 +166,18 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): # and do clean up stuff if stdout is not None and not stdoutRedirected: try: - with open(tmpFileStdoutName, "r") as tmpFileStdout: + with open(tmpFileStdoutName) as tmpFileStdout: stdout.write(tmpFileStdout.read()) os.remove(tmpFileStdoutName) - except (IOError, OSError): + except OSError: pass if stderr is not None and not stderrRedirected: try: - with open(tmpFileStderrName, "r") as tmpFileStderr: + with open(tmpFileStderrName) as tmpFileStderr: stderr.write(tmpFileStderr.read()) os.remove(tmpFileStderrName) - except (IOError, OSError): + except OSError: pass return ret @@ -186,7 +186,7 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): def exec_spawn(l, env): try: result = spawnve(os.P_WAIT, l[0], l, env) - except (OSError, EnvironmentError) as e: + except OSError as e: try: result = exitvalmap[e.errno] sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror)) diff --git a/SCons/SConsign.py b/SCons/SConsign.py index 3d56304..1215c6a 100644 --- a/SCons/SConsign.py +++ b/SCons/SConsign.py @@ -87,7 +87,7 @@ def Get_DataBase(dir): except KeyError: path = d.entry_abspath(DB_Name) try: db = DataBase[d] = DB_Module.open(path, mode) - except (IOError, OSError): + except OSError: pass else: if mode != "r": @@ -339,7 +339,7 @@ class DirFile(Dir): try: fp = open(self.sconsign, 'rb') - except IOError: + except OSError: fp = None try: @@ -378,11 +378,11 @@ class DirFile(Dir): try: file = open(temp, 'wb') fname = temp - except IOError: + except OSError: try: file = open(self.sconsign, 'wb') fname = self.sconsign - except IOError: + except OSError: return for key, entry in self.entries.items(): entry.convert_to_sconsign() @@ -393,7 +393,7 @@ class DirFile(Dir): mode = os.stat(self.sconsign)[0] os.chmod(self.sconsign, 0o666) os.unlink(self.sconsign) - except (IOError, OSError): + except OSError: # Try to carry on in the face of either OSError # (things like permission issues) or IOError (disk # or network issues). If there's a really dangerous @@ -414,7 +414,7 @@ class DirFile(Dir): os.chmod(self.sconsign, mode) try: os.unlink(temp) - except (IOError, OSError): + except OSError: pass ForDirectory = DB diff --git a/SCons/Scanner/C.py b/SCons/Scanner/C.py index 5fa1bbb..2f1cb41 100644 --- a/SCons/Scanner/C.py +++ b/SCons/Scanner/C.py @@ -62,7 +62,7 @@ class SConsCPPScanner(SCons.cpp.PreProcessor): try: with open(str(file.rfile())) as fp: return fp.read() - except EnvironmentError as e: + except OSError as e: self.missing.append((file, self.current_file)) return '' @@ -213,7 +213,7 @@ class SConsCPPConditionalScanner(SCons.cpp.PreProcessor): try: with open(str(file.rfile())) as fp: return fp.read() - except EnvironmentError: + except OSError: self.missing.append((file, self.current_file)) return "" diff --git a/SCons/Scanner/Dir.py b/SCons/Scanner/Dir.py index 239b1ec..6e0002a 100644 --- a/SCons/Scanner/Dir.py +++ b/SCons/Scanner/Dir.py @@ -100,7 +100,7 @@ def scan_on_disk(node, env, path=()): """ try: flist = node.fs.listdir(node.get_abspath()) - except (IOError, OSError): + except OSError: return [] e = node.Entry for f in filter(do_not_scan, flist): diff --git a/SCons/Script/Interactive.py b/SCons/Script/Interactive.py index 8fd3aa0..aa390cb 100644 --- a/SCons/Script/Interactive.py +++ b/SCons/Script/Interactive.py @@ -350,7 +350,7 @@ version Prints SCons version information. # Doing the right thing with an argument list currently # requires different shell= values on Windows and Linux. p = subprocess.Popen(argv, shell=(sys.platform=='win32')) - except EnvironmentError as e: + except OSError as e: sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror)) else: p.wait() diff --git a/SCons/Script/Main.py b/SCons/Script/Main.py index 361b4b2..ed9d69f 100644 --- a/SCons/Script/Main.py +++ b/SCons/Script/Main.py @@ -378,7 +378,7 @@ class CleanTask(SCons.Taskmaster.AlwaysTask): raise SCons.Errors.UserError(errstr % pathstr) except SCons.Errors.UserError as e: print(e) - except (IOError, OSError) as e: + except OSError as e: print("scons: Could not remove '%s':" % pathstr, e.strerror) def _get_files_to_clean(self): @@ -411,7 +411,7 @@ class CleanTask(SCons.Taskmaster.AlwaysTask): # the file not existing. In either case, print a # message and keep going to try to remove as many # targets as possible. - print("scons: Could not remove '{0}'".format(str(t)), e.strerror) + print(f"scons: Could not remove '{str(t)}'", e.strerror) else: if removed: display("Removed " + str(t)) @@ -792,7 +792,7 @@ def _load_site_scons_dir(topdir, site_dir_name=None): if not re_dunder.match(k): site_m[k] = v - with open(spec.origin, 'r') as f: + with open(spec.origin) as f: code = f.read() try: codeobj = compile(code, spec.name, "exec") diff --git a/SCons/Taskmaster/__init__.py b/SCons/Taskmaster/__init__.py index 7965ca8..d3002fa 100644 --- a/SCons/Taskmaster/__init__.py +++ b/SCons/Taskmaster/__init__.py @@ -240,7 +240,7 @@ class Task(ABC): for t in cached_targets: try: t.fs.unlink(t.get_internal_path()) - except (IOError, OSError) as e: + except OSError as e: SCons.Warnings.warn(SCons.Warnings.CacheCleanupErrorWarning, "Failed copying all target files from cache, Error while attempting to remove file %s retrieved from cache: %s" % (t.get_internal_path(), e)) self.targets[0].build() @@ -404,7 +404,7 @@ class Task(ABC): t.disambiguate().make_ready() is_up_to_date = not t.has_builder() or \ (not t.always_build and t.is_up_to_date()) - except EnvironmentError as e: + except OSError as e: raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename) if not is_up_to_date: diff --git a/SCons/Tool/JavaCommon.py b/SCons/Tool/JavaCommon.py index b3557c7..0722f00 100644 --- a/SCons/Tool/JavaCommon.py +++ b/SCons/Tool/JavaCommon.py @@ -449,7 +449,7 @@ if java_parsing: def parse_java_file(fn, version=default_java_version): - with open(fn, 'r', encoding='utf-8') as f: + with open(fn, encoding='utf-8') as f: data = f.read() return parse_java(data, version) diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py index 015cf72..29d6f24 100644 --- a/SCons/Tool/MSCommon/MSVC/Config.py +++ b/SCons/Tool/MSCommon/MSVC/Config.py @@ -322,10 +322,10 @@ def verify(): from .. import vc for msvc_version in vc._VCVER: if msvc_version not in MSVC_VERSION_SUFFIX: - err_msg = 'msvc_version {} not in MSVC_VERSION_SUFFIX'.format(repr(msvc_version)) + err_msg = f'msvc_version {msvc_version!r} not in MSVC_VERSION_SUFFIX' raise MSVCInternalError(err_msg) vc_version = Util.get_msvc_version_prefix(msvc_version) if vc_version not in MSVC_VERSION_INTERNAL: - err_msg = 'vc_version {} not in MSVC_VERSION_INTERNAL'.format(repr(vc_version)) + err_msg = f'vc_version {vc_version!r} not in MSVC_VERSION_INTERNAL' raise MSVCInternalError(err_msg) diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py index a5ceb33..107e05b 100644 --- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py +++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py @@ -73,7 +73,7 @@ def _verify_re_sdk_dispatch_map(): for sdk_version in Config.MSVC_SDK_VERSIONS: if sdk_version in re_sdk_dispatch_map: continue - err_msg = 'sdk version {} not in re_sdk_dispatch_map'.format(sdk_version) + err_msg = f'sdk version {sdk_version} not in re_sdk_dispatch_map' raise MSVCInternalError(err_msg) return None @@ -235,7 +235,7 @@ def _user_script_argument_uwp(env, uwp, user_argstr) -> bool: if len(matches) > 1: debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr)) - err_msg = "multiple uwp declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr)) + err_msg = f"multiple uwp declarations: MSVC_SCRIPT_ARGS={repr(user_argstr)}" raise MSVCArgumentError(err_msg) if not uwp: @@ -270,7 +270,7 @@ def _msvc_script_argument_sdk_constraints(msvc, sdk_version): return None debug('invalid: method exit: sdk_version=%s', repr(sdk_version)) - err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version)) + err_msg = f"MSVC_SDK_VERSION ({repr(sdk_version)}) is not supported" return err_msg def _msvc_script_argument_sdk_platform_constraints(msvc, toolset, sdk_version, platform_def): @@ -361,7 +361,7 @@ def _user_script_argument_sdk(env, sdk_version, user_argstr): if len(matches) > 1: debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr)) - err_msg = "multiple sdk version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr)) + err_msg = f"multiple sdk version declarations: MSVC_SCRIPT_ARGS={user_argstr!r}" raise MSVCArgumentError(err_msg) if not sdk_version: @@ -434,7 +434,7 @@ def _msvc_read_toolset_folders(msvc, vc_dir): sxs_folder, sxs_version = _msvc_sxs_toolset_folder(msvc, sxs_folder) if not sxs_version: continue - filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_folder) + filename = f'Microsoft.VCToolsVersion.{sxs_folder}.txt' filepath = os.path.join(sxs_path, filename) debug('sxs toolset: check file=%s', repr(filepath)) if os.path.exists(filepath): @@ -496,7 +496,7 @@ def _msvc_read_toolset_default(msvc, vc_dir): build_dir = os.path.join(vc_dir, "Auxiliary", "Build") # VS2019+ - filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools) + filename = f"Microsoft.VCToolsVersion.{msvc.vs_def.vc_buildtools_def.vc_buildtools}.default.txt" filepath = os.path.join(build_dir, filename) debug('default toolset: check file=%s', repr(filepath)) @@ -639,7 +639,7 @@ def _msvc_script_argument_toolset_constraints(msvc, toolset_version): return None debug('invalid: method exit: toolset_version=%s', repr(toolset_version)) - err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version)) + err_msg = f"MSVC_TOOLSET_VERSION ({toolset_version!r}) format is not supported" return err_msg def _msvc_script_argument_toolset_vcvars(msvc, toolset_version, vc_dir): @@ -681,7 +681,7 @@ def _msvc_script_argument_toolset(env, msvc, vc_dir, arglist): toolset_vcvars = _msvc_script_argument_toolset_vcvars(msvc, toolset_version, vc_dir) # toolset may not be installed for host/target - argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars)) + argpair = (SortOrder.TOOLSET, f'-vcvars_ver={toolset_vcvars}') arglist.append(argpair) return toolset_vcvars @@ -698,7 +698,7 @@ def _msvc_script_default_toolset(env, msvc, vc_dir, arglist, force_toolset: bool debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default)) if force_toolset: - argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default)) + argpair = (SortOrder.TOOLSET, f'-vcvars_ver={toolset_default}') arglist.append(argpair) return toolset_default @@ -711,7 +711,7 @@ def _user_script_argument_toolset(env, toolset_version, user_argstr): if len(matches) > 1: debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr)) - err_msg = "multiple toolset version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr)) + err_msg = f"multiple toolset version declarations: MSVC_SCRIPT_ARGS={user_argstr!r}" raise MSVCArgumentError(err_msg) if not toolset_version: @@ -799,7 +799,7 @@ def _msvc_script_argument_spectre(env, msvc, vc_dir, toolset, platform_def, argl spectre_arg = 'spectre' # spectre libs may not be installed for host/target - argpair = (SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg)) + argpair = (SortOrder.SPECTRE, f'-vcvars_spectre_libs={spectre_arg}') arglist.append(argpair) return spectre_arg @@ -812,7 +812,7 @@ def _user_script_argument_spectre(env, spectre, user_argstr): if len(matches) > 1: debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr)) - err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr)) + err_msg = f"multiple spectre declarations: MSVC_SCRIPT_ARGS={user_argstr!r}" raise MSVCArgumentError(err_msg) if not spectre: diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py index f0e47e2..64b8d67 100644 --- a/SCons/Tool/MSCommon/MSVC/Util.py +++ b/SCons/Tool/MSCommon/MSVC/Util.py @@ -228,7 +228,7 @@ def msvc_version_components(vcver): msvc_vernum = float(msvc_verstr) msvc_comps = tuple(msvc_verstr.split('.')) - msvc_major, msvc_minor = [int(x) for x in msvc_comps] + msvc_major, msvc_minor = (int(x) for x in msvc_comps) msvc_version_components_def = _MSVC_VERSION_COMPONENTS_DEFINITION( msvc_version = msvc_version, @@ -291,7 +291,7 @@ def msvc_extended_version_components(version): msvc_vernum = float(msvc_verstr) msvc_comps = tuple(msvc_verstr.split('.')) - msvc_major, msvc_minor = [int(x) for x in msvc_comps] + msvc_major, msvc_minor = (int(x) for x in msvc_comps) msvc_extended_version_components_def = _MSVC_EXTENDED_VERSION_COMPONENTS_DEFINITION( msvc_version = msvc_version, @@ -351,7 +351,7 @@ def msvc_sdk_version_components(version): sdk_verstr = '.'.join(sdk_comps[:2]) sdk_vernum = float(sdk_verstr) - sdk_major, sdk_minor = [int(x) for x in sdk_comps[:2]] + sdk_major, sdk_minor = (int(x) for x in sdk_comps[:2]) msvc_sdk_version_components_def = _MSVC_SDK_VERSION_COMPONENTS_DEFINITION( sdk_version = sdk_version, diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py index a5a48c4..39617b1 100644 --- a/SCons/Tool/MSCommon/MSVC/WinSDK.py +++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py @@ -194,7 +194,7 @@ def _verify_sdk_dispatch_map(): for sdk_version in Config.MSVC_SDK_VERSIONS: if sdk_version in _sdk_dispatch_map: continue - err_msg = 'sdk version {} not in sdk_dispatch_map'.format(sdk_version) + err_msg = f'sdk version {sdk_version} not in sdk_dispatch_map' raise MSVCInternalError(err_msg) return None diff --git a/SCons/Tool/MSCommon/common.py b/SCons/Tool/MSCommon/common.py index de460dc..f497f1a 100644 --- a/SCons/Tool/MSCommon/common.py +++ b/SCons/Tool/MSCommon/common.py @@ -154,7 +154,7 @@ def write_script_env_cache(cache) -> None: # data can't serialize to json, don't leave partial file with suppress(FileNotFoundError): p.unlink() - except IOError: + except OSError: # can't write the file, just skip pass @@ -344,7 +344,7 @@ def get_output(vcbat, args=None, env=None, skip_sendtelemetry=False): if sys.version_info.major == 3 and sys.version_info.minor < 6: from ctypes import windll - OEM = "cp{}".format(windll.kernel32.GetConsoleOutputCP()) + OEM = f"cp{windll.kernel32.GetConsoleOutputCP()}" else: OEM = "oem" if stderr: @@ -352,7 +352,7 @@ def get_output(vcbat, args=None, env=None, skip_sendtelemetry=False): # this at least prevents errors from getting swallowed. sys.stderr.write(stderr.decode(OEM)) if popen.wait() != 0: - raise IOError(stderr.decode(OEM)) + raise OSError(stderr.decode(OEM)) return stdout.decode(OEM) diff --git a/SCons/Tool/MSCommon/sdk.py b/SCons/Tool/MSCommon/sdk.py index fd0892c..8499dc8 100644 --- a/SCons/Tool/MSCommon/sdk.py +++ b/SCons/Tool/MSCommon/sdk.py @@ -334,7 +334,7 @@ def set_sdk_by_directory(env, sdk_dir) -> None: def get_sdk_by_version(mssdk): if mssdk not in SupportedSDKMap: - raise SCons.Errors.UserError("SDK version {} is not supported".format(repr(mssdk))) + raise SCons.Errors.UserError(f"SDK version {mssdk!r} is not supported") get_installed_sdks() return InstalledSDKMap.get(mssdk) diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py index d7da4ea..fd806bd 100644 --- a/SCons/Tool/MSCommon/vc.py +++ b/SCons/Tool/MSCommon/vc.py @@ -917,7 +917,7 @@ def find_vc_pdir(env, msvc_version): return comps else: debug('reg says dir is %s, but it does not exist. (ignoring)', comps) - raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps)) + raise MissingConfiguration(f"registry dir {comps} not found on the filesystem") return None def find_batch_file(msvc_version, host_arch, target_arch, pdir): @@ -1043,7 +1043,7 @@ def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version) -> bool: try: with open(default_toolset_file) as f: vc_specific_version = f.readlines()[0].strip() - except IOError: + except OSError: debug('failed to read %s', default_toolset_file) return False except IndexError: @@ -1501,7 +1501,7 @@ def msvc_setup_env(env): if SCons.Util.is_String(use_script): use_script = use_script.strip() if not os.path.exists(use_script): - raise MSVCScriptNotFound('Script specified by MSVC_USE_SCRIPT not found: "{}"'.format(use_script)) + raise MSVCScriptNotFound(f'Script specified by MSVC_USE_SCRIPT not found: "{use_script}"') args = env.subst('$MSVC_USE_SCRIPT_ARGS') debug('use_script 1 %s %s', repr(use_script), repr(args)) d = script_env(env, use_script, args) @@ -1512,7 +1512,7 @@ def msvc_setup_env(env): return d elif use_settings is not None: if not SCons.Util.is_Dict(use_settings): - error_msg = 'MSVC_USE_SETTINGS type error: expected a dictionary, found {}'.format(type(use_settings).__name__) + error_msg = f'MSVC_USE_SETTINGS type error: expected a dictionary, found {type(use_settings).__name__}' raise MSVCUseSettingsError(error_msg) d = use_settings debug('use_settings %s', d) @@ -1531,10 +1531,10 @@ def msvc_setup_env(env): if not find_program_path(env, 'cl'): debug("did not find %s", _CL_EXE_NAME) if CONFIG_CACHE: - propose = "SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {} if out of date.".format(CONFIG_CACHE) + propose = f"SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {CONFIG_CACHE} if out of date." else: propose = "It may need to be installed separately with Visual Studio." - warn_msg = "Could not find MSVC compiler 'cl'. {}".format(propose) + warn_msg = f"Could not find MSVC compiler 'cl'. {propose}" SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) def msvc_exists(env=None, version=None): @@ -1603,7 +1603,7 @@ def msvc_sdk_versions(version=None, msvc_uwp_app: bool=False): version_def = MSVC.Util.msvc_extended_version_components(version) if not version_def: - msg = 'Unsupported version {}'.format(repr(version)) + msg = f'Unsupported version {version!r}' raise MSVCArgumentError(msg) rval = MSVC.WinSDK.get_msvc_sdk_version_list(version, msvc_uwp_app) @@ -1623,7 +1623,7 @@ def msvc_toolset_versions(msvc_version=None, full: bool=True, sxs: bool=False): return rval if msvc_version not in _VCVER: - msg = 'Unsupported msvc version {}'.format(repr(msvc_version)) + msg = f'Unsupported msvc version {msvc_version!r}' raise MSVCArgumentError(msg) vc_dir = find_vc_pdir(env, msvc_version) @@ -1648,7 +1648,7 @@ def msvc_toolset_versions_spectre(msvc_version=None): return rval if msvc_version not in _VCVER: - msg = 'Unsupported msvc version {}'.format(repr(msvc_version)) + msg = f'Unsupported msvc version {msvc_version!r}' raise MSVCArgumentError(msg) vc_dir = find_vc_pdir(env, msvc_version) @@ -1720,13 +1720,13 @@ def msvc_query_version_toolset(version=None, prefer_newest: bool=True): version_def = MSVC.Util.msvc_extended_version_components(version) if not version_def: - msg = 'Unsupported msvc version {}'.format(repr(version)) + msg = f'Unsupported msvc version {version!r}' raise MSVCArgumentError(msg) if version_def.msvc_suffix: if version_def.msvc_verstr != version_def.msvc_toolset_version: # toolset version with component suffix - msg = 'Unsupported toolset version {}'.format(repr(version)) + msg = f'Unsupported toolset version {version!r}' raise MSVCArgumentError(msg) if version_def.msvc_vernum > 14.0: @@ -1805,11 +1805,11 @@ def msvc_query_version_toolset(version=None, prefer_newest: bool=True): ) if version_def.msvc_verstr == msvc_toolset_version: - msg = 'MSVC version {} was not found'.format(repr(version)) + msg = f'MSVC version {version!r} was not found' MSVC.Policy.msvc_notfound_handler(None, msg) return msvc_version, msvc_toolset_version - msg = 'MSVC toolset version {} not found'.format(repr(version)) + msg = f'MSVC toolset version {version!r} not found' raise MSVCToolsetVersionNotFound(msg) diff --git a/SCons/Tool/PharLapCommon.py b/SCons/Tool/PharLapCommon.py index e1907ab..034d9d8 100644 --- a/SCons/Tool/PharLapCommon.py +++ b/SCons/Tool/PharLapCommon.py @@ -79,7 +79,7 @@ def getPharLapVersion(): include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h")) if not os.path.exists(include_path): raise SCons.Errors.UserError("Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?") - with open(include_path, 'r') as f: + with open(include_path) as f: mo = REGEX_ETS_VER.search(f.read()) if mo: return int(mo.group(1)) diff --git a/SCons/Tool/cyglink.py b/SCons/Tool/cyglink.py index 0925a3d..80caf0b 100644 --- a/SCons/Tool/cyglink.py +++ b/SCons/Tool/cyglink.py @@ -24,7 +24,7 @@ def cyglink_lib_emitter(target, source, env, **kw): no_import_lib = env.get('no_import_lib', False) if verbose: - print("cyglink_lib_emitter: target[0]={!r}".format(target[0].get_path())) + print(f"cyglink_lib_emitter: target[0]={target[0].get_path()!r}") if not no_import_lib: # Specify import lib and add to targets @@ -35,7 +35,7 @@ def cyglink_lib_emitter(target, source, env, **kw): target.append(import_lib_target) if verbose: - print("cyglink_lib_emitter: import_lib={}".format(import_lib)) + print(f"cyglink_lib_emitter: import_lib={import_lib}") print("cyglink_lib_emitter: target=%s" % target) for tgt in target: diff --git a/SCons/Tool/dmd.py b/SCons/Tool/dmd.py index c3ac0ca..13e9e7e 100644 --- a/SCons/Tool/dmd.py +++ b/SCons/Tool/dmd.py @@ -145,7 +145,7 @@ def generate(env) -> None: env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' - env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format( + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {}$TARGET $SOURCES $_DLIBFLAGS'.format( '-c ' if env['PLATFORM'] == 'win32' else '') # env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' diff --git a/SCons/Tool/docbook/__init__.py b/SCons/Tool/docbook/__init__.py index 54f1883..3a35f1a 100644 --- a/SCons/Tool/docbook/__init__.py +++ b/SCons/Tool/docbook/__init__.py @@ -319,7 +319,7 @@ def __build_lxml(target, source, env): with open(str(target[0]), "wb") as of: of.write(etree.tostring(result, encoding="utf-8", pretty_print=True)) except Exception as e: - print("ERROR: Failed to write {}".format(str(target[0]))) + print(f"ERROR: Failed to write {str(target[0])}") print(e) return None @@ -362,7 +362,7 @@ def __xinclude_lxml(target, source, env): doc.write(str(target[0]), xml_declaration=True, encoding="UTF-8", pretty_print=True) except Exception as e: - print("ERROR: Failed to write {}".format(str(target[0]))) + print(f"ERROR: Failed to write {str(target[0])}") print(e) return None @@ -655,7 +655,7 @@ def DocbookMan(env, target, source=None, *args, **kw): except Exception: # Use simple regex parsing - with open(__ensure_suffix(str(s),'.xml'), 'r') as f: + with open(__ensure_suffix(str(s), '.xml')) as f: content = f.read() for m in re_manvolnum.finditer(content): diff --git a/SCons/Tool/gdc.py b/SCons/Tool/gdc.py index 9f29d72..96748b9 100644 --- a/SCons/Tool/gdc.py +++ b/SCons/Tool/gdc.py @@ -105,7 +105,7 @@ def generate(env) -> None: env['SHDLINKCOM'] = '$DLINK -o $TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' - env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {}$TARGET $SOURCES $_DLINKLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' diff --git a/SCons/Tool/hpcxx.py b/SCons/Tool/hpcxx.py index c02a06f..1f5e319 100644 --- a/SCons/Tool/hpcxx.py +++ b/SCons/Tool/hpcxx.py @@ -48,7 +48,7 @@ acc = None try: dirs = os.listdir('/opt') -except (IOError, OSError): +except OSError: # Not being able to read the directory because it doesn't exist # (IOError) or isn't readable (OSError) is okay. dirs = [] diff --git a/SCons/Tool/hplink.py b/SCons/Tool/hplink.py index 0d26fa4..ab2154a 100644 --- a/SCons/Tool/hplink.py +++ b/SCons/Tool/hplink.py @@ -40,7 +40,7 @@ ccLinker = None try: dirs = os.listdir('/opt') -except (IOError, OSError): +except OSError: # Not being able to read the directory because it doesn't exist # (IOError) or isn't readable (OSError) is okay. dirs = [] diff --git a/SCons/Tool/install.py b/SCons/Tool/install.py index 5c98fb3..d553e31 100644 --- a/SCons/Tool/install.py +++ b/SCons/Tool/install.py @@ -230,7 +230,7 @@ def installShlibLinks(dest, source, env) -> None: Verbose = False symlinks = listShlibLinksToInstall(dest, source, env) if Verbose: - print('installShlibLinks: symlinks={!r}'.format(StringizeLibSymlinks(symlinks))) + print(f'installShlibLinks: symlinks={StringizeLibSymlinks(symlinks)!r}') if symlinks: CreateLibSymlinks(env, symlinks) return @@ -326,7 +326,7 @@ def add_versioned_targets_to_INSTALLED_FILES(target, source, env): Verbose = False _INSTALLED_FILES.extend(target) if Verbose: - print("add_versioned_targets_to_INSTALLED_FILES: target={!r}".format(list(map(str, target)))) + print(f"add_versioned_targets_to_INSTALLED_FILES: target={list(map(str, target))!r}") symlinks = listShlibLinksToInstall(target[0], source, env) if symlinks: EmitLibSymlinks(env, symlinks, target[0]) diff --git a/SCons/Tool/intelc.py b/SCons/Tool/intelc.py index a7b4802..1fcadca 100644 --- a/SCons/Tool/intelc.py +++ b/SCons/Tool/intelc.py @@ -250,7 +250,7 @@ def get_all_compiler_versions(): print("scons: *** Ignoring "+str(value)) i = i + 1 - except EnvironmentError: + except OSError: # no more subkeys pass elif is_linux or is_mac: diff --git a/SCons/Tool/ldc.py b/SCons/Tool/ldc.py index 5fb6070..bd0767e 100644 --- a/SCons/Tool/ldc.py +++ b/SCons/Tool/ldc.py @@ -122,7 +122,7 @@ def generate(env) -> None: env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}' env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr' - env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') + env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '') # env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}' diff --git a/SCons/Tool/linkCommon/__init__.py b/SCons/Tool/linkCommon/__init__.py index f0cf4fc..6a558d8 100644 --- a/SCons/Tool/linkCommon/__init__.py +++ b/SCons/Tool/linkCommon/__init__.py @@ -161,7 +161,7 @@ def smart_link(source, target, env, for_signature) -> str: def lib_emitter(target, source, env, **kw): verbose = False if verbose: - print("_lib_emitter: target[0]={!r}".format(target[0].get_path())) + print(f"_lib_emitter: target[0]={target[0].get_path()!r}") for tgt in target: if SCons.Util.is_String(tgt): tgt = env.File(tgt) diff --git a/SCons/Tool/linkloc.py b/SCons/Tool/linkloc.py index 6122d9b..6f7a732 100644 --- a/SCons/Tool/linkloc.py +++ b/SCons/Tool/linkloc.py @@ -51,9 +51,9 @@ def repl_linker_command(m): # Replaces any linker command file directives (e.g. "@foo.lnk") with # the actual contents of the file. try: - with open(m.group(2), "r") as f: + with open(m.group(2)) as f: return m.group(1) + f.read() - except IOError: + except OSError: # the linker should return an error if it can't # find the linker command file so we will remain quiet. # However, we will replace the @ with a # so we will not continue diff --git a/SCons/Tool/msvs.py b/SCons/Tool/msvs.py index 3e6a960..153b84e 100644 --- a/SCons/Tool/msvs.py +++ b/SCons/Tool/msvs.py @@ -263,7 +263,7 @@ class _UserGenerator: try: filename = self.dspabs +'.user' self.usrfile = open(filename, 'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + filename + '" for writing:' + str(detail)) else: self.UserHeader() @@ -757,8 +757,8 @@ class _GenerateV6DSP(_DSPGenerator): def Parse(self): try: - dspfile = open(self.dspabs,'r') - except IOError: + dspfile = open(self.dspabs) + except OSError: return # doesn't exist yet, so can't add anything to configs. line = dspfile.readline() @@ -810,7 +810,7 @@ class _GenerateV6DSP(_DSPGenerator): def Build(self): try: self.file = open(self.dspabs,'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() @@ -1075,8 +1075,8 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User): def Parse(self): try: - dspfile = open(self.dspabs,'r') - except IOError: + dspfile = open(self.dspabs) + except OSError: return # doesn't exist yet, so can't add anything to configs. line = dspfile.readline() @@ -1127,7 +1127,7 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User): def Build(self): try: self.file = open(self.dspabs,'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() @@ -1314,7 +1314,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): self.filtersabs = self.dspabs + '.filters' try: self.filters_file = open(self.filtersabs, 'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.filtersabs + '" for writing:' + str(detail)) self.filters_file.write('\n' @@ -1451,7 +1451,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): def Build(self): try: self.file = open(self.dspabs, 'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() @@ -1573,8 +1573,8 @@ class _GenerateV7DSW(_DSWGenerator): def Parse(self): try: - dswfile = open(self.dswfile,'r') - except IOError: + dswfile = open(self.dswfile) + except OSError: return # doesn't exist yet, so can't add anything to configs. line = dswfile.readline() @@ -1729,7 +1729,7 @@ class _GenerateV7DSW(_DSWGenerator): def Build(self): try: self.file = open(self.dswfile,'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) else: self.PrintSolution() @@ -1778,7 +1778,7 @@ class _GenerateV6DSW(_DSWGenerator): def Build(self): try: self.file = open(self.dswfile,'w') - except IOError as detail: + except OSError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) else: self.PrintWorkspace() @@ -1835,7 +1835,7 @@ def GenerateProject(target, source, env): if dspfile is not builddspfile: try: bdsp = open(str(builddspfile), "w+") - except IOError as detail: + except OSError as detail: print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') raise @@ -1852,7 +1852,7 @@ def GenerateProject(target, source, env): try: bdsw = open(str(builddswfile), "w+") - except IOError as detail: + except OSError as detail: print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') raise diff --git a/SCons/Tool/ninja/Methods.py b/SCons/Tool/ninja/Methods.py index 7259475..899f761 100644 --- a/SCons/Tool/ninja/Methods.py +++ b/SCons/Tool/ninja/Methods.py @@ -47,7 +47,7 @@ def register_custom_rule(env, rule, command, description: str="", deps=None, poo """Allows specification of Ninja rules from inside SCons files.""" rule_obj = { "command": command, - "description": description if description else "{} $out".format(rule), + "description": description if description else f"{rule} $out", } if use_depfile: diff --git a/SCons/Tool/ninja/NinjaState.py b/SCons/Tool/ninja/NinjaState.py index 707a9e2..549af78 100644 --- a/SCons/Tool/ninja/NinjaState.py +++ b/SCons/Tool/ninja/NinjaState.py @@ -342,7 +342,7 @@ class NinjaState: self.builds[node_string] = tmp_build print(warn_msg) else: - raise InternalError("Node {} added to ninja build state more than once".format(node_string)) + raise InternalError(f"Node {node_string} added to ninja build state more than once") self.builds[node_string] = build return True diff --git a/SCons/Tool/ninja/Utils.py b/SCons/Tool/ninja/Utils.py index 7c85f62..470599f 100644 --- a/SCons/Tool/ninja/Utils.py +++ b/SCons/Tool/ninja/Utils.py @@ -250,7 +250,7 @@ def generate_depfile(env, node, dependencies) -> None: need_rewrite = False try: - with open(depfile, 'r') as f: + with open(depfile) as f: need_rewrite = (f.read() != depfile_contents) except FileNotFoundError: need_rewrite = True @@ -315,7 +315,7 @@ def get_command_env(env, target, source): scons_specified_env = SCons.Util.sanitize_shell_env(scons_specified_env) for key, value in scons_specified_env.items(): if windows: - command_env += "set '{}={}' && ".format(key, value) + command_env += f"set '{key}={value}' && " else: # We address here *only* the specific case that a user might have # an environment variable which somehow gets included and has @@ -323,7 +323,7 @@ def get_command_env(env, target, source): # doesn't make builds on paths with spaces (Ninja and SCons issues) # nor expanding response file paths with spaces (Ninja issue) work. value = value.replace(r' ', r'$ ') - command_env += "export {}='{}';".format(key, value) + command_env += f"export {key}='{value}';" env["NINJA_ENV_VAR_CACHE"] = command_env return command_env diff --git a/SCons/Tool/ninja/__init__.py b/SCons/Tool/ninja/__init__.py index 0ee72d2..7320d03 100644 --- a/SCons/Tool/ninja/__init__.py +++ b/SCons/Tool/ninja/__init__.py @@ -85,7 +85,7 @@ def ninja_builder(env, target, source): with open('run_ninja_env.bat', 'w') as f: for key in env['ENV']: f.write('set {}={}\n'.format(key, env['ENV'][key])) - f.write('{} -f {} %*\n'.format(NINJA_STATE.ninja_bin_path, generated_build_ninja)) + f.write(f'{NINJA_STATE.ninja_bin_path} -f {generated_build_ninja} %*\n') cmd = ['run_ninja_env.bat'] else: @@ -112,8 +112,7 @@ def ninja_builder(env, target, source): universal_newlines=True, env=spawn_env ) - for stdout_line in iter(proc.stdout.readline, ""): - yield stdout_line + yield from iter(proc.stdout.readline, "") proc.stdout.close() return_code = proc.wait() if return_code: diff --git a/SCons/Tool/ninja/ninja_scons_daemon.py b/SCons/Tool/ninja/ninja_scons_daemon.py index 2084097..8e297d3 100644 --- a/SCons/Tool/ninja/ninja_scons_daemon.py +++ b/SCons/Tool/ninja/ninja_scons_daemon.py @@ -220,7 +220,7 @@ def daemon_thread_func(): break if "exit" in building_node: daemon_log("input: " + "exit") - p.stdin.write("exit\n".encode("utf-8")) + p.stdin.write(b"exit\n") p.stdin.flush() with building_cv: shared_state.finished_building += [building_node] diff --git a/SCons/Tool/rpmutils.py b/SCons/Tool/rpmutils.py index 209fcea..cc1cc23 100644 --- a/SCons/Tool/rpmutils.py +++ b/SCons/Tool/rpmutils.py @@ -480,10 +480,10 @@ def updateRpmDicts(rpmrc, pyfile) -> None: """ try: # Read old rpmutils.py file - with open(pyfile,"r") as f: + with open(pyfile) as f: oldpy = f.readlines() # Read current rpmrc.in file - with open(rpmrc,"r") as f: + with open(rpmrc) as f: rpm = f.readlines() # Parse for data data = {} diff --git a/SCons/Tool/suncxx.py b/SCons/Tool/suncxx.py index 51dc373..ac0b0c7 100644 --- a/SCons/Tool/suncxx.py +++ b/SCons/Tool/suncxx.py @@ -55,9 +55,9 @@ def get_package_info(package_name, pkginfo, pkgchk): from subprocess import DEVNULL try: - with open('/var/sadm/install/contents', 'r', encoding='UTF-8') as f: + with open('/var/sadm/install/contents', encoding='UTF-8') as f: sadm_contents = f.read() - except EnvironmentError: + except OSError: pass else: sadm_re = re.compile(r'^(\S*/bin/CC)(=\S*)? %s$' % package_name, re.M) @@ -70,7 +70,7 @@ def get_package_info(package_name, pkginfo, pkgchk): universal_newlines=True, stdout=subprocess.PIPE, stderr=DEVNULL) - except EnvironmentError: + except OSError: pass else: pkginfo_contents = p.communicate()[0] @@ -85,7 +85,7 @@ def get_package_info(package_name, pkginfo, pkgchk): universal_newlines=True, stdout=subprocess.PIPE, stderr=DEVNULL) - except EnvironmentError: + except OSError: pass else: pkgchk_contents = p.communicate()[0] diff --git a/SCons/Tool/sunlink.py b/SCons/Tool/sunlink.py index c86d7c2..a05fdb8 100644 --- a/SCons/Tool/sunlink.py +++ b/SCons/Tool/sunlink.py @@ -43,7 +43,7 @@ ccLinker = None try: dirs = os.listdir('/opt') -except (IOError, OSError): +except OSError: # Not being able to read the directory because it doesn't exist # (IOError) or isn't readable (OSError) is okay. dirs = [] diff --git a/SCons/Tool/swig.py b/SCons/Tool/swig.py index aefd7cb..0941fc7 100644 --- a/SCons/Tool/swig.py +++ b/SCons/Tool/swig.py @@ -68,7 +68,7 @@ def _find_modules(src): with open(src) as f: data = f.read() matches = _reModule.findall(data) - except IOError: + except OSError: # If the file's not yet generated, guess the module name from the file stem matches = [] mnames.append(os.path.splitext(os.path.basename(src))[0]) diff --git a/SCons/Tool/tex.py b/SCons/Tool/tex.py index 72526c3..54b21fb 100644 --- a/SCons/Tool/tex.py +++ b/SCons/Tool/tex.py @@ -300,7 +300,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None flsContent = '' auxfiles = [] if os.path.isfile(flsfilename): - with open(flsfilename, "r") as f: + with open(flsfilename) as f: flsContent = f.read() auxfiles = openout_aux_re.findall(flsContent) # remove duplicates @@ -311,7 +311,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None bcffiles = [] if os.path.isfile(flsfilename): - with open(flsfilename, "r") as f: + with open(flsfilename) as f: flsContent = f.read() bcffiles = openout_bcf_re.findall(flsContent) # remove duplicates @@ -335,7 +335,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None already_bibtexed.append(auxfilename) target_aux = os.path.join(targetdir, auxfilename) if os.path.isfile(target_aux): - with open(target_aux, "r") as f: + with open(target_aux) as f: content = f.read() if content.find("bibdata") != -1: if Verbose: @@ -359,7 +359,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None already_bibtexed.append(bcffilename) target_bcf = os.path.join(targetdir, bcffilename) if os.path.isfile(target_bcf): - with open(target_bcf, "r") as f: + with open(target_bcf) as f: content = f.read() if content.find("bibdata") != -1: if Verbose: @@ -823,7 +823,7 @@ def tex_emitter_core(target, source, env, graphics_extensions): # read fls file to get all other files that latex creates and will read on the next pass # remove files from list that we explicitly dealt with above if os.path.isfile(flsfilename): - with open(flsfilename, "r") as f: + with open(flsfilename) as f: content = f.read() out_files = openout_re.findall(content) myfiles = [auxfilename, logfilename, flsfilename, targetbase+'.dvi',targetbase+'.pdf'] diff --git a/SCons/Tool/textfile.py b/SCons/Tool/textfile.py index f79f808..04a5cd7 100644 --- a/SCons/Tool/textfile.py +++ b/SCons/Tool/textfile.py @@ -120,7 +120,7 @@ def _action(target, source, env): # write the file try: target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE, newline='', encoding=file_encoding) - except (OSError, IOError) as e: + except OSError as e: raise SCons.Errors.UserError("Can't write target file %s [%s]" % (target[0],e)) # separate lines by 'linesep' only if linesep is not empty diff --git a/SCons/Util/types.py b/SCons/Util/types.py index 44aae5f..b2bc040 100644 --- a/SCons/Util/types.py +++ b/SCons/Util/types.py @@ -112,7 +112,7 @@ class Null: def __new__(cls, *args, **kwargs): if '_instance' not in vars(cls): - cls._instance = super(Null, cls).__new__(cls, *args, **kwargs) + cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance def __init__(self, *args, **kwargs) -> None: diff --git a/SCons/Utilities/ConfigureCache.py b/SCons/Utilities/ConfigureCache.py index f0de77b..fe2aabb 100644 --- a/SCons/Utilities/ConfigureCache.py +++ b/SCons/Utilities/ConfigureCache.py @@ -123,7 +123,7 @@ def main(): if not os.path.exists('config'): # old config dirs did not have a 'config' file. Try to update. # Validate the only files in the directory are directories 0-9, a-f - expected = ['{:X}'.format(x) for x in range(0, 16)] + expected = [f'{x:X}' for x in range(0, 16)] if not set(os.listdir('.')).issubset(expected): raise RuntimeError( "%s does not look like a valid version 1 cache directory" % cache) diff --git a/SCons/Utilities/sconsign.py b/SCons/Utilities/sconsign.py index c12782d..a02ebb0 100644 --- a/SCons/Utilities/sconsign.py +++ b/SCons/Utilities/sconsign.py @@ -46,7 +46,7 @@ def my_whichdb(filename): try: with open(filename + ".dblite", "rb"): return "SCons.dblite" - except IOError: + except OSError: pass return whichdb(filename) @@ -297,7 +297,7 @@ class Do_SConsignDB: # .sconsign => .sconsign.dblite # .sconsign.dblite => .sconsign.dblite.dblite db = self.dbm.open(fname, "r") - except (IOError, OSError) as e: + except OSError as e: print_e = e try: # That didn't work, so try opening the base name, @@ -305,14 +305,14 @@ class Do_SConsignDB: # (for example), the dbm module will put the suffix back # on for us and open it anyway. db = self.dbm.open(os.path.splitext(fname)[0], "r") - except (IOError, OSError): + except OSError: # That didn't work either. See if the file name # they specified even exists (independent of the dbm # suffix-mangling). try: with open(fname, "rb"): pass # this is a touch only, we don't use it here. - except (IOError, OSError) as e: + except OSError as e: # Nope, that file doesn't even exist, so report that # fact back. print_e = e @@ -370,7 +370,7 @@ def Do_SConsignDir(name): sys.stderr.write(err) return printentries(sconsign.entries, args[0]) - except (IOError, OSError) as e: + except OSError as e: sys.stderr.write("sconsign: %s\n" % e) return diff --git a/SCons/Variables/__init__.py b/SCons/Variables/__init__.py index 4d40986..fe1b498 100644 --- a/SCons/Variables/__init__.py +++ b/SCons/Variables/__init__.py @@ -182,7 +182,7 @@ class Variables: sys.path.insert(0, dir) try: values['__name__'] = filename - with open(filename, 'r') as f: + with open(filename) as f: contents = f.read() exec(contents, {}, values) finally: @@ -285,7 +285,7 @@ class Variables: fh.write('%s = %s\n' % (option.key, repr(value))) except KeyError: pass - except IOError as x: + except OSError as x: raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) def GenerateHelpText(self, env, sort=None) -> str: diff --git a/SCons/compat/__init__.py b/SCons/compat/__init__.py index 2174f38..0a9669d 100644 --- a/SCons/compat/__init__.py +++ b/SCons/compat/__init__.py @@ -95,7 +95,7 @@ class NoSlotsPyPy(type): def __new__(meta, name, bases, dct): if PYPY and '__slots__' in dct: dct.pop('__slots__') - return super(NoSlotsPyPy, meta).__new__(meta, name, bases, dct) + return super().__new__(meta, name, bases, dct) # Local Variables: # tab-width:4 diff --git a/SCons/compat/win32.py b/SCons/compat/win32.py index e01adfa..5f25dd8 100644 --- a/SCons/compat/win32.py +++ b/SCons/compat/win32.py @@ -78,8 +78,8 @@ def get_memory_info(process=None): ctypes.sizeof(counters)) if not ret: raise ctypes.WinError() - info = dict((name, getattr(counters, name)) - for name, _ in counters._fields_) + info = {name: getattr(counters, name) + for name, _ in counters._fields_} return info diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index 5ad5448..bf492f0 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # SCons documentation build configuration file, created by # sphinx-quickstart on Mon Apr 30 09:36:53 2018. diff --git a/site_scons/SConsRevision.py b/site_scons/SConsRevision.py index dab623c..5d76449 100644 --- a/site_scons/SConsRevision.py +++ b/site_scons/SConsRevision.py @@ -14,7 +14,7 @@ def SCons_revision(target, source, env): s = source[0].rstr() try: - with open(s, 'r') as fp: + with open(s) as fp: contents = fp.read() diff --git a/site_scons/soe_utils.py b/site_scons/soe_utils.py index 8fb0257..bbe4247 100644 --- a/site_scons/soe_utils.py +++ b/site_scons/soe_utils.py @@ -22,11 +22,11 @@ def soelim(target, source, env): t = str(target[0]) s = str(source[0]) dir, f = os.path.split(s) - with open(t, 'w') as tfp, open(s, 'r') as sfp: + with open(t, 'w') as tfp, open(s) as sfp: for line in sfp.readlines(): if line[:4] in ['.so ', "'so "]: sofile = os.path.join(dir, line[4:-1]) - with open(sofile, 'r') as f: + with open(sofile) as f: tfp.write(f.read()) else: tfp.write(line) diff --git a/test/D/SharedObjects/Common/common.py b/test/D/SharedObjects/Common/common.py index 6a75e34..e9611a1 100644 --- a/test/D/SharedObjects/Common/common.py +++ b/test/D/SharedObjects/Common/common.py @@ -54,7 +54,7 @@ def testForTool(tool): match = re.search(r'[0-9]+(\.[0-9]+)+', vstr) if match: version = match.group(0) - major, minor, debug = [int(x) for x in version.split('.')] + major, minor, debug = (int(x) for x in version.split('.')) else: major = 0 if (major < 6) or (major == 6 and minor < 3): @@ -83,7 +83,7 @@ def testForTool(tool): test.fail_test() test.dir_fixture('Image') - with open('SConstruct_template', 'r') as f: + with open('SConstruct_template') as f: config = f.read().format(tool) test.write('SConstruct', config) diff --git a/test/D/di/Image/SConstruct_template b/test/D/di/Image/SConstruct_template index d734329..ae84430 100644 --- a/test/D/di/Image/SConstruct_template +++ b/test/D/di/Image/SConstruct_template @@ -1,5 +1,3 @@ -# -*- mode:python; coding:utf-8; -*- - import os DefaultEnvironment(tools=[]) diff --git a/test/Docbook/basedir/slideshtml/image/xsltver.py b/test/Docbook/basedir/slideshtml/image/xsltver.py index e1a7074..1296703 100644 --- a/test/Docbook/basedir/slideshtml/image/xsltver.py +++ b/test/Docbook/basedir/slideshtml/image/xsltver.py @@ -11,7 +11,7 @@ def detectXsltVersion(fpath): file couldn't be found/parsed correctly. """ with open(os.path.join(fpath, 'VERSION'), 'rb') as fin: - re_version = re.compile("([^<]+)".encode('utf-8')) + re_version = re.compile(b"([^<]+)") m = re_version.search(fin.read()) if m: try: diff --git a/test/Docbook/basic/slideshtml/image/xsltver.py b/test/Docbook/basic/slideshtml/image/xsltver.py index e1a7074..1296703 100644 --- a/test/Docbook/basic/slideshtml/image/xsltver.py +++ b/test/Docbook/basic/slideshtml/image/xsltver.py @@ -11,7 +11,7 @@ def detectXsltVersion(fpath): file couldn't be found/parsed correctly. """ with open(os.path.join(fpath, 'VERSION'), 'rb') as fin: - re_version = re.compile("([^<]+)".encode('utf-8')) + re_version = re.compile(b"([^<]+)") m = re_version.search(fin.read()) if m: try: diff --git a/test/Docbook/rootname/slideshtml/image/xsltver.py b/test/Docbook/rootname/slideshtml/image/xsltver.py index e1a7074..1296703 100644 --- a/test/Docbook/rootname/slideshtml/image/xsltver.py +++ b/test/Docbook/rootname/slideshtml/image/xsltver.py @@ -11,7 +11,7 @@ def detectXsltVersion(fpath): file couldn't be found/parsed correctly. """ with open(os.path.join(fpath, 'VERSION'), 'rb') as fin: - re_version = re.compile("([^<]+)".encode('utf-8')) + re_version = re.compile(b"([^<]+)") m = re_version.search(fin.read()) if m: try: diff --git a/test/Fortran/F90FLAGS.py b/test/Fortran/F90FLAGS.py index 5a469e9..10a2f35 100644 --- a/test/Fortran/F90FLAGS.py +++ b/test/Fortran/F90FLAGS.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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 TestSCons diff --git a/test/MSVS/CPPPATH-Dirs.py b/test/MSVS/CPPPATH-Dirs.py index 3883331..27a05ba 100644 --- a/test/MSVS/CPPPATH-Dirs.py +++ b/test/MSVS/CPPPATH-Dirs.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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__" """ Test that MSVS generation works when CPPPATH contains Dir nodes. diff --git a/test/MSVS/common-prefix.py b/test/MSVS/common-prefix.py index 7bba783..ea95c03 100644 --- a/test/MSVS/common-prefix.py +++ b/test/MSVS/common-prefix.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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__" """ Test that we can generate Visual Studio 8.0 project (.vcproj) and diff --git a/test/MSVS/runfile.py b/test/MSVS/runfile.py index 1cc4720..d2319f3 100644 --- a/test/MSVS/runfile.py +++ b/test/MSVS/runfile.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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__" """ Test that we can generate Visual Studio 8.0 project (.vcproj) and diff --git a/test/Parallel/failed-build/fixture/teststate.py b/test/Parallel/failed-build/fixture/teststate.py index 8499720..1d1ca8c 100644 --- a/test/Parallel/failed-build/fixture/teststate.py +++ b/test/Parallel/failed-build/fixture/teststate.py @@ -85,7 +85,7 @@ def server_thread(PORT): self.send_header('Content-type', 'text/html') self.end_headers() if response != Response.DONE: - self.wfile.write("".encode('utf-8')) + self.wfile.write(b"") def log_message(self, format, *args): return diff --git a/test/Removed/SourceSignatures/Old/no-csigs.py b/test/Removed/SourceSignatures/Old/no-csigs.py index 483eeea..ff6968c 100644 --- a/test/Removed/SourceSignatures/Old/no-csigs.py +++ b/test/Removed/SourceSignatures/Old/no-csigs.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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 TestSCons import TestSConsign diff --git a/test/Scanner/unicode.py b/test/Scanner/unicode.py index 0edd5b6..514a92c 100644 --- a/test/Scanner/unicode.py +++ b/test/Scanner/unicode.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -20,15 +22,12 @@ # 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. -# """ Verify that we can scan Unicode-encoded files for implicit dependencies. """ -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import TestSCons _python_ = TestSCons._python_ @@ -108,28 +107,28 @@ include utf16be.k foo.k 1 line 4 """) -contents = (u"""\ +contents = ("""\ ascii.k 1 line 1 include ascii.inc ascii.k 1 line 3 """) test.write('ascii.k', contents.encode('ascii')) -contents = (u"""\ +contents = ("""\ utf8.k 1 line 1 include utf8.inc utf8.k 1 line 3 """) test.write('utf8.k', codecs.BOM_UTF8 + contents.encode('utf-8')) -contents = (u"""\ +contents = ("""\ utf16le.k 1 line 1 include utf16le.inc utf16le.k 1 line 3 """) test.write('utf16le.k', codecs.BOM_UTF16_LE + contents.encode('utf-16-le')) -contents = (u"""\ +contents = ("""\ utf16be.k 1 line 1 include utf16be.inc utf16be.k 1 line 3 diff --git a/test/Subst/fixture/SConstruct.callable_exception b/test/Subst/fixture/SConstruct.callable_exception index 1c1b952..2352489 100644 --- a/test/Subst/fixture/SConstruct.callable_exception +++ b/test/Subst/fixture/SConstruct.callable_exception @@ -2,7 +2,7 @@ # # Copyright The SCons Foundation -class TestCallable(object): +class TestCallable: def __init__(self, thing, makePathsRelative = True, debug = False): pass diff --git a/test/VariantDir/no-execute.py b/test/VariantDir/no-execute.py index 022bf7e..e9a4c48 100644 --- a/test/VariantDir/no-execute.py +++ b/test/VariantDir/no-execute.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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__" """ Verify that use of a VariantDir works when the -n option is used (and diff --git a/test/fixture/mycompile.py b/test/fixture/mycompile.py index d858f6a..0e28e5b 100644 --- a/test/fixture/mycompile.py +++ b/test/fixture/mycompile.py @@ -22,7 +22,7 @@ import fileinput import sys def fake_compile(): - skipline = f"/*{sys.argv[1]}*/\n".encode("utf-8") + skipline = f"/*{sys.argv[1]}*/\n".encode() with open(sys.argv[2], 'wb') as ofp, fileinput.input(files=sys.argv[3:], mode='rb') as ifp: for line in ifp: if line != skipline: diff --git a/test/gettext/MOFiles/UserExamples.py b/test/gettext/MOFiles/UserExamples.py index 5cc3037..4dcaa2e 100644 --- a/test/gettext/MOFiles/UserExamples.py +++ b/test/gettext/MOFiles/UserExamples.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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__" """ Make sure, that the examples given in user guide all work. diff --git a/test/packaging/option--package-type.py b/test/packaging/option--package-type.py index b9ed05e..715dc96 100644 --- a/test/packaging/option--package-type.py +++ b/test/packaging/option--package-type.py @@ -52,7 +52,6 @@ test.subdir('src') test.write( 'main', '' ) test.write('SConstruct', """ -# -*- coding: iso-8859-15 -*- env=Environment(tools=['packaging', 'filesystem', 'tar', 'rpm']) env.Prepend(RPM = 'TAR_OPTIONS=--wildcards ') env.Append(RPMFLAGS = r' --buildroot %(rpm_build_root)s') diff --git a/test/packaging/rpm/internationalization.py b/test/packaging/rpm/internationalization.py index eea30ca..6123607 100644 --- a/test/packaging/rpm/internationalization.py +++ b/test/packaging/rpm/internationalization.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # # __COPYRIGHT__ # @@ -54,7 +53,6 @@ rpm_build_root = test.workpath('rpm_build_root') test.file_fixture('src/main.c', 'main.c') test.write('SConstruct', """ -# -*- coding: utf-8 -*- import os env = Environment(tools=['default', 'packaging']) @@ -129,7 +127,6 @@ test.write( ['man.en'], '' ) test.write( ['man.fr'], '' ) test.write('SConstruct', """ -# -*- coding: utf-8 -*- import os env = Environment(tools=['default', 'packaging']) diff --git a/test/scons-time/run/option/outdir.py b/test/scons-time/run/option/outdir.py index 370974b..a067bc0 100644 --- a/test/scons-time/run/option/outdir.py +++ b/test/scons-time/run/option/outdir.py @@ -1,7 +1,8 @@ - #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -21,9 +22,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__" """ Verify specifying an alternate output directory with the --outdir option. diff --git a/test/special-filenames.py b/test/special-filenames.py index 1ba764e..6ae7afd 100644 --- a/test/special-filenames.py +++ b/test/special-filenames.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# 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 @@ -20,9 +22,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 TestSCons @@ -30,7 +29,7 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() -attempt_file_names = [ +attempt_file_names = [ 'File with spaces', 'File"with"double"quotes', "File'with'single'quotes", @@ -59,7 +58,7 @@ for fn in attempt_file_names: in_name = fn.replace('$$', '$') + '.in' test.write(in_name, fn + '\n') file_names.append(fn) - except IOError: + except OSError: # if the Python interpreter can't handle it, don't bother # testing to see if SCons can pass diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py index 5cdeea0..723b9ec 100644 --- a/testing/framework/TestCmd.py +++ b/testing/framework/TestCmd.py @@ -605,7 +605,7 @@ def match_re(lines=None, res=None): print(f"match_re: expected {len(res)} lines, found {len(lines)}") return None for i, (line, regex) in enumerate(zip(lines, res)): - s = r"^{}$".format(regex) + s = fr"^{regex}$" try: expr = re.compile(s) except re.error as e: @@ -635,7 +635,7 @@ def match_re_dotall(lines=None, res=None): lines = "\n".join(lines) if not isinstance(res, str): res = "\n".join(res) - s = r"^{}$".format(res) + s = fr"^{res}$" try: expr = re.compile(s, re.DOTALL) except re.error as e: @@ -714,7 +714,7 @@ def diff_re(a, b, fromfile: str='', tofile: str='', elif diff > 0: b = b + [''] * diff for i, (aline, bline) in enumerate(zip(a, b)): - s = r"^{}$".format(aline) + s = fr"^{aline}$" try: expr = re.compile(s) except re.error as e: diff --git a/testing/framework/TestSCons.py b/testing/framework/TestSCons.py index 0211283..39a4245 100644 --- a/testing/framework/TestSCons.py +++ b/testing/framework/TestSCons.py @@ -1835,7 +1835,7 @@ class TimeSCons(TestSCons): def uptime(self) -> None: try: fp = open('/proc/loadavg') - except EnvironmentError: + except OSError: pass else: avg1, avg5, avg15 = fp.readline().split(" ")[:3] diff --git a/testing/framework/TestUnit/__init__.py b/testing/framework/TestUnit/__init__.py index 51cf972..be5007f 100644 --- a/testing/framework/TestUnit/__init__.py +++ b/testing/framework/TestUnit/__init__.py @@ -1,4 +1,3 @@ - __all__ = ['TAPTestRunner', 'TAPTestResult', 'run'] from .taprunner import TAPTestRunner, TAPTestResult -- cgit v0.12 From 20e9f1ec80889ede2bd5a2d71536ae68b15a8786 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 4 Aug 2023 09:08:54 -0600 Subject: More conversions: {repr(var)} -> {var!r} Some of these got done in the tool conversion, some not, so picked up the rest manually. Signed-off-by: Mats Wichmann --- SCons/Tool/MSCommon/MSVC/ScriptArguments.py | 4 ++-- testing/framework/TestCmd.py | 8 ++++---- testing/framework/TestCommon.py | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py index 107e05b..8848095 100644 --- a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py +++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py @@ -235,7 +235,7 @@ def _user_script_argument_uwp(env, uwp, user_argstr) -> bool: if len(matches) > 1: debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr)) - err_msg = f"multiple uwp declarations: MSVC_SCRIPT_ARGS={repr(user_argstr)}" + err_msg = f"multiple uwp declarations: MSVC_SCRIPT_ARGS={user_argstr!r}" raise MSVCArgumentError(err_msg) if not uwp: @@ -270,7 +270,7 @@ def _msvc_script_argument_sdk_constraints(msvc, sdk_version): return None debug('invalid: method exit: sdk_version=%s', repr(sdk_version)) - err_msg = f"MSVC_SDK_VERSION ({repr(sdk_version)}) is not supported" + err_msg = f"MSVC_SDK_VERSION ({sdk_version!r}) is not supported" return err_msg def _msvc_script_argument_sdk_platform_constraints(msvc, toolset, sdk_version, platform_def): diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py index 723b9ec..48238a0 100644 --- a/testing/framework/TestCmd.py +++ b/testing/framework/TestCmd.py @@ -722,9 +722,9 @@ def diff_re(a, b, fromfile: str='', tofile: str='', raise re.error(msg % (repr(s), e.args[0])) if not expr.search(bline): result.append(f"{i + 1}c{i + 1}") - result.append(f"< {repr(a[i])}") + result.append(f"< {a[i]!r}") result.append('---') - result.append(f"> {repr(b[i])}") + result.append(f"> {b[i]!r}") return result @@ -1672,7 +1672,7 @@ class TestCmd: except subprocess.TimeoutExpired: p.terminate() stdout, stderr = p.communicate() - + # this is instead of using Popen as a context manager: if p.stdout: p.stdout.close() @@ -1683,7 +1683,7 @@ class TestCmd: p.stdin.close() finally: p.wait() - + self.status = p.returncode self.process = None diff --git a/testing/framework/TestCommon.py b/testing/framework/TestCommon.py index b0879a6..993dc02 100644 --- a/testing/framework/TestCommon.py +++ b/testing/framework/TestCommon.py @@ -369,7 +369,7 @@ class TestCommon(TestCmd): title = 'output' sys.stdout.write(f"Missing expected lines from {title}:\n") for line in missing: - sys.stdout.write(f" {repr(line)}\n") + sys.stdout.write(f" {line!r}\n") sys.stdout.write(f"{self.banner(f'{title} ')}\n") sys.stdout.write(output) self.fail_test() @@ -396,7 +396,7 @@ class TestCommon(TestCmd): title = 'output' sys.stdout.write(f"Unexpected number of lines from {title}:\n") for line in counts: - sys.stdout.write(f" {repr(line)}: found {str(counts[line])}\n") + sys.stdout.write(f" {line!r}: found {str(counts[line])}\n") sys.stdout.write(f"{self.banner(f'{title} ')}\n") sys.stdout.write(output) self.fail_test() @@ -420,7 +420,7 @@ class TestCommon(TestCmd): title = 'output' sys.stdout.write(f"Missing any expected line from {title}:\n") for line in lines: - sys.stdout.write(f" {repr(line)}\n") + sys.stdout.write(f" {line!r}\n") sys.stdout.write(f"{self.banner(f'{title} ')}\n") sys.stdout.write(output) self.fail_test() @@ -463,12 +463,12 @@ class TestCommon(TestCmd): if missing: sys.stdout.write(f"Missing expected lines from {title}:\n") for line in missing: - sys.stdout.write(f" {repr(line)}\n") + sys.stdout.write(f" {line!r}\n") sys.stdout.write(f"{self.banner(f'Missing {title} ')}\n") if out: sys.stdout.write(f"Extra unexpected lines from {title}:\n") for line in out: - sys.stdout.write(f" {repr(line)}\n") + sys.stdout.write(f" {line!r}\n") sys.stdout.write(f"{self.banner(f'Extra {title} ')}\n") sys.stdout.flush() self.fail_test() @@ -582,7 +582,7 @@ class TestCommon(TestCmd): title = 'output' sys.stdout.write(f"Unexpected lines in {title}:\n") for line in unexpected: - sys.stdout.write(f" {repr(line)}\n") + sys.stdout.write(f" {line!r}\n") sys.stdout.write(f"{self.banner(f'{title} ')}\n") sys.stdout.write(output) self.fail_test() -- cgit v0.12 From fd6676a3d652b3a5eef51879ee03515992a65732 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 23 Feb 2022 07:50:00 -0700 Subject: Change the default to error on missing SConscript This completes a change begun in 3.0.2, when the behavior changed from "skip silently" to "skip but issue a warning"; that behavior was marked deprecated in 3.1. Use must_exist=False to get the old "skip silently" behavior. Fixes #3958 Signed-off-by: Mats Wichmann --- CHANGES.txt | 3 + README.rst | 2 +- RELEASE.txt | 6 + SCons/Script/SConscript.py | 42 +++---- SCons/Script/SConscript.xml | 17 +-- SCons/Script/__init__.py | 6 +- SCons/Warnings.py | 1 + doc/man/scons.xml | 4 +- .../Old/SConscript-must_exist_deprecation.py | 57 +++++++++ test/Removed/Old/warn-missing-sconscript.py | 75 ++++++++++++ test/SConscript/must_exist.py | 135 ++++++++++++--------- test/SConscript/must_exist_deprecation.py | 57 --------- test/option/option-f.py | 62 +++++----- test/option/warn-missing-sconscript.py | 79 ------------ 14 files changed, 282 insertions(+), 264 deletions(-) create mode 100644 test/Removed/Old/SConscript-must_exist_deprecation.py create mode 100644 test/Removed/Old/warn-missing-sconscript.py delete mode 100644 test/SConscript/must_exist_deprecation.py delete mode 100644 test/option/warn-missing-sconscript.py diff --git a/CHANGES.txt b/CHANGES.txt index db96df0..30953a8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -131,6 +131,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - More tweaking of test framework overview (which is duplicated onto the website, but not in the regular documentation section). - Extend range of recognized Java versions to 20. + - Finish the change to make calling SConscript() with a nonexistent + file an error. It has issued a warning since 3.0, with "warn instead + of fail" deprecated since 3.1. Fixes #3958. From Jonathon Reinhart: - Fix another instance of `int main()` in CheckLib() causing failures diff --git a/README.rst b/README.rst index 6cc89bd..f779b0b 100755 --- a/README.rst +++ b/README.rst @@ -167,7 +167,7 @@ messages during installation like this:: Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. -If you are running on a system which uses a package manager +If you are running on a system which uses a package manager (for example most Linux distributions), you may, at your option, use the package manager (e.g. ``apt``, ``dnf``, ``yum``, ``zypper``, ``brew``, ``pacman`` etc.) to install a version diff --git a/RELEASE.txt b/RELEASE.txt index f72a2a6..59215dd 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -60,6 +60,12 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY architecture combination. For example, when using VS2022 on arm64, the arm64 native tools are only installed for the 14.3x toolsets. - Extend range of recognized Java versions to 20. +- Calling SConscript() with a nonexistent file is now an error. + Previously this succeeded - prior to SCons 3.0, silently; since 3.0, with + a warning. Developers can still instruct such an SConscript() call not + to fail by being explicit: pass keyword argument "must_exist=False". + The "--warn=missing-sconscript" commandline option is no longer available + as the warning was part of the transitional phase. FIXES ----- diff --git a/SCons/Script/SConscript.py b/SCons/Script/SConscript.py index c0b556c..28a3773 100644 --- a/SCons/Script/SConscript.py +++ b/SCons/Script/SConscript.py @@ -145,40 +145,32 @@ def Return(*vars, **kw): stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) -def handle_missing_SConscript(f, must_exist=None): +def handle_missing_SConscript(f: str, must_exist: bool = True) -> None: """Take appropriate action on missing file in SConscript() call. Print a warning or raise an exception on missing file, unless - missing is explicitly allowed by the *must_exist* value. - On first warning, print a deprecation message. + missing is explicitly allowed by the *must_exist* parameter or by + a global flag. Args: - f (str): path of missing configuration file - must_exist (bool): if true, fail. If false, but not ``None``, - allow the file to be missing. The default is ``None``, - which means issue the warning. The default is deprecated. + f: path to missing configuration file + must_exist: if true (the default), fail. If false + do nothing, allowing a build to declare it's okay to be missing. Raises: - UserError: if *must_exist* is true or if global + UserError: if *must_exist* is true or if global :data:`SCons.Script._no_missing_sconscript` is true. + + .. versionchanged: 4.6.0 + Changed default from False. """ + if not must_exist: # explicitly set False: ok + return + if not SCons.Script._no_missing_sconscript: # system default changed: ok + return + msg = f"Fatal: missing SConscript '{f.get_internal_path()}'" + raise SCons.Errors.UserError(msg) - if must_exist or (SCons.Script._no_missing_sconscript and must_exist is not False): - msg = "Fatal: missing SConscript '%s'" % f.get_internal_path() - raise SCons.Errors.UserError(msg) - - if must_exist is None: - if SCons.Script._warn_missing_sconscript_deprecated: - msg = ( - "Calling missing SConscript without error is deprecated.\n" - "Transition by adding must_exist=False to SConscript calls.\n" - "Missing SConscript '%s'" % f.get_internal_path() - ) - SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) - SCons.Script._warn_missing_sconscript_deprecated = False - else: - msg = "Ignoring missing SConscript '%s'" % f.get_internal_path() - SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg) def _SConscript(fs, *files, **kw): top = fs.Top @@ -294,7 +286,7 @@ def _SConscript(fs, *files, **kw): call_stack[-1].globals.update({__file__:old_file}) else: - handle_missing_SConscript(f, kw.get('must_exist', None)) + handle_missing_SConscript(f, kw.get('must_exist', True)) finally: SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1 diff --git a/SCons/Script/SConscript.xml b/SCons/Script/SConscript.xml index 7a4bc29..e5d9a72 100644 --- a/SCons/Script/SConscript.xml +++ b/SCons/Script/SConscript.xml @@ -538,18 +538,21 @@ TODO??? SConscript('build/SConscript', src_dir='src') If the optional must_exist -is True, +is True (the default), causes an exception to be raised if a requested -SConscript file is not found. The current default is -False, -causing only a warning to be emitted, but this default is deprecated -(since 3.1). -For scripts which truly intend to be optional, transition to -explicitly supplying +SConscript file is not found. +To allow missing scripts to be silently ignored +(the default behavior prior to &SCons; version 3.1), +pass must_exist=False to the &f-SConscript; call. +Changed in 4.6.0: must_exist +now defaults to True. + + + Here are some composite examples: diff --git a/SCons/Script/__init__.py b/SCons/Script/__init__.py index e398ecf..3249817 100644 --- a/SCons/Script/__init__.py +++ b/SCons/Script/__init__.py @@ -269,10 +269,10 @@ def HelpFunction(text, append: bool=False) -> None: # Will be non-zero if we are reading an SConscript file. sconscript_reading = 0 -_no_missing_sconscript = False -_warn_missing_sconscript_deprecated = True +_no_missing_sconscript = True +_warn_missing_sconscript_deprecated = False # TODO: now unused -def set_missing_sconscript_error(flag: int=1): +def set_missing_sconscript_error(flag: bool = True) -> bool: """Set behavior on missing file in SConscript() call. Returns: diff --git a/SCons/Warnings.py b/SCons/Warnings.py index 5c2a0db..f6809fb 100644 --- a/SCons/Warnings.py +++ b/SCons/Warnings.py @@ -70,6 +70,7 @@ class LinkWarning(WarningOnByDefault): class MisleadingKeywordsWarning(WarningOnByDefault): pass +# TODO: no longer needed, now an error instead of warning. Leave for a bit. class MissingSConscriptWarning(WarningOnByDefault): pass diff --git a/doc/man/scons.xml b/doc/man/scons.xml index 4a422be..b3bf372 100644 --- a/doc/man/scons.xml +++ b/doc/man/scons.xml @@ -2272,13 +2272,13 @@ of this tool module. - + no-object-count diff --git a/test/Removed/Old/SConscript-must_exist_deprecation.py b/test/Removed/Old/SConscript-must_exist_deprecation.py new file mode 100644 index 0000000..4c1db12 --- /dev/null +++ b/test/Removed/Old/SConscript-must_exist_deprecation.py @@ -0,0 +1,57 @@ +#!/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 deprecation warning if must_exist flag is used in an SConscript() call +""" + +import os +import TestSCons + +test = TestSCons.TestSCons() + +# catch the exception if is raised, send it on as a warning +# this gives us traceability of the line responsible +SConstruct_path = test.workpath('SConstruct') +test.file_fixture("fixture/SConstruct") + +# we should see two warnings, the second being the deprecation message. +# need to build the path in the expected msg in an OS-agnostic way +missing = os.path.normpath('missing/SConscript') +warnmsg = """ +scons: warning: Calling missing SConscript without error is deprecated. +Transition by adding must_exist=False to SConscript calls. +Missing SConscript '{}' +""".format(missing) + test.python_file_line(SConstruct_path, 18) + +expect_stderr = warnmsg +test.run(arguments=".", stderr=expect_stderr) +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/Removed/Old/warn-missing-sconscript.py b/test/Removed/Old/warn-missing-sconscript.py new file mode 100644 index 0000000..7859b64 --- /dev/null +++ b/test/Removed/Old/warn-missing-sconscript.py @@ -0,0 +1,75 @@ +#!/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. + +""" +Verify use of the --warn=missing-sconscript option. +""" + +import TestSCons + +test = TestSCons.TestSCons(match = TestSCons.match_re_dotall) + + +test.write("SConstruct", """\ +DefaultEnvironment(tools=[]) +def build(target, source, env): + pass + +env=Environment(tools=[]) +env['BUILDERS']['test'] = Builder(action=build) +env.test(target='foo', source='foo.c') +WARN = ARGUMENTS.get('WARN') +if WARN: + SetOption('warn', WARN) +SConscript('no_such_file') +""") + +test.write("foo.c",""" +#include "not_there.h" +""") + +expect = r""" +scons: warning: Calling missing SConscript without error is deprecated. +Transition by adding must_exist=False to SConscript calls. +Missing SConscript 'no_such_file' +""" + TestSCons.file_expr + +# this is the old message: +#expect = r""" +#scons: warning: Ignoring missing SConscript 'no_such_file' +"" + TestSCons.file_expr + +test.run(arguments='--warn=missing-sconscript .', stderr=expect) +test.run(arguments='--warn=no-missing-sconscript .', stderr="") +test.run(arguments='WARN=missing-sconscript .', stderr=expect) +test.run(arguments='WARN=no-missing-sconscript .', stderr="") + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/SConscript/must_exist.py b/test/SConscript/must_exist.py index 81e018a..52b3e45 100644 --- a/test/SConscript/must_exist.py +++ b/test/SConscript/must_exist.py @@ -37,76 +37,93 @@ test = TestSCons.TestSCons() # this gives us traceability of the line responsible SConstruct_path = test.workpath('SConstruct') test.write(SConstruct_path, """\ -import SCons -from SCons.Warnings import _warningOut import sys +import traceback + +import SCons.Script +from SCons.Errors import UserError +from SCons.Script.Main import find_deepest_user_frame DefaultEnvironment(tools=[]) -# 1. 1st default call should succeed with deprecation warning -try: - SConscript('missing/SConscript') -except SCons.Errors.UserError as e: - if _warningOut: - _warningOut(e) -# 2. 2nd default call should succeed with warning (no depr) + +def user_error(e): + "Synthesize msg from UserError." + # Borrowed from SCons.Script._scons_user_error which we don't use + # because it exits - we only want the message. + etype, value, tb = sys.exc_info() + filename, lineno, routine, _ = find_deepest_user_frame(traceback.extract_tb(tb)) + sys.stderr.write(f"\\nscons: *** {value}\\n") + sys.stderr.write(f'File "{filename}", line {lineno}, in {routine}\\n') + +# 1. Call with defaults raises exception try: - SConscript('missing/SConscript') -except SCons.Errors.UserError as e: - if _warningOut: - _warningOut(e) -# 3. must_exist True call should raise exception + SConscript("missing/SConscript") +except UserError as e: + user_error(e) + +# 2. Call with must_exist=True raises exception try: - SConscript('missing/SConscript', must_exist=True) -except SCons.Errors.UserError as e: - if _warningOut: - _warningOut(e) -# 4. must_exist False call should succeed silently + SConscript("missing/SConscript", must_exist=True) +except UserError as e: + user_error(e) + +# 3. Call with must_exist=False call should succeed silently try: - SConscript('missing/SConscript', must_exist=False) -except SCons.Errors.UserError as e: - if _warningOut: - _warningOut(e) -# 5. with system setting changed, should raise exception -SCons.Script.set_missing_sconscript_error() + SConscript("missing/SConscript", must_exist=False) +except UserError as e: + user_error(e) + +# 4. with system setting changed, should succeed silently +SCons.Script.set_missing_sconscript_error(flag=False) try: - SConscript('missing/SConscript') -except SCons.Errors.UserError as e: - if _warningOut: - _warningOut(e) -# 6. must_exist=False overrides system setting, should emit warning + SConscript("missing/SConscript") +except UserError as e: + user_error(e) + +# 5. must_exist=True "wins" over system setting try: - SConscript('missing/SConscript', must_exist=False) -except SCons.Errors.UserError as e: - if _warningOut: - _warningOut(e) -""") - -# we should see two exceptions as "Fatal" and -# and see four warnings, the first having the depr message -# need to build the path in the expected msg in an OS-agnostic way -missing = os.path.normpath('missing/SConscript') -warn1 = """ -scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=False to SConscript calls. -Missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 8) - -warn2 = """ -scons: warning: Ignoring missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 14) - -err1 = """ -scons: warning: Fatal: missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 23) - -err2 = """ -scons: warning: Fatal: missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 36) + SConscript("missing/SConscript", must_exist=True) +except UserError as e: + user_error(e) +""", +) + +missing = "missing/SConscript" +err1 = f""" +scons: *** Fatal: missing SConscript {missing!r} +""" + test.python_file_line( + SConstruct_path, 21 +) + +err2 = f""" +scons: *** Fatal: missing SConscript {missing!r} +""" + test.python_file_line( + SConstruct_path, 27 +) + +err3 = f""" +scons: *** Fatal: missing SConscript {missing!r} +""" + test.python_file_line( + SConstruct_path, 33 +) + +err4 = f""" +scons: *** Fatal: missing SConscript {missing!r} +""" + test.python_file_line( + SConstruct_path, 40 +) + +err5 = f""" +scons: *** Fatal: missing SConscript {missing!r} +""" + test.python_file_line( + SConstruct_path, 46 +) nowarn = "" -expect_stderr = warn1 + warn2 + err1 + nowarn + err2 + nowarn -test.run(arguments = ".", stderr = expect_stderr) +# of the five tests, we actually expect fails from 1 and 2 +expect_stderr = err1 + err2 + nowarn + nowarn + nowarn +test.run(arguments=".", stderr=expect_stderr) test.pass_test() # Local Variables: diff --git a/test/SConscript/must_exist_deprecation.py b/test/SConscript/must_exist_deprecation.py deleted file mode 100644 index 4c1db12..0000000 --- a/test/SConscript/must_exist_deprecation.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/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 deprecation warning if must_exist flag is used in an SConscript() call -""" - -import os -import TestSCons - -test = TestSCons.TestSCons() - -# catch the exception if is raised, send it on as a warning -# this gives us traceability of the line responsible -SConstruct_path = test.workpath('SConstruct') -test.file_fixture("fixture/SConstruct") - -# we should see two warnings, the second being the deprecation message. -# need to build the path in the expected msg in an OS-agnostic way -missing = os.path.normpath('missing/SConscript') -warnmsg = """ -scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=False to SConscript calls. -Missing SConscript '{}' -""".format(missing) + test.python_file_line(SConstruct_path, 18) - -expect_stderr = warnmsg -test.run(arguments=".", stderr=expect_stderr) -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/option/option-f.py b/test/option/option-f.py index e1343a6..14a7ecc 100644 --- a/test/option/option-f.py +++ b/test/option/option-f.py @@ -34,21 +34,24 @@ test.subdir('subdir') subdir_BuildThis = os.path.join('subdir', 'Buildthis') test.write('SConscript', """ -DefaultEnvironment(tools=[]) import os + +DefaultEnvironment(tools=[]) print("SConscript " + os.getcwd()) """) test.write(subdir_BuildThis, """ -DefaultEnvironment(tools=[]) import os -print("subdir/BuildThis "+ os.getcwd()) + +DefaultEnvironment(tools=[]) +print("subdir/BuildThis " + os.getcwd()) """) test.write('Build2', """ -DefaultEnvironment(tools=[]) import os -print("Build2 "+ os.getcwd()) + +DefaultEnvironment(tools=[]) +print("Build2 " + os.getcwd()) """) wpath = test.workpath() @@ -56,14 +59,15 @@ wpath = test.workpath() test.run( arguments='-f SConscript .', stdout=test.wrap_stdout( - read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + read_str=f'SConscript {wpath}\n', + build_str="scons: `.' is up to date.\n" ), ) test.run( - arguments='-f %s .' % subdir_BuildThis, + arguments=f'-f {subdir_BuildThis} .', stdout=test.wrap_stdout( - read_str='subdir/BuildThis %s\n' % wpath, + read_str=f'subdir/BuildThis {wpath}\n', build_str="scons: `.' is up to date.\n", ), ) @@ -71,14 +75,15 @@ test.run( test.run( arguments='--file=SConscript .', stdout=test.wrap_stdout( - read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + read_str=f'SConscript {wpath}\n', + build_str="scons: `.' is up to date.\n" ), ) test.run( - arguments='--file=%s .' % subdir_BuildThis, + arguments=f'--file={subdir_BuildThis} .', stdout=test.wrap_stdout( - read_str='subdir/BuildThis %s\n' % wpath, + read_str=f'subdir/BuildThis {wpath}\n', build_str="scons: `.' is up to date.\n", ), ) @@ -86,14 +91,15 @@ test.run( test.run( arguments='--makefile=SConscript .', stdout=test.wrap_stdout( - read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + read_str=f'SConscript {wpath}\n', + build_str="scons: `.' is up to date.\n" ), ) test.run( - arguments='--makefile=%s .' % subdir_BuildThis, + arguments=f'--makefile={subdir_BuildThis} .', stdout=test.wrap_stdout( - read_str='subdir/BuildThis %s\n' % wpath, + read_str=f'subdir/BuildThis {wpath}\n', build_str="scons: `.' is up to date.\n", ), ) @@ -101,14 +107,15 @@ test.run( test.run( arguments='--sconstruct=SConscript .', stdout=test.wrap_stdout( - read_str='SConscript %s\n' % wpath, build_str="scons: `.' is up to date.\n" + read_str=f'SConscript {wpath}\n', + build_str="scons: `.' is up to date.\n" ), ) test.run( - arguments='--sconstruct=%s .' % subdir_BuildThis, + arguments=f'--sconstruct={subdir_BuildThis} .', stdout=test.wrap_stdout( - read_str='subdir/BuildThis %s\n' % wpath, + read_str=f'subdir/BuildThis {wpath}\n', build_str="scons: `.' is up to date.\n", ), ) @@ -121,28 +128,21 @@ import os print("STDIN " + os.getcwd()) """, stdout=test.wrap_stdout( - read_str='STDIN %s\n' % wpath, build_str="scons: `.' is up to date.\n" + read_str=f'STDIN {wpath}\n', + build_str="scons: `.' is up to date.\n" ), ) expect = test.wrap_stdout( - read_str='Build2 %s\nSConscript %s\n' % (wpath, wpath), + read_str=f'Build2 {wpath}\nSConscript {wpath}\n', build_str="scons: `.' is up to date.\n", ) test.run(arguments='-f Build2 -f SConscript .', stdout=expect) -test.run( - arguments='-f no_such_file .', - stdout=test.wrap_stdout("scons: `.' is up to date.\n"), - stderr=None, -) - -expect = """ -scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=False to SConscript calls. -Missing SConscript 'no_such_file'""" -stderr = test.stderr() -test.must_contain_all(test.stderr(), expect) +missing = "no_such_file" +test.run(arguments=f"-f {missing} .", status=2, stderr=None) +expect = [f"scons: *** Fatal: missing SConscript {missing!r}"] +test.must_contain_all_lines(test.stderr(), expect) test.pass_test() diff --git a/test/option/warn-missing-sconscript.py b/test/option/warn-missing-sconscript.py deleted file mode 100644 index 5413229..0000000 --- a/test/option/warn-missing-sconscript.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/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. - -""" -Verify use of the --warn=missing-sconscript option. -""" - -import TestSCons - -test = TestSCons.TestSCons(match = TestSCons.match_re_dotall) - - -test.write("SConstruct", """\ -DefaultEnvironment(tools=[]) -def build(target, source, env): - pass - -env=Environment(tools=[]) -env['BUILDERS']['test'] = Builder(action=build) -env.test(target='foo', source='foo.c') -WARN = ARGUMENTS.get('WARN') -if WARN: - SetOption('warn', WARN) -SConscript('no_such_file') -""") - -test.write("foo.c",""" -#include "not_there.h" -""") - -expect = r""" -scons: warning: Calling missing SConscript without error is deprecated. -Transition by adding must_exist=False to SConscript calls. -Missing SConscript 'no_such_file' -""" + TestSCons.file_expr - -# this is the old message: -#expect = r""" -#scons: warning: Ignoring missing SConscript 'no_such_file' -"" + TestSCons.file_expr - -test.run(arguments = '--warn=missing-sconscript .', stderr = expect) - -test.run(arguments = '--warn=no-missing-sconscript .', stderr = "") - -test.run(arguments = 'WARN=missing-sconscript .', stderr = expect) - -test.run(arguments = 'WARN=no-missing-sconscript .', stderr = "") - - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: -- cgit v0.12 From da270a8b9fa2a8f19c2f56de8ccbba4d576d9326 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 6 Aug 2023 13:14:16 -0600 Subject: SConscript must_exist test: fix Windows Make the path to the missing script in expected errors be OS-independent to avoid Windows failing on wrong path separator Signed-off-by: Mats Wichmann --- test/SConscript/must_exist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConscript/must_exist.py b/test/SConscript/must_exist.py index 52b3e45..85b2438 100644 --- a/test/SConscript/must_exist.py +++ b/test/SConscript/must_exist.py @@ -88,7 +88,7 @@ except UserError as e: """, ) -missing = "missing/SConscript" +missing = os.path.join("missing", "SConscript") err1 = f""" scons: *** Fatal: missing SConscript {missing!r} """ + test.python_file_line( -- cgit v0.12 From 0654a72eb779d329421fde4fad7ee411c70f9e0d Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Mon, 7 Aug 2023 09:01:52 -0600 Subject: missing-sconscript: fix Windows test again Also dropped the word Fatal from the error, it's not consistent with any other scons-generated exception. Signed-off-by: Mats Wichmann --- SCons/Script/SConscript.py | 2 +- test/SConscript/must_exist.py | 10 +++++----- test/option/option-f.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SCons/Script/SConscript.py b/SCons/Script/SConscript.py index 28a3773..2a36a6f 100644 --- a/SCons/Script/SConscript.py +++ b/SCons/Script/SConscript.py @@ -168,7 +168,7 @@ def handle_missing_SConscript(f: str, must_exist: bool = True) -> None: return if not SCons.Script._no_missing_sconscript: # system default changed: ok return - msg = f"Fatal: missing SConscript '{f.get_internal_path()}'" + msg = f"missing SConscript file {f.get_internal_path()!r}" raise SCons.Errors.UserError(msg) diff --git a/test/SConscript/must_exist.py b/test/SConscript/must_exist.py index 85b2438..90f447e 100644 --- a/test/SConscript/must_exist.py +++ b/test/SConscript/must_exist.py @@ -90,31 +90,31 @@ except UserError as e: missing = os.path.join("missing", "SConscript") err1 = f""" -scons: *** Fatal: missing SConscript {missing!r} +scons: *** missing SConscript file {missing!r} """ + test.python_file_line( SConstruct_path, 21 ) err2 = f""" -scons: *** Fatal: missing SConscript {missing!r} +scons: *** missing SConscript file {missing!r} """ + test.python_file_line( SConstruct_path, 27 ) err3 = f""" -scons: *** Fatal: missing SConscript {missing!r} +scons: *** missing SConscript file {missing!r} """ + test.python_file_line( SConstruct_path, 33 ) err4 = f""" -scons: *** Fatal: missing SConscript {missing!r} +scons: *** missing SConscript file {missing!r} """ + test.python_file_line( SConstruct_path, 40 ) err5 = f""" -scons: *** Fatal: missing SConscript {missing!r} +scons: *** missing SConscript file {missing!r} """ + test.python_file_line( SConstruct_path, 46 ) diff --git a/test/option/option-f.py b/test/option/option-f.py index 14a7ecc..a2c8561 100644 --- a/test/option/option-f.py +++ b/test/option/option-f.py @@ -141,7 +141,7 @@ test.run(arguments='-f Build2 -f SConscript .', stdout=expect) missing = "no_such_file" test.run(arguments=f"-f {missing} .", status=2, stderr=None) -expect = [f"scons: *** Fatal: missing SConscript {missing!r}"] +expect = [f"scons: *** missing SConscript file {missing!r}"] test.must_contain_all_lines(test.stderr(), expect) test.pass_test() -- cgit v0.12 From 99e97832fc1fbb92a2d53eccb8404c711c64bdd2 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 9 Aug 2023 07:55:26 -0600 Subject: Update Help note in CHANGES, RELEASE [skip ci] Signed-off-by: Mats Wichmann --- CHANGES.txt | 6 +++--- RELEASE.txt | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d2c074d..a17c799 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -132,9 +132,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER the website, but not in the regular documentation section). - Extend range of recognized Java versions to 20. - The Help() function now takes an additional keyword argument - keep_local, which if combined with the append argument direct - help from only AddOption ("project local") calls to be kept in the - help message, not SCons' own option help. + keep_local: when starting to build a help message, you can now + retain help from AddOption calls, but omit help for SCons' own + command-line options with "Help(newtext, append=True, local_only=True)". From Jonathon Reinhart: - Fix another instance of `int main()` in CheckLib() causing failures diff --git a/RELEASE.txt b/RELEASE.txt index 22be0f5..60c361e 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -60,10 +60,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY architecture combination. For example, when using VS2022 on arm64, the arm64 native tools are only installed for the 14.3x toolsets. - Extend range of recognized Java versions to 20. -- The Help() function now takes an additional keyword argument keep_local. - On first call to Help(), if both append and keep_local are True, - the help from project AddOption calls is kept in the help message, - but not SCons' own option help. + The Help() function now takes an additional keyword argument keep_local: + when starting to build a help message, you can now retain help from AddOption + calls (options added for the project_, but omit help for SCons' own cmdline + options with "Help(newtext, append=True, local_only=True)". FIXES ----- -- cgit v0.12 From 52fbd8c9accfc6244a8c2443b46dd5cb73d0e3eb Mon Sep 17 00:00:00 2001 From: Max Bachmann Date: Sat, 12 Aug 2023 02:53:53 +0200 Subject: add missing include directories --- SCons/Platform/mingw.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SCons/Platform/mingw.py b/SCons/Platform/mingw.py index 1d38a9b..55dd3b8 100644 --- a/SCons/Platform/mingw.py +++ b/SCons/Platform/mingw.py @@ -29,5 +29,7 @@ MINGW_DEFAULT_PATHS = [] if sys.platform == 'win32': MINGW_DEFAULT_PATHS = [ r'C:\msys64', - r'C:\msys' + r'C:\msys64\usr\bin', + r'C:\msys', + r'C:\msys\usr\bin' ] -- cgit v0.12 From 78d27feb199a04713373660bd62167dad6f4a6e7 Mon Sep 17 00:00:00 2001 From: Max Bachmann Date: Sat, 12 Aug 2023 11:52:12 +0200 Subject: add changelog entry --- CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index db96df0..dabeee7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -136,6 +136,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix another instance of `int main()` in CheckLib() causing failures when using -Wstrict-prototypes. + From Max Bachmann: + - Add missing directories to searched paths for mingw installs RELEASE 4.5.2 - Sun, 21 Mar 2023 14:08:29 -0700 -- cgit v0.12 From e98715057f2f95fd5713b023de2090a5960e81c6 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 24 Aug 2023 11:00:17 -0700 Subject: [ci skip] added blurb to RELEASE.txt. Reordered items in CHANGES.txt be alphbetical by last name --- CHANGES.txt | 18 +++++++++--------- RELEASE.txt | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index dabeee7..126651a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,12 +9,8 @@ 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: - - The --debug flag now has a 'json' option which will write information - generated by --debug={count, memory, time, action-timestamps} and about - the build. - - Obsoleted YACCVCGFILESUFFIX, being replaced by YACC_GRAPH_FILE_SUFFIX. - If YACC_GRAPH_FILE_SUFFIX is not set, it will respect YACCVCGFILESUFFIX. + From Max Bachmann: + - Add missing directories to searched paths for mingw installs From Joseph Brill: - Fix issue #4312: the cached installed msvc list had an indirect dependency @@ -43,6 +39,13 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Add arm64 to the MSVS supported architectures list for VS2017 and later to be consistent with the current documentation of MSVS_ARCH. + From William Deegan: + - The --debug flag now has a 'json' option which will write information + generated by --debug={count, memory, time, action-timestamps} and about + the build. + - 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 @@ -136,9 +139,6 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix another instance of `int main()` in CheckLib() causing failures when using -Wstrict-prototypes. - From Max Bachmann: - - Add missing directories to searched paths for mingw installs - RELEASE 4.5.2 - Sun, 21 Mar 2023 14:08:29 -0700 From Michał Górny: diff --git a/RELEASE.txt b/RELEASE.txt index f72a2a6..42199c1 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -60,6 +60,7 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY architecture combination. For example, when using VS2022 on arm64, the arm64 native tools are only installed for the 14.3x toolsets. - Extend range of recognized Java versions to 20. +- Add missing directories to searched paths for mingw installs FIXES ----- -- cgit v0.12