summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W <garlicbready@googlemail.com>2017-08-02 13:04:08 (GMT)
committerRichard W <garlicbready@googlemail.com>2017-08-02 13:04:08 (GMT)
commit3f97b5364380d51a446786fc6514f9e29e26ea4a (patch)
treefe3306419eff308b602775b880ca258f60484950
parent11e0313db795b4d160219fd939e15e479fcbbfd9 (diff)
parent8093bd31e5a12c8e17b9953732020c39c1eb09c4 (diff)
downloadSCons-3f97b5364380d51a446786fc6514f9e29e26ea4a.zip
SCons-3f97b5364380d51a446786fc6514f9e29e26ea4a.tar.gz
SCons-3f97b5364380d51a446786fc6514f9e29e26ea4a.tar.bz2
Merged scons/scons into default
-rw-r--r--src/CHANGES.txt2
-rw-r--r--src/engine/SCons/Action.py83
-rw-r--r--src/engine/SCons/ActionTests.py190
-rw-r--r--src/engine/SCons/Environment.py24
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