decorators.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. __author__ = 'SmileyBarry'
  2. import threading
  3. import time
  4. class debug(object):
  5. @staticmethod
  6. def no_return(originalFunction, *args, **kwargs):
  7. def callNoReturn(*args, **kwargs):
  8. originalFunction(*args, **kwargs)
  9. # This code should never return!
  10. raise AssertionError("No-return function returned.")
  11. return callNoReturn
  12. MINUTE = 60
  13. HOUR = 60 * MINUTE
  14. INFINITE = 0
  15. class cached_property(object):
  16. """(C) 2011 Christopher Arndt, MIT License
  17. Decorator for read-only properties evaluated only once within TTL period.
  18. It can be used to created a cached property like this::
  19. import random
  20. # the class containing the property must be a new-style class
  21. class MyClass(object):
  22. # create property whose value is cached for ten minutes
  23. @cached_property(ttl=600)
  24. def randint(self):
  25. # will only be evaluated every 10 min. at maximum.
  26. return random.randint(0, 100)
  27. The value is cached in the '_cache' attribute of the object instance that
  28. has the property getter method wrapped by this decorator. The '_cache'
  29. attribute value is a dictionary which has a key for every property of the
  30. object which is wrapped by this decorator. Each entry in the cache is
  31. created only when the property is accessed for the first time and is a
  32. two-element tuple with the last computed property value and the last time
  33. it was updated in seconds since the epoch.
  34. The default time-to-live (TTL) is 300 seconds (5 minutes). Set the TTL to
  35. zero for the cached value to never expire.
  36. To expire a cached property value manually just do::
  37. del instance._cache[<property name>]
  38. """
  39. def __init__(self, ttl=300):
  40. self.ttl = ttl
  41. def __call__(self, fget, doc=None):
  42. self.fget = fget
  43. self.__doc__ = doc or fget.__doc__
  44. self.__name__ = fget.__name__
  45. self.__module__ = fget.__module__
  46. return self
  47. def __get__(self, inst, owner):
  48. now = time.time()
  49. try:
  50. value, last_update = inst._cache[self.__name__]
  51. if self.ttl > 0 and now - last_update > self.ttl:
  52. raise AttributeError
  53. except (KeyError, AttributeError):
  54. value = self.fget(inst)
  55. try:
  56. cache = inst._cache
  57. except AttributeError:
  58. cache = inst._cache = {}
  59. cache[self.__name__] = (value, now)
  60. return value
  61. class Singleton:
  62. """
  63. A non-thread-safe helper class to ease implementing singletons.
  64. This should be used as a decorator -- not a metaclass -- to the
  65. class that should be a singleton.
  66. The decorated class can define one `__init__` function that
  67. takes only the `self` argument. Other than that, there are
  68. no restrictions that apply to the decorated class.
  69. Limitations: The decorated class cannot be inherited from.
  70. :author: Paul Manta, Stack Overflow.
  71. http://stackoverflow.com/a/7346105/2081507
  72. (with slight modification)
  73. """
  74. def __init__(self, decorated):
  75. self._lock = threading.Lock()
  76. self._decorated = decorated
  77. def __call__(self, *args, **kwargs):
  78. """
  79. Returns the singleton instance. Upon its first call, it creates a
  80. new instance of the decorated class and calls its `__init__` method.
  81. On all subsequent calls, the already created instance is returned.
  82. """
  83. with self._lock:
  84. try:
  85. return self._instance
  86. except AttributeError:
  87. self._instance = self._decorated(*args, **kwargs)
  88. return self._instance
  89. def __instancecheck__(self, inst):
  90. return isinstance(inst, self._decorated)