| Index: third_party/logilab/common/compat.py | 
| diff --git a/third_party/logilab/common/compat.py b/third_party/logilab/common/compat.py | 
| index f2eb5905601add2c30207278883b69d67934c3e1..8983ece98915f29254296326d2e127fc8adc9e24 100644 | 
| --- a/third_party/logilab/common/compat.py | 
| +++ b/third_party/logilab/common/compat.py | 
| @@ -26,6 +26,7 @@ See another compatibility snippets from other projects: | 
| :mod:`unittest2.compatibility` | 
| """ | 
|  | 
| +from __future__ import generators | 
|  | 
| __docformat__ = "restructuredtext en" | 
|  | 
| @@ -34,8 +35,7 @@ import sys | 
| import types | 
| from warnings import warn | 
|  | 
| -# not used here, but imported to preserve API | 
| -from six.moves import builtins | 
| +import __builtin__ as builtins # 2to3 will tranform '__builtin__' to 'builtins' | 
|  | 
| if sys.version_info < (3, 0): | 
| str_to_bytes = str | 
| @@ -51,6 +51,15 @@ else: | 
| def str_encode(string, encoding): | 
| return str(string) | 
|  | 
| +# XXX callable built-in seems back in all python versions | 
| +try: | 
| +    callable = builtins.callable | 
| +except AttributeError: | 
| +    from collections import Callable | 
| +    def callable(something): | 
| +        return isinstance(something, Callable) | 
| +    del Callable | 
| + | 
| # See also http://bugs.python.org/issue11776 | 
| if sys.version_info[0] == 3: | 
| def method_type(callable, instance, klass): | 
| @@ -60,6 +69,11 @@ else: | 
| # alias types otherwise | 
| method_type = types.MethodType | 
|  | 
| +if sys.version_info < (3, 0): | 
| +    raw_input = raw_input | 
| +else: | 
| +    raw_input = input | 
| + | 
| # Pythons 2 and 3 differ on where to get StringIO | 
| if sys.version_info < (3, 0): | 
| from cStringIO import StringIO | 
| @@ -70,9 +84,160 @@ else: | 
| from io import FileIO, BytesIO, StringIO | 
| from imp import reload | 
|  | 
| +# Where do pickles come from? | 
| +try: | 
| +    import cPickle as pickle | 
| +except ImportError: | 
| +    import pickle | 
| + | 
| from logilab.common.deprecation import deprecated | 
|  | 
| -# Other projects import these from here, keep providing them for | 
| -# backwards compat | 
| -any = deprecated('use builtin "any"')(any) | 
| -all = deprecated('use builtin "all"')(all) | 
| +from itertools import izip, chain, imap | 
| +if sys.version_info < (3, 0):# 2to3 will remove the imports | 
| +    izip = deprecated('izip exists in itertools since py2.3')(izip) | 
| +    imap = deprecated('imap exists in itertools since py2.3')(imap) | 
| +chain = deprecated('chain exists in itertools since py2.3')(chain) | 
| + | 
| +sum = deprecated('sum exists in builtins since py2.3')(sum) | 
| +enumerate = deprecated('enumerate exists in builtins since py2.3')(enumerate) | 
| +frozenset = deprecated('frozenset exists in builtins since py2.4')(frozenset) | 
| +reversed = deprecated('reversed exists in builtins since py2.4')(reversed) | 
| +sorted = deprecated('sorted exists in builtins since py2.4')(sorted) | 
| +max = deprecated('max exists in builtins since py2.4')(max) | 
| + | 
| + | 
| +# Python2.5 builtins | 
| +try: | 
| +    any = any | 
| +    all = all | 
| +except NameError: | 
| +    def any(iterable): | 
| +        """any(iterable) -> bool | 
| + | 
| +        Return True if bool(x) is True for any x in the iterable. | 
| +        """ | 
| +        for elt in iterable: | 
| +            if elt: | 
| +                return True | 
| +        return False | 
| + | 
| +    def all(iterable): | 
| +        """all(iterable) -> bool | 
| + | 
| +        Return True if bool(x) is True for all values x in the iterable. | 
| +        """ | 
| +        for elt in iterable: | 
| +            if not elt: | 
| +                return False | 
| +        return True | 
| + | 
| + | 
| +# Python2.5 subprocess added functions and exceptions | 
| +try: | 
| +    from subprocess import Popen | 
| +except ImportError: | 
| +    # gae or python < 2.3 | 
| + | 
| +    class CalledProcessError(Exception): | 
| +        """This exception is raised when a process run by check_call() returns | 
| +        a non-zero exit status.  The exit status will be stored in the | 
| +        returncode attribute.""" | 
| +        def __init__(self, returncode, cmd): | 
| +            self.returncode = returncode | 
| +            self.cmd = cmd | 
| +        def __str__(self): | 
| +            return "Command '%s' returned non-zero exit status %d" % (self.cmd, | 
| +    self.returncode) | 
| + | 
| +    def call(*popenargs, **kwargs): | 
| +        """Run command with arguments.  Wait for command to complete, then | 
| +        return the returncode attribute. | 
| + | 
| +        The arguments are the same as for the Popen constructor.  Example: | 
| + | 
| +        retcode = call(["ls", "-l"]) | 
| +        """ | 
| +        # workaround: subprocess.Popen(cmd, stdout=sys.stdout) fails | 
| +        # see http://bugs.python.org/issue1531862 | 
| +        if "stdout" in kwargs: | 
| +            fileno = kwargs.get("stdout").fileno() | 
| +            del kwargs['stdout'] | 
| +            return Popen(stdout=os.dup(fileno), *popenargs, **kwargs).wait() | 
| +        return Popen(*popenargs, **kwargs).wait() | 
| + | 
| +    def check_call(*popenargs, **kwargs): | 
| +        """Run command with arguments.  Wait for command to complete.  If | 
| +        the exit code was zero then return, otherwise raise | 
| +        CalledProcessError.  The CalledProcessError object will have the | 
| +        return code in the returncode attribute. | 
| + | 
| +        The arguments are the same as for the Popen constructor.  Example: | 
| + | 
| +        check_call(["ls", "-l"]) | 
| +        """ | 
| +        retcode = call(*popenargs, **kwargs) | 
| +        cmd = kwargs.get("args") | 
| +        if cmd is None: | 
| +            cmd = popenargs[0] | 
| +        if retcode: | 
| +            raise CalledProcessError(retcode, cmd) | 
| +        return retcode | 
| + | 
| +try: | 
| +    from os.path import relpath | 
| +except ImportError: # python < 2.6 | 
| +    from os.path import curdir, abspath, sep, commonprefix, pardir, join | 
| +    def relpath(path, start=curdir): | 
| +        """Return a relative version of a path""" | 
| + | 
| +        if not path: | 
| +            raise ValueError("no path specified") | 
| + | 
| +        start_list = abspath(start).split(sep) | 
| +        path_list = abspath(path).split(sep) | 
| + | 
| +        # Work out how much of the filepath is shared by start and path. | 
| +        i = len(commonprefix([start_list, path_list])) | 
| + | 
| +        rel_list = [pardir] * (len(start_list)-i) + path_list[i:] | 
| +        if not rel_list: | 
| +            return curdir | 
| +        return join(*rel_list) | 
| + | 
| + | 
| +# XXX don't know why tests don't pass if I don't do that : | 
| +_real_set, set = set, deprecated('set exists in builtins since py2.4')(set) | 
| +if (2, 5) <= sys.version_info[:2]: | 
| +    InheritableSet = _real_set | 
| +else: | 
| +    class InheritableSet(_real_set): | 
| +        """hacked resolving inheritancy issue from old style class in 2.4""" | 
| +        def __new__(cls, *args, **kwargs): | 
| +            if args: | 
| +                new_args = (args[0], ) | 
| +            else: | 
| +                new_args = () | 
| +            obj = _real_set.__new__(cls, *new_args) | 
| +            obj.__init__(*args, **kwargs) | 
| +            return obj | 
| + | 
| +# XXX shouldn't we remove this and just let 2to3 do his job ? | 
| +# range or xrange? | 
| +try: | 
| +    range = xrange | 
| +except NameError: | 
| +    range = range | 
| + | 
| +# ConfigParser was renamed to the more-standard configparser | 
| +try: | 
| +    import configparser | 
| +except ImportError: | 
| +    import ConfigParser as configparser | 
| + | 
| +try: | 
| +    import json | 
| +except ImportError: | 
| +    try: | 
| +        import simplejson as json | 
| +    except ImportError: | 
| +        json = None | 
|  |