From a6ea2d760464092ea91a0dd01ba6260288aa3587 Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Sun, 20 Apr 2014 06:56:10 -0400 Subject: Added six module as SCons.compat.six, for python3 port. --- QMTest/TestCmd.py | 4 +- QMTest/TestCmdTests.py | 50 +-- bin/install_scons.py | 2 +- review.py | 8 +- runtest.py | 5 +- src/engine/SCons/MemoizeTests.py | 2 +- src/engine/SCons/Script/Main.py | 2 +- src/engine/SCons/Taskmaster.py | 10 +- src/engine/SCons/Tool/xgettext.py | 30 +- src/engine/SCons/Util.py | 32 +- src/engine/SCons/UtilTests.py | 6 +- src/engine/SCons/compat/_scons_subprocess.py | 2 +- src/engine/SCons/compat/six.py | 646 +++++++++++++++++++++++++++ src/engine/SCons/compat/sixTests.py | 34 ++ src/script/sconsign.py | 4 +- test/option/profile.py | 4 +- 16 files changed, 760 insertions(+), 81 deletions(-) create mode 100755 src/engine/SCons/compat/six.py create mode 100644 src/engine/SCons/compat/sixTests.py diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py index 55c198f..e6b128b 100644 --- a/QMTest/TestCmd.py +++ b/QMTest/TestCmd.py @@ -287,7 +287,7 @@ version. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. from __future__ import division, print_function -from six import PY3 +from SCons.compat.six import PY3 __author__ = "Steven Knight " __revision__ = "TestCmd.py 1.3.D001 2010/06/03 12:58:27 knight" @@ -685,7 +685,7 @@ if subprocess.mswindows: assert ol is None lpBuffer = ctypes.create_string_buffer(bufSize) bytesRead = DWORD() - bErr = ctypes.windll.kernel32.ReadFile( + bErr = ctypes.windll.kernel32.ReadFile( hFile, lpBuffer, bufSize, ctypes.byref(bytesRead), ol) if not bErr: raise ctypes.WinError() return (0, ctypes.string_at(lpBuffer, bytesRead.value)) diff --git a/QMTest/TestCmdTests.py b/QMTest/TestCmdTests.py index 6611590..a2e7022 100644 --- a/QMTest/TestCmdTests.py +++ b/QMTest/TestCmdTests.py @@ -19,7 +19,7 @@ AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. """ -from six import PY3 +from SCons.compat.six import PY3 __author__ = "Steven Knight " __revision__ = "TestCmdTests.py 1.3.D001 2010/06/03 12:58:27 knight" @@ -1870,24 +1870,24 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 1) - + sys.stdout = StringIO() sys.stderr = StringIO() - + test.run(arguments = ['arg1 arg2']) o = sys.stdout.getvalue() assert o == '', o e = sys.stderr.getvalue() expect = 'python "%s" "arg1 arg2"\n' % t.script_path assert expect == e, (expect, e) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 1) - + sys.stdout = StringIO() sys.stderr = StringIO() - + testx.run(arguments = ['arg1 arg2']) expect = '"%s" "arg1 arg2"\n' % t.scriptx_path o = sys.stdout.getvalue() @@ -1921,10 +1921,10 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 2) - + sys.stdout = StringIO() sys.stderr = StringIO() - + test.run(arguments = ['arg1 arg2']) line_fmt = "script: %s: %s: ['arg1 arg2']\n" @@ -1938,14 +1938,14 @@ class run_verbose_TestCase(TestCmdTestCase): expect = 'python "%s" "arg1 arg2"\n' % t.script_path e = sys.stderr.getvalue() assert e == expect, (e, expect) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 2) - + sys.stdout = StringIO() sys.stderr = StringIO() - + testx.run(arguments = ['arg1 arg2']) line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" @@ -1966,10 +1966,10 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 2) - + sys.stdout = StringIO() sys.stderr = StringIO() - + test.run(arguments = ['arg1 arg2']) line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" @@ -1986,10 +1986,10 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 3) - + sys.stdout = StringIO() sys.stderr = StringIO() - + test.run(arguments = ['arg1 arg2']) line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" @@ -2010,10 +2010,10 @@ class run_verbose_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(program = t.script, interpreter = 'python', workdir = '') - + sys.stdout = StringIO() sys.stderr = StringIO() - + test.run(arguments = ['arg1 arg2']) line_fmt = "script: %s: %s: ['arg1 arg2']\n" @@ -2027,13 +2027,13 @@ class run_verbose_TestCase(TestCmdTestCase): expect = 'python "%s" "arg1 arg2"\n' % t.script_path e = sys.stderr.getvalue() assert e == expect, (e, expect) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '') - + sys.stdout = StringIO() sys.stderr = StringIO() - + testx.run(arguments = ['arg1 arg2']) line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" @@ -2056,24 +2056,24 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 1) - + sys.stdout = StringIO() sys.stderr = StringIO() - + test.run(arguments = ['arg1 arg2']) o = sys.stdout.getvalue() assert o == '', o e = sys.stderr.getvalue() expect = 'python "%s" "arg1 arg2"\n' % t.script_path assert expect == e, (expect, e) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 1) - + sys.stdout = StringIO() sys.stderr = StringIO() - + testx.run(arguments = ['arg1 arg2']) expect = '"%s" "arg1 arg2"\n' % t.scriptx_path o = sys.stdout.getvalue() diff --git a/bin/install_scons.py b/bin/install_scons.py index afd0789..55e327d 100644 --- a/bin/install_scons.py +++ b/bin/install_scons.py @@ -19,7 +19,7 @@ # hierarchy. from __future__ import print_function -from six import PY3 +from SCons.compat.six import PY3 import getopt import os diff --git a/review.py b/review.py index 9f1ba82..a796b2f 100644 --- a/review.py +++ b/review.py @@ -15,7 +15,7 @@ # limitations under the License. from __future__ import print_function -from six import PY3 +from SCons.compat.six import PY3 """Tool for uploading diffs from a version control system to the codereview app. @@ -120,7 +120,7 @@ VCS_UNKNOWN = "Unknown" # whitelist for non-binary filetypes which do not start with "text/" # .mm (Objective-C) shows up as application/x-freemind on my Linux box. TEXT_MIMETYPES = ['application/javascript', 'application/x-javascript', - 'application/xml', 'application/x-freemind', + 'application/xml', 'application/x-freemind', 'application/x-sh'] VCS_ABBREVIATIONS = { @@ -1474,7 +1474,7 @@ def GuessVCSName(): """ def RunDetectCommand(vcs_type, command): """Helper to detect VCS by executing command. - + Returns: A pair (vcs, output) or None. Throws exception on error. """ @@ -1486,7 +1486,7 @@ def GuessVCSName(): (errcode, message) = xxx_todo_changeme.args if errcode != errno.ENOENT: # command not found code raise - + # Mercurial has a command to get the base directory of a repository # Try running it, but don't die if we don't have hg installed. # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. diff --git a/runtest.py b/runtest.py index 7155556..485374a 100755 --- a/runtest.py +++ b/runtest.py @@ -81,7 +81,6 @@ # rather than reinventing that wheel.) from __future__ import print_function -from six import PY3 import getopt import glob @@ -93,9 +92,9 @@ import time try: import threading - if PY3: + try: # python3 from queue import Queue - else: + except ImportError as e: # python2 from Queue import Queue threading_ok = True except ImportError: diff --git a/src/engine/SCons/MemoizeTests.py b/src/engine/SCons/MemoizeTests.py index c1c69ae..8476349 100644 --- a/src/engine/SCons/MemoizeTests.py +++ b/src/engine/SCons/MemoizeTests.py @@ -20,7 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -from six import add_metaclass +from SCons.compat.six import add_metaclass __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 0663c7a..1357e7f 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -12,7 +12,7 @@ it goes here. # Would affect exec()'d site_init.py: ## from __future__ import print_function -from six import print_ +from SCons.compat.six import print_ unsupported_python_version = (2, 3, 0) deprecated_python_version = (2, 7, 0) diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 00147b2..4a06654 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -306,7 +306,7 @@ class Task(object): t.push_to_cache() t.built() t.visited() - if (not print_prepare and + if (not print_prepare and (not hasattr(self, 'options') or not self.options.debug_includes)): t.release_target_info() else: @@ -424,7 +424,7 @@ class Task(object): # parallel build...) t.visited() t.set_state(NODE_UP_TO_DATE) - if (not print_prepare and + if (not print_prepare and (not hasattr(self, 'options') or not self.options.debug_includes)): t.release_target_info() @@ -533,8 +533,8 @@ class Task(object): Task ready for execution. """ - import six - six.reraise(*self.exc_info()) + import SCons.compat.six + SCons.compat.six.reraise(*self.exc_info()) class AlwaysTask(Task): def needs_execute(self): @@ -940,7 +940,7 @@ class Taskmaster(object): executor = node.get_executor() if executor is None: return None - + tlist = executor.get_all_targets() task = self.tasker(self, tlist, node in self.original_top, node) diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py index f9375a2..923fd17 100644 --- a/src/engine/SCons/Tool/xgettext.py +++ b/src/engine/SCons/Tool/xgettext.py @@ -1,10 +1,10 @@ -""" xgettext tool +""" xgettext tool Tool specific initialization of `xgettext` tool. """ # __COPYRIGHT__ -# +# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -12,10 +12,10 @@ Tool specific initialization of `xgettext` tool. # 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 @@ -23,7 +23,7 @@ Tool specific initialization of `xgettext` tool. # 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. -from six import u +from SCons.compat.six import u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -40,12 +40,12 @@ class _CmdRunner(object): self.command = command self.commandstr = commandstr - def __call__(self, target, source, env): + def __call__(self, target, source, env): import SCons.Action import subprocess import os import sys - kw = { + kw = { 'stdin' : 'devnull', 'stdout' : subprocess.PIPE, 'stderr' : subprocess.PIPE, @@ -105,9 +105,9 @@ def _update_pot_file(target, source, env): os.chdir(save_os_cwd) # If the command was not successfull, return error code. if status: return status - + new_content = cmd.out - + if not new_content: # When xgettext finds no internationalized messages, no *.pot is created # (because we don't want to bother translators with empty POT files). @@ -145,7 +145,7 @@ def _update_pot_file(target, source, env): # Print message employing SCons.Action.Action for that. msg = "Not writting " + repr(str(target[0])) + " (" + explain + ")" env.Execute(SCons.Action.Action(nop, msg)) - return 0 + return 0 ############################################################################# ############################################################################# @@ -208,7 +208,7 @@ def _scan_xgettext_from_files(target, source, env, files = None, path = None): contents = re_emptyln.sub("", contents) contents = re_trailws.sub("", contents) depnames = contents.splitlines() - for depname in depnames: + for depname in depnames: depfile = SCons.Node.FS.find_file(depname, dirs) if not depfile: depfile = env.arg2nodes(depname, dirs[0].File) @@ -223,7 +223,7 @@ def _pot_update_emitter(target, source, env): import SCons.Util import SCons.Node.FS - if 'XGETTEXTFROM' in env: + if 'XGETTEXTFROM' in env: xfrom = env['XGETTEXTFROM'] else: return target, source @@ -231,13 +231,13 @@ def _pot_update_emitter(target, source, env): xfrom = [ xfrom ] xfrom = SCons.Util.flatten(xfrom) - + # Prepare list of 'POTFILE.in' files. files = [] for xf in xfrom: if not isinstance(xf, SCons.Node.FS.Base): if SCons.Util.is_String(xf): - # Interpolate variables in strings + # Interpolate variables in strings xf = env.subst(xf, source = source, target = target) xf = env.arg2nodes(xf) files.extend(xf) @@ -275,7 +275,7 @@ def generate(env,**kw): try: env['XGETTEXT'] = _detect_xgettext(env) except: - env['XGETTEXT'] = 'xgettext' + env['XGETTEXT'] = 'xgettext' # NOTE: sources="$SOURCES" would work as well. However, we use following # construction to convert absolute paths provided by scons onto paths # relative to current working dir. Note, that scons expands $SOURCE(S) to diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 052b3fc..3a368cb 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -23,7 +23,7 @@ Various utility functions go here. # 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. -from six import PY2, PY3, u +from SCons.compat.six import PY2, PY3, u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -348,7 +348,7 @@ def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes # assumes that the obj argument is a string must of the time. return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes) -def do_flatten(sequence, result, isinstance=isinstance, +def do_flatten(sequence, result, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes): for item in sequence: if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): @@ -356,7 +356,7 @@ def do_flatten(sequence, result, isinstance=isinstance, else: do_flatten(item, result) -def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, +def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes, do_flatten=do_flatten): """Flatten a sequence to a non-nested list. @@ -374,7 +374,7 @@ def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, do_flatten(item, result) return result -def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, +def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes, do_flatten=do_flatten): """Flatten a sequence to a non-nested list. @@ -395,7 +395,7 @@ def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, # to_String_for_signature() will use a for_signature() method if the # specified object has one. # -def to_String(s, +def to_String(s, isinstance=isinstance, str=str, UserString=UserString, BaseStringTypes=BaseStringTypes): if isinstance(s,BaseStringTypes): @@ -408,11 +408,11 @@ def to_String(s, else: return str(s) -def to_String_for_subst(s, +def to_String_for_subst(s, isinstance=isinstance, str=str, to_String=to_String, BaseStringTypes=BaseStringTypes, SequenceTypes=SequenceTypes, UserString=UserString): - + # Note that the test cases are sorted by order of probability. if isinstance(s, BaseStringTypes): return s @@ -428,7 +428,7 @@ def to_String_for_subst(s, else: return str(s) -def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, +def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, AttributeError=AttributeError): try: f = obj.for_signature @@ -486,7 +486,7 @@ def semi_deepcopy(x): return x.__class__(semi_deepcopy_dict(x)) elif isinstance(x, UserList): return x.__class__(_semi_deepcopy_list(x)) - + return x @@ -632,7 +632,7 @@ else: builtins.WindowsError = WindowsError else: del e - + HKEY_CLASSES_ROOT = None HKEY_LOCAL_MACHINE = None HKEY_CURRENT_USER = None @@ -741,7 +741,7 @@ else: continue return None -def PrependPath(oldpath, newpath, sep = os.pathsep, +def PrependPath(oldpath, newpath, sep = os.pathsep, delete_existing=1, canonicalize=None): """This prepends newpath elements to the given oldpath. Will only add any particular path once (leaving the first one it encounters @@ -760,7 +760,7 @@ def PrependPath(oldpath, newpath, sep = os.pathsep, not move it to the beginning; it will stay where it is in the list. - If canonicalize is not None, it is applied to each element of + If canonicalize is not None, it is applied to each element of newpath before use. """ @@ -782,7 +782,7 @@ def PrependPath(oldpath, newpath, sep = os.pathsep, newpaths=list(map(canonicalize, newpaths)) if not delete_existing: - # First uniquify the old paths, making sure to + # First uniquify the old paths, making sure to # preserve the first instance (in Unix/Linux, # the first one wins), and remembering them in normpaths. # Then insert the new paths at the head of the list @@ -823,7 +823,7 @@ def PrependPath(oldpath, newpath, sep = os.pathsep, else: return sep.join(paths) -def AppendPath(oldpath, newpath, sep = os.pathsep, +def AppendPath(oldpath, newpath, sep = os.pathsep, delete_existing=1, canonicalize=None): """This appends new path elements to the given old path. Will only add any particular path once (leaving the last one it @@ -841,7 +841,7 @@ def AppendPath(oldpath, newpath, sep = os.pathsep, If delete_existing is 0, then adding a path that exists will not move it to the end; it will stay where it is in the list. - If canonicalize is not None, it is applied to each element of + If canonicalize is not None, it is applied to each element of newpath before use. """ @@ -1436,7 +1436,7 @@ else: m.update(to_bytes (str(blck))) f.close() return m.hexdigest() - + def MD5collect(signatures): """ Collects a list of signatures into an aggregate signature. diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index 3167b9d..c52c910 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -20,7 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -from six import u +from SCons.compat.six import u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -697,7 +697,7 @@ bling def test_intern(self): s1 = silent_intern("spam") # Python 3.x does not have a unicode() global function - if sys.version[0] == '2': + if sys.version[0] == '2': s2 = silent_intern(unicode("unicode spam")) s3 = silent_intern(42) s4 = silent_intern("spam") @@ -710,7 +710,7 @@ class MD5TestCase(unittest.TestCase): """Test collecting a list of signatures into a new signature value """ s = list(map(MD5signature, ('111', '222', '333'))) - + assert '698d51a19d8a121ce581499d7b701668' == MD5collect(s[0:1]) assert '8980c988edc2c78cc43ccb718c06efd5' == MD5collect(s[0:2]) assert '53fd88c84ff8a285eb6e0a687e55b8c7' == MD5collect(s) diff --git a/src/engine/SCons/compat/_scons_subprocess.py b/src/engine/SCons/compat/_scons_subprocess.py index e4ac777..a58539d 100644 --- a/src/engine/SCons/compat/_scons_subprocess.py +++ b/src/engine/SCons/compat/_scons_subprocess.py @@ -352,7 +352,7 @@ except that: """ from __future__ import print_function -from six import integer_types +from SCons.compat.six import integer_types import sys mswindows = (sys.platform == "win32") diff --git a/src/engine/SCons/compat/six.py b/src/engine/SCons/compat/six.py new file mode 100755 index 0000000..019130f --- /dev/null +++ b/src/engine/SCons/compat/six.py @@ -0,0 +1,646 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2014 Benjamin Peterson +# +# 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. + +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.6.1" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + try: + result = self._resolve() + except ImportError: + # See the nice big comment in MovedModule.__getattr__. + raise AttributeError("%s could not be imported " % self.name) + setattr(obj, self.name, result) # Invokes __set__. + # This is a bit ugly, but it avoids running this again. + delattr(obj.__class__, self.name) + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + # It turns out many Python frameworks like to traverse sys.modules and + # try to load various attributes. This causes problems if this is a + # platform-specific module on the wrong platform, like _winreg on + # Unixes. Therefore, we silently pretend unimportable modules do not + # have any attributes. See issues #51, #53, #56, and #63 for the full + # tales of woe. + # + # First, if possible, avoid loading the module just to look at __file__, + # __name__, or __path__. + if (attr in ("__file__", "__name__", "__path__") and + self.mod not in sys.modules): + raise AttributeError(attr) + try: + _module = self._resolve() + except ImportError: + raise AttributeError(attr) + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + + +class _MovedItems(_LazyModule): + """Lazy loading of moved objects""" + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "xmlrpclib", "xmlrpc.server"), + MovedModule("winreg", "_winreg"), +] +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + sys.modules[__name__ + ".moves." + attr.name] = attr +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +sys.modules[__name__ + ".moves.urllib_parse"] = sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse") + + +class Module_six_moves_urllib_error(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +sys.modules[__name__ + ".moves.urllib_error"] = sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +sys.modules[__name__ + ".moves.urllib_request"] = sys.modules[__name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +sys.modules[__name__ + ".moves.urllib_response"] = sys.modules[__name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +sys.modules[__name__ + ".moves.urllib_robotparser"] = sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + parse = sys.modules[__name__ + ".moves.urllib_parse"] + error = sys.modules[__name__ + ".moves.urllib_error"] + request = sys.modules[__name__ + ".moves.urllib_request"] + response = sys.modules[__name__ + ".moves.urllib_response"] + robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"] + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + + +sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" + + _iterkeys = "keys" + _itervalues = "values" + _iteritems = "items" + _iterlists = "lists" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + _iterkeys = "iterkeys" + _itervalues = "itervalues" + _iteritems = "iteritems" + _iterlists = "iterlists" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +def iterkeys(d, **kw): + """Return an iterator over the keys of a dictionary.""" + return iter(getattr(d, _iterkeys)(**kw)) + +def itervalues(d, **kw): + """Return an iterator over the values of a dictionary.""" + return iter(getattr(d, _itervalues)(**kw)) + +def iteritems(d, **kw): + """Return an iterator over the (key, value) pairs of a dictionary.""" + return iter(getattr(d, _iteritems)(**kw)) + +def iterlists(d, **kw): + """Return an iterator over the (key, [values]) pairs of a dictionary.""" + return iter(getattr(d, _iterlists)(**kw)) + + +if PY3: + def b(s): + return s.encode("latin-1") + def u(s): + return s + unichr = chr + if sys.version_info[1] <= 1: + def int2byte(i): + return bytes((i,)) + else: + # This is about 2x faster than the implementation above on 3.2+ + int2byte = operator.methodcaller("to_bytes", 1, "big") + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO +else: + def b(s): + return s + # Workaround for standalone backslash + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + def byte2int(bs): + return ord(bs[0]) + def indexbytes(buf, i): + return ord(buf[i]) + def iterbytes(buf): + return (ord(byte) for byte in buf) + import StringIO + StringIO = BytesIO = StringIO.StringIO +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + + def reraise(tp, value, tb=None): + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) + +_add_doc(reraise, """Reraise an exception.""") + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + return meta("NewBase", bases, {}) + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper diff --git a/src/engine/SCons/compat/sixTests.py b/src/engine/SCons/compat/sixTests.py new file mode 100644 index 0000000..f8c1979 --- /dev/null +++ b/src/engine/SCons/compat/sixTests.py @@ -0,0 +1,34 @@ +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# 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. +# + +import unittest + +class sixTestCase(unittest.TestCase): + + def test_import(self): + """Test that six imports correctly.""" + import sys + print sys.path + from SCons.compat.six import PY2, PY3 + self.assertTrue(PY2 or PY3) + diff --git a/src/script/sconsign.py b/src/script/sconsign.py index e99a741..9f75e3a 100644 --- a/src/script/sconsign.py +++ b/src/script/sconsign.py @@ -24,7 +24,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. from __future__ import print_function -from six import PY2, PY3 +from SCons.compat.six import PY2, PY3 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -85,7 +85,7 @@ try: except ImportError: pass else: - # when running from an egg add the egg's directory + # when running from an egg add the egg's directory try: d = pkg_resources.get_distribution('scons') except pkg_resources.DistributionNotFound: diff --git a/test/option/profile.py b/test/option/profile.py index 97f84db..f408136 100644 --- a/test/option/profile.py +++ b/test/option/profile.py @@ -21,7 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from six import u +from SCons.compat.six import u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -113,7 +113,7 @@ memory_lines = [l for l in lines if l.find(expect) != -1] test.fail_test(len(memory_lines) != 1) - + test.pass_test() -- cgit v0.12