diff options
author | Richard W <garlicbready@googlemail.com> | 2017-08-02 13:04:08 (GMT) |
---|---|---|
committer | Richard W <garlicbready@googlemail.com> | 2017-08-02 13:04:08 (GMT) |
commit | 3f97b5364380d51a446786fc6514f9e29e26ea4a (patch) | |
tree | fe3306419eff308b602775b880ca258f60484950 | |
parent | 11e0313db795b4d160219fd939e15e479fcbbfd9 (diff) | |
parent | 8093bd31e5a12c8e17b9953732020c39c1eb09c4 (diff) | |
download | SCons-3f97b5364380d51a446786fc6514f9e29e26ea4a.zip SCons-3f97b5364380d51a446786fc6514f9e29e26ea4a.tar.gz SCons-3f97b5364380d51a446786fc6514f9e29e26ea4a.tar.bz2 |
Merged scons/scons into default
-rw-r--r-- | src/CHANGES.txt | 2 | ||||
-rw-r--r-- | src/engine/SCons/Action.py | 83 | ||||
-rw-r--r-- | src/engine/SCons/ActionTests.py | 190 | ||||
-rw-r--r-- | src/engine/SCons/Environment.py | 24 |
4 files changed, 168 insertions, 131 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index aa22e5e..d032949 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -42,6 +42,8 @@ may cause rebuilds. In no case should rebuilds not happen. tool found is used) - Fixed MSVSProject example code (http://scons.tigris.org/issues/show_bug.cgi?id=2979) - Defined MS SDK 10.0 and Changed VS 2015 to use SDK 10.0 + - Changes to Action Function and Action Class signiture creation. NOTE: This will cause rebuilds + for many builds when upgrading to SCons 3.0 From Daniel Holth: - Add basic support for PyPy (by deleting __slots__ from Node with a diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 118c495..d6fe30b 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -105,6 +105,8 @@ import pickle import re import sys import subprocess +import itertools +import inspect import SCons.Debug from SCons.Debug import logInstanceCreation @@ -195,8 +197,11 @@ def _object_contents(obj): except AttributeError as ae: # Should be a pickle-able Python object. try: - return pickle.dumps(obj, ACTION_SIGNATURE_PICKLE_PROTOCOL) - except (pickle.PicklingError, TypeError, AttributeError): + return _object_instance_content(obj) + # pickling an Action instance or object doesn't yield a stable + # content as instance property may be dumped in different orders + # return pickle.dumps(obj, ACTION_SIGNATURE_PICKLE_PROTOCOL) + except (pickle.PicklingError, TypeError, AttributeError) as ex: # This is weird, but it seems that nested classes # are unpickable. The Python docs say it should # always be a PicklingError, but some Python @@ -205,7 +210,7 @@ def _object_contents(obj): return bytearray(repr(obj), 'utf-8') -def _code_contents(code): +def _code_contents(code, docstring=None): """Return the signature contents of a code object. By providing direct access to the code object of the @@ -252,12 +257,7 @@ def _code_contents(code): # function. Note that we have to call _object_contents on each # constants because the code object of nested functions can # show-up among the constants. - # - # Note that we also always ignore the first entry of co_consts - # which contains the function doc string. We assume that the - # function does not access its doc string. - # NOTE: This is not necessarily true. If no docstring, then co_consts[0] does - # have a string which is used. + z = [_object_contents(cc) for cc in code.co_consts[1:]] contents.extend(b',(') contents.extend(bytearray(',', 'utf-8').join(z)) @@ -296,7 +296,7 @@ def _function_contents(func): func.__closure__ - None or a tuple of cells that contain bindings for the function's free variables. """ - contents = [_code_contents(func.__code__)] + contents = [_code_contents(func.__code__, func.__doc__)] # The function contents depends on the value of defaults arguments if func.__defaults__: @@ -308,15 +308,12 @@ def _function_contents(func): defaults.extend(b')') contents.append(defaults) - - # contents.append(bytearray(',(','utf-8') + b','.join(function_defaults_contents) + bytearray(')','utf-8')) else: contents.append(b',()') # The function contents depends on the closure captured cell values. closure = func.__closure__ or [] - #xxx = [_object_contents(x.cell_contents) for x in closure] try: closure_contents = [_object_contents(x.cell_contents) for x in closure] except AttributeError: @@ -325,10 +322,66 @@ def _function_contents(func): contents.append(b',(') contents.append(bytearray(b',').join(closure_contents)) contents.append(b')') - # contents.append(b'BBBBBBBB') - return bytearray(b'').join(contents) + retval = bytearray(b'').join(contents) + return retval + +def _object_instance_content(obj): + """ + Returns consistant content for a action class or an instance thereof + :param obj: Should be either and action class or an instance thereof + :return: bytearray or bytes representing the obj suitable for generating + a signiture from. + """ + retval = bytearray() + + if obj is None: + return b'N.' + + if isinstance(obj, SCons.Util.BaseStringTypes): + return SCons.Util.to_bytes(obj) + + inst_class = obj.__class__ + inst_class_name = bytearray(obj.__class__.__name__,'utf-8') + inst_class_module = bytearray(obj.__class__.__module__,'utf-8') + inst_class_hierarchy = bytearray(repr(inspect.getclasstree([obj.__class__,])),'utf-8') + # print("ICH:%s : %s"%(inst_class_hierarchy, repr(obj))) + + properties = [(p, getattr(obj, p, "None")) for p in dir(obj) if not (p[:2] == '__' or inspect.ismethod(getattr(obj, p)) or inspect.isbuiltin(getattr(obj,p))) ] + properties.sort() + properties_str = ','.join(["%s=%s"%(p[0],p[1]) for p in properties]) + properties_bytes = bytearray(properties_str,'utf-8') + + methods = [p for p in dir(obj) if inspect.ismethod(getattr(obj, p))] + methods.sort() + + method_contents = [] + for m in methods: + # print("Method:%s"%m) + v = _function_contents(getattr(obj, m)) + # print("[%s->]V:%s [%s]"%(m,v,type(v))) + method_contents.append(v) + + retval = bytearray(b'{') + retval.extend(inst_class_name) + retval.extend(b":") + retval.extend(inst_class_module) + retval.extend(b'}[[') + retval.extend(inst_class_hierarchy) + retval.extend(b']]{{') + retval.extend(bytearray(b",").join(method_contents)) + retval.extend(b"}}{{{") + retval.extend(properties_bytes) + retval.extend(b'}}}') + return retval + + # print("class :%s"%inst_class) + # print("class_name :%s"%inst_class_name) + # print("class_module :%s"%inst_class_module) + # print("Class hier :\n%s"%pp.pformat(inst_class_hierarchy)) + # print("Inst Properties:\n%s"%pp.pformat(properties)) + # print("Inst Methods :\n%s"%pp.pformat(methods)) def _actionAppend(act1, act2): # This function knows how to slap two actions together. diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 34d9ffc..9d856c9 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -1428,16 +1428,12 @@ class CommandGeneratorActionTestCase(unittest.TestCase): def LocalFunc(): pass - if TestCmd.IS_PY3 and TestCmd.IS_WINDOWS: - func_matches = [ - b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()', # PY 3.6 - b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()', # PY 3.5 - ] - else: - func_matches = [ - b"0, 0, 0, 0,(),(),(d\000\000S),(),()", - b"0, 0, 0, 0,(),(),(d\x00\x00S),(),()", - ] + # Since the python bytecode has per version differences, we need different expected results per version + func_matches = { + (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + } meth_matches = [ b"1, 1, 0, 0,(),(),(d\000\000S),(),()", @@ -1454,11 +1450,11 @@ class CommandGeneratorActionTestCase(unittest.TestCase): a = self.factory(f_global) c = a.get_contents(target=[], source=[], env=env) - assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches]) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+repr(func_matches[sys.version_info[:2]]) a = self.factory(f_local) c = a.get_contents(target=[], source=[], env=env) - assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches]) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+repr(func_matches[sys.version_info[:2]]) def f_global(target, source, env, for_signature): return SCons.Action.Action(GlobalFunc, varlist=['XYZ']) @@ -1466,7 +1462,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase): def f_local(target, source, env, for_signature): return SCons.Action.Action(LocalFunc, varlist=['XYZ']) - matches_foo = [x + b"foo" for x in func_matches] + matches_foo = func_matches[sys.version_info[:2]] + b'foo' a = self.factory(f_global) c = a.get_contents(target=[], source=[], env=env) @@ -1596,52 +1592,48 @@ class FunctionActionTestCase(unittest.TestCase): def LocalFunc(): pass - if TestCmd.IS_PY3 and TestCmd.IS_WINDOWS: - func_matches = [ - b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()', # py 3.6 - b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()' # py 3.5 - ] - meth_matches = [ - b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()', # py 3.6 - b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()', # py 3.5 - ] - - else: - func_matches = [ - b"0, 0, 0, 0,(),(),(d\000\000S),(),()", - b"0, 0, 0, 0,(),(),(d\x00\x00S),(),()", - ] + func_matches = { + (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + } - meth_matches = [ - b"1, 1, 0, 0,(),(),(d\000\000S),(),()", - b"1, 1, 0, 0,(),(),(d\x00\x00S),(),()", - ] + meth_matches = { + (2,7) : bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,5) : bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,6) : bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'), + } def factory(act, **kw): return SCons.Action.FunctionAction(act, kw) a = factory(GlobalFunc) c = a.get_contents(target=[], source=[], env=Environment()) - assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches]) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) a = factory(LocalFunc) c = a.get_contents(target=[], source=[], env=Environment()) - assert c in func_matches, repr(c) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) - matches_foo = [x + b"foo" for x in func_matches] + matches_foo = func_matches[sys.version_info[:2]] + b'foo' a = factory(GlobalFunc, varlist=['XYZ']) c = a.get_contents(target=[], source=[], env=Environment()) - assert c in func_matches, repr(c) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) + # assert c in func_matches, repr(c) + c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo')) - assert c in matches_foo, repr(c) + assert c == matches_foo, repr(c) ##TODO: is this set of tests still needed? # Make sure a bare string varlist works a = factory(GlobalFunc, varlist='XYZ') c = a.get_contents(target=[], source=[], env=Environment()) - assert c in func_matches, repr(c) + # assert c in func_matches, repr(c) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) + + c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo')) assert c in matches_foo, repr(c) @@ -1658,7 +1650,7 @@ class FunctionActionTestCase(unittest.TestCase): lc = LocalClass() a = factory(lc.LocalMethod) c = a.get_contents(target=[], source=[], env=Environment()) - assert c in meth_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in meth_matches]) + assert c == meth_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(meth_matches[sys.version_info[:2]]) def test_strfunction(self): """Test the FunctionAction.strfunction() method @@ -1824,16 +1816,12 @@ class LazyActionTestCase(unittest.TestCase): def LocalFunc(): pass - if TestCmd.IS_PY3 and TestCmd.IS_WINDOWS: - func_matches = [ - b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()', - b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()' - ] - else: - func_matches = [ - b"0, 0, 0, 0,(),(),(d\000\000S),(),()", - b"0, 0, 0, 0,(),(),(d\x00\x00S),(),()", - ] + + func_matches = { + (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'), + (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'), + } meth_matches = [ b"1, 1, 0, 0,(),(),(d\000\000S),(),()", @@ -1848,17 +1836,22 @@ class LazyActionTestCase(unittest.TestCase): env = Environment(FOO = factory(GlobalFunc)) c = a.get_contents(target=[], source=[], env=env) - assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches]) + # assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches]) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) + + env = Environment(FOO = factory(LocalFunc)) c = a.get_contents(target=[], source=[], env=env) - assert c in func_matches, repr(c) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) + + # matches_foo = [x + b"foo" for x in func_matches] + matches_foo = func_matches[sys.version_info[:2]] + b'foo' - matches_foo = [x + b"foo" for x in func_matches] env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ'])) c = a.get_contents(target=[], source=[], env=env) - assert c in func_matches, repr(c) + assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]]) env['XYZ'] = 'foo' c = a.get_contents(target=[], source=[], env=env) @@ -1881,32 +1874,23 @@ class ActionCallerTestCase(unittest.TestCase): def LocalFunc(): pass - if TestCmd.IS_PY3 and TestCmd.IS_WINDOWS: - matches = [ - b'd\x00S\x00', - b'd\x00\x00S' - ] - else: - matches = [ - b"d\000\000S", - b"d\\x00\\x00S" - ] + + matches = { + (2,7) : b'd\x00\x00S', + (3,5) : b'd\x00\x00S', + (3,6) : b'd\x00S\x00', + } + af = SCons.Action.ActionFactory(GlobalFunc, strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c in matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in matches]) + assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]]) af = SCons.Action.ActionFactory(LocalFunc, strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c in matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in matches]) - - # TODO: Same as above, why redefine? - # matches = [ - # b'd\000\000S', - # b"d\x00\x00S" - # ] + assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]]) class LocalActFunc(object): def __call__(self): @@ -1915,12 +1899,12 @@ class ActionCallerTestCase(unittest.TestCase): af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c in matches, "C [%s] not in matches [%s]"%(repr(c),matches) + assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]]) af = SCons.Action.ActionFactory(LocalActFunc(), strfunc) ac = SCons.Action.ActionCaller(af, [], {}) c = ac.get_contents([], [], Environment()) - assert c in matches, repr(c) + assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]]) matches = [ b"<built-in function str>", @@ -2054,7 +2038,7 @@ class ActionCompareTestCase(unittest.TestCase): assert dog.get_name(env) == 'DOG', dog.get_name(env) -class TestClass: +class TestClass(object): """A test class used by ObjectContentsTestCase.test_object_contents""" def __init__(self): self.a = "a" @@ -2072,16 +2056,17 @@ class ObjectContentsTestCase(unittest.TestCase): """A test function""" return a + # Since the python bytecode has per version differences, we need different expected results per version + expected = { + (2,7) : bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'), + (3,5) : bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'), + (3,6) : bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'), + } + c = SCons.Action._function_contents(func1) - if TestCmd.IS_PY3 and TestCmd.IS_WINDOWS: - expected = [b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()', - b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'] - else: - expected = [b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'] - assert c in expected, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(e) for e in expected]) + assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+repr(expected[sys.version_info[:2]]) - # @unittest.skip("Results vary between py2 and py3, not sure if test makes sense to implement") def test_object_contents(self): """Test that Action._object_contents works""" @@ -2089,39 +2074,31 @@ class ObjectContentsTestCase(unittest.TestCase): o = TestClass() c = SCons.Action._object_contents(o) - if TestCmd.IS_PY3: - if TestCmd.IS_WINDOWS: - expected = [b'ccopy_reg\n_reconstructor\nq\x00(c__main__\nTestClass\nq\x01c__builtin__\nobject\nq\x02Ntq\x03Rq\x04}q\x05(X\x01\x00\x00\x00aq\x06h\x06X\x01\x00\x00\x00bq\x07h\x07ub.', # py 3.6 - b'ccopy_reg\n_reconstructor\nq\x00(c__main__\nTestClass\nq\x01c__builtin__\nobject\nq\x02Ntq\x03Rq\x04}q\x05(X\x01\x00\x00\x00bq\x06h\x06X\x01\x00\x00\x00aq\x07h\x07ub.', # py 3.5 - ] - else: - expected = [b'ccopy_reg\n_reconstructor\nq\x00(c__main__\nTestClass\nq\x01c__builtin__\nobject\nq\x02Ntq\x03Rq\x04}q\x05(X\x01\x00\x00\x00bq\x06h\x06X\x01\x00\x00\x00aq\x07h\x07ub.'] - else: - if TestCmd.IS_WINDOWS: - expected = [b'(c__main__\nTestClass\nq\x01oq\x02}q\x03(U\x01aU\x01aU\x01bU\x01bub.'] - else: - expected = [b'(c__main__\nTestClass\nq\x01oq\x02}q\x03(U\x01aU\x01aU\x01bU\x01bub.'] + # c = SCons.Action._object_instance_content(o) + + # Since the python bytecode has per version differences, we need different expected results per version + expected = { + (2,7): bytearray(b"{TestClass:__main__}[[[(<type \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<type \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"), + (3,5): bytearray(b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"), + (3,6): bytearray(b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"), + } - assert c in expected, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(e) for e in expected]) + assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+repr(expected[sys.version_info[:2]]) - # @unittest.skip("Results vary between py2 and py3, not sure if test makes sense to implement") def test_code_contents(self): """Test that Action._code_contents works""" code = compile("print('Hello, World!')", '<string>', 'exec') c = SCons.Action._code_contents(code) - if TestCmd.IS_PY3: - if TestCmd.IS_WINDOWS: - expected = [b'0, 0, 0, 0,(N.),(X\x05\x00\x00\x00printq\x00.),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)', - b'0, 0, 0, 0,(N.),(X\x05\x00\x00\x00printq\x00.),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)' - ] - else: - expected = [b'0, 0, 0, 0,(N.),(X\x05\x00\x00\x00printq\x00.),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'] - else: - expected = [b"0, 0, 0, 0,(N.),(),(d\x00\x00GHd\x01\x00S)"] - assert c in expected, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(e) for e in expected]) + # Since the python bytecode has per version differences, we need different expected results per version + expected = { + (2,7) : bytearray(b'0, 0, 0, 0,(N.),(),(d\x00\x00GHd\x01\x00S)'), + (3,5) : bytearray(b'0, 0, 0, 0,(N.),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'), + (3,6) : bytearray(b'0, 0, 0, 0,(N.),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'), + } + assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+expected[sys.version_info[:2]] @@ -2144,6 +2121,9 @@ if __name__ == "__main__": TestUnit.run(suite) + # Swap this for above to debug otherwise you can't run individual tests as TestUnit is swallowing arguments + # unittest.main() + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 85f9fa7..60a45e4 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -2368,19 +2368,21 @@ class OverrideEnvironment(Base): Environment = Base -# An entry point for returning a proxy subclass instance that overrides -# the subst*() methods so they don't actually perform construction -# variable substitution. This is specifically intended to be the shim -# layer in between global function calls (which don't want construction -# variable substitution) and the DefaultEnvironment() (which would -# substitute variables if left to its own devices).""" -# -# We have to wrap this in a function that allows us to delay definition of -# the class until it's necessary, so that when it subclasses Environment -# it will pick up whatever Environment subclass the wrapper interface -# might have assigned to SCons.Environment.Environment. def NoSubstitutionProxy(subject): + """ + An entry point for returning a proxy subclass instance that overrides + the subst*() methods so they don't actually perform construction + variable substitution. This is specifically intended to be the shim + layer in between global function calls (which don't want construction + variable substitution) and the DefaultEnvironment() (which would + substitute variables if left to its own devices). + + We have to wrap this in a function that allows us to delay definition of + the class until it's necessary, so that when it subclasses Environment + it will pick up whatever Environment subclass the wrapper interface + might have assigned to SCons.Environment.Environment. + """ class _NoSubstitutionProxy(Environment): def __init__(self, subject): self.__dict__['__subject'] = subject |