_compat.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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. def make_sha(source=''):
  37. """A python2.4 workaround for the sha/hashlib module fiasco."""
  38. try:
  39. return hashlib.sha1(source)
  40. except NameError:
  41. sha1 = sha.sha(source)
  42. return sha1
  43. def unpack_from(fmt, buf, offset=0):
  44. """A python2.4 workaround for struct missing unpack_from."""
  45. try:
  46. return struct.unpack_from(fmt, buf, offset)
  47. except AttributeError:
  48. b = buf[offset:offset+struct.calcsize(fmt)]
  49. return struct.unpack(fmt, b)
  50. try:
  51. all = all
  52. except NameError:
  53. # Implementation of all from Python 2.6 documentation:
  54. # http://docs.python.org/2.6/library/functions.html#all
  55. # Copyright (c) 2001-2010 Python Software Foundation; All Rights Reserved
  56. # Licensed under the Python Software Foundation License.
  57. def all(iterable):
  58. for element in iterable:
  59. if not element:
  60. return False
  61. return True
  62. try:
  63. from collections import namedtuple
  64. except ImportError:
  65. # Recipe for namedtuple from http://code.activestate.com/recipes/500261/
  66. # Copyright (c) 2007 Python Software Foundation; All Rights Reserved
  67. # Licensed under the Python Software Foundation License.
  68. from operator import itemgetter as _itemgetter
  69. from keyword import iskeyword as _iskeyword
  70. import sys as _sys
  71. def namedtuple(typename, field_names, verbose=False, rename=False):
  72. """Returns a new subclass of tuple with named fields.
  73. >>> Point = namedtuple('Point', 'x y')
  74. >>> Point.__doc__ # docstring for the new class
  75. 'Point(x, y)'
  76. >>> p = Point(11, y=22) # instantiate with positional args or keywords
  77. >>> p[0] + p[1] # indexable like a plain tuple
  78. 33
  79. >>> x, y = p # unpack like a regular tuple
  80. >>> x, y
  81. (11, 22)
  82. >>> p.x + p.y # fields also accessable by name
  83. 33
  84. >>> d = p._asdict() # convert to a dictionary
  85. >>> d['x']
  86. 11
  87. >>> Point(**d) # convert from a dictionary
  88. Point(x=11, y=22)
  89. >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
  90. Point(x=100, y=22)
  91. """
  92. # Parse and validate the field names. Validation serves two purposes,
  93. # generating informative error messages and preventing template injection attacks.
  94. if isinstance(field_names, basestring):
  95. field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
  96. field_names = tuple(map(str, field_names))
  97. if rename:
  98. names = list(field_names)
  99. seen = set()
  100. for i, name in enumerate(names):
  101. if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
  102. or not name or name[0].isdigit() or name.startswith('_')
  103. or name in seen):
  104. names[i] = '_%d' % i
  105. seen.add(name)
  106. field_names = tuple(names)
  107. for name in (typename,) + field_names:
  108. if not min(c.isalnum() or c=='_' for c in name):
  109. raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
  110. if _iskeyword(name):
  111. raise ValueError('Type names and field names cannot be a keyword: %r' % name)
  112. if name[0].isdigit():
  113. raise ValueError('Type names and field names cannot start with a number: %r' % name)
  114. seen_names = set()
  115. for name in field_names:
  116. if name.startswith('_') and not rename:
  117. raise ValueError('Field names cannot start with an underscore: %r' % name)
  118. if name in seen_names:
  119. raise ValueError('Encountered duplicate field name: %r' % name)
  120. seen_names.add(name)
  121. # Create and fill-in the class template
  122. numfields = len(field_names)
  123. argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes
  124. reprtxt = ', '.join('%s=%%r' % name for name in field_names)
  125. template = '''class %(typename)s(tuple):
  126. '%(typename)s(%(argtxt)s)' \n
  127. __slots__ = () \n
  128. _fields = %(field_names)r \n
  129. def __new__(_cls, %(argtxt)s):
  130. return _tuple.__new__(_cls, (%(argtxt)s)) \n
  131. @classmethod
  132. def _make(cls, iterable, new=tuple.__new__, len=len):
  133. 'Make a new %(typename)s object from a sequence or iterable'
  134. result = new(cls, iterable)
  135. if len(result) != %(numfields)d:
  136. raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
  137. return result \n
  138. def __repr__(self):
  139. return '%(typename)s(%(reprtxt)s)' %% self \n
  140. def _asdict(self):
  141. 'Return a new dict which maps field names to their values'
  142. return dict(zip(self._fields, self)) \n
  143. def _replace(_self, **kwds):
  144. 'Return a new %(typename)s object replacing specified fields with new values'
  145. result = _self._make(map(kwds.pop, %(field_names)r, _self))
  146. if kwds:
  147. raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
  148. return result \n
  149. def __getnewargs__(self):
  150. return tuple(self) \n\n''' % locals()
  151. for i, name in enumerate(field_names):
  152. template += ' %s = _property(_itemgetter(%d))\n' % (name, i)
  153. if verbose:
  154. print template
  155. # Execute the template string in a temporary namespace
  156. namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
  157. _property=property, _tuple=tuple)
  158. try:
  159. exec template in namespace
  160. except SyntaxError, e:
  161. raise SyntaxError(e.message + ':\n' + template)
  162. result = namespace[typename]
  163. # For pickling to work, the __module__ variable needs to be set to the frame
  164. # where the named tuple is created. Bypass this step in enviroments where
  165. # sys._getframe is not defined (Jython for example) or sys._getframe is not
  166. # defined for arguments greater than 0 (IronPython).
  167. try:
  168. result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
  169. except (AttributeError, ValueError):
  170. pass
  171. return result
  172. # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
  173. # Passes Python2.7's test suite and incorporates all the latest updates.
  174. # Copyright (C) Raymond Hettinger, MIT license
  175. try:
  176. from thread import get_ident as _get_ident
  177. except ImportError:
  178. from dummy_thread import get_ident as _get_ident
  179. try:
  180. from _abcoll import KeysView, ValuesView, ItemsView
  181. except ImportError:
  182. pass
  183. class OrderedDict(dict):
  184. 'Dictionary that remembers insertion order'
  185. # An inherited dict maps keys to values.
  186. # The inherited dict provides __getitem__, __len__, __contains__, and get.
  187. # The remaining methods are order-aware.
  188. # Big-O running times for all methods are the same as for regular dictionaries.
  189. # The internal self.__map dictionary maps keys to links in a doubly linked list.
  190. # The circular doubly linked list starts and ends with a sentinel element.
  191. # The sentinel element never gets deleted (this simplifies the algorithm).
  192. # Each link is stored as a list of length three: [PREV, NEXT, KEY].
  193. def __init__(self, *args, **kwds):
  194. '''Initialize an ordered dictionary. Signature is the same as for
  195. regular dictionaries, but keyword arguments are not recommended
  196. because their insertion order is arbitrary.
  197. '''
  198. if len(args) > 1:
  199. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  200. try:
  201. self.__root
  202. except AttributeError:
  203. self.__root = root = [] # sentinel node
  204. root[:] = [root, root, None]
  205. self.__map = {}
  206. self.__update(*args, **kwds)
  207. def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
  208. 'od.__setitem__(i, y) <==> od[i]=y'
  209. # Setting a new item creates a new link which goes at the end of the linked
  210. # list, and the inherited dictionary is updated with the new key/value pair.
  211. if key not in self:
  212. root = self.__root
  213. last = root[0]
  214. last[1] = root[0] = self.__map[key] = [last, root, key]
  215. dict_setitem(self, key, value)
  216. def __delitem__(self, key, dict_delitem=dict.__delitem__):
  217. 'od.__delitem__(y) <==> del od[y]'
  218. # Deleting an existing item uses self.__map to find the link which is
  219. # then removed by updating the links in the predecessor and successor nodes.
  220. dict_delitem(self, key)
  221. link_prev, link_next, key = self.__map.pop(key)
  222. link_prev[1] = link_next
  223. link_next[0] = link_prev
  224. def __iter__(self):
  225. 'od.__iter__() <==> iter(od)'
  226. root = self.__root
  227. curr = root[1]
  228. while curr is not root:
  229. yield curr[2]
  230. curr = curr[1]
  231. def __reversed__(self):
  232. 'od.__reversed__() <==> reversed(od)'
  233. root = self.__root
  234. curr = root[0]
  235. while curr is not root:
  236. yield curr[2]
  237. curr = curr[0]
  238. def clear(self):
  239. 'od.clear() -> None. Remove all items from od.'
  240. try:
  241. for node in self.__map.itervalues():
  242. del node[:]
  243. root = self.__root
  244. root[:] = [root, root, None]
  245. self.__map.clear()
  246. except AttributeError:
  247. pass
  248. dict.clear(self)
  249. def popitem(self, last=True):
  250. """od.popitem() -> (k, v), return and remove a (key, value) pair.
  251. Pairs are returned in LIFO order if last is true or FIFO order if false.
  252. """
  253. if not self:
  254. raise KeyError('dictionary is empty')
  255. root = self.__root
  256. if last:
  257. link = root[0]
  258. link_prev = link[0]
  259. link_prev[1] = root
  260. root[0] = link_prev
  261. else:
  262. link = root[1]
  263. link_next = link[1]
  264. root[1] = link_next
  265. link_next[0] = root
  266. key = link[2]
  267. del self.__map[key]
  268. value = dict.pop(self, key)
  269. return key, value
  270. # -- the following methods do not depend on the internal structure --
  271. def keys(self):
  272. """'od.keys() -> list of keys in od"""
  273. return list(self)
  274. def values(self):
  275. """od.values() -> list of values in od"""
  276. return [self[key] for key in self]
  277. def items(self):
  278. """od.items() -> list of (key, value) pairs in od"""
  279. return [(key, self[key]) for key in self]
  280. def iterkeys(self):
  281. """od.iterkeys() -> an iterator over the keys in od"""
  282. return iter(self)
  283. def itervalues(self):
  284. """od.itervalues -> an iterator over the values in od"""
  285. for k in self:
  286. yield self[k]
  287. def iteritems(self):
  288. """od.iteritems -> an iterator over the (key, value) items in od"""
  289. for k in self:
  290. yield (k, self[k])
  291. def update(*args, **kwds):
  292. """od.update(E, F) -> None. Update od from dict/iterable E and F.
  293. If E is a dict instance, does: for k in E: od[k] = E[k]
  294. If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
  295. Or if E is an iterable of items, does: for k, v in E: od[k] = v
  296. In either case, this is followed by: for k, v in F.items(): od[k] = v
  297. """
  298. if len(args) > 2:
  299. raise TypeError('update() takes at most 2 positional '
  300. 'arguments (%d given)' % (len(args),))
  301. elif not args:
  302. raise TypeError('update() takes at least 1 argument (0 given)')
  303. self = args[0]
  304. # Make progressively weaker assumptions about "other"
  305. other = ()
  306. if len(args) == 2:
  307. other = args[1]
  308. if isinstance(other, dict):
  309. for key in other:
  310. self[key] = other[key]
  311. elif hasattr(other, 'keys'):
  312. for key in other.keys():
  313. self[key] = other[key]
  314. else:
  315. for key, value in other:
  316. self[key] = value
  317. for key, value in kwds.items():
  318. self[key] = value
  319. __update = update # let subclasses override update without breaking __init__
  320. __marker = object()
  321. def pop(self, key, default=__marker):
  322. """od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
  323. If key is not found, d is returned if given, otherwise KeyError is raised.
  324. """
  325. if key in self:
  326. result = self[key]
  327. del self[key]
  328. return result
  329. if default is self.__marker:
  330. raise KeyError(key)
  331. return default
  332. def setdefault(self, key, default=None):
  333. 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
  334. if key in self:
  335. return self[key]
  336. self[key] = default
  337. return default
  338. def __repr__(self, _repr_running={}):
  339. 'od.__repr__() <==> repr(od)'
  340. call_key = id(self), _get_ident()
  341. if call_key in _repr_running:
  342. return '...'
  343. _repr_running[call_key] = 1
  344. try:
  345. if not self:
  346. return '%s()' % (self.__class__.__name__,)
  347. return '%s(%r)' % (self.__class__.__name__, self.items())
  348. finally:
  349. del _repr_running[call_key]
  350. def __reduce__(self):
  351. 'Return state information for pickling'
  352. items = [[k, self[k]] for k in self]
  353. inst_dict = vars(self).copy()
  354. for k in vars(OrderedDict()):
  355. inst_dict.pop(k, None)
  356. if inst_dict:
  357. return (self.__class__, (items,), inst_dict)
  358. return self.__class__, (items,)
  359. def copy(self):
  360. 'od.copy() -> a shallow copy of od'
  361. return self.__class__(self)
  362. @classmethod
  363. def fromkeys(cls, iterable, value=None):
  364. '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
  365. and values equal to v (which defaults to None).
  366. '''
  367. d = cls()
  368. for key in iterable:
  369. d[key] = value
  370. return d
  371. def __eq__(self, other):
  372. '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
  373. while comparison to a regular mapping is order-insensitive.
  374. '''
  375. if isinstance(other, OrderedDict):
  376. return len(self)==len(other) and self.items() == other.items()
  377. return dict.__eq__(self, other)
  378. def __ne__(self, other):
  379. return not self == other
  380. # -- the following methods are only used in Python 2.7 --
  381. def viewkeys(self):
  382. "od.viewkeys() -> a set-like object providing a view on od's keys"
  383. return KeysView(self)
  384. def viewvalues(self):
  385. "od.viewvalues() -> an object providing a view on od's values"
  386. return ValuesView(self)
  387. def viewitems(self):
  388. "od.viewitems() -> a set-like object providing a view on od's items"
  389. return ItemsView(self)