import threading
import inspect
class ThreadSafeFactory:
@staticmethod
def make_threadsafe_instance(type_name, *instance_args, **instance_kwargs):
class ThreadSafeCls(type_name):
PUBLIC_WARP_METHODS = []
WARP_METHODS_MAP = {
set: ['add', 'pop'],
dict: ['get', 'items', 'values', 'keys', '__getitem__']
}
def __init__(self, *args, **kwargs):
self.wrap_kwargs = {
'wrap_all_func': kwargs.pop('wrap_all_func', False),
'skip_magic_func': kwargs.pop('skip_magic_func', False)
}
super().__init__(*args, **kwargs)
self.lock = threading.RLock()
self._wrap_safe_methods(**self.wrap_kwargs)
def _wrap_safe_methods(self, wrap_all_func=False, skip_magic_func=False):
all_methods = [name for name, _ in inspect.getmembers(self, inspect.ismethod)]
wrap_methods = all_methods if wrap_all_func else self.WARP_METHODS_MAP.get(type_name, [])
for method_name in wrap_methods:
if skip_magic_func and (method_name.startswith('__') or method_name.startswith('_')):
continue
if not hasattr(self, method_name):
continue
if callable(getattr(self, method_name)):
setattr(self, method_name, self._create_safe_method(method_name))
def _create_safe_method(self, name):
with self.lock:
attr = getattr(super(), name)
def wrapper(*args, **kwargs):
with self.lock:
return attr(*args, **kwargs)
return wrapper
return ThreadSafeCls(*instance_args, **instance_kwargs)