A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

12 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
11 лет назад
12 лет назад
12 лет назад
11 лет назад
12 лет назад
12 лет назад
12 лет назад
11 лет назад
12 лет назад
12 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2009-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. # SOFTWARE.
  22. import re
  23. __all__ = ["Data"]
  24. class Data(object):
  25. """Store data from an individual line received on IRC."""
  26. def __init__(self, bot, my_nick, line, msgtype):
  27. self._bot = bot
  28. self._my_nick = my_nick.lower()
  29. self._line = line
  30. self._is_private = self._is_command = False
  31. self._msg = self._command = self._trigger = None
  32. self._args = []
  33. self._kwargs = {}
  34. self._parse(msgtype)
  35. def __repr__(self):
  36. """Return the canonical string representation of the Data."""
  37. res = "Data(bot={0!r}, my_nick={1!r}, line={2!r})"
  38. return res.format(self._bot, self.my_nick, self.line)
  39. def __str__(self):
  40. """Return a nice string representation of the Data."""
  41. return "<Data of {0!r}>".format(" ".join(self.line))
  42. def _parse(self, msgtype):
  43. """Parse a line from IRC into its components as instance attributes."""
  44. sender = re.findall(r":(.*?)!(.*?)@(.*?)\Z", self.line[0])[0]
  45. self._nick, self._ident, self._host = sender
  46. self._chan = self.line[2]
  47. if msgtype == "PRIVMSG":
  48. if self.chan.lower() == self.my_nick:
  49. # This is a privmsg to us, so set 'chan' as the nick of the
  50. # sender instead of the 'channel', which is ourselves:
  51. self._chan = self._nick
  52. self._is_private = True
  53. self._msg = " ".join(self.line[3:])[1:]
  54. self._parse_args()
  55. self._parse_kwargs()
  56. def _parse_args(self):
  57. """Parse command arguments from the message.
  58. self.msg is converted into the string self.command and the argument
  59. list self.args if the message starts with a "trigger" ("!", ".", or the
  60. bot's name); self.is_command will be set to True, and self.trigger will
  61. store the trigger string. Otherwise, is_command will be set to False.
  62. """
  63. self._args = self.msg.strip().split()
  64. try:
  65. self._command = self.args.pop(0).lower()
  66. except IndexError:
  67. return
  68. if self.command.startswith("!") or self.command.startswith("."):
  69. # e.g. "!command arg1 arg2"
  70. self._is_command = True
  71. self._trigger = self.command[0]
  72. self._command = self.command[1:] # Strip the "!" or "."
  73. elif re.match(r"{0}\W*?$".format(re.escape(self.my_nick)),
  74. self.command, re.U):
  75. # e.g. "EarwigBot, command arg1 arg2"
  76. self._is_command = True
  77. self._trigger = self.my_nick
  78. try:
  79. self._command = self.args.pop(0).lower()
  80. except IndexError:
  81. self._command = ""
  82. else:
  83. try:
  84. if self.msg[-1] == "." and self.msg[-2] != ".":
  85. if self.args:
  86. self.args[-1] = self.args[-1][:-1]
  87. else:
  88. self._command = self.command[:-1]
  89. except IndexError:
  90. pass
  91. def _parse_kwargs(self):
  92. """Parse keyword arguments embedded in self.args.
  93. Parse a command given as "!command key1=value1 key2=value2..." into a
  94. dict, self.kwargs, like {'key1': 'value2', 'key2': 'value2'...}.
  95. """
  96. for arg in self.args:
  97. try:
  98. key, value = re.findall(r"^(.*?)\=(.*?)$", arg)[0]
  99. except IndexError:
  100. continue
  101. if key and value:
  102. self.kwargs[key] = value
  103. @property
  104. def my_nick(self):
  105. """Our nickname, *not* the nickname of the sender."""
  106. return self._my_nick
  107. @property
  108. def line(self):
  109. """The full message received on IRC, including escape characters."""
  110. return self._line
  111. @property
  112. def chan(self):
  113. """Channel the message was sent from.
  114. This will be equal to :py:attr:`nick` if the message is a private
  115. message.
  116. """
  117. return self._chan
  118. @property
  119. def nick(self):
  120. """Nickname of the sender."""
  121. return self._nick
  122. @property
  123. def ident(self):
  124. """`Ident <http://en.wikipedia.org/wiki/Ident>`_ of the sender."""
  125. return self._ident
  126. @property
  127. def host(self):
  128. """Hostname of the sender."""
  129. return self._host
  130. @property
  131. def msg(self):
  132. """Text of the sent message, if it is a message, else ``None``."""
  133. return self._msg
  134. @property
  135. def is_private(self):
  136. """``True`` if this message was sent to us *only*, else ``False``."""
  137. return self._is_private
  138. @property
  139. def is_command(self):
  140. """Boolean telling whether or not this message is a bot command.
  141. A message is considered a command if and only if it begins with the
  142. character ``"!"``, ``"."``, or the bot's name followed by optional
  143. punctuation and a space (so ``EarwigBot: do something``, ``EarwigBot,
  144. do something``, and ``EarwigBot do something`` are all valid).
  145. """
  146. return self._is_command
  147. @property
  148. def command(self):
  149. """If the message is a command, this is the name of the command used.
  150. See :py:attr:`is_command <self.is_command>` for when a message is
  151. considered a command. If it's not a command, this will be set to
  152. ``None``.
  153. """
  154. return self._command
  155. @property
  156. def trigger(self):
  157. """If this message is a command, this is what triggered it.
  158. It can be either "!" (``"!help"``), "." (``".help"``), or the bot's
  159. name (``"EarwigBot: help"``). Otherwise, it will be ``None``."""
  160. return self._trigger
  161. @property
  162. def args(self):
  163. """List of all arguments given to this command.
  164. For example, the message ``"!command arg1 arg2 arg3=val3"`` will
  165. produce the args ``["arg1", "arg2", "arg3=val3"]``. This is empty if
  166. the message was not a command or if it doesn't have arguments.
  167. """
  168. return self._args
  169. @property
  170. def kwargs(self):
  171. """Dictionary of keyword arguments given to this command.
  172. For example, the message ``"!command arg1=val1 arg2=val2"`` will
  173. produce the kwargs ``{"arg1": "val1", "arg2": "val2"}``. This is empty
  174. if the message was not a command or if it doesn't have keyword
  175. arguments.
  176. """
  177. return self._kwargs