1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
# -*- coding: utf-8 -*-
#
# This file is part of Linux Show Player
#
# Copyright 2012-2016 Francesco Ceruti <ceppofrancy@gmail.com>
#
# Linux Show Player is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Linux Show Player is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Linux Show Player. If not, see <http://www.gnu.org/licenses/>.
import logging
import traceback
from functools import wraps, partial
from threading import Thread, Lock, RLock
def async_function(target):
"""Decorator. Make a function asynchronous.
The decorated function is executed in a differed thread.
"""
@wraps(target)
def wrapped(*args, **kwargs):
Thread(target=target, args=args, kwargs=kwargs, daemon=True).start()
return wrapped
def async_in_pool(pool):
"""Decorator. Make a function asynchronous in a specified pool.
The decorated function is executed in the specified threads-pool.
.. Usage::
class MyClass:
__MyPool = ThreadPoolExecutor(10)
@async_in_pool(__MyPool)
def do_some_task(self):
pass
"""
def decorator(target):
@wraps(target)
def wrapped(*args, **kwargs):
pool.submit(target, *args, **kwargs)
return wrapped
return decorator
def locked_function(target=None, *, lock=None, blocking=True, timeout=-1):
"""Decorator. Make a *function* "synchronized".
Only one thread at time can access the decorated function.
:param target: the function to decorate
:param lock: the lock to be used (if not specified an RLock is created)
:param blocking: if True the lock-acquirement is blocking
:param timeout: timeout for the lock-acquirement
"""
# If called with (keywords) arguments
if target is None:
return partial(locked_function, lock=lock, blocking=blocking,
timeout=timeout)
if lock is None:
target.__lock__ = RLock()
else:
target.__lock__ = lock
@wraps(target)
def locked(*args, **kwargs):
try:
if target.__lock__.acquire(blocking=blocking, timeout=timeout):
return target(*args, **kwargs)
else:
return
finally:
try:
target.__lock__.release()
except RuntimeError:
pass
return locked
def locked_method(target=None, *, blocking=True, timeout=-1):
"""Decorator. Make a *method* synchronized.
Only one thread at time can access the decorated method.
:param target: the function to decorate
:param blocking: if True the lock-acquirement is blocking
:param timeout: timeout for the lock-acquirement
"""
# If called with (keywords) arguments
if target is None:
return partial(locked_method, blocking=blocking, timeout=timeout)
# generate a lock_name like "__method_name_lock__"
lock_name = '__' + target.__name__ + '_lock__'
target.__meta_lock__ = Lock()
@wraps(target)
def locked(self, *args, **kwargs):
with target.__meta_lock__:
lock = getattr(self, lock_name, None)
# If the lock is not defined, then define it
if lock is None:
lock = RLock()
setattr(self, lock_name, lock)
try:
if lock.acquire(blocking=blocking, timeout=timeout):
return target(self, *args, **kwargs)
else:
return
finally:
try:
lock.release()
except RuntimeError:
pass
return locked
def suppress_exceptions(target=None, *, log=True):
"""Decorator. Suppress all the exception in the decorated function.
:param log: If True (the default) exceptions are logged as warnings.
"""
if target is None:
return partial(suppress_exceptions, print_exc=log)
@wraps(target)
def wrapped(*args, **kwargs):
try:
return target(*args, **kwargs)
except Exception:
logging.warning('Exception suppressed:\n' + traceback.format_exc())
return wrapped
def memoize(callable_):
"""Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
.. Note::
This works for any callable object.
The arguments are cached (as strings) in object.cache.
"""
cache = callable_.cache = {}
@wraps(callable_)
def memoizer(*args, **kwargs):
key = str(args) + str(kwargs)
if key not in cache:
cache[key] = callable_(*args, **kwargs)
return cache[key]
return memoizer
|