/python/psutil/psutil/_compat.py

https://github.com/rillian/firefox · Python · 189 lines · 150 code · 24 blank · 15 comment · 36 complexity · 8cd3dd7302ba7dee28261d381b8a3160 MD5 · raw file

  1. #!/usr/bin/env python
  2. # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Module which provides compatibility with older Python versions."""
  6. import collections
  7. import functools
  8. import sys
  9. __all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"]
  10. PY3 = sys.version_info[0] == 3
  11. if PY3:
  12. long = int
  13. xrange = range
  14. unicode = str
  15. def u(s):
  16. return s
  17. else:
  18. long = long
  19. xrange = xrange
  20. unicode = unicode
  21. def u(s):
  22. return unicode(s, "unicode_escape")
  23. # removed in 3.0, reintroduced in 3.2
  24. try:
  25. callable = callable
  26. except NameError:
  27. def callable(obj):
  28. return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
  29. # --- stdlib additions
  30. # py 3.2 functools.lru_cache
  31. # Taken from: http://code.activestate.com/recipes/578078
  32. # Credit: Raymond Hettinger
  33. try:
  34. from functools import lru_cache
  35. except ImportError:
  36. try:
  37. from threading import RLock
  38. except ImportError:
  39. from dummy_threading import RLock
  40. _CacheInfo = collections.namedtuple(
  41. "CacheInfo", ["hits", "misses", "maxsize", "currsize"])
  42. class _HashedSeq(list):
  43. __slots__ = 'hashvalue'
  44. def __init__(self, tup, hash=hash):
  45. self[:] = tup
  46. self.hashvalue = hash(tup)
  47. def __hash__(self):
  48. return self.hashvalue
  49. def _make_key(args, kwds, typed,
  50. kwd_mark=(object(), ),
  51. fasttypes=set((int, str, frozenset, type(None))),
  52. sorted=sorted, tuple=tuple, type=type, len=len):
  53. key = args
  54. if kwds:
  55. sorted_items = sorted(kwds.items())
  56. key += kwd_mark
  57. for item in sorted_items:
  58. key += item
  59. if typed:
  60. key += tuple(type(v) for v in args)
  61. if kwds:
  62. key += tuple(type(v) for k, v in sorted_items)
  63. elif len(key) == 1 and type(key[0]) in fasttypes:
  64. return key[0]
  65. return _HashedSeq(key)
  66. def lru_cache(maxsize=100, typed=False):
  67. """Least-recently-used cache decorator, see:
  68. http://docs.python.org/3/library/functools.html#functools.lru_cache
  69. """
  70. def decorating_function(user_function):
  71. cache = dict()
  72. stats = [0, 0]
  73. HITS, MISSES = 0, 1
  74. make_key = _make_key
  75. cache_get = cache.get
  76. _len = len
  77. lock = RLock()
  78. root = []
  79. root[:] = [root, root, None, None]
  80. nonlocal_root = [root]
  81. PREV, NEXT, KEY, RESULT = 0, 1, 2, 3
  82. if maxsize == 0:
  83. def wrapper(*args, **kwds):
  84. result = user_function(*args, **kwds)
  85. stats[MISSES] += 1
  86. return result
  87. elif maxsize is None:
  88. def wrapper(*args, **kwds):
  89. key = make_key(args, kwds, typed)
  90. result = cache_get(key, root)
  91. if result is not root:
  92. stats[HITS] += 1
  93. return result
  94. result = user_function(*args, **kwds)
  95. cache[key] = result
  96. stats[MISSES] += 1
  97. return result
  98. else:
  99. def wrapper(*args, **kwds):
  100. if kwds or typed:
  101. key = make_key(args, kwds, typed)
  102. else:
  103. key = args
  104. lock.acquire()
  105. try:
  106. link = cache_get(key)
  107. if link is not None:
  108. root, = nonlocal_root
  109. link_prev, link_next, key, result = link
  110. link_prev[NEXT] = link_next
  111. link_next[PREV] = link_prev
  112. last = root[PREV]
  113. last[NEXT] = root[PREV] = link
  114. link[PREV] = last
  115. link[NEXT] = root
  116. stats[HITS] += 1
  117. return result
  118. finally:
  119. lock.release()
  120. result = user_function(*args, **kwds)
  121. lock.acquire()
  122. try:
  123. root, = nonlocal_root
  124. if key in cache:
  125. pass
  126. elif _len(cache) >= maxsize:
  127. oldroot = root
  128. oldroot[KEY] = key
  129. oldroot[RESULT] = result
  130. root = nonlocal_root[0] = oldroot[NEXT]
  131. oldkey = root[KEY]
  132. root[KEY] = root[RESULT] = None
  133. del cache[oldkey]
  134. cache[key] = oldroot
  135. else:
  136. last = root[PREV]
  137. link = [last, root, key, result]
  138. last[NEXT] = root[PREV] = cache[key] = link
  139. stats[MISSES] += 1
  140. finally:
  141. lock.release()
  142. return result
  143. def cache_info():
  144. """Report cache statistics"""
  145. lock.acquire()
  146. try:
  147. return _CacheInfo(stats[HITS], stats[MISSES], maxsize,
  148. len(cache))
  149. finally:
  150. lock.release()
  151. def cache_clear():
  152. """Clear the cache and cache statistics"""
  153. lock.acquire()
  154. try:
  155. cache.clear()
  156. root = nonlocal_root[0]
  157. root[:] = [root, root, None, None]
  158. stats[:] = [0, 0]
  159. finally:
  160. lock.release()
  161. wrapper.__wrapped__ = user_function
  162. wrapper.cache_info = cache_info
  163. wrapper.cache_clear = cache_clear
  164. return functools.update_wrapper(wrapper, user_function)
  165. return decorating_function