From 52773da0faddc808056ffec34ed0112e2b42b5f7 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Fri, 15 May 2020 23:31:41 -0400 Subject: use signature to check function signature instead of relying on TypeErrors --- SCons/Subst.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SCons/Subst.py b/SCons/Subst.py index a1ef053..29698d5 100644 --- a/SCons/Subst.py +++ b/SCons/Subst.py @@ -30,7 +30,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import collections import re - +from inspect import signature import SCons.Errors from SCons.Util import is_String, is_Sequence @@ -420,12 +420,13 @@ class StringSubber(object): return conv(substitute(l, lvars)) return list(map(func, s)) elif callable(s): - try: + if (s and + set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])): s = s(target=lvars['TARGETS'], source=lvars['SOURCES'], env=self.env, for_signature=(self.mode != SUBST_CMD)) - except TypeError: + else: # This probably indicates that it's a callable # object that doesn't match our calling arguments # (like an Action). -- cgit v0.12 From cffd40b44080dcce1d238d037e026051eaa7a60b Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 17 May 2020 15:41:12 -0400 Subject: cover other type of subber and add test --- SCons/Subst.py | 5 +++-- test/Subst/TypeError.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/SCons/Subst.py b/SCons/Subst.py index 29698d5..fbb89b3 100644 --- a/SCons/Subst.py +++ b/SCons/Subst.py @@ -591,12 +591,13 @@ class ListSubber(collections.UserList): self.substitute(a, lvars, 1) self.next_word() elif callable(s): - try: + if (s and + set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])): s = s(target=lvars['TARGETS'], source=lvars['SOURCES'], env=self.env, for_signature=(self.mode != SUBST_CMD)) - except TypeError: + else: # This probably indicates that it's a callable # object that doesn't match our calling arguments # (like an Action). diff --git a/test/Subst/TypeError.py b/test/Subst/TypeError.py index 628db2f..b288961 100644 --- a/test/Subst/TypeError.py +++ b/test/Subst/TypeError.py @@ -85,8 +85,36 @@ expect = expect_build % (r' \[foo\.bar\]', r'\$\{func\(1\)\}') test.run(status=2, stderr=expect) +# callable exceptions: +test.write('foo.c', """\ +#include +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("foo.c"); + exit (0); +} +""") + +test.write('SConstruct', """\ +class TestCallable(object): + def __init__(self, thing, makePathsRelative = True, debug = False): + pass + def __call__(self, target, source, env, for_signature): + raise TypeError("User callable exception") + +env = Environment() +env["TESTCLASS"] = TestCallable +env["CCCOM"] = "$CC $_CCCOMCOM $CCFLAGS -o ${TESTCLASS('$TARGET')} -c ${TESTCLASS('$SOURCES')}" + +env.Program(target='foo', source='foo.c') +""") +test.run(status=2, stderr=r'.*TypeError\s:\sUser\scallable\sexception.*') +print(test.stdout()) test.pass_test() # Local Variables: -- cgit v0.12 From 2a9eb7778a553d44bb2103953b4d563c9dab59d7 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 17 May 2020 23:17:43 -0400 Subject: update CHANGES.txt --- CHANGES.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 431ecc1..e22dafd 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -10,12 +10,6 @@ NOTE: Please include a reference to any Issues resolved by your changes in the b RELEASE VERSION/DATE TO BE FILLED IN LATER - From Daniel Moody: - - Add no_progress (-Q) option as a set-able option. However, setting it in the - SConstruct/SConscript will still cause "scons: Reading SConscript files ..." to be - printed, since the option is not set when the build scripts first get read. - - Added check for SONAME in environment to setup symlinks correctly (Github Issue #3246) - From James Benton: - Improve Visual Studio solution/project generation code to add support for a per-variant cppflags. Intellisense can be affected by cppflags, @@ -86,6 +80,16 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER macro which is not located in a state TABLE. * Cleanup CPP expressions before evaluating (strip comments, carriage returns) + From Daniel Moody: + - Add no_progress (-Q) option as a set-able option. However, setting it in the + SConstruct/SConscript will still cause "scons: Reading SConscript files ..." to be + printed, since the option is not set when the build scripts first get read. + - Added check for SONAME in environment to setup symlinks correctly (Github Issue #3246) + - User callable's called during substition expansion could possibly throw a TypeError + exception, however SCons was using TypeError to detect if the callable had a different + signature than expected, and would silently fail to report user's exceptions. Fixed to + use signature module to detect function signature instead of TypeError. (Github Issue #3654) + From Andrew Morrow: - Fix Issue #3469 - Fixed improper reuse of temporary and compiled files by Configure when changing the order and/or number of tests. This is done by using the hash of the generated temporary files -- cgit v0.12 From 23a99693e3603a47f4bcb7b08351a774923b0f2e Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Mon, 18 May 2020 17:24:40 -0400 Subject: add check for SCons null class --- SCons/Subst.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/SCons/Subst.py b/SCons/Subst.py index fbb89b3..cc2eeab 100644 --- a/SCons/Subst.py +++ b/SCons/Subst.py @@ -420,7 +420,10 @@ class StringSubber(object): return conv(substitute(l, lvars)) return list(map(func, s)) elif callable(s): - if (s and + # SCons has the unusual Null class where any __getattr__ call returns it's self, + # which does not work the signature module, and the Null class returns an empty + # string if called on, so we make an exception in this condition for Null class + if (isinstance(s, SCons.Util.Null) or set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])): s = s(target=lvars['TARGETS'], source=lvars['SOURCES'], @@ -591,7 +594,10 @@ class ListSubber(collections.UserList): self.substitute(a, lvars, 1) self.next_word() elif callable(s): - if (s and + # SCons has the unusual Null class where any __getattr__ call returns it's self, + # which does not work the signature module, and the Null class returns an empty + # string if called on, so we make an exception in this condition for Null class + if (isinstance(s, SCons.Util.Null) or set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])): s = s(target=lvars['TARGETS'], source=lvars['SOURCES'], -- cgit v0.12 From deacd0898818a0358fc29e0edff387acda5b7bc5 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Tue, 19 May 2020 17:14:41 -0400 Subject: used fixtures in test TypeError test --- test/Subst/TypeError.py | 32 +++--------------------- test/Subst/fixture/SConstruct.callable_exception | 11 ++++++++ 2 files changed, 15 insertions(+), 28 deletions(-) create mode 100644 test/Subst/fixture/SConstruct.callable_exception diff --git a/test/Subst/TypeError.py b/test/Subst/TypeError.py index b288961..c52434f 100644 --- a/test/Subst/TypeError.py +++ b/test/Subst/TypeError.py @@ -85,36 +85,12 @@ expect = expect_build % (r' \[foo\.bar\]', r'\$\{func\(1\)\}') test.run(status=2, stderr=expect) -# callable exceptions: -test.write('foo.c', """\ -#include -#include -int -main(int argc, char *argv[]) -{ - argv[argc++] = "--"; - printf("foo.c"); - exit (0); -} -""") - -test.write('SConstruct', """\ - -class TestCallable(object): - def __init__(self, thing, makePathsRelative = True, debug = False): - pass - def __call__(self, target, source, env, for_signature): - raise TypeError("User callable exception") - -env = Environment() -env["TESTCLASS"] = TestCallable -env["CCCOM"] = "$CC $_CCCOMCOM $CCFLAGS -o ${TESTCLASS('$TARGET')} -c ${TESTCLASS('$SOURCES')}" - -env.Program(target='foo', source='foo.c') -""") +# user callable exceptions (Github issue #3654): +test.file_fixture('test_main.c') +test.file_fixture('./fixture/SConstruct.callable_exception', 'SConstruct') test.run(status=2, stderr=r'.*TypeError\s:\sUser\scallable\sexception.*') -print(test.stdout()) + test.pass_test() # Local Variables: diff --git a/test/Subst/fixture/SConstruct.callable_exception b/test/Subst/fixture/SConstruct.callable_exception new file mode 100644 index 0000000..3f1b337 --- /dev/null +++ b/test/Subst/fixture/SConstruct.callable_exception @@ -0,0 +1,11 @@ +class TestCallable(object): + def __init__(self, thing, makePathsRelative = True, debug = False): + pass + def __call__(self, target, source, env, for_signature): + raise TypeError("User callable exception") + +env = Environment() +env["TESTCLASS"] = TestCallable +env["CCCOM"] = "$CC $_CCCOMCOM $CCFLAGS -o ${TESTCLASS('$TARGET')} -c ${TESTCLASS('$SOURCES')}" + +env.Program(target='test_main', source='test_main.c') \ No newline at end of file -- cgit v0.12