compat.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. from __future__ import generators
  2. ############## py3k #########################################################
  3. try:
  4. from UserList import UserList
  5. except ImportError:
  6. from collections import UserList
  7. try:
  8. from UserDict import UserDict
  9. except ImportError:
  10. from collections import UserDict
  11. try:
  12. from cStringIO import StringIO
  13. except ImportError:
  14. try:
  15. from StringIO import StringIO
  16. except ImportError:
  17. from io import StringIO
  18. ############## urlparse.parse_qsl ###########################################
  19. try:
  20. from urlparse import parse_qsl
  21. except ImportError:
  22. from cgi import parse_qsl
  23. parse_sql = parse_qsl
  24. ############## __builtin__.all ##############################################
  25. try:
  26. all([True])
  27. all = all
  28. except NameError:
  29. def all(iterable):
  30. for item in iterable:
  31. if not item:
  32. return False
  33. return True
  34. ############## __builtin__.any ##############################################
  35. try:
  36. any([True])
  37. any = any
  38. except NameError:
  39. def any(iterable):
  40. for item in iterable:
  41. if item:
  42. return True
  43. return False
  44. ############## collections.OrderedDict ######################################
  45. import weakref
  46. try:
  47. from collections import MutableMapping
  48. except ImportError:
  49. from UserDict import DictMixin as MutableMapping
  50. from itertools import imap as _imap
  51. from operator import eq as _eq
  52. class _Link(object):
  53. """Doubly linked list."""
  54. # next can't be lowercase because 2to3 thinks it's a generator
  55. # and renames it to __next__.
  56. __slots__ = 'PREV', 'NEXT', 'key', '__weakref__'
  57. class CompatOrderedDict(dict, MutableMapping):
  58. """Dictionary that remembers insertion order"""
  59. # An inherited dict maps keys to values.
  60. # The inherited dict provides __getitem__, __len__, __contains__, and get.
  61. # The remaining methods are order-aware.
  62. # Big-O running times for all methods are the same as for regular
  63. # dictionaries.
  64. # The internal self.__map dictionary maps keys to links in a doubly
  65. # linked list.
  66. # The circular doubly linked list starts and ends with a sentinel element.
  67. # The sentinel element never gets deleted (this simplifies the algorithm).
  68. # The prev/next links are weakref proxies (to prevent circular
  69. # references).
  70. # Individual links are kept alive by the hard reference in self.__map.
  71. # Those hard references disappear when a key is deleted from
  72. # an OrderedDict.
  73. __marker = object()
  74. def __init__(self, *args, **kwds):
  75. """Initialize an ordered dictionary.
  76. Signature is the same as for regular dictionaries, but keyword
  77. arguments are not recommended because their insertion order is
  78. arbitrary.
  79. """
  80. if len(args) > 1:
  81. raise TypeError("expected at most 1 arguments, got %d" % (
  82. len(args)))
  83. try:
  84. self._root
  85. except AttributeError:
  86. # sentinel node for the doubly linked list
  87. self._root = root = _Link()
  88. root.PREV = root.NEXT = root
  89. self.__map = {}
  90. self.update(*args, **kwds)
  91. def clear(self):
  92. "od.clear() -> None. Remove all items from od."
  93. root = self._root
  94. root.PREV = root.NEXT = root
  95. self.__map.clear()
  96. dict.clear(self)
  97. def __setitem__(self, key, value):
  98. "od.__setitem__(i, y) <==> od[i]=y"
  99. # Setting a new item creates a new link which goes at the end of the
  100. # linked list, and the inherited dictionary is updated with the new
  101. # key/value pair.
  102. if key not in self:
  103. self.__map[key] = link = _Link()
  104. root = self._root
  105. last = root.PREV
  106. link.PREV, link.NEXT, link.key = last, root, key
  107. last.NEXT = root.PREV = weakref.proxy(link)
  108. dict.__setitem__(self, key, value)
  109. def __delitem__(self, key):
  110. """od.__delitem__(y) <==> del od[y]"""
  111. # Deleting an existing item uses self.__map to find the
  112. # link which is then removed by updating the links in the
  113. # predecessor and successor nodes.
  114. dict.__delitem__(self, key)
  115. link = self.__map.pop(key)
  116. link.PREV.NEXT = link.NEXT
  117. link.NEXT.PREV = link.PREV
  118. def __iter__(self):
  119. """od.__iter__() <==> iter(od)"""
  120. # Traverse the linked list in order.
  121. root = self._root
  122. curr = root.NEXT
  123. while curr is not root:
  124. yield curr.key
  125. curr = curr.NEXT
  126. def __reversed__(self):
  127. """od.__reversed__() <==> reversed(od)"""
  128. # Traverse the linked list in reverse order.
  129. root = self._root
  130. curr = root.PREV
  131. while curr is not root:
  132. yield curr.key
  133. curr = curr.PREV
  134. def __reduce__(self):
  135. """Return state information for pickling"""
  136. items = [[k, self[k]] for k in self]
  137. tmp = self.__map, self._root
  138. del(self.__map, self._root)
  139. inst_dict = vars(self).copy()
  140. self.__map, self._root = tmp
  141. if inst_dict:
  142. return (self.__class__, (items,), inst_dict)
  143. return self.__class__, (items,)
  144. def setdefault(self, key, default=None):
  145. try:
  146. return self[key]
  147. except KeyError:
  148. self[key] = default
  149. return default
  150. def update(self, other=(), **kwds):
  151. if isinstance(other, dict):
  152. for key in other:
  153. self[key] = other[key]
  154. elif hasattr(other, "keys"):
  155. for key in other.keys():
  156. self[key] = other[key]
  157. else:
  158. for key, value in other:
  159. self[key] = value
  160. for key, value in kwds.items():
  161. self[key] = value
  162. def pop(self, key, default=__marker):
  163. try:
  164. value = self[key]
  165. except KeyError:
  166. if default is self.__marker:
  167. raise
  168. return default
  169. else:
  170. del self[key]
  171. return value
  172. def values(self):
  173. return [self[key] for key in self]
  174. def items(self):
  175. return [(key, self[key]) for key in self]
  176. def itervalues(self):
  177. for key in self:
  178. yield self[key]
  179. def iteritems(self):
  180. for key in self:
  181. yield (key, self[key])
  182. def iterkeys(self):
  183. return iter(self)
  184. def keys(self):
  185. return list(self)
  186. def popitem(self, last=True):
  187. """od.popitem() -> (k, v)
  188. Return and remove a (key, value) pair.
  189. Pairs are returned in LIFO order if last is true or FIFO
  190. order if false.
  191. """
  192. if not self:
  193. raise KeyError('dictionary is empty')
  194. key = (last and reversed(self) or iter(self)).next()
  195. value = self.pop(key)
  196. return key, value
  197. def __repr__(self):
  198. "od.__repr__() <==> repr(od)"
  199. if not self:
  200. return '%s()' % (self.__class__.__name__,)
  201. return '%s(%r)' % (self.__class__.__name__, self.items())
  202. def copy(self):
  203. "od.copy() -> a shallow copy of od"
  204. return self.__class__(self)
  205. @classmethod
  206. def fromkeys(cls, iterable, value=None):
  207. """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
  208. and values equal to v (which defaults to None)."""
  209. d = cls()
  210. for key in iterable:
  211. d[key] = value
  212. return d
  213. def __eq__(self, other):
  214. """od.__eq__(y) <==> od==y. Comparison to another OD is
  215. order-sensitive while comparison to a regular mapping
  216. is order-insensitive."""
  217. if isinstance(other, OrderedDict):
  218. return len(self) == len(other) and \
  219. all(_imap(_eq, self.iteritems(), other.iteritems()))
  220. return dict.__eq__(self, other)
  221. def __ne__(self, other):
  222. return not (self == other)
  223. try:
  224. from collections import OrderedDict
  225. except ImportError:
  226. OrderedDict = CompatOrderedDict
  227. ############## collections.defaultdict ######################################
  228. try:
  229. from collections import defaultdict
  230. except ImportError:
  231. # Written by Jason Kirtland, taken from Python Cookbook:
  232. # <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/523034>
  233. class defaultdict(dict):
  234. def __init__(self, default_factory=None, *args, **kwargs):
  235. dict.__init__(self, *args, **kwargs)
  236. self.default_factory = default_factory
  237. def __getitem__(self, key):
  238. try:
  239. return dict.__getitem__(self, key)
  240. except KeyError:
  241. return self.__missing__(key)
  242. def __missing__(self, key):
  243. if self.default_factory is None:
  244. raise KeyError(key)
  245. self[key] = value = self.default_factory()
  246. return value
  247. def __reduce__(self):
  248. f = self.default_factory
  249. args = f is None and tuple() or f
  250. return type(self), args, None, None, self.iteritems()
  251. def copy(self):
  252. return self.__copy__()
  253. def __copy__(self):
  254. return type(self)(self.default_factory, self)
  255. def __deepcopy__(self):
  256. import copy
  257. return type(self)(self.default_factory,
  258. copy.deepcopy(self.items()))
  259. def __repr__(self):
  260. return "defaultdict(%s, %s)" % (self.default_factory,
  261. dict.__repr__(self))
  262. import collections
  263. collections.defaultdict = defaultdict # Pickle needs this.
  264. ############## logging.LoggerAdapter ########################################
  265. import inspect
  266. import logging
  267. try:
  268. import multiprocessing
  269. except ImportError:
  270. multiprocessing = None
  271. import sys
  272. from logging import LogRecord
  273. log_takes_extra = "extra" in inspect.getargspec(logging.Logger._log)[0]
  274. # The func argument to LogRecord was added in 2.5
  275. if "func" not in inspect.getargspec(LogRecord.__init__)[0]:
  276. def LogRecord(name, level, fn, lno, msg, args, exc_info, func):
  277. return logging.LogRecord(name, level, fn, lno, msg, args, exc_info)
  278. def _checkLevel(level):
  279. if isinstance(level, int):
  280. rv = level
  281. elif str(level) == level:
  282. if level not in logging._levelNames:
  283. raise ValueError("Unknown level: %r" % level)
  284. rv = logging._levelNames[level]
  285. else:
  286. raise TypeError("Level not an integer or a valid string: %r" % level)
  287. return rv
  288. class _CompatLoggerAdapter(object):
  289. def __init__(self, logger, extra):
  290. self.logger = logger
  291. self.extra = extra
  292. def setLevel(self, level):
  293. self.logger.level = _checkLevel(level)
  294. def process(self, msg, kwargs):
  295. kwargs["extra"] = self.extra
  296. return msg, kwargs
  297. def debug(self, msg, *args, **kwargs):
  298. self.log(logging.DEBUG, msg, *args, **kwargs)
  299. def info(self, msg, *args, **kwargs):
  300. self.log(logging.INFO, msg, *args, **kwargs)
  301. def warning(self, msg, *args, **kwargs):
  302. self.log(logging.WARNING, msg, *args, **kwargs)
  303. warn = warning
  304. def error(self, msg, *args, **kwargs):
  305. self.log(logging.ERROR, msg, *args, **kwargs)
  306. def exception(self, msg, *args, **kwargs):
  307. kwargs.setdefault("exc_info", 1)
  308. self.error(msg, *args, **kwargs)
  309. def critical(self, msg, *args, **kwargs):
  310. self.log(logging.CRITICAL, msg, *args, **kwargs)
  311. fatal = critical
  312. def log(self, level, msg, *args, **kwargs):
  313. if self.logger.isEnabledFor(level):
  314. msg, kwargs = self.process(msg, kwargs)
  315. self._log(level, msg, args, **kwargs)
  316. def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
  317. func=None, extra=None):
  318. rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
  319. if extra is not None:
  320. for key, value in extra.items():
  321. if key in ("message", "asctime") or key in rv.__dict__:
  322. raise KeyError(
  323. "Attempt to override %r in LogRecord" % key)
  324. rv.__dict__[key] = value
  325. if multiprocessing is not None:
  326. rv.processName = multiprocessing.current_process()._name
  327. else:
  328. rv.processName = ""
  329. return rv
  330. def _log(self, level, msg, args, exc_info=None, extra=None):
  331. defcaller = "(unknown file)", 0, "(unknown function)"
  332. if logging._srcfile:
  333. # IronPython doesn't track Python frames, so findCaller
  334. # throws an exception on some versions of IronPython.
  335. # We trap it here so that IronPython can use logging.
  336. try:
  337. fn, lno, func = self.logger.findCaller()
  338. except ValueError:
  339. fn, lno, func = defcaller
  340. else:
  341. fn, lno, func = defcaller
  342. if exc_info:
  343. if not isinstance(exc_info, tuple):
  344. exc_info = sys.exc_info()
  345. record = self.makeRecord(self.logger.name, level, fn, lno, msg,
  346. args, exc_info, func, extra)
  347. self.logger.handle(record)
  348. def isEnabledFor(self, level):
  349. return self.logger.isEnabledFor(level)
  350. def addHandler(self, hdlr):
  351. self.logger.addHandler(hdlr)
  352. def removeHandler(self, hdlr):
  353. self.logger.removeHandler(hdlr)
  354. @property
  355. def level(self):
  356. return self.logger.level
  357. try:
  358. from logging import LoggerAdapter
  359. except ImportError:
  360. LoggerAdapter = _CompatLoggerAdapter
  361. def log_with_extra(logger, level, msg, *args, **kwargs):
  362. if not log_takes_extra:
  363. kwargs.pop("extra", None)
  364. return logger.log(level, msg, *args, **kwargs)
  365. ############## itertools.izip_longest #######################################
  366. try:
  367. from itertools import izip_longest
  368. except ImportError:
  369. import itertools
  370. def izip_longest(*args, **kwds):
  371. fillvalue = kwds.get("fillvalue")
  372. def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
  373. yield counter() # yields the fillvalue, or raises IndexError
  374. fillers = itertools.repeat(fillvalue)
  375. iters = [itertools.chain(it, sentinel(), fillers)
  376. for it in args]
  377. try:
  378. for tup in itertools.izip(*iters):
  379. yield tup
  380. except IndexError:
  381. pass
  382. ############## itertools.chain.from_iterable ################################
  383. from itertools import chain
  384. def _compat_chain_from_iterable(iterables):
  385. for it in iterables:
  386. for element in it:
  387. yield element
  388. try:
  389. chain_from_iterable = getattr(chain, "from_iterable")
  390. except AttributeError:
  391. chain_from_iterable = _compat_chain_from_iterable