decorators.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. from collections.abc import Callable
  2. from typing import Union
  3. import inspect
  4. from ..types import Message, Context, CommandType, Response, StartupShutdownType, CommandConfiguration
  5. from .failure import RollbotFailureException
  6. decorated_startup: list[StartupShutdownType] = []
  7. decorated_shutdown: list[StartupShutdownType] = []
  8. decorated_commands: dict[str, CommandType] = {}
  9. def on_startup(fn):
  10. decorated_startup.append(fn)
  11. return fn
  12. def on_shutdown(fn):
  13. decorated_shutdown.append(fn)
  14. return fn
  15. def as_command(arg: Union[str, Callable]):
  16. def impl(name, fn):
  17. if inspect.isasyncgenfunction(fn):
  18. lifted = fn
  19. elif inspect.iscoroutinefunction(fn):
  20. async def lifted(*args):
  21. yield await fn(*args)
  22. elif inspect.isgeneratorfunction(fn):
  23. async def lifted(*args):
  24. for res in fn(*args):
  25. yield res
  26. elif inspect.isfunction(fn):
  27. async def lifted(*args):
  28. yield fn(*args)
  29. else:
  30. raise ValueError # TODO details
  31. async def command_impl(message: Message, context: Context):
  32. args = [] # TODO implement dep injection
  33. try:
  34. async for result in lifted(*args):
  35. if isinstance(result, Response):
  36. response = result
  37. elif isinstance(result, str):
  38. response = Response.from_message(message, text=result)
  39. # TODO handle attachments, other special returns
  40. else:
  41. response = Response.from_message(message, str(result))
  42. await context.respond(response)
  43. except RollbotFailureException as exc:
  44. # TODO handle errors more specifically
  45. await context.respond(Response.from_message(message, str(exc.failure)))
  46. decorated_commands[name] = command_impl
  47. return fn
  48. if isinstance(arg, str):
  49. return lambda fn: impl(arg, fn)
  50. else:
  51. return impl(arg.__name__, arg)
  52. def get_command_config() -> CommandConfiguration:
  53. return CommandConfiguration(
  54. commands=decorated_commands,
  55. call_and_response={},
  56. aliases={},
  57. bangs=(),
  58. startup=decorated_startup,
  59. shutdown=decorated_shutdown,
  60. )