OLD | NEW |
1 # pylint: disable=E0601,W0622,W0611 | 1 # pylint: disable=E0601,W0622,W0611 |
2 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 2 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
4 # | 4 # |
5 # This file is part of logilab-common. | 5 # This file is part of logilab-common. |
6 # | 6 # |
7 # logilab-common is free software: you can redistribute it and/or modify it unde
r | 7 # logilab-common is free software: you can redistribute it and/or modify it unde
r |
8 # the terms of the GNU Lesser General Public License as published by the Free | 8 # the terms of the GNU Lesser General Public License as published by the Free |
9 # Software Foundation, either version 2.1 of the License, or (at your option) an
y | 9 # Software Foundation, either version 2.1 of the License, or (at your option) an
y |
10 # later version. | 10 # later version. |
11 # | 11 # |
12 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 12 # logilab-common is distributed in the hope that it will be useful, but WITHOUT |
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | 14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
15 # details. | 15 # details. |
16 # | 16 # |
17 # You should have received a copy of the GNU Lesser General Public License along | 17 # You should have received a copy of the GNU Lesser General Public License along |
18 # with logilab-common. If not, see <http://www.gnu.org/licenses/>. | 18 # with logilab-common. If not, see <http://www.gnu.org/licenses/>. |
19 """Wrappers around some builtins introduced in python 2.3, 2.4 and | 19 """Wrappers around some builtins introduced in python 2.3, 2.4 and |
20 2.5, making them available in for earlier versions of python. | 20 2.5, making them available in for earlier versions of python. |
21 | 21 |
22 See another compatibility snippets from other projects: | 22 See another compatibility snippets from other projects: |
23 | 23 |
24 :mod:`lib2to3.fixes` | 24 :mod:`lib2to3.fixes` |
25 :mod:`coverage.backward` | 25 :mod:`coverage.backward` |
26 :mod:`unittest2.compatibility` | 26 :mod:`unittest2.compatibility` |
27 """ | 27 """ |
28 | 28 |
| 29 from __future__ import generators |
29 | 30 |
30 __docformat__ = "restructuredtext en" | 31 __docformat__ = "restructuredtext en" |
31 | 32 |
32 import os | 33 import os |
33 import sys | 34 import sys |
34 import types | 35 import types |
35 from warnings import warn | 36 from warnings import warn |
36 | 37 |
37 # not used here, but imported to preserve API | 38 import __builtin__ as builtins # 2to3 will tranform '__builtin__' to 'builtins' |
38 from six.moves import builtins | |
39 | 39 |
40 if sys.version_info < (3, 0): | 40 if sys.version_info < (3, 0): |
41 str_to_bytes = str | 41 str_to_bytes = str |
42 def str_encode(string, encoding): | 42 def str_encode(string, encoding): |
43 if isinstance(string, unicode): | 43 if isinstance(string, unicode): |
44 return string.encode(encoding) | 44 return string.encode(encoding) |
45 return str(string) | 45 return str(string) |
46 else: | 46 else: |
47 def str_to_bytes(string): | 47 def str_to_bytes(string): |
48 return str.encode(string) | 48 return str.encode(string) |
49 # we have to ignore the encoding in py3k to be able to write a string into a | 49 # we have to ignore the encoding in py3k to be able to write a string into a |
50 # TextIOWrapper or like object (which expect an unicode string) | 50 # TextIOWrapper or like object (which expect an unicode string) |
51 def str_encode(string, encoding): | 51 def str_encode(string, encoding): |
52 return str(string) | 52 return str(string) |
53 | 53 |
| 54 # XXX callable built-in seems back in all python versions |
| 55 try: |
| 56 callable = builtins.callable |
| 57 except AttributeError: |
| 58 from collections import Callable |
| 59 def callable(something): |
| 60 return isinstance(something, Callable) |
| 61 del Callable |
| 62 |
54 # See also http://bugs.python.org/issue11776 | 63 # See also http://bugs.python.org/issue11776 |
55 if sys.version_info[0] == 3: | 64 if sys.version_info[0] == 3: |
56 def method_type(callable, instance, klass): | 65 def method_type(callable, instance, klass): |
57 # api change. klass is no more considered | 66 # api change. klass is no more considered |
58 return types.MethodType(callable, instance) | 67 return types.MethodType(callable, instance) |
59 else: | 68 else: |
60 # alias types otherwise | 69 # alias types otherwise |
61 method_type = types.MethodType | 70 method_type = types.MethodType |
62 | 71 |
| 72 if sys.version_info < (3, 0): |
| 73 raw_input = raw_input |
| 74 else: |
| 75 raw_input = input |
| 76 |
63 # Pythons 2 and 3 differ on where to get StringIO | 77 # Pythons 2 and 3 differ on where to get StringIO |
64 if sys.version_info < (3, 0): | 78 if sys.version_info < (3, 0): |
65 from cStringIO import StringIO | 79 from cStringIO import StringIO |
66 FileIO = file | 80 FileIO = file |
67 BytesIO = StringIO | 81 BytesIO = StringIO |
68 reload = reload | 82 reload = reload |
69 else: | 83 else: |
70 from io import FileIO, BytesIO, StringIO | 84 from io import FileIO, BytesIO, StringIO |
71 from imp import reload | 85 from imp import reload |
72 | 86 |
| 87 # Where do pickles come from? |
| 88 try: |
| 89 import cPickle as pickle |
| 90 except ImportError: |
| 91 import pickle |
| 92 |
73 from logilab.common.deprecation import deprecated | 93 from logilab.common.deprecation import deprecated |
74 | 94 |
75 # Other projects import these from here, keep providing them for | 95 from itertools import izip, chain, imap |
76 # backwards compat | 96 if sys.version_info < (3, 0):# 2to3 will remove the imports |
77 any = deprecated('use builtin "any"')(any) | 97 izip = deprecated('izip exists in itertools since py2.3')(izip) |
78 all = deprecated('use builtin "all"')(all) | 98 imap = deprecated('imap exists in itertools since py2.3')(imap) |
| 99 chain = deprecated('chain exists in itertools since py2.3')(chain) |
| 100 |
| 101 sum = deprecated('sum exists in builtins since py2.3')(sum) |
| 102 enumerate = deprecated('enumerate exists in builtins since py2.3')(enumerate) |
| 103 frozenset = deprecated('frozenset exists in builtins since py2.4')(frozenset) |
| 104 reversed = deprecated('reversed exists in builtins since py2.4')(reversed) |
| 105 sorted = deprecated('sorted exists in builtins since py2.4')(sorted) |
| 106 max = deprecated('max exists in builtins since py2.4')(max) |
| 107 |
| 108 |
| 109 # Python2.5 builtins |
| 110 try: |
| 111 any = any |
| 112 all = all |
| 113 except NameError: |
| 114 def any(iterable): |
| 115 """any(iterable) -> bool |
| 116 |
| 117 Return True if bool(x) is True for any x in the iterable. |
| 118 """ |
| 119 for elt in iterable: |
| 120 if elt: |
| 121 return True |
| 122 return False |
| 123 |
| 124 def all(iterable): |
| 125 """all(iterable) -> bool |
| 126 |
| 127 Return True if bool(x) is True for all values x in the iterable. |
| 128 """ |
| 129 for elt in iterable: |
| 130 if not elt: |
| 131 return False |
| 132 return True |
| 133 |
| 134 |
| 135 # Python2.5 subprocess added functions and exceptions |
| 136 try: |
| 137 from subprocess import Popen |
| 138 except ImportError: |
| 139 # gae or python < 2.3 |
| 140 |
| 141 class CalledProcessError(Exception): |
| 142 """This exception is raised when a process run by check_call() returns |
| 143 a non-zero exit status. The exit status will be stored in the |
| 144 returncode attribute.""" |
| 145 def __init__(self, returncode, cmd): |
| 146 self.returncode = returncode |
| 147 self.cmd = cmd |
| 148 def __str__(self): |
| 149 return "Command '%s' returned non-zero exit status %d" % (self.cmd, |
| 150 self.returncode) |
| 151 |
| 152 def call(*popenargs, **kwargs): |
| 153 """Run command with arguments. Wait for command to complete, then |
| 154 return the returncode attribute. |
| 155 |
| 156 The arguments are the same as for the Popen constructor. Example: |
| 157 |
| 158 retcode = call(["ls", "-l"]) |
| 159 """ |
| 160 # workaround: subprocess.Popen(cmd, stdout=sys.stdout) fails |
| 161 # see http://bugs.python.org/issue1531862 |
| 162 if "stdout" in kwargs: |
| 163 fileno = kwargs.get("stdout").fileno() |
| 164 del kwargs['stdout'] |
| 165 return Popen(stdout=os.dup(fileno), *popenargs, **kwargs).wait() |
| 166 return Popen(*popenargs, **kwargs).wait() |
| 167 |
| 168 def check_call(*popenargs, **kwargs): |
| 169 """Run command with arguments. Wait for command to complete. If |
| 170 the exit code was zero then return, otherwise raise |
| 171 CalledProcessError. The CalledProcessError object will have the |
| 172 return code in the returncode attribute. |
| 173 |
| 174 The arguments are the same as for the Popen constructor. Example: |
| 175 |
| 176 check_call(["ls", "-l"]) |
| 177 """ |
| 178 retcode = call(*popenargs, **kwargs) |
| 179 cmd = kwargs.get("args") |
| 180 if cmd is None: |
| 181 cmd = popenargs[0] |
| 182 if retcode: |
| 183 raise CalledProcessError(retcode, cmd) |
| 184 return retcode |
| 185 |
| 186 try: |
| 187 from os.path import relpath |
| 188 except ImportError: # python < 2.6 |
| 189 from os.path import curdir, abspath, sep, commonprefix, pardir, join |
| 190 def relpath(path, start=curdir): |
| 191 """Return a relative version of a path""" |
| 192 |
| 193 if not path: |
| 194 raise ValueError("no path specified") |
| 195 |
| 196 start_list = abspath(start).split(sep) |
| 197 path_list = abspath(path).split(sep) |
| 198 |
| 199 # Work out how much of the filepath is shared by start and path. |
| 200 i = len(commonprefix([start_list, path_list])) |
| 201 |
| 202 rel_list = [pardir] * (len(start_list)-i) + path_list[i:] |
| 203 if not rel_list: |
| 204 return curdir |
| 205 return join(*rel_list) |
| 206 |
| 207 |
| 208 # XXX don't know why tests don't pass if I don't do that : |
| 209 _real_set, set = set, deprecated('set exists in builtins since py2.4')(set) |
| 210 if (2, 5) <= sys.version_info[:2]: |
| 211 InheritableSet = _real_set |
| 212 else: |
| 213 class InheritableSet(_real_set): |
| 214 """hacked resolving inheritancy issue from old style class in 2.4""" |
| 215 def __new__(cls, *args, **kwargs): |
| 216 if args: |
| 217 new_args = (args[0], ) |
| 218 else: |
| 219 new_args = () |
| 220 obj = _real_set.__new__(cls, *new_args) |
| 221 obj.__init__(*args, **kwargs) |
| 222 return obj |
| 223 |
| 224 # XXX shouldn't we remove this and just let 2to3 do his job ? |
| 225 # range or xrange? |
| 226 try: |
| 227 range = xrange |
| 228 except NameError: |
| 229 range = range |
| 230 |
| 231 # ConfigParser was renamed to the more-standard configparser |
| 232 try: |
| 233 import configparser |
| 234 except ImportError: |
| 235 import ConfigParser as configparser |
| 236 |
| 237 try: |
| 238 import json |
| 239 except ImportError: |
| 240 try: |
| 241 import simplejson as json |
| 242 except ImportError: |
| 243 json = None |
OLD | NEW |