A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot

92 line
2.7 KiB

  1. # -*- coding: utf-8 -*-
  2. """
  3. EarwigBot's IRC Command Manager
  4. This package provides the IRC "commands" used by the bot's front-end component.
  5. In __init__, you can find some functions used to load and run these commands.
  6. """
  7. import logging
  8. import os
  9. import sys
  10. from classes import BaseCommand
  11. import config
  12. __all__ = ["load", "get_all", "check"]
  13. # Base directory when searching for commands:
  14. base_dir = os.path.join(config.root_dir, "bot", "commands")
  15. # Store commands in a dict, where the key is the command's name and the value
  16. # is an instance of the command's class:
  17. _commands = {}
  18. # Logger for this module:
  19. logger = logging.getLogger("tasks")
  20. def _load_command(connection, filename):
  21. """Try to load a specific command from a module, identified by file name.
  22. Given a Connection object and a filename, we'll first try to import it,
  23. and if that works, make an instance of the 'Command' class inside (assuming
  24. it is an instance of BaseCommand), add it to _commands, and report the
  25. addition to the user. Any problems along the way will either be ignored or
  26. reported.
  27. """
  28. global _commands
  29. # Strip .py from the end of the filename and join with our package name:
  30. name = ".".join(("commands", filename[:-3]))
  31. try:
  32. __import__(name)
  33. except:
  34. logger.exception("Couldn't load file {0}".format(filename))
  35. return
  36. command = sys.modules[name].Command(connection)
  37. if not isinstance(command, BaseCommand):
  38. return
  39. _commands[command.name] = command
  40. logger.debug("Added command {0}".format(command.name))
  41. def load(connection):
  42. """Load all valid commands into the _commands global variable.
  43. `connection` is a Connection object that is given to each command's
  44. constructor.
  45. """
  46. files = os.listdir(base_dir)
  47. files.sort()
  48. for filename in files:
  49. if filename.startswith("_") or not filename.endswith(".py"):
  50. continue
  51. try:
  52. _load_command(connection, filename)
  53. except AttributeError:
  54. pass # The file is doesn't contain a command, so just move on
  55. msg = "Found {0} commands: {1}"
  56. logger.info(msg.format(len(_commands), ", ".join(_commands.keys())))
  57. def get_all():
  58. """Return our dict of all loaded commands."""
  59. return _commands
  60. def check(hook, data):
  61. """Given an event on IRC, check if there's anything we can respond to."""
  62. # Parse command arguments into data.command and data.args:
  63. data.parse_args()
  64. for command in _commands.values():
  65. if hook in command.hooks:
  66. if command.check(data):
  67. try:
  68. command.process(data)
  69. except:
  70. logger.exception("Error executing command '{0}'".format(data.command))
  71. break