__init__.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. # Copyright 2007 Matt Chaput. All rights reserved.
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions are met:
  5. #
  6. # 1. Redistributions of source code must retain the above copyright notice,
  7. # this list of conditions and the following disclaimer.
  8. #
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. #
  13. # THIS SOFTWARE IS PROVIDED BY MATT CHAPUT ``AS IS'' AND ANY EXPRESS OR
  14. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  15. # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  16. # EVENT SHALL MATT CHAPUT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  17. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  18. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  19. # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  20. # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  21. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  22. # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. #
  24. # The views and conclusions contained in the software and documentation are
  25. # those of the authors and should not be interpreted as representing official
  26. # policies, either expressed or implied, of Matt Chaput.
  27. from __future__ import with_statement
  28. import random, sys, time
  29. from bisect import insort, bisect_left
  30. from functools import wraps
  31. from whoosh.compat import xrange
  32. # These must be valid separate characters in CASE-INSENSTIVE filenames
  33. IDCHARS = "0123456789abcdefghijklmnopqrstuvwxyz"
  34. if hasattr(time, "perf_counter"):
  35. now = time.perf_counter
  36. elif sys.platform == 'win32':
  37. now = time.clock
  38. else:
  39. now = time.time
  40. def random_name(size=28):
  41. return "".join(random.choice(IDCHARS) for _ in xrange(size))
  42. def random_bytes(size=28):
  43. gen = (random.randint(0, 255) for _ in xrange(size))
  44. if sys.version_info[0] >= 3:
  45. return bytes(gen)
  46. else:
  47. return array("B", gen).tostring()
  48. def make_binary_tree(fn, args, **kwargs):
  49. """Takes a function/class that takes two positional arguments and a list of
  50. arguments and returns a binary tree of results/instances.
  51. >>> make_binary_tree(UnionMatcher, [matcher1, matcher2, matcher3])
  52. UnionMatcher(matcher1, UnionMatcher(matcher2, matcher3))
  53. Any keyword arguments given to this function are passed to the class
  54. initializer.
  55. """
  56. count = len(args)
  57. if not count:
  58. raise ValueError("Called make_binary_tree with empty list")
  59. elif count == 1:
  60. return args[0]
  61. half = count // 2
  62. return fn(make_binary_tree(fn, args[:half], **kwargs),
  63. make_binary_tree(fn, args[half:], **kwargs), **kwargs)
  64. def make_weighted_tree(fn, ls, **kwargs):
  65. """Takes a function/class that takes two positional arguments and a list of
  66. (weight, argument) tuples and returns a huffman-like weighted tree of
  67. results/instances.
  68. """
  69. if not ls:
  70. raise ValueError("Called make_weighted_tree with empty list")
  71. ls.sort()
  72. while len(ls) > 1:
  73. a = ls.pop(0)
  74. b = ls.pop(0)
  75. insort(ls, (a[0] + b[0], fn(a[1], b[1])))
  76. return ls[0][1]
  77. # Fibonacci function
  78. _fib_cache = {}
  79. def fib(n):
  80. """Returns the nth value in the Fibonacci sequence.
  81. """
  82. if n <= 2:
  83. return n
  84. if n in _fib_cache:
  85. return _fib_cache[n]
  86. result = fib(n - 1) + fib(n - 2)
  87. _fib_cache[n] = result
  88. return result
  89. # Decorators
  90. def synchronized(func):
  91. """Decorator for storage-access methods, which synchronizes on a threading
  92. lock. The parent object must have 'is_closed' and '_sync_lock' attributes.
  93. """
  94. @wraps(func)
  95. def synchronized_wrapper(self, *args, **kwargs):
  96. with self._sync_lock:
  97. return func(self, *args, **kwargs)
  98. return synchronized_wrapper
  99. def unclosed(method):
  100. """
  101. Decorator to check if the object is closed.
  102. """
  103. @wraps(method)
  104. def unclosed_wrapper(self, *args, **kwargs):
  105. if self.closed:
  106. raise ValueError("Operation on a closed object")
  107. return method(self, *args, **kwargs)
  108. return unclosed_wrapper