Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scipy/_lib/_threadsafety.py: 72%
32 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
1import threading
3import scipy._lib.decorator
6__all__ = ['ReentrancyError', 'ReentrancyLock', 'non_reentrant']
9class ReentrancyError(RuntimeError):
10 pass
13class ReentrancyLock:
14 """
15 Threading lock that raises an exception for reentrant calls.
17 Calls from different threads are serialized, and nested calls from the
18 same thread result to an error.
20 The object can be used as a context manager or to decorate functions
21 via the decorate() method.
23 """
25 def __init__(self, err_msg):
26 self._rlock = threading.RLock()
27 self._entered = False
28 self._err_msg = err_msg
30 def __enter__(self):
31 self._rlock.acquire()
32 if self._entered:
33 self._rlock.release()
34 raise ReentrancyError(self._err_msg)
35 self._entered = True
37 def __exit__(self, type, value, traceback):
38 self._entered = False
39 self._rlock.release()
41 def decorate(self, func):
42 def caller(func, *a, **kw):
43 with self:
44 return func(*a, **kw)
45 return scipy._lib.decorator.decorate(func, caller)
48def non_reentrant(err_msg=None):
49 """
50 Decorate a function with a threading lock and prevent reentrant calls.
51 """
52 def decorator(func):
53 msg = err_msg
54 if msg is None:
55 msg = "%s is not re-entrant" % func.__name__
56 lock = ReentrancyLock(msg)
57 return lock.decorate(func)
58 return decorator