compat.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # -*- coding: utf-8 -*-
  2. """
  3. celery.utils.compat
  4. ~~~~~~~~~~~~~~~~~~~
  5. Backward compatible implementations of features
  6. only available in newer Python versions.
  7. :copyright: (c) 2009 - 2012 by Ask Solem.
  8. :license: BSD, see LICENSE for more details.
  9. """
  10. from __future__ import absolute_import
  11. ############## py3k #########################################################
  12. import sys
  13. is_py3k = sys.version_info[0] == 3
  14. try:
  15. reload = reload # noqa
  16. except NameError: # pragma: no cover
  17. from imp import reload # noqa
  18. try:
  19. from UserList import UserList # noqa
  20. except ImportError: # pragma: no cover
  21. from collections import UserList # noqa
  22. try:
  23. from UserDict import UserDict # noqa
  24. except ImportError: # pragma: no cover
  25. from collections import UserDict # noqa
  26. if is_py3k: # pragma: no cover
  27. from io import StringIO, BytesIO
  28. from .encoding import bytes_to_str
  29. class WhateverIO(StringIO):
  30. def write(self, data):
  31. StringIO.write(self, bytes_to_str(data))
  32. else:
  33. from StringIO import StringIO # noqa
  34. BytesIO = WhateverIO = StringIO # noqa
  35. ############## collections.OrderedDict ######################################
  36. try:
  37. from collections import OrderedDict
  38. except ImportError: # pragma: no cover
  39. from ordereddict import OrderedDict # noqa
  40. ############## itertools.zip_longest #######################################
  41. try:
  42. from itertools import izip_longest as zip_longest
  43. except ImportError: # pragma: no cover
  44. import itertools
  45. def zip_longest(*args, **kwds): # noqa
  46. fillvalue = kwds.get("fillvalue")
  47. def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
  48. yield counter() # yields the fillvalue, or raises IndexError
  49. fillers = itertools.repeat(fillvalue)
  50. iters = [itertools.chain(it, sentinel(), fillers)
  51. for it in args]
  52. try:
  53. for tup in itertools.izip(*iters):
  54. yield tup
  55. except IndexError:
  56. pass
  57. ############## itertools.chain.from_iterable ################################
  58. from itertools import chain
  59. def _compat_chain_from_iterable(iterables): # pragma: no cover
  60. for it in iterables:
  61. for element in it:
  62. yield element
  63. try:
  64. chain_from_iterable = getattr(chain, "from_iterable")
  65. except AttributeError: # pragma: no cover
  66. chain_from_iterable = _compat_chain_from_iterable
  67. ############## logging.handlers.WatchedFileHandler ##########################
  68. import logging
  69. import os
  70. from stat import ST_DEV, ST_INO
  71. import platform as _platform
  72. if _platform.system() == "Windows": # pragma: no cover
  73. #since windows doesn't go with WatchedFileHandler use FileHandler instead
  74. WatchedFileHandler = logging.FileHandler
  75. else:
  76. try:
  77. from logging.handlers import WatchedFileHandler
  78. except ImportError: # pragma: no cover
  79. class WatchedFileHandler(logging.FileHandler): # noqa
  80. """
  81. A handler for logging to a file, which watches the file
  82. to see if it has changed while in use. This can happen because of
  83. usage of programs such as newsyslog and logrotate which perform
  84. log file rotation. This handler, intended for use under Unix,
  85. watches the file to see if it has changed since the last emit.
  86. (A file has changed if its device or inode have changed.)
  87. If it has changed, the old file stream is closed, and the file
  88. opened to get a new stream.
  89. This handler is not appropriate for use under Windows, because
  90. under Windows open files cannot be moved or renamed - logging
  91. opens the files with exclusive locks - and so there is no need
  92. for such a handler. Furthermore, ST_INO is not supported under
  93. Windows; stat always returns zero for this value.
  94. This handler is based on a suggestion and patch by Chad J.
  95. Schroeder.
  96. """
  97. def __init__(self, *args, **kwargs):
  98. logging.FileHandler.__init__(self, *args, **kwargs)
  99. if not os.path.exists(self.baseFilename):
  100. self.dev, self.ino = -1, -1
  101. else:
  102. stat = os.stat(self.baseFilename)
  103. self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
  104. def emit(self, record):
  105. """
  106. Emit a record.
  107. First check if the underlying file has changed, and if it
  108. has, close the old stream and reopen the file to get the
  109. current stream.
  110. """
  111. if not os.path.exists(self.baseFilename):
  112. stat = None
  113. changed = 1
  114. else:
  115. stat = os.stat(self.baseFilename)
  116. changed = ((stat[ST_DEV] != self.dev) or
  117. (stat[ST_INO] != self.ino))
  118. if changed and self.stream is not None:
  119. self.stream.flush()
  120. self.stream.close()
  121. self.stream = self._open()
  122. if stat is None:
  123. stat = os.stat(self.baseFilename)
  124. self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
  125. logging.FileHandler.emit(self, record)