compat.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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 inspect
  202. import logging
  203. try:
  204. import multiprocessing
  205. except ImportError:
  206. multiprocessing = None # noqa
  207. import sys
  208. def _checkLevel(level):
  209. if isinstance(level, int):
  210. rv = level
  211. elif str(level) == level:
  212. if level not in logging._levelNames:
  213. raise ValueError("Unknown level: %r" % level)
  214. rv = logging._levelNames[level]
  215. else:
  216. raise TypeError("Level not an integer or a valid string: %r" % level)
  217. return rv
  218. class _CompatLoggerAdapter(object):
  219. def __init__(self, logger, extra):
  220. self.logger = logger
  221. self.extra = extra
  222. def setLevel(self, level):
  223. self.logger.level = _checkLevel(level)
  224. def process(self, msg, kwargs):
  225. kwargs["extra"] = self.extra
  226. return msg, kwargs
  227. def debug(self, msg, *args, **kwargs):
  228. self.log(logging.DEBUG, msg, *args, **kwargs)
  229. def info(self, msg, *args, **kwargs):
  230. self.log(logging.INFO, msg, *args, **kwargs)
  231. def warning(self, msg, *args, **kwargs):
  232. self.log(logging.WARNING, msg, *args, **kwargs)
  233. warn = warning
  234. def error(self, msg, *args, **kwargs):
  235. self.log(logging.ERROR, msg, *args, **kwargs)
  236. def exception(self, msg, *args, **kwargs):
  237. kwargs.setdefault("exc_info", 1)
  238. self.error(msg, *args, **kwargs)
  239. def critical(self, msg, *args, **kwargs):
  240. self.log(logging.CRITICAL, msg, *args, **kwargs)
  241. fatal = critical
  242. def log(self, level, msg, *args, **kwargs):
  243. if self.logger.isEnabledFor(level):
  244. msg, kwargs = self.process(msg, kwargs)
  245. self._log(level, msg, args, **kwargs)
  246. def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
  247. func=None, extra=None):
  248. rv = logging.LogRecord(name, level, fn, lno, msg, args, exc_info, func)
  249. if extra is not None:
  250. for key, value in extra.items():
  251. if key in ("message", "asctime") or key in rv.__dict__:
  252. raise KeyError(
  253. "Attempt to override %r in LogRecord" % key)
  254. rv.__dict__[key] = value
  255. if multiprocessing is not None:
  256. rv.processName = multiprocessing.current_process()._name
  257. else:
  258. rv.processName = ""
  259. return rv
  260. def _log(self, level, msg, args, exc_info=None, extra=None):
  261. defcaller = "(unknown file)", 0, "(unknown function)"
  262. if logging._srcfile:
  263. # IronPython doesn't track Python frames, so findCaller
  264. # throws an exception on some versions of IronPython.
  265. # We trap it here so that IronPython can use logging.
  266. try:
  267. fn, lno, func = self.logger.findCaller()
  268. except ValueError:
  269. fn, lno, func = defcaller
  270. else:
  271. fn, lno, func = defcaller
  272. if exc_info:
  273. if not isinstance(exc_info, tuple):
  274. exc_info = sys.exc_info()
  275. record = self.makeRecord(self.logger.name, level, fn, lno, msg,
  276. args, exc_info, func, extra)
  277. self.logger.handle(record)
  278. def isEnabledFor(self, level):
  279. return self.logger.isEnabledFor(level)
  280. def addHandler(self, hdlr):
  281. self.logger.addHandler(hdlr)
  282. def removeHandler(self, hdlr):
  283. self.logger.removeHandler(hdlr)
  284. @property
  285. def level(self):
  286. return self.logger.level
  287. try:
  288. from logging import LoggerAdapter
  289. except ImportError:
  290. LoggerAdapter = _CompatLoggerAdapter # noqa
  291. ############## itertools.izip_longest #######################################
  292. try:
  293. from itertools import izip_longest
  294. except ImportError:
  295. import itertools
  296. def izip_longest(*args, **kwds): # noqa
  297. fillvalue = kwds.get("fillvalue")
  298. def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
  299. yield counter() # yields the fillvalue, or raises IndexError
  300. fillers = itertools.repeat(fillvalue)
  301. iters = [itertools.chain(it, sentinel(), fillers)
  302. for it in args]
  303. try:
  304. for tup in itertools.izip(*iters):
  305. yield tup
  306. except IndexError:
  307. pass
  308. ############## itertools.chain.from_iterable ################################
  309. from itertools import chain
  310. def _compat_chain_from_iterable(iterables):
  311. for it in iterables:
  312. for element in it:
  313. yield element
  314. try:
  315. chain_from_iterable = getattr(chain, "from_iterable")
  316. except AttributeError:
  317. chain_from_iterable = _compat_chain_from_iterable
  318. ############## logging.handlers.WatchedFileHandler ##########################
  319. import os
  320. from stat import ST_DEV, ST_INO
  321. import platform as _platform
  322. if _platform.system() == "Windows":
  323. #since windows doesn't go with WatchedFileHandler use FileHandler instead
  324. WatchedFileHandler = logging.FileHandler
  325. else:
  326. try:
  327. from logging.handlers import WatchedFileHandler
  328. except ImportError:
  329. class WatchedFileHandler(logging.FileHandler): # noqa
  330. """
  331. A handler for logging to a file, which watches the file
  332. to see if it has changed while in use. This can happen because of
  333. usage of programs such as newsyslog and logrotate which perform
  334. log file rotation. This handler, intended for use under Unix,
  335. watches the file to see if it has changed since the last emit.
  336. (A file has changed if its device or inode have changed.)
  337. If it has changed, the old file stream is closed, and the file
  338. opened to get a new stream.
  339. This handler is not appropriate for use under Windows, because
  340. under Windows open files cannot be moved or renamed - logging
  341. opens the files with exclusive locks - and so there is no need
  342. for such a handler. Furthermore, ST_INO is not supported under
  343. Windows; stat always returns zero for this value.
  344. This handler is based on a suggestion and patch by Chad J.
  345. Schroeder.
  346. """
  347. def __init__(self, *args, **kwargs):
  348. logging.FileHandler.__init__(self, *args, **kwargs)
  349. if not os.path.exists(self.baseFilename):
  350. self.dev, self.ino = -1, -1
  351. else:
  352. stat = os.stat(self.baseFilename)
  353. self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
  354. def emit(self, record):
  355. """
  356. Emit a record.
  357. First check if the underlying file has changed, and if it
  358. has, close the old stream and reopen the file to get the
  359. current stream.
  360. """
  361. if not os.path.exists(self.baseFilename):
  362. stat = None
  363. changed = 1
  364. else:
  365. stat = os.stat(self.baseFilename)
  366. changed = ((stat[ST_DEV] != self.dev) or
  367. (stat[ST_INO] != self.ino))
  368. if changed and self.stream is not None:
  369. self.stream.flush()
  370. self.stream.close()
  371. self.stream = self._open()
  372. if stat is None:
  373. stat = os.stat(self.baseFilename)
  374. self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
  375. logging.FileHandler.emit(self, record)