2017-08-13 18:12:00 -04:00
|
|
|
import logging
|
|
|
|
from functools import wraps
|
|
|
|
|
2017-08-13 19:11:40 -04:00
|
|
|
from optimize_later.utils import NoArgDecoratorMeta, with_metaclass
|
2017-08-13 18:12:00 -04:00
|
|
|
|
|
|
|
try:
|
|
|
|
import threading
|
|
|
|
except ImportError:
|
|
|
|
import dummy_threading as threading
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__.rpartition('.')[0] or __name__)
|
|
|
|
|
|
|
|
_global_callbacks = []
|
|
|
|
_local = threading.local()
|
|
|
|
|
|
|
|
|
|
|
|
def get_callbacks():
|
|
|
|
try:
|
|
|
|
return _local.callbacks
|
|
|
|
except AttributeError:
|
|
|
|
return _global_callbacks
|
2017-08-11 16:08:59 -04:00
|
|
|
|
|
|
|
|
|
|
|
def register_callback(callback):
|
2017-08-13 18:12:00 -04:00
|
|
|
get_callbacks().append(callback)
|
2017-08-11 16:08:59 -04:00
|
|
|
return callback
|
|
|
|
|
|
|
|
|
|
|
|
def deregister_callback(callback):
|
2017-08-13 18:12:00 -04:00
|
|
|
get_callbacks().remove(callback)
|
|
|
|
|
|
|
|
|
|
|
|
def global_callback(report):
|
|
|
|
for callback in get_callbacks():
|
|
|
|
try:
|
|
|
|
callback(report)
|
|
|
|
except Exception:
|
|
|
|
log.exception('Failed to invoke global callback: %r', callback)
|
|
|
|
|
|
|
|
|
2017-08-13 19:11:40 -04:00
|
|
|
class optimize_context(with_metaclass(NoArgDecoratorMeta)):
|
2017-08-13 20:21:17 -04:00
|
|
|
def __init__(self, callbacks=None, reset=False):
|
|
|
|
self.callbacks = callbacks or []
|
|
|
|
self.reset = reset
|
2017-08-13 18:12:00 -04:00
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
try:
|
|
|
|
self.old_context = _local.callbacks
|
|
|
|
except AttributeError:
|
|
|
|
self.old_context = None
|
|
|
|
|
2017-08-13 20:21:17 -04:00
|
|
|
if self.reset:
|
|
|
|
base_context = []
|
|
|
|
elif self.old_context is None:
|
|
|
|
base_context = _global_callbacks
|
2017-08-13 18:12:00 -04:00
|
|
|
else:
|
2017-08-13 20:21:17 -04:00
|
|
|
base_context = self.old_context
|
|
|
|
_local.callbacks = base_context + self.callbacks
|
2017-08-13 18:12:00 -04:00
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
|
|
if self.old_context is None:
|
|
|
|
del _local.callbacks
|
|
|
|
else:
|
|
|
|
_local.callbacks = self.old_context
|
|
|
|
|
|
|
|
def __call__(self, function):
|
|
|
|
@wraps(function)
|
|
|
|
def wrapper(*args, **kwargs):
|
2017-08-14 18:30:55 -04:00
|
|
|
with optimize_context(self.callbacks, reset=self.reset):
|
2017-08-13 18:12:00 -04:00
|
|
|
return function(*args, **kwargs)
|
|
|
|
return wrapper
|