Package logilab :: Package common :: Module compat
[frames] | no frames]

Source Code for Module logilab.common.compat

  1  # pylint: disable-msg=E0601,W0622,W0611 
  2  """Wrappers around some builtins introduced in python 2.3, 2.4 and 
  3  2.5, making them available in for earlier versions of python. 
  4   
  5  :copyright: 2000-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 
  6  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr 
  7  :license: General Public License version 2 - http://www.gnu.org/licenses 
  8  """ 
  9  from __future__ import generators 
 10  __docformat__ = "restructuredtext en" 
 11   
 12  import os 
 13  from warnings import warn 
 14   
 15  import __builtin__ 
 16   
 17  try: 
 18      set = set 
 19      frozenset = frozenset 
 20  except NameError: 
 21      try: 
 22          from sets import Set as set, ImmutableSet as frozenset 
 23      except ImportError: 
24 - class _baseset(object):
25 - def __init__(self, values=()):
26 self._data = {} 27 warn("This implementation of Set is not complete !", 28 stacklevel=2) 29 for v in values: 30 self._data[v] = 1
31
32 - def __or__(self, other):
33 result = self.__class__(self._data.keys()) 34 for val in other: 35 result.add(val) 36 return result
37 __add__ = __or__ 38
39 - def __and__(self, other):
40 result = self.__class__() 41 for val in other: 42 if val in self._data: 43 result.add(val) 44 return result
45
46 - def __sub__(self, other):
47 result = self.__class__(self._data.keys()) 48 for val in other: 49 if val in self._data: 50 result.remove(val) 51 return result
52
53 - def __cmp__(self, other):
54 keys = self._data.keys() 55 okeys = other._data.keys() 56 keys.sort() 57 okeys.sort() 58 return cmp(keys, okeys)
59
60 - def __len__(self):
61 return len(self._data)
62
63 - def __repr__(self):
64 elements = self._data.keys() 65 return 'lcc.%s(%r)' % (self.__class__.__name__, elements)
66 __str__ = __repr__ 67
68 - def __iter__(self):
69 return iter(self._data)
70
71 - class frozenset(_baseset):
72 """immutable set (can be set in dictionaries)"""
73 - def __init__(self, values=()):
74 super(frozenset, self).__init__(values) 75 self._hashcode = None
76
77 - def _compute_hash(self):
78 """taken from python stdlib (sets.py)""" 79 # Calculate hash code for a set by xor'ing the hash codes of 80 # the elements. This ensures that the hash code does not depend 81 # on the order in which elements are added to the set. This is 82 # not called __hash__ because a BaseSet should not be hashable; 83 # only an ImmutableSet is hashable. 84 result = 0 85 for elt in self: 86 result ^= hash(elt) 87 return result
88
89 - def __hash__(self):
90 """taken from python stdlib (sets.py)""" 91 if self._hashcode is None: 92 self._hashcode = self._compute_hash() 93 return self._hashcode
94 95
96 - class set(_baseset):
97 """mutable set"""
98 - def add(self, value):
99 self._data[value] = 1
100
101 - def remove(self, element):
102 """removes <element> from set""" 103 del self._data[element]
104
105 - def pop(self):
106 """pops an arbitrary element from set""" 107 return self._data.popitem()[0]
108
109 - def __hash__(self):
110 """mutable set cannot be hashed.""" 111 raise TypeError("set objects are not hashable")
112 113 del _baseset # don't explicitly provide this class 114 115 try: 116 from itertools import izip, chain, imap 117 except ImportError: 118 # from itertools documentation ###
119 - def izip(*iterables):
120 iterables = map(iter, iterables) 121 while iterables: 122 result = [i.next() for i in iterables] 123 yield tuple(result)
124
125 - def chain(*iterables):
126 for it in iterables: 127 for element in it: 128 yield element
129
130 - def imap(function, *iterables):
131 iterables = map(iter, iterables) 132 while True: 133 args = [i.next() for i in iterables] 134 if function is None: 135 yield tuple(args) 136 else: 137 yield function(*args)
138 try: 139 sum = sum 140 enumerate = enumerate 141 except NameError: 142 # define the sum and enumerate functions (builtins introduced in py 2.3) 143 import operator
144 - def sum(seq, start=0):
145 """Returns the sum of all elements in the sequence""" 146 return reduce(operator.add, seq, start)
147
148 - def enumerate(iterable):
149 """emulates the python2.3 enumerate() function""" 150 i = 0 151 for val in iterable: 152 yield i, val 153 i += 1
154 #return zip(range(len(iterable)), iterable) 155 try: 156 sorted = sorted 157 reversed = reversed 158 except NameError: 159
160 - def sorted(iterable, cmp=None, key=None, reverse=False):
161 original = list(iterable) 162 if key: 163 l2 = [(key(elt), index) for index, elt in enumerate(original)] 164 else: 165 l2 = original 166 l2.sort(cmp) 167 if reverse: 168 l2.reverse() 169 if key: 170 return [original[index] for elt, index in l2] 171 return l2
172
173 - def reversed(l):
174 l2 = list(l) 175 l2.reverse() 176 return l2
177 178 try: # 179 max = max 180 max(("ab","cde"),key=len) 181 except TypeError:
182 - def max( *args, **kargs):
183 if len(args) == 0: 184 raise TypeError("max expected at least 1 arguments, got 0") 185 key= kargs.pop("key", None) 186 #default implementation 187 if key is None: 188 return __builtin__.max(*args,**kargs) 189 190 for karg in kargs: 191 raise TypeError("unexpected keyword argument %s for function max") % karg 192 193 if len(args) == 1: 194 items = iter(args[0]) 195 else: 196 items = iter(args) 197 198 try: 199 best_item = items.next() 200 best_value = key(best_item) 201 except StopIteration: 202 raise ValueError("max() arg is an empty sequence") 203 204 for item in items: 205 value = key(item) 206 if value > best_value: 207 best_item = item 208 best_value = value 209 210 return best_item
211 212 213 # Python2.5 builtins 214 try: 215 any = any 216 all = all 217 except NameError:
218 - def any(iterable):
219 """any(iterable) -> bool 220 221 Return True if bool(x) is True for any x in the iterable. 222 """ 223 for elt in iterable: 224 if elt: 225 return True 226 return False
227
228 - def all(iterable):
229 """all(iterable) -> bool 230 231 Return True if bool(x) is True for all values x in the iterable. 232 """ 233 for elt in iterable: 234 if not elt: 235 return False 236 return True
237 238 239 # Python2.5 subprocess added functions and exceptions 240 try: 241 from subprocess import Popen 242 except ImportError: 243 # gae or python < 2.3 244
245 - class CalledProcessError(Exception):
246 """This exception is raised when a process run by check_call() returns 247 a non-zero exit status. The exit status will be stored in the 248 returncode attribute."""
249 - def __init__(self, returncode, cmd):
250 self.returncode = returncode 251 self.cmd = cmd
252 - def __str__(self):
253 return "Command '%s' returned non-zero exit status %d" % (self.cmd, 254 self.returncode)
255
256 - def call(*popenargs, **kwargs):
257 """Run command with arguments. Wait for command to complete, then 258 return the returncode attribute. 259 260 The arguments are the same as for the Popen constructor. Example: 261 262 retcode = call(["ls", "-l"]) 263 """ 264 # workaround: subprocess.Popen(cmd, stdout=sys.stdout) fails 265 # see http://bugs.python.org/issue1531862 266 if "stdout" in kwargs: 267 fileno = kwargs.get("stdout").fileno() 268 del kwargs['stdout'] 269 return Popen(stdout=os.dup(fileno), *popenargs, **kwargs).wait() 270 return Popen(*popenargs, **kwargs).wait()
271
272 - def check_call(*popenargs, **kwargs):
273 """Run command with arguments. Wait for command to complete. If 274 the exit code was zero then return, otherwise raise 275 CalledProcessError. The CalledProcessError object will have the 276 return code in the returncode attribute. 277 278 The arguments are the same as for the Popen constructor. Example: 279 280 check_call(["ls", "-l"]) 281 """ 282 retcode = call(*popenargs, **kwargs) 283 cmd = kwargs.get("args") 284 if cmd is None: 285 cmd = popenargs[0] 286 if retcode: 287 raise CalledProcessError(retcode, cmd) 288 return retcode
289