compat.py 15 KB

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