Index: third_party/logilab/common/compat.py |
diff --git a/third_party/logilab/common/compat.py b/third_party/logilab/common/compat.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8983ece98915f29254296326d2e127fc8adc9e24 |
--- /dev/null |
+++ b/third_party/logilab/common/compat.py |
@@ -0,0 +1,243 @@ |
+# pylint: disable=E0601,W0622,W0611 |
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
+# |
+# This file is part of logilab-common. |
+# |
+# logilab-common is free software: you can redistribute it and/or modify it under |
+# the terms of the GNU Lesser General Public License as published by the Free |
+# Software Foundation, either version 2.1 of the License, or (at your option) any |
+# later version. |
+# |
+# logilab-common is distributed in the hope that it will be useful, but WITHOUT |
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
+# details. |
+# |
+# You should have received a copy of the GNU Lesser General Public License along |
+# with logilab-common. If not, see <http://www.gnu.org/licenses/>. |
+"""Wrappers around some builtins introduced in python 2.3, 2.4 and |
+2.5, making them available in for earlier versions of python. |
+ |
+See another compatibility snippets from other projects: |
+ |
+ :mod:`lib2to3.fixes` |
+ :mod:`coverage.backward` |
+ :mod:`unittest2.compatibility` |
+""" |
+ |
+from __future__ import generators |
+ |
+__docformat__ = "restructuredtext en" |
+ |
+import os |
+import sys |
+import types |
+from warnings import warn |
+ |
+import __builtin__ as builtins # 2to3 will tranform '__builtin__' to 'builtins' |
+ |
+if sys.version_info < (3, 0): |
+ str_to_bytes = str |
+ def str_encode(string, encoding): |
+ if isinstance(string, unicode): |
+ return string.encode(encoding) |
+ return str(string) |
+else: |
+ def str_to_bytes(string): |
+ return str.encode(string) |
+ # we have to ignore the encoding in py3k to be able to write a string into a |
+ # TextIOWrapper or like object (which expect an unicode string) |
+ 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): |
+ # api change. klass is no more considered |
+ return types.MethodType(callable, instance) |
+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 |
+ FileIO = file |
+ BytesIO = StringIO |
+ reload = reload |
+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 |
+ |
+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 |