@@ -7,7 +7,6 @@ commands Package | |||
.. automodule:: earwigbot.commands | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`afc_report` Module | |||
------------------------ | |||
@@ -152,4 +151,3 @@ commands Package | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
@@ -7,7 +7,6 @@ irc Package | |||
.. automodule:: earwigbot.irc | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`connection` Module | |||
------------------------ | |||
@@ -15,7 +14,6 @@ irc Package | |||
.. automodule:: earwigbot.irc.connection | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`data` Module | |||
------------------ | |||
@@ -23,7 +21,6 @@ irc Package | |||
.. automodule:: earwigbot.irc.data | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`frontend` Module | |||
---------------------- | |||
@@ -39,7 +36,6 @@ irc Package | |||
.. automodule:: earwigbot.irc.rc | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`watcher` Module | |||
--------------------- | |||
@@ -48,4 +44,3 @@ irc Package | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
@@ -54,4 +54,3 @@ Subpackages | |||
earwigbot.irc | |||
earwigbot.tasks | |||
earwigbot.wiki | |||
@@ -7,7 +7,6 @@ tasks Package | |||
.. automodule:: earwigbot.tasks | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`afc_catdelink` Module | |||
--------------------------- | |||
@@ -88,4 +87,3 @@ tasks Package | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
@@ -1,17 +1,17 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2009-2012 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
# | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
# in the Software without restriction, including without limitation the rights | |||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
# copies of the Software, and to permit persons to whom the Software is | |||
# furnished to do so, subject to the following conditions: | |||
# | |||
# | |||
# The above copyright notice and this permission notice shall be included in | |||
# all copies or substantial portions of the Software. | |||
# | |||
# | |||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
@@ -34,8 +34,10 @@ __all__ = ["Bot"] | |||
class Bot(object): | |||
""" | |||
The Bot class is the core of EarwigBot, essentially responsible for | |||
starting the various bot components and making sure they are all happy. | |||
**EarwigBot: Main Bot Class** | |||
The :py:class:`Bot` class is the core of EarwigBot, essentially responsible | |||
for starting the various bot components and making sure they are all happy. | |||
EarwigBot has three components that can run independently of each other: an | |||
IRC front-end, an IRC watcher, and a wiki scheduler. | |||
@@ -47,14 +49,14 @@ class Bot(object): | |||
- The wiki scheduler runs wiki-editing bot tasks in separate threads at | |||
user-defined times through a cron-like interface. | |||
The :py:class:`Bot` object is accessable from within commands and tasks as | |||
The :py:class:`Bot` object is accessible from within commands and tasks as | |||
:py:attr:`self.bot`. This is the primary way to access data from other | |||
components of the bot. For example, our | |||
:py:class:`~earwigbot.config.BotConfig` object is accessable from | |||
:py:attr:`bot.config`, tasks can be started with | |||
:py:meth:`bot.tasks.start <earwigbot.managers.TaskManager.start>`, and | |||
sites can be loaded from the wiki toolset with :py:meth:`bot.wiki.get_site | |||
<earwigbot.wiki.sitesdb.SitesDB.get_site>`. | |||
:py:meth:`bot.tasks.start() <earwigbot.managers.TaskManager.start>`, and | |||
sites can be loaded from the wiki toolset with | |||
:py:meth:`bot.wiki.get_site() <earwigbot.wiki.sitesdb.SitesDB.get_site>`. | |||
""" | |||
def __init__(self, root_dir, level=logging.INFO): | |||
@@ -163,9 +165,10 @@ class Bot(object): | |||
This is thread-safe, and it will gracefully stop IRC components before | |||
reloading anything. Note that you can safely reload commands or tasks | |||
without restarting the bot with :py:meth:`bot.commands.load` or | |||
:py:meth:`bot.tasks.load`. These should not interfere with running | |||
components or tasks. | |||
without restarting the bot with :py:meth:`bot.commands.load() | |||
<earwigbot.managers._ResourceManager.load>` or | |||
:py:meth:`bot.tasks.load() <earwigbot.managers._ResourceManager.load>`. | |||
These should not interfere with running components or tasks. | |||
If given, *msg* will be used as our quit message. | |||
""" | |||
@@ -24,16 +24,17 @@ __all__ = ["BaseCommand"] | |||
class BaseCommand(object): | |||
""" | |||
EarwigBot's Base IRC Command | |||
**EarwigBot: Base IRC Command** | |||
This package provides built-in IRC "commands" used by the bot's front-end | |||
component. Additional commands can be installed as plugins in the bot's | |||
working directory. | |||
This class (import with `from earwigbot.commands import BaseCommand`), | |||
This class (import with ``from earwigbot.commands import BaseCommand``), | |||
can be subclassed to create custom IRC commands. | |||
This docstring is reported to the user when they use !help <command>. | |||
This docstring is reported to the user when they type ``"!help | |||
<command>"``. | |||
""" | |||
# This is the command's name, as reported to the user when they use !help: | |||
name = None | |||
@@ -47,9 +48,10 @@ class BaseCommand(object): | |||
"""Constructor for new commands. | |||
This is called once when the command is loaded (from | |||
commands._load_command()). `bot` is out base Bot object. Generally you | |||
:py:meth:`commands.load() <earwigbot.managers._ResourceManager.load>`). | |||
*bot* is out base :py:class:`~earwigbot.bot.Bot` object. Generally you | |||
shouldn't need to override this; if you do, call | |||
super(Command, self).__init__() first. | |||
``super(Command, self).__init__()`` first. | |||
""" | |||
self.bot = bot | |||
self.config = bot.config | |||
@@ -66,16 +68,18 @@ class BaseCommand(object): | |||
self.pong = lambda target: self.bot.frontend.pong(target) | |||
def check(self, data): | |||
"""Return whether this command should be called in response to 'data'. | |||
"""Return whether this command should be called in response to *data*. | |||
Given a Data() instance, return True if we should respond to this | |||
activity, or False if we should ignore it or it doesn't apply to us. | |||
Be aware that since this is called for each message sent on IRC, it | |||
should not be cheap to execute and unlikely to throw exceptions. | |||
Given a :py:class:`~earwigbot.irc.data.Data` instance, return ``True`` | |||
if we should respond to this activity, or ``False`` if we should ignore | |||
it and move on. Be aware that since this is called for each message | |||
sent on IRC, it should be cheap to execute and unlikely to throw | |||
exceptions. | |||
Most commands return True if data.command == self.name, otherwise they | |||
return False. This is the default behavior of check(); you need only | |||
override it if you wish to change that. | |||
Most commands return ``True`` if :py:attr:`data.command | |||
<earwigbot.irc.data.Data.command>` ``==`` :py:attr:`self.name <name>`, | |||
otherwise they return ``False``. This is the default behavior of | |||
:py:meth:`check`; you need only override it if you wish to change that. | |||
""" | |||
return data.is_command and data.command == self.name | |||
@@ -83,9 +87,8 @@ class BaseCommand(object): | |||
"""Main entry point for doing a command. | |||
Handle an activity (usually a message) on IRC. At this point, thanks | |||
to self.check() which is called automatically by the command handler, | |||
we know this is something we should respond to, so something like | |||
`if data.command != "command_name": return` is usually unnecessary. | |||
Note that | |||
to :py:meth:`check` which is called automatically by the command | |||
handler, we know this is something we should respond to. Place your | |||
command's body here. | |||
""" | |||
pass |
@@ -35,7 +35,7 @@ __all__ = ["BotConfig"] | |||
class BotConfig(object): | |||
""" | |||
**EarwigBot's YAML Config File Manager** | |||
**EarwigBot: YAML Config File Manager** | |||
This handles all tasks involving reading and writing to our config file, | |||
including encrypting and decrypting passwords and making a new config file | |||
@@ -226,7 +226,7 @@ class BotConfig(object): | |||
exit. | |||
Data from the config file is stored in five | |||
:py:class:`~earwigbot.config._ConfigNode` s (:py:attr:`components`, | |||
:py:class:`~earwigbot.config._ConfigNode`\ s (:py:attr:`components`, | |||
:py:attr:`wiki`, :py:attr:`tasks`, :py:attr:`irc`, :py:attr:`metadata`) | |||
for easy access (as well as the lower-level :py:attr:`data` attribute). | |||
If passwords are encrypted, we'll use :py:func:`~getpass.getpass` for | |||
@@ -21,7 +21,7 @@ | |||
# SOFTWARE. | |||
""" | |||
EarwigBot Exceptions | |||
**EarwigBot: Exceptions** | |||
This module contains all exceptions used by EarwigBot:: | |||
@@ -29,7 +29,7 @@ from earwigbot.exceptions import BrokenSocketError | |||
__all__ = ["IRCConnection"] | |||
class IRCConnection(object): | |||
"""A class to interface with IRC.""" | |||
"""Interface with an IRC server.""" | |||
def __init__(self, host, port, nick, ident, realname): | |||
self.host = host | |||
@@ -28,13 +28,15 @@ __all__ = ["Frontend"] | |||
class Frontend(IRCConnection): | |||
""" | |||
EarwigBot's IRC Frontend Component | |||
**EarwigBot: IRC Frontend Component** | |||
The IRC frontend runs on a normal IRC server and expects users to interact | |||
with it and give it commands. Commands are stored as "command classes", | |||
subclasses of BaseCommand in classes/base_command.py. All command classes | |||
are automatically imported by commands/__init__.py if they are in | |||
commands/. | |||
subclasses of :py:class:`~earwigbot.commands.BaseCommand`. All command | |||
classes are automatically imported by :py:meth:`commands.load() | |||
<earwigbot.managers._ResourceManager.load>` if they are in | |||
:py:mod:`earwigbot.commands` or the bot's custom command directory | |||
(explained in the :doc:`documentation </customizing>`). | |||
""" | |||
sender_regex = re.compile(":(.*?)!(.*?)@(.*?)\Z") | |||
@@ -1,17 +1,17 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Copyright (C) 2009-2012 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
# | |||
# | |||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||
# of this software and associated documentation files (the "Software"), to deal | |||
# in the Software without restriction, including without limitation the rights | |||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
# copies of the Software, and to permit persons to whom the Software is | |||
# furnished to do so, subject to the following conditions: | |||
# | |||
# | |||
# The above copyright notice and this permission notice shall be included in | |||
# all copies or substantial portions of the Software. | |||
# | |||
# | |||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
@@ -25,7 +25,7 @@ import re | |||
__all__ = ["RC"] | |||
class RC(object): | |||
"""A class to store data from an event received from our IRC watcher.""" | |||
"""Store data from an event received from our IRC watcher.""" | |||
re_color = re.compile("\x03([0-9]{1,2}(,[0-9]{1,2})?)?") | |||
re_edit = re.compile("\A\[\[(.*?)\]\]\s(.*?)\s(http://.*?)\s\*\s(.*?)\s\*\s(.*?)\Z") | |||
re_log = re.compile("\A\[\[(.*?)\]\]\s(.*?)\s\*\s(.*?)\s\*\s(.*?)\Z") | |||
@@ -65,8 +65,6 @@ class RC(object): | |||
def prettify(self): | |||
"""Make a nice, colorful message to send back to the IRC front-end.""" | |||
flags = self.flags | |||
# "New <event>:" if we don't know exactly what happened: | |||
event_type = flags | |||
if "N" in flags: | |||
event_type = "page" # "New page:" | |||
elif flags == "delete": | |||
@@ -28,7 +28,7 @@ __all__ = ["Watcher"] | |||
class Watcher(IRCConnection): | |||
""" | |||
EarwigBot's IRC Watcher Component | |||
**EarwigBot: IRC Watcher Component** | |||
The IRC watcher runs on a wiki recent-changes server and listens for | |||
edits. Users cannot interact with this part of the bot. When an event | |||
@@ -34,6 +34,8 @@ __all__ = ["CommandManager", "TaskManager"] | |||
class _ResourceManager(object): | |||
""" | |||
**EarwigBot: Resource Manager** | |||
Resources are essentially objects dynamically loaded by the bot, both | |||
packaged with it (built-in resources) and created by users (plugins, aka | |||
custom resources). Currently, the only two types of resources are IRC | |||
@@ -27,17 +27,17 @@ __all__ = ["BaseTask"] | |||
class BaseTask(object): | |||
""" | |||
EarwigBot's Base Bot Task | |||
**EarwigBot: Base Bot Task** | |||
This package provides built-in wiki bot "tasks" EarwigBot runs. Additional | |||
tasks can be installed as plugins in the bot's working directory. | |||
This class (import with `from earwigbot.tasks import BaseTask`) can be | |||
This class (import with ``from earwigbot.tasks import BaseTask``) can be | |||
subclassed to create custom bot tasks. | |||
To run a task, use :py:meth:`bot.tasks.start(name, **kwargs) | |||
<earwigbot.managers.TaskManager.start>`. ``**kwargs`` get passed to the | |||
Task's run() function. | |||
Task's :meth:`run` method. | |||
""" | |||
name = None | |||
number = 0 | |||
@@ -46,8 +46,10 @@ class BaseTask(object): | |||
"""Constructor for new tasks. | |||
This is called once immediately after the task class is loaded by | |||
the task manager (in tasks._load_task()). Don't override this directly | |||
(or if you do, remember super(Task, self).__init()) - use setup(). | |||
the task manager (in :py:meth:`tasks.load() | |||
<earwigbot.managers._ResourceManager.load>`). Don't override this | |||
directly; if you do, remember to place ``super(Task, self).__init()`` | |||
first. Use :py:meth:`setup` for typical task-init/setup needs. | |||
""" | |||
self.bot = bot | |||
self.config = bot.config | |||
@@ -64,25 +66,22 @@ class BaseTask(object): | |||
def run(self, **kwargs): | |||
"""Main entry point to run a given task. | |||
This is called directly by tasks.start() and is the main way to make a | |||
task do stuff. kwargs will be any keyword arguments passed to start() | |||
which are entirely optional. | |||
The same task instance is preserved between runs, so you can | |||
theoretically store data in self (e.g. | |||
start('mytask', action='store', data='foo')) and then use it later | |||
(e.g. start('mytask', action='save')). | |||
This is called directly by :py:meth:`tasks.start() | |||
<earwigbot.managers.TaskManager.start>` and is the main way to make a | |||
task do stuff. *kwargs* will be any keyword arguments passed to | |||
:py:meth:`~earwigbot.managers.TaskManager.start`, which are entirely | |||
optional. | |||
""" | |||
pass | |||
def make_summary(self, comment): | |||
"""Makes an edit summary by filling in variables in a config value. | |||
"""Make an edit summary by filling in variables in a config value. | |||
config.wiki["summary"] is used, where $2 is replaced by the main | |||
summary body, given as a method arg, and $1 is replaced by the task | |||
number. | |||
:py:attr:`config.wiki["summary"] <earwigbot.config.BotConfig.wiki>` is | |||
used, where ``$2`` is replaced by the main summary body, given by the | |||
*comment* argument, and ``$1`` is replaced by the task number. | |||
If the config value is not found, we just return the arg as-is. | |||
If the config value is not found, we'll just return *comment* as-is. | |||
""" | |||
try: | |||
summary = self.bot.config.wiki["summary"] | |||
@@ -91,20 +90,22 @@ class BaseTask(object): | |||
return summary.replace("$1", str(self.number)).replace("$2", comment) | |||
def shutoff_enabled(self, site=None): | |||
"""Returns whether on-wiki shutoff is enabled for this task. | |||
"""Return whether on-wiki shutoff is enabled for this task. | |||
We check a certain page for certain content. This is determined by | |||
our config file: config.wiki["shutoff"]["page"] is used as the title, | |||
with $1 replaced by our username and $2 replaced by the task number, | |||
and config.wiki["shutoff"]["disabled"] is used as the content. | |||
If the page has that content or the page does not exist, then shutoff | |||
is "disabled", meaning the bot is supposed to run normally, and we | |||
return False. If the page's content is something other than what we | |||
expect, shutoff is enabled, and we return True. | |||
If a site is not provided, we'll try to use self.site if it's set. | |||
Otherwise, we'll use our default site. | |||
our config file: :py:attr:`config.wiki["shutoff"]["page"] | |||
<earwigbot.config.BotConfig.wiki>` is used as the title, with any | |||
embedded ``$1`` replaced by our username and ``$2`` replaced by the | |||
task number; and :py:attr:`config.wiki["shutoff"]["disabled"] | |||
<earwigbot.config.BotConfig.wiki>` is used as the content. | |||
If the page has that exact content or the page does not exist, then | |||
shutoff is "disabled", meaning the bot is supposed to run normally, and | |||
we return ``False``. If the page's content is something other than | |||
what we expect, shutoff is enabled, and we return ``True``. | |||
If a site is not provided, we'll try to use :py:attr:`self.site <site>` | |||
if it's set. Otherwise, we'll use our default site. | |||
""" | |||
if not site: | |||
if hasattr(self, "site"): | |||
@@ -21,7 +21,7 @@ | |||
# SOFTWARE. | |||
""" | |||
**EarwigBot's Wiki Toolset** | |||
**EarwigBot: Wiki Toolset** | |||
This is a collection of classes and functions to read from and write to | |||
Wikipedia and other wiki sites. No connection whatsoever to `python-wikitools | |||
@@ -26,7 +26,7 @@ __all__ = ["Category"] | |||
class Category(Page): | |||
""" | |||
**EarwigBot's Wiki Toolset: Category Class** | |||
**EarwigBot: Wiki Toolset: Category** | |||
Represents a category on a given :py:class:`~earwigbot.wiki.site.Site`, a | |||
subclass of :py:class:`~earwigbot.wiki.page.Page`. Provides additional | |||
@@ -21,7 +21,7 @@ | |||
# SOFTWARE. | |||
""" | |||
**EarwigBot's Wiki Toolset: Constants** | |||
**EarwigBot: Wiki Toolset: Constants** | |||
This module defines some useful constants: | |||
@@ -32,7 +32,7 @@ __all__ = ["Page"] | |||
class Page(CopyrightMixin): | |||
""" | |||
**EarwigBot's Wiki Toolset: Page Class** | |||
**EarwigBot: Wiki Toolset: Page** | |||
Represents a page on a given :py:class:`~earwigbot.wiki.site.Site`. Has | |||
methods for getting information about the page, getting page content, and | |||
@@ -48,7 +48,7 @@ __all__ = ["Site"] | |||
class Site(object): | |||
""" | |||
**EarwigBot's Wiki Toolset: Site Class** | |||
**EarwigBot: Wiki Toolset: Site** | |||
Represents a site, with support for API queries and returning | |||
:py:class:`~earwigbot.wiki.page.Page`, | |||
@@ -35,7 +35,7 @@ __all__ = ["SitesDB"] | |||
class SitesDB(object): | |||
""" | |||
**EarwigBot's Wiki Toolset: Sites Database Manager** | |||
**EarwigBot: Wiki Toolset: Sites Database Manager** | |||
This class controls the :file:`sites.db` file, which stores information | |||
about all wiki sites known to the bot. Three public methods act as bridges | |||
@@ -30,7 +30,7 @@ __all__ = ["User"] | |||
class User(object): | |||
""" | |||
**EarwigBot's Wiki Toolset: User Class** | |||
**EarwigBot: Wiki Toolset: User** | |||
Represents a user on a given :py:class:`~earwigbot.wiki.site.Site`. Has | |||
methods for getting a bunch of information about the user, such as | |||