A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

util.py 5.8 KiB

12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
9 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright (C) 2009-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  5. #
  6. # Permission is hereby granted, free of charge, to any person obtaining a copy
  7. # of this software and associated documentation files (the "Software"), to deal
  8. # in the Software without restriction, including without limitation the rights
  9. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. # copies of the Software, and to permit persons to whom the Software is
  11. # furnished to do so, subject to the following conditions:
  12. #
  13. # The above copyright notice and this permission notice shall be included in
  14. # all copies or substantial portions of the Software.
  15. #
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. # SOFTWARE.
  23. """
  24. usage: :command:`earwigbot [-h] [-v] [-d | -q] [-t NAME] [PATH] ...`
  25. This is EarwigBot's command-line utility, enabling you to easily start the bot
  26. or run specific tasks.
  27. .. glossary::
  28. ``PATH``
  29. path to the bot's working directory, which will be created if it doesn't
  30. exist; current directory assumed if not specified
  31. ``-h``, ``--help``
  32. show this help message and exit
  33. ``-v``, ``--version``
  34. show program's version number and exit
  35. ``-d``, ``--debug``
  36. print all logs, including ``DEBUG``-level messages
  37. ``-q``, ``--quiet``
  38. don't print any logs except warnings and errors
  39. ``-t NAME``, ``--task NAME``
  40. given the name of a task, the bot will run it instead of the main bot and
  41. then exit
  42. ``TASK_ARGS``
  43. with --task, will pass any remaining arguments to the task's
  44. :py:meth:`.Task.run` method
  45. """
  46. from argparse import Action, ArgumentParser, REMAINDER
  47. import logging
  48. from os import path
  49. from time import sleep
  50. from earwigbot import __version__
  51. from earwigbot.bot import Bot
  52. __all__ = ["main"]
  53. class _StoreTaskArg(Action):
  54. """A custom argparse action to read remaining command-line arguments."""
  55. def __call__(self, parser, namespace, values, option_string=None):
  56. kwargs = {}
  57. name = None
  58. for value in values:
  59. if value.startswith("-") and "=" in value:
  60. key, value = value.split("=", 1)
  61. self.insert(kwargs, key.lstrip("-"), value)
  62. elif name:
  63. if value.startswith("-"):
  64. if name not in kwargs:
  65. kwargs[name] = True
  66. name = value.lstrip("-")
  67. else:
  68. self.insert(kwargs, name, value)
  69. name = None
  70. else:
  71. if value.startswith("-"):
  72. name = value.lstrip("-")
  73. if name and name not in kwargs:
  74. kwargs[name] = True
  75. namespace.task_args = kwargs
  76. def insert(self, kwargs, key, value):
  77. """Add a key/value pair to kwargs; support multiple values per key."""
  78. if key in kwargs:
  79. try:
  80. kwargs[key].append(value)
  81. except AttributeError:
  82. kwargs[key] = [kwargs[key], value]
  83. else:
  84. kwargs[key] = value
  85. def main():
  86. """Main entry point for the command-line utility."""
  87. version = "EarwigBot v{0}".format(__version__)
  88. desc = """This is EarwigBot's command-line utility, enabling you to easily
  89. start the bot or run specific tasks."""
  90. parser = ArgumentParser(description=desc)
  91. parser.add_argument("path", nargs="?", metavar="PATH", default=path.curdir,
  92. help="""path to the bot's working directory, which will
  93. be created if it doesn't exist; current
  94. directory assumed if not specified""")
  95. parser.add_argument("-v", "--version", action="version", version=version)
  96. logger = parser.add_mutually_exclusive_group()
  97. logger.add_argument("-d", "--debug", action="store_true",
  98. help="print all logs, including DEBUG-level messages")
  99. logger.add_argument("-q", "--quiet", action="store_true",
  100. help="don't print any logs except warnings and errors")
  101. parser.add_argument("-t", "--task", metavar="NAME",
  102. help="""given the name of a task, the bot will run it
  103. instead of the main bot and then exit""")
  104. parser.add_argument("task_args", nargs=REMAINDER, action=_StoreTaskArg,
  105. metavar="TASK_ARGS",
  106. help="""with --task, will pass these arguments to the
  107. task's run() method""")
  108. args = parser.parse_args()
  109. if not args.task and args.task_args:
  110. unrecognized = " ".join(args.task_args)
  111. parser.error("unrecognized arguments: {0}".format(unrecognized))
  112. level = logging.INFO
  113. if args.debug:
  114. level = logging.DEBUG
  115. elif args.quiet:
  116. level = logging.WARNING
  117. print(version)
  118. print()
  119. bot = Bot(path.abspath(args.path), level=level)
  120. if args.task:
  121. thread = bot.tasks.start(args.task, **args.task_args)
  122. if not thread:
  123. return
  124. try:
  125. while thread.is_alive(): # Keep it alive; it's a daemon
  126. sleep(1)
  127. except KeyboardInterrupt:
  128. pass
  129. finally:
  130. if thread.is_alive():
  131. bot.tasks.logger.warn("The task will be killed")
  132. else:
  133. try:
  134. bot.run()
  135. except KeyboardInterrupt:
  136. pass
  137. finally:
  138. if bot.is_running:
  139. bot.stop()
  140. if __name__ == "__main__":
  141. main()