import inspect import thread import traceback import Queue def _isfunc(x): if type(x) == type(_isfunc): return True return False def _hook_add(func, add, name=''): if not hasattr(func, '_skybot_hook'): func._skybot_hook = [] func._skybot_hook.append(add) if not hasattr(func, '_skybot_args'): argspec = inspect.getargspec(func) if name: n_args = len(argspec.args) if argspec.defaults: n_args -= len(argspec.defaults) if argspec.keywords: n_args -= 1 if argspec.varargs: n_args -= 1 if n_args != 1: err = '%ss must take 1 non-keyword argument (%s)' % (name, func.__name__) raise ValueError(err) args = [] if argspec.defaults: end = bool(argspec.keywords) + bool(argspec.varargs) args.extend(argspec.args[-len(argspec.defaults): end if end else None]) if argspec.keywords: args.append(0) # means kwargs present func._skybot_args = args def _make_sig(f): return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno def sieve(func): if func.func_code.co_argcount != 4: raise ValueError( 'sieves must take 4 arguments: (bot, input, func, args)') _hook_add(func, ['sieve', (_make_sig(func), func)]) return func def command(func=None, hook=None, **kwargs): args = {} def command_wrapper(func): args.setdefault('name', func.func_name) args.setdefault('hook', args['name'] + r'(?:\s+|$)(.*)') _hook_add(func, ['command', (_make_sig(func), func, args)], 'command') return func if hook is not None or kwargs or not _isfunc(func): if func is not None: args['name'] = func if hook is not None: args['hook'] = hook args.update(kwargs) return command_wrapper else: return command_wrapper(func) def event(arg=None, **kwargs): args = kwargs def event_wrapper(func): args['name'] = func.func_name args['prefix'] = False args.setdefault('events', '*') _hook_add(func, ['event', (_make_sig(func), func, args)], 'event') return func if _isfunc(arg): return event_wrapper(arg, kwargs) else: if arg is not None: args['events'] = arg.split() return event_wrapper def tee(func, **kwargs): "passes _all_ input lines to function, in order (skips sieves)" if func.func_code.co_argcount != 2: raise ValueError('tees must take 2 arguments: (bot, input)') _hook_add(func, ['tee', (_make_sig(func), func, kwargs)]) func._iqueue = Queue.Queue() def trampoline(func): input = None while True: input = func._iqueue.get() if input == StopIteration: return try: func(*input) except Exception: traceback.print_exc(Exception) thread.start_new_thread(trampoline, (func,)) return func