decorators.py 2.4 KB

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