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

1import threading 

2 

3import scipy._lib.decorator 

4 

5 

6__all__ = ['ReentrancyError', 'ReentrancyLock', 'non_reentrant'] 

7 

8 

9class ReentrancyError(RuntimeError): 

10 pass 

11 

12 

13class ReentrancyLock: 

14 """ 

15 Threading lock that raises an exception for reentrant calls. 

16 

17 Calls from different threads are serialized, and nested calls from the 

18 same thread result to an error. 

19 

20 The object can be used as a context manager or to decorate functions 

21 via the decorate() method. 

22 

23 """ 

24 

25 def __init__(self, err_msg): 

26 self._rlock = threading.RLock() 

27 self._entered = False 

28 self._err_msg = err_msg 

29 

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 

36 

37 def __exit__(self, type, value, traceback): 

38 self._entered = False 

39 self._rlock.release() 

40 

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) 

46 

47 

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