Python module (submodule repositary), which provides content (video streams) from various online stream sources to corresponding Enigma2, Kodi, Plex plugins

memo.py 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. """Memoization utilities.
  2. """
  3. from functools import wraps
  4. from .core import ENOVAL
  5. def memoize(cache, name=None, typed=False, expire=None, tag=None):
  6. """Memoizing cache decorator.
  7. Decorator to wrap callable with memoizing function using cache. Repeated
  8. calls with the same arguments will lookup result in cache and avoid
  9. function evaluation.
  10. If name is set to None (default), the callable name will be determined
  11. automatically.
  12. If typed is set to True, function arguments of different types will be
  13. cached separately. For example, f(3) and f(3.0) will be treated as distinct
  14. calls with distinct results.
  15. The original underlying function is accessible through the __wrapped__
  16. attribute. This is useful for introspection, for bypassing the cache, or
  17. for rewrapping the function with a different cache.
  18. >>> from diskcache import FanoutCache
  19. >>> cache = FanoutCache('/tmp/diskcache/fanoutcache')
  20. >>> @cache.memoize(typed=True, expire=1, tag='fib')
  21. ... def fibonacci(number):
  22. ... if number == 0:
  23. ... return 0
  24. ... elif number == 1:
  25. ... return 1
  26. ... else:
  27. ... return fibonacci(number - 1) + fibonacci(number - 2)
  28. >>> print(sum(fibonacci(number=value) for value in range(100)))
  29. 573147844013817084100
  30. Remember to call memoize when decorating a callable. If you forget, then a
  31. TypeError will occur. Note the lack of parenthenses after memoize below:
  32. >>> @cache.memoize
  33. ... def test():
  34. ... pass
  35. Traceback (most recent call last):
  36. ...
  37. TypeError: name cannot be callable
  38. :param cache: cache to store callable arguments and return values
  39. :param str name: name given for callable (default None, automatic)
  40. :param bool typed: cache different types separately (default False)
  41. :param float expire: seconds until arguments expire
  42. (default None, no expiry)
  43. :param str tag: text to associate with arguments (default None)
  44. :return: callable decorator
  45. """
  46. if callable(name):
  47. raise TypeError('name cannot be callable')
  48. def decorator(function):
  49. "Decorator created by memoize call for callable."
  50. if name is None:
  51. try:
  52. reference = function.__qualname__
  53. except AttributeError:
  54. reference = function.__name__
  55. reference = function.__module__ + reference
  56. else:
  57. reference = name
  58. reference = (reference,)
  59. @wraps(function)
  60. def wrapper(*args, **kwargs):
  61. "Wrapper for callable to cache arguments and return values."
  62. key = reference + args
  63. if kwargs:
  64. key += (ENOVAL,)
  65. sorted_items = sorted(kwargs.items())
  66. for item in sorted_items:
  67. key += item
  68. if typed:
  69. key += tuple(type(arg) for arg in args)
  70. if kwargs:
  71. key += tuple(type(value) for _, value in sorted_items)
  72. result = cache.get(key, default=ENOVAL, retry=True)
  73. if result is ENOVAL:
  74. result = function(*args, **kwargs)
  75. cache.set(key, result, expire=expire, tag=tag, retry=True)
  76. return result
  77. return wrapper
  78. return decorator