_compat.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. # _compat.py -- For dealing with python2.4 oddness
  2. # Copyright (C) 2008 Canonical Ltd.
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; version 2
  7. # of the License or (at your option) a later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17. # MA 02110-1301, USA.
  18. """Misc utilities to work with python <2.6.
  19. These utilities can all be deleted when dulwich decides it wants to stop
  20. support for python <2.6.
  21. """
  22. try:
  23. import hashlib
  24. except ImportError:
  25. import sha
  26. try:
  27. from urlparse import parse_qs
  28. except ImportError:
  29. from cgi import parse_qs
  30. try:
  31. from os import SEEK_CUR, SEEK_END
  32. except ImportError:
  33. SEEK_CUR = 1
  34. SEEK_END = 2
  35. import struct
  36. class defaultdict(dict):
  37. """A python 2.4 equivalent of collections.defaultdict."""
  38. def __init__(self, default_factory=None, *a, **kw):
  39. if (default_factory is not None and
  40. not hasattr(default_factory, '__call__')):
  41. raise TypeError('first argument must be callable')
  42. dict.__init__(self, *a, **kw)
  43. self.default_factory = default_factory
  44. def __getitem__(self, key):
  45. try:
  46. return dict.__getitem__(self, key)
  47. except KeyError:
  48. return self.__missing__(key)
  49. def __missing__(self, key):
  50. if self.default_factory is None:
  51. raise KeyError(key)
  52. self[key] = value = self.default_factory()
  53. return value
  54. def __reduce__(self):
  55. if self.default_factory is None:
  56. args = tuple()
  57. else:
  58. args = self.default_factory,
  59. return type(self), args, None, None, self.items()
  60. def copy(self):
  61. return self.__copy__()
  62. def __copy__(self):
  63. return type(self)(self.default_factory, self)
  64. def __deepcopy__(self, memo):
  65. import copy
  66. return type(self)(self.default_factory,
  67. copy.deepcopy(self.items()))
  68. def __repr__(self):
  69. return 'defaultdict(%s, %s)' % (self.default_factory,
  70. dict.__repr__(self))
  71. def make_sha(source=''):
  72. """A python2.4 workaround for the sha/hashlib module fiasco."""
  73. try:
  74. return hashlib.sha1(source)
  75. except NameError:
  76. sha1 = sha.sha(source)
  77. return sha1
  78. def unpack_from(fmt, buf, offset=0):
  79. """A python2.4 workaround for struct missing unpack_from."""
  80. try:
  81. return struct.unpack_from(fmt, buf, offset)
  82. except AttributeError:
  83. b = buf[offset:offset+struct.calcsize(fmt)]
  84. return struct.unpack(fmt, b)
  85. try:
  86. from itertools import permutations
  87. except ImportError:
  88. # Implementation of permutations from Python 2.6 documentation:
  89. # http://docs.python.org/2.6/library/itertools.html#itertools.permutations
  90. # Copyright (c) 2001-2010 Python Software Foundation; All Rights Reserved
  91. # Modified syntax slightly to run under Python 2.4.
  92. def permutations(iterable, r=None):
  93. # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
  94. # permutations(range(3)) --> 012 021 102 120 201 210
  95. pool = tuple(iterable)
  96. n = len(pool)
  97. if r is None:
  98. r = n
  99. if r > n:
  100. return
  101. indices = range(n)
  102. cycles = range(n, n-r, -1)
  103. yield tuple(pool[i] for i in indices[:r])
  104. while n:
  105. for i in reversed(range(r)):
  106. cycles[i] -= 1
  107. if cycles[i] == 0:
  108. indices[i:] = indices[i+1:] + indices[i:i+1]
  109. cycles[i] = n - i
  110. else:
  111. j = cycles[i]
  112. indices[i], indices[-j] = indices[-j], indices[i]
  113. yield tuple(pool[i] for i in indices[:r])
  114. break
  115. else:
  116. return
  117. try:
  118. all = all
  119. except NameError:
  120. # Implementation of permutations from Python 2.6 documentation:
  121. # http://docs.python.org/2.6/library/functions.html#all
  122. # Copyright (c) 2001-2010 Python Software Foundation; All Rights Reserved
  123. # Licensed under the Python Software Foundation License.
  124. def all(iterable):
  125. for element in iterable:
  126. if not element:
  127. return False
  128. return True
  129. try:
  130. from collections import namedtuple
  131. except ImportError:
  132. # Recipe for namedtuple from http://code.activestate.com/recipes/500261/
  133. # Copyright (c) 2007 Python Software Foundation; All Rights Reserved
  134. # Licensed under the Python Software Foundation License.
  135. from operator import itemgetter as _itemgetter
  136. from keyword import iskeyword as _iskeyword
  137. import sys as _sys
  138. def namedtuple(typename, field_names, verbose=False, rename=False):
  139. """Returns a new subclass of tuple with named fields.
  140. >>> Point = namedtuple('Point', 'x y')
  141. >>> Point.__doc__ # docstring for the new class
  142. 'Point(x, y)'
  143. >>> p = Point(11, y=22) # instantiate with positional args or keywords
  144. >>> p[0] + p[1] # indexable like a plain tuple
  145. 33
  146. >>> x, y = p # unpack like a regular tuple
  147. >>> x, y
  148. (11, 22)
  149. >>> p.x + p.y # fields also accessable by name
  150. 33
  151. >>> d = p._asdict() # convert to a dictionary
  152. >>> d['x']
  153. 11
  154. >>> Point(**d) # convert from a dictionary
  155. Point(x=11, y=22)
  156. >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
  157. Point(x=100, y=22)
  158. """
  159. # Parse and validate the field names. Validation serves two purposes,
  160. # generating informative error messages and preventing template injection attacks.
  161. if isinstance(field_names, basestring):
  162. field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
  163. field_names = tuple(map(str, field_names))
  164. if rename:
  165. names = list(field_names)
  166. seen = set()
  167. for i, name in enumerate(names):
  168. if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
  169. or not name or name[0].isdigit() or name.startswith('_')
  170. or name in seen):
  171. names[i] = '_%d' % i
  172. seen.add(name)
  173. field_names = tuple(names)
  174. for name in (typename,) + field_names:
  175. if not min(c.isalnum() or c=='_' for c in name):
  176. raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
  177. if _iskeyword(name):
  178. raise ValueError('Type names and field names cannot be a keyword: %r' % name)
  179. if name[0].isdigit():
  180. raise ValueError('Type names and field names cannot start with a number: %r' % name)
  181. seen_names = set()
  182. for name in field_names:
  183. if name.startswith('_') and not rename:
  184. raise ValueError('Field names cannot start with an underscore: %r' % name)
  185. if name in seen_names:
  186. raise ValueError('Encountered duplicate field name: %r' % name)
  187. seen_names.add(name)
  188. # Create and fill-in the class template
  189. numfields = len(field_names)
  190. argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes
  191. reprtxt = ', '.join('%s=%%r' % name for name in field_names)
  192. template = '''class %(typename)s(tuple):
  193. '%(typename)s(%(argtxt)s)' \n
  194. __slots__ = () \n
  195. _fields = %(field_names)r \n
  196. def __new__(_cls, %(argtxt)s):
  197. return _tuple.__new__(_cls, (%(argtxt)s)) \n
  198. @classmethod
  199. def _make(cls, iterable, new=tuple.__new__, len=len):
  200. 'Make a new %(typename)s object from a sequence or iterable'
  201. result = new(cls, iterable)
  202. if len(result) != %(numfields)d:
  203. raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
  204. return result \n
  205. def __repr__(self):
  206. return '%(typename)s(%(reprtxt)s)' %% self \n
  207. def _asdict(self):
  208. 'Return a new dict which maps field names to their values'
  209. return dict(zip(self._fields, self)) \n
  210. def _replace(_self, **kwds):
  211. 'Return a new %(typename)s object replacing specified fields with new values'
  212. result = _self._make(map(kwds.pop, %(field_names)r, _self))
  213. if kwds:
  214. raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
  215. return result \n
  216. def __getnewargs__(self):
  217. return tuple(self) \n\n''' % locals()
  218. for i, name in enumerate(field_names):
  219. template += ' %s = _property(_itemgetter(%d))\n' % (name, i)
  220. if verbose:
  221. print template
  222. # Execute the template string in a temporary namespace
  223. namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
  224. _property=property, _tuple=tuple)
  225. try:
  226. exec template in namespace
  227. except SyntaxError, e:
  228. raise SyntaxError(e.message + ':\n' + template)
  229. result = namespace[typename]
  230. # For pickling to work, the __module__ variable needs to be set to the frame
  231. # where the named tuple is created. Bypass this step in enviroments where
  232. # sys._getframe is not defined (Jython for example) or sys._getframe is not
  233. # defined for arguments greater than 0 (IronPython).
  234. try:
  235. result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
  236. except (AttributeError, ValueError):
  237. pass
  238. return result
  239. # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
  240. # Passes Python2.7's test suite and incorporates all the latest updates.
  241. # Copyright (C) Raymond Hettinger, MIT license
  242. try:
  243. from thread import get_ident as _get_ident
  244. except ImportError:
  245. from dummy_thread import get_ident as _get_ident
  246. try:
  247. from _abcoll import KeysView, ValuesView, ItemsView
  248. except ImportError:
  249. pass
  250. class OrderedDict(dict):
  251. 'Dictionary that remembers insertion order'
  252. # An inherited dict maps keys to values.
  253. # The inherited dict provides __getitem__, __len__, __contains__, and get.
  254. # The remaining methods are order-aware.
  255. # Big-O running times for all methods are the same as for regular dictionaries.
  256. # The internal self.__map dictionary maps keys to links in a doubly linked list.
  257. # The circular doubly linked list starts and ends with a sentinel element.
  258. # The sentinel element never gets deleted (this simplifies the algorithm).
  259. # Each link is stored as a list of length three: [PREV, NEXT, KEY].
  260. def __init__(self, *args, **kwds):
  261. '''Initialize an ordered dictionary. Signature is the same as for
  262. regular dictionaries, but keyword arguments are not recommended
  263. because their insertion order is arbitrary.
  264. '''
  265. if len(args) > 1:
  266. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  267. try:
  268. self.__root
  269. except AttributeError:
  270. self.__root = root = [] # sentinel node
  271. root[:] = [root, root, None]
  272. self.__map = {}
  273. self.__update(*args, **kwds)
  274. def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
  275. 'od.__setitem__(i, y) <==> od[i]=y'
  276. # Setting a new item creates a new link which goes at the end of the linked
  277. # list, and the inherited dictionary is updated with the new key/value pair.
  278. if key not in self:
  279. root = self.__root
  280. last = root[0]
  281. last[1] = root[0] = self.__map[key] = [last, root, key]
  282. dict_setitem(self, key, value)
  283. def __delitem__(self, key, dict_delitem=dict.__delitem__):
  284. 'od.__delitem__(y) <==> del od[y]'
  285. # Deleting an existing item uses self.__map to find the link which is
  286. # then removed by updating the links in the predecessor and successor nodes.
  287. dict_delitem(self, key)
  288. link_prev, link_next, key = self.__map.pop(key)
  289. link_prev[1] = link_next
  290. link_next[0] = link_prev
  291. def __iter__(self):
  292. 'od.__iter__() <==> iter(od)'
  293. root = self.__root
  294. curr = root[1]
  295. while curr is not root:
  296. yield curr[2]
  297. curr = curr[1]
  298. def __reversed__(self):
  299. 'od.__reversed__() <==> reversed(od)'
  300. root = self.__root
  301. curr = root[0]
  302. while curr is not root:
  303. yield curr[2]
  304. curr = curr[0]
  305. def clear(self):
  306. 'od.clear() -> None. Remove all items from od.'
  307. try:
  308. for node in self.__map.itervalues():
  309. del node[:]
  310. root = self.__root
  311. root[:] = [root, root, None]
  312. self.__map.clear()
  313. except AttributeError:
  314. pass
  315. dict.clear(self)
  316. def popitem(self, last=True):
  317. """od.popitem() -> (k, v), return and remove a (key, value) pair.
  318. Pairs are returned in LIFO order if last is true or FIFO order if false.
  319. """
  320. if not self:
  321. raise KeyError('dictionary is empty')
  322. root = self.__root
  323. if last:
  324. link = root[0]
  325. link_prev = link[0]
  326. link_prev[1] = root
  327. root[0] = link_prev
  328. else:
  329. link = root[1]
  330. link_next = link[1]
  331. root[1] = link_next
  332. link_next[0] = root
  333. key = link[2]
  334. del self.__map[key]
  335. value = dict.pop(self, key)
  336. return key, value
  337. # -- the following methods do not depend on the internal structure --
  338. def keys(self):
  339. """'od.keys() -> list of keys in od"""
  340. return list(self)
  341. def values(self):
  342. """od.values() -> list of values in od"""
  343. return [self[key] for key in self]
  344. def items(self):
  345. """od.items() -> list of (key, value) pairs in od"""
  346. return [(key, self[key]) for key in self]
  347. def iterkeys(self):
  348. """od.iterkeys() -> an iterator over the keys in od"""
  349. return iter(self)
  350. def itervalues(self):
  351. """od.itervalues -> an iterator over the values in od"""
  352. for k in self:
  353. yield self[k]
  354. def iteritems(self):
  355. """od.iteritems -> an iterator over the (key, value) items in od"""
  356. for k in self:
  357. yield (k, self[k])
  358. def update(*args, **kwds):
  359. """od.update(E, **F) -> None. Update od from dict/iterable E and F.
  360. If E is a dict instance, does: for k in E: od[k] = E[k]
  361. If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
  362. Or if E is an iterable of items, does: for k, v in E: od[k] = v
  363. In either case, this is followed by: for k, v in F.items(): od[k] = v
  364. """
  365. if len(args) > 2:
  366. raise TypeError('update() takes at most 2 positional '
  367. 'arguments (%d given)' % (len(args),))
  368. elif not args:
  369. raise TypeError('update() takes at least 1 argument (0 given)')
  370. self = args[0]
  371. # Make progressively weaker assumptions about "other"
  372. other = ()
  373. if len(args) == 2:
  374. other = args[1]
  375. if isinstance(other, dict):
  376. for key in other:
  377. self[key] = other[key]
  378. elif hasattr(other, 'keys'):
  379. for key in other.keys():
  380. self[key] = other[key]
  381. else:
  382. for key, value in other:
  383. self[key] = value
  384. for key, value in kwds.items():
  385. self[key] = value
  386. __update = update # let subclasses override update without breaking __init__
  387. __marker = object()
  388. def pop(self, key, default=__marker):
  389. """od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
  390. If key is not found, d is returned if given, otherwise KeyError is raised.
  391. """
  392. if key in self:
  393. result = self[key]
  394. del self[key]
  395. return result
  396. if default is self.__marker:
  397. raise KeyError(key)
  398. return default
  399. def setdefault(self, key, default=None):
  400. 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
  401. if key in self:
  402. return self[key]
  403. self[key] = default
  404. return default
  405. def __repr__(self, _repr_running={}):
  406. 'od.__repr__() <==> repr(od)'
  407. call_key = id(self), _get_ident()
  408. if call_key in _repr_running:
  409. return '...'
  410. _repr_running[call_key] = 1
  411. try:
  412. if not self:
  413. return '%s()' % (self.__class__.__name__,)
  414. return '%s(%r)' % (self.__class__.__name__, self.items())
  415. finally:
  416. del _repr_running[call_key]
  417. def __reduce__(self):
  418. 'Return state information for pickling'
  419. items = [[k, self[k]] for k in self]
  420. inst_dict = vars(self).copy()
  421. for k in vars(OrderedDict()):
  422. inst_dict.pop(k, None)
  423. if inst_dict:
  424. return (self.__class__, (items,), inst_dict)
  425. return self.__class__, (items,)
  426. def copy(self):
  427. 'od.copy() -> a shallow copy of od'
  428. return self.__class__(self)
  429. @classmethod
  430. def fromkeys(cls, iterable, value=None):
  431. '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
  432. and values equal to v (which defaults to None).
  433. '''
  434. d = cls()
  435. for key in iterable:
  436. d[key] = value
  437. return d
  438. def __eq__(self, other):
  439. '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
  440. while comparison to a regular mapping is order-insensitive.
  441. '''
  442. if isinstance(other, OrderedDict):
  443. return len(self)==len(other) and self.items() == other.items()
  444. return dict.__eq__(self, other)
  445. def __ne__(self, other):
  446. return not self == other
  447. # -- the following methods are only used in Python 2.7 --
  448. def viewkeys(self):
  449. "od.viewkeys() -> a set-like object providing a view on od's keys"
  450. return KeysView(self)
  451. def viewvalues(self):
  452. "od.viewvalues() -> an object providing a view on od's values"
  453. return ValuesView(self)
  454. def viewitems(self):
  455. "od.viewitems() -> a set-like object providing a view on od's items"
  456. return ItemsView(self)