python-lastfm/lastfm/util/wormhole.py

89 lines
2.6 KiB
Python

#!/usr/bin/env python
__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm.util"
from collections import defaultdict
from decorator import decorator
from threading import Lock
_lock = Lock()
class Wormhole(object):
_entrances = defaultdict(set)
_exits = defaultdict(set)
_enabled = False
@staticmethod
def disable():
with _lock:
Wormhole._enabled = False
@staticmethod
def enable():
with _lock:
Wormhole._enabled = True
@staticmethod
def add_entrance(topic, entrance):
wrapped = Wormhole.entrance(topic)(entrance)
wrapped._orginal = entrance
return wrapped
@staticmethod
def add_exit(topic, exit):
Wormhole._exits[topic].add(exit)
@staticmethod
def remove_entrance(topic, entrance):
entrance = entrance._orginal
if topic in Wormhole._entrances:
if entrance in Wormhole._entrances[topic]:
Wormhole._entrances[topic].remove(entrance)
return entrance
@staticmethod
def remove_exit(topic, exit):
if topic in Wormhole._exits:
if exit in Wormhole._exits[topic]:
Wormhole._exits[topic].remove(exit)
@classmethod
def entrance(cls, topic):
@decorator
def wrapper(func, *args, **kwargs):
Wormhole._entrances[topic].add(func)
retval = func(*args, **kwargs)
if topic in Wormhole._exits:
if Wormhole._enabled:
if func in Wormhole._entrances[topic]:
cls._jump(topic, retval, *args, **kwargs)
return retval
return wrapper
@staticmethod
def exit(topic):
def wrapper(func):
Wormhole._exits[topic].add(func)
return func
return wrapper
@staticmethod
def _jump(topic, retval, *args, **kwargs):
exceptions = []
for f in Wormhole._exits[topic]:
try:
f(retval, *args, **kwargs)
except Exception as e:
exceptions.append(e)
for e in exceptions:
raise e
class ThreadedWormhole(Wormhole):
@staticmethod
def _jump(topic, retval, *args, **kwargs):
import threading
for f in Wormhole._exits[topic]:
threading.Thread(target = lambda: f(retval, *args, **kwargs)).start()