@@ -9,14 +9,6 @@ earwigbot Package | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`blowfish` Module | |||
.. automodule:: earwigbot.blowfish | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`bot` Module | |||
----------------- | |||
@@ -33,6 +25,14 @@ earwigbot Package | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`exceptions` Module | |||
------------------------ | |||
.. automodule:: earwigbot.exceptions | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`managers` Module | |||
---------------------- | |||
@@ -33,14 +33,6 @@ wiki Package | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`exceptions` Module | |||
.. automodule:: earwigbot.wiki.exceptions | |||
:members: | |||
:undoc-members: | |||
:show-inheritance: | |||
:mod:`page` Module | |||
------------------ | |||
@@ -49,4 +49,12 @@ if not __release__: | |||
finally: | |||
del _add_git_commit_id_to_version_string | |||
from earwigbot import bot, commands, config, irc, managers, tasks, util, wiki | |||
from earwigbot import bot | |||
from earwigbot import commands | |||
from earwigbot import config | |||
from earwigbot import exceptions | |||
from earwigbot import irc | |||
from earwigbot import managers | |||
from earwigbot import tasks | |||
from earwigbot import util | |||
from earwigbot import wiki |
@@ -24,7 +24,7 @@ import threading | |||
import re | |||
from earwigbot.commands import BaseCommand | |||
from earwigbot.irc import KwargParseException | |||
from earwigbot.exceptions import KwargParseError | |||
class Command(BaseCommand): | |||
"""Manage wiki tasks from IRC, and check on thread status.""" | |||
@@ -135,7 +135,7 @@ class Command(BaseCommand): | |||
try: | |||
data.parse_kwargs() | |||
except KwargParseException, arg: | |||
except KwargParseError, arg: | |||
msg = "error parsing argument: \x0303{0}\x0301.".format(arg) | |||
self.reply(data, msg) | |||
return | |||
@@ -0,0 +1,244 @@ | |||
# -*- 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 | |||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
# SOFTWARE. | |||
""" | |||
EarwigBot Exceptions | |||
This module contains all exceptions used by EarwigBot:: | |||
EarwigBotError | |||
+-- IRCError | |||
| +-- BrokenSocketError | |||
| +-- KwargParseError | |||
+-- WikiToolsetError | |||
+-- SiteNotFoundError | |||
+-- SiteAPIError | |||
+-- LoginError | |||
+-- NamespaceNotFoundError | |||
+-- PageNotFoundError | |||
+-- InvalidPageError | |||
+-- RedirectError | |||
+-- UserNotFoundError | |||
+-- EditError | |||
| +-- PermissionsError | |||
| +-- EditConflictError | |||
| +-- NoContentError | |||
| +-- ContentTooBigError | |||
| +-- SpamDetectedError | |||
| +-- FilteredError | |||
+-- SQLError | |||
+-- CopyvioCheckError | |||
+-- UnknownSearchEngineError | |||
+-- UnsupportedSearchEngineError | |||
+-- SearchQueryError | |||
""" | |||
class EarwigBotError(Exception): | |||
"""Base exception class for errors in EarwigBot.""" | |||
class IRCError(EarwigBotError): | |||
"""Base exception class for errors in IRC-relation sections of the bot.""" | |||
class BrokenSocketError(IRCError): | |||
"""A socket has broken, because it is not sending data. | |||
Raised by :py:meth:`IRCConnection._get | |||
<earwigbot.irc.connection.IRCConnection._get>`. | |||
""" | |||
class KwargParseError(IRCError): | |||
"""Couldn't parse a certain keyword argument in an IRC message. | |||
This is usually caused by it being given incorrectly: e.g., no value (abc), | |||
just a value (=xyz), just an equal sign (=), instead of the correct form | |||
(abc=xyz). | |||
Raised by :py:meth:`Data.parse_kwargs | |||
<earwigbot.irc.data.Data.parse_kwargs>`. | |||
""" | |||
class WikiToolsetError(EarwigBotError): | |||
"""Base exception class for errors in the Wiki Toolset.""" | |||
class SiteNotFoundError(WikiToolsetError): | |||
"""A particular site could not be found in the sites database. | |||
Raised by :py:class:`~earwigbot.wiki.sitesdb.SitesDB`. | |||
""" | |||
class SiteAPIError(WikiToolsetError): | |||
"""Couldn't connect to a site's API. | |||
Perhaps the server doesn't exist, our URL is wrong or incomplete, or | |||
there are temporary problems on their end. | |||
Raised by :py:meth:`Site.api_query <earwigbot.wiki.site.Site.api_query>`. | |||
""" | |||
class LoginError(WikiToolsetError): | |||
"""An error occured while trying to login. | |||
Perhaps the username/password is incorrect. | |||
Raised by :py:meth:`Site._login <earwigbot.wiki.site.Site._login>`. | |||
""" | |||
class NamespaceNotFoundError(WikiToolsetError): | |||
"""A requested namespace name or namespace ID does not exist. | |||
Raised by :py:meth:`Site.namespace_id_to_name | |||
<earwigbot.wiki.site.Site.namespace_id_to_name>` and | |||
:py:meth:`Site.namespace_name_to_id | |||
<earwigbot.wiki.site.Site.namespace_name_to_id>`. | |||
""" | |||
class PageNotFoundError(WikiToolsetError): | |||
"""Attempted to get information about a page that does not exist. | |||
Raised by :py:class:`~earwigbot.wiki.page.Page`. | |||
""" | |||
class InvalidPageError(WikiToolsetError): | |||
"""Attempted to get information about a page whose title is invalid. | |||
Raised by :py:class:`~earwigbot.wiki.page.Page`. | |||
""" | |||
class RedirectError(WikiToolsetError): | |||
"""A redirect-only method was called on a malformed or non-redirect page. | |||
Raised by :py:meth:`Page.get_redirect_target | |||
<earwigbot.wiki.page.Page.get_redirect_target>`. | |||
""" | |||
class UserNotFoundError(WikiToolsetError): | |||
"""Attempted to get certain information about a user that does not exist. | |||
Raised by :py:class:`~earwigbot.wiki.user.User`. | |||
""" | |||
class EditError(WikiToolsetError): | |||
"""An error occured while editing. | |||
This is used as a base class for all editing errors; this one specifically | |||
is used only when a generic error occurs that we don't know about. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class PermissionsError(EditError): | |||
"""A permissions error ocurred while editing. | |||
We tried to do something we don't have permission to, like trying to delete | |||
a page as a non-admin, or trying to edit a page without login information | |||
and AssertEdit enabled. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class EditConflictError(EditError): | |||
"""We gotten an edit conflict or a (rarer) delete/recreate conflict. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class NoContentError(EditError): | |||
"""We tried to create a page or new section with no content. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class ContentTooBigError(EditError): | |||
"""The edit we tried to push exceeded the article size limit. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class SpamDetectedError(EditError): | |||
"""The spam filter refused our edit. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class FilteredError(EditError): | |||
"""The edit filter refused our edit. | |||
Raised by :py:meth:`Page.edit <earwigbot.wiki.page.Page.edit>` and | |||
:py:meth:`Page.add_section <earwigbot.wiki.page.Page.add_section>`. | |||
""" | |||
class SQLError(WikiToolsetError): | |||
"""Some error involving SQL querying occurred. | |||
Raised by :py:meth:`Site.sql_query <earwigbot.wiki.site.Site.sql_query>`. | |||
""" | |||
class CopyvioCheckError(WikiToolsetError): | |||
"""An error occured when checking a page for copyright violations. | |||
This is a base class for multiple exceptions; usually one of those will be | |||
raised instead of this. | |||
Raised by :py:meth:`Page.copyvio_check | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_check>` and | |||
:py:meth:`Page.copyvio_compare | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_compare>`. | |||
""" | |||
class UnknownSearchEngineError(CopyvioCheckError): | |||
"""Attempted to do a copyvio check with an unknown search engine. | |||
Search engines are specified in :file:`config.yml` as | |||
:py:attr:`config.wiki["search"]["engine"]`. | |||
Raised by :py:meth:`Page.copyvio_check | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_check>` and | |||
:py:meth:`Page.copyvio_compare | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_compare>`. | |||
""" | |||
class UnsupportedSearchEngineError(CopyvioCheckError): | |||
"""Attmpted to do a copyvio check using an unavailable engine. | |||
This might occur if, for example, an engine requires oauth2 but the package | |||
couldn't be imported. | |||
Raised by :py:meth:`Page.copyvio_check | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_check>` and | |||
:py:meth:`Page.copyvio_compare | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_compare>`. | |||
""" | |||
class SearchQueryError(CopyvioCheckError): | |||
"""Some error ocurred while doing a search query. | |||
Raised by :py:meth:`Page.copyvio_check | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_check>` and | |||
:py:meth:`Page.copyvio_compare | |||
<earwigbot.wiki.copyvios.CopyvioMixin.copyvio_compare>`. | |||
""" |
@@ -24,14 +24,9 @@ import socket | |||
from threading import Lock | |||
from time import sleep | |||
__all__ = ["BrokenSocketException", "IRCConnection"] | |||
from earwigbot.exceptions import BrokenSocketError | |||
class BrokenSocketException(Exception): | |||
"""A socket has broken, because it is not sending data. | |||
Raised by IRCConnection()._get(). | |||
""" | |||
pass | |||
__all__ = ["IRCConnection"] | |||
class IRCConnection(object): | |||
"""A class to interface with IRC.""" | |||
@@ -72,7 +67,7 @@ class IRCConnection(object): | |||
data = self._sock.recv(size) | |||
if not data: | |||
# Socket isn't giving us any data, so it is dead or broken: | |||
raise BrokenSocketException() | |||
raise BrokenSocketError() | |||
return data | |||
def _send(self, msg): | |||
@@ -137,7 +132,7 @@ class IRCConnection(object): | |||
while 1: | |||
try: | |||
read_buffer += self._get() | |||
except BrokenSocketException: | |||
except BrokenSocketError: | |||
self._is_running = False | |||
break | |||
@@ -22,13 +22,9 @@ | |||
import re | |||
__all__ = ["KwargParseException", "Data"] | |||
from earwigbot.exceptions import KwargParseError | |||
class KwargParseException(Exception): | |||
"""Couldn't parse a certain keyword argument in self.args, probably because | |||
it was given incorrectly: e.g., no value (abc), just a value (=xyz), just | |||
an equal sign (=), instead of the correct (abc=xyz).""" | |||
pass | |||
__all__ = ["Data"] | |||
class Data(object): | |||
"""Store data from an individual line received on IRC.""" | |||
@@ -81,8 +77,8 @@ class Data(object): | |||
try: | |||
key, value = re.findall("^(.*?)\=(.*?)$", arg)[0] | |||
except IndexError: | |||
raise KwargParseException(arg) | |||
raise KwargParseError(arg) | |||
if key and value: | |||
self.kwargs[key] = value | |||
else: | |||
raise KwargParseException(arg) | |||
raise KwargParseError(arg) |
@@ -37,7 +37,6 @@ Category, and User) needs. | |||
from earwigbot.wiki.category import * | |||
from earwigbot.wiki.constants import * | |||
from earwigbot.wiki.exceptions import * | |||
from earwigbot.wiki.page import * | |||
from earwigbot.wiki.site import * | |||
from earwigbot.wiki.sitesdb import * | |||
@@ -35,7 +35,8 @@ earwigbot.wiki (e.g. `earwigbot.wiki.USER_AGENT`). | |||
# Default User Agent when making API queries: | |||
from earwigbot import __version__ as _v | |||
from platform import python_version as _p | |||
USER_AGENT = "EarwigBot/{0} (Python/{1}; https://github.com/earwig/earwigbot)".format(_v, _p()) | |||
USER_AGENT = "EarwigBot/{0} (Python/{1}; https://github.com/earwig/earwigbot)" | |||
USER_AGENT = USER_AGENT.format(_v, _p()) | |||
del _v, _p | |||
# Default namespace IDs: | |||
@@ -35,7 +35,7 @@ try: | |||
except ImportError: | |||
oauth = None | |||
from earwigbot.wiki.exceptions import * | |||
from earwigbot.exceptions import * | |||
class _CopyvioCheckResult(object): | |||
def __init__(self, violation, confidence, url, queries, article, chains): | |||
@@ -1,124 +0,0 @@ | |||
# -*- 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 | |||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
# SOFTWARE. | |||
""" | |||
EarwigBot's Wiki Toolset: Exceptions | |||
This module contains all exceptions used by the wiki package. There are a lot: | |||
-- SiteNotFoundError | |||
-- SiteAPIError | |||
-- LoginError | |||
-- NamespaceNotFoundError | |||
-- PageNotFoundError | |||
-- InvalidPageError | |||
-- RedirectError | |||
-- UserNotFoundError | |||
-- EditError | |||
-- PermissionsError | |||
-- EditConflictError | |||
-- NoContentError | |||
-- ContentTooBigError | |||
-- SpamDetectedError | |||
-- FilteredError | |||
-- SQLError | |||
-- CopyvioCheckError | |||
-- UnknownSearchEngineError | |||
-- UnsupportedSearchEngineError | |||
-- SearchQueryError | |||
""" | |||
class WikiToolsetError(Exception): | |||
"""Base exception class for errors in the Wiki Toolset.""" | |||
class SiteNotFoundError(WikiToolsetError): | |||
"""A site matching the args given to get_site() could not be found in the | |||
config file.""" | |||
class SiteAPIError(WikiToolsetError): | |||
"""We couldn't connect to a site's API, perhaps because the server doesn't | |||
exist, our URL is wrong or incomplete, or they're having temporary | |||
problems.""" | |||
class LoginError(WikiToolsetError): | |||
"""An error occured while trying to login. Perhaps the username/password is | |||
incorrect.""" | |||
class NamespaceNotFoundError(WikiToolsetError): | |||
"""A requested namespace name or namespace ID does not exist.""" | |||
class PageNotFoundError(WikiToolsetError): | |||
"""Attempting to get certain information about a page that does not | |||
exist.""" | |||
class InvalidPageError(WikiToolsetError): | |||
"""Attempting to get certain information about a page whose title is | |||
invalid.""" | |||
class RedirectError(WikiToolsetError): | |||
"""Page's get_redirect_target() method failed because the page is either | |||
not a redirect, or it is malformed.""" | |||
class UserNotFoundError(WikiToolsetError): | |||
"""Attempting to get certain information about a user that does not | |||
exist.""" | |||
class EditError(WikiToolsetError): | |||
"""We got some error while editing. Sometimes, a subclass of this exception | |||
will be used, like PermissionsError or EditConflictError.""" | |||
class PermissionsError(EditError): | |||
"""We tried to do something we don't have permission to, like a non-admin | |||
trying to delete a page, or trying to edit a page when no login information | |||
was provided.""" | |||
class EditConflictError(EditError): | |||
"""We've gotten an edit conflict or a (rarer) delete/recreate conflict.""" | |||
class NoContentError(EditError): | |||
"""We tried to create a page or new section with no content.""" | |||
class ContentTooBigError(EditError): | |||
"""The edit we tried to push exceeded the article size limit.""" | |||
class SpamDetectedError(EditError): | |||
"""The spam filter refused our edit.""" | |||
class FilteredError(EditError): | |||
"""The edit filter refused our edit.""" | |||
class SQLError(WikiToolsetError): | |||
"""Some error involving SQL querying occurred.""" | |||
class CopyvioCheckError(WikiToolsetError): | |||
"""An error occured when checking a page for copyright violations.""" | |||
class UnknownSearchEngineError(CopyvioCheckError): | |||
"""CopyrightMixin().copyvio_check() called with an unknown engine.""" | |||
class UnsupportedSearchEngineError(CopyvioCheckError): | |||
"""The engine requested is not available, e.g., because a required package | |||
is missing.""" | |||
class SearchQueryError(CopyvioCheckError): | |||
"""Some error ocurred while doing a search query.""" |
@@ -25,8 +25,8 @@ import re | |||
from time import gmtime, strftime | |||
from urllib import quote | |||
from earwigbot import exceptions | |||
from earwigbot.wiki.copyright import CopyrightMixin | |||
from earwigbot.wiki.exceptions import * | |||
__all__ = ["Page"] | |||
@@ -132,7 +132,7 @@ class Page(CopyrightMixin): | |||
""" | |||
if self._exists == 1: | |||
e = "Page '{0}' is invalid.".format(self._title) | |||
raise InvalidPageError(e) | |||
raise exceptions.InvalidPageError(e) | |||
def _force_existence(self): | |||
"""Used to ensure that our page exists. | |||
@@ -144,7 +144,7 @@ class Page(CopyrightMixin): | |||
self._force_validity() | |||
if self._exists == 2: | |||
e = "Page '{0}' does not exist.".format(self._title) | |||
raise PageNotFoundError(e) | |||
raise exceptions.PageNotFoundError(e) | |||
def _load_wrapper(self): | |||
"""Calls _load_attributes() and follows redirects if we're supposed to. | |||
@@ -278,8 +278,8 @@ class Page(CopyrightMixin): | |||
self._load_attributes() | |||
if not self._token: | |||
e = "You don't have permission to edit this page." | |||
raise PermissionsError(e) | |||
raise exceptions.PermissionsError(e) | |||
# Weed out invalid pages before we get too far: | |||
self._force_validity() | |||
@@ -310,7 +310,7 @@ class Page(CopyrightMixin): | |||
try: | |||
assertion = result["edit"]["assert"] | |||
except KeyError: | |||
raise EditError(result["edit"]) | |||
raise exceptions.EditError(result["edit"]) | |||
self._handle_assert_edit(assertion, params, tries) | |||
def _build_edit_params(self, text, summary, minor, bot, force, section, | |||
@@ -353,13 +353,13 @@ class Page(CopyrightMixin): | |||
""" | |||
if error.code in ["noedit", "cantcreate", "protectedtitle", | |||
"noimageredirect"]: | |||
raise PermissionsError(error.info) | |||
raise exceptions.PermissionsError(error.info) | |||
elif error.code in ["noedit-anon", "cantcreate-anon", | |||
"noimageredirect-anon"]: | |||
if not all(self._site._login_info): | |||
# Insufficient login info: | |||
raise PermissionsError(error.info) | |||
raise exceptions.PermissionsError(error.info) | |||
if tries == 0: | |||
# We have login info; try to login: | |||
self._site._login(self._site._login_info) | |||
@@ -368,28 +368,28 @@ class Page(CopyrightMixin): | |||
else: | |||
# We already tried to log in and failed! | |||
e = "Although we should be logged in, we are not. This may be a cookie problem or an odd bug." | |||
raise LoginError(e) | |||
raise exceptions.LoginError(e) | |||
elif error.code in ["editconflict", "pagedeleted", "articleexists"]: | |||
# These attributes are now invalidated: | |||
self._content = None | |||
self._basetimestamp = None | |||
self._exists = 0 | |||
raise EditConflictError(error.info) | |||
raise exceptions.EditConflictError(error.info) | |||
elif error.code in ["emptypage", "emptynewsection"]: | |||
raise NoContentError(error.info) | |||
raise exceptions.NoContentError(error.info) | |||
elif error.code == "contenttoobig": | |||
raise ContentTooBigError(error.info) | |||
raise exceptions.ContentTooBigError(error.info) | |||
elif error.code == "spamdetected": | |||
raise SpamDetectedError(error.info) | |||
raise exceptions.SpamDetectedError(error.info) | |||
elif error.code == "filtered": | |||
raise FilteredError(error.info) | |||
raise exceptions.FilteredError(error.info) | |||
raise EditError(": ".join((error.code, error.info))) | |||
raise exceptions.EditError(": ".join((error.code, error.info))) | |||
def _handle_assert_edit(self, assertion, params, tries): | |||
"""If we can't edit due to a failed AssertEdit assertion, handle that. | |||
@@ -401,7 +401,7 @@ class Page(CopyrightMixin): | |||
if not all(self._site._login_info): | |||
# Insufficient login info: | |||
e = "AssertEdit: user assertion failed, and no login info was provided." | |||
raise PermissionsError(e) | |||
raise exceptions.PermissionsError(e) | |||
if tries == 0: | |||
# We have login info; try to login: | |||
self._site._login(self._site._login_info) | |||
@@ -410,15 +410,15 @@ class Page(CopyrightMixin): | |||
else: | |||
# We already tried to log in and failed! | |||
e = "Although we should be logged in, we are not. This may be a cookie problem or an odd bug." | |||
raise LoginError(e) | |||
raise exceptions.LoginError(e) | |||
elif assertion == "bot": | |||
e = "AssertEdit: bot assertion failed; we don't have a bot flag!" | |||
raise PermissionsError(e) | |||
raise exceptions.PermissionsError(e) | |||
# Unknown assertion, maybe "true", "false", or "exists": | |||
e = "AssertEdit: assertion '{0}' failed.".format(assertion) | |||
raise PermissionsError(e) | |||
raise exceptions.PermissionsError(e) | |||
def title(self, force=False): | |||
"""Returns the Page's title, or pagename. | |||
@@ -570,7 +570,7 @@ class Page(CopyrightMixin): | |||
if self._namespace < 0: | |||
ns = self._site.namespace_id_to_name(self._namespace) | |||
e = "Pages in the {0} namespace can't have talk pages.".format(ns) | |||
raise InvalidPageError(e) | |||
raise exceptions.InvalidPageError(e) | |||
if self._is_talkpage: | |||
new_ns = self._namespace - 1 | |||
@@ -650,7 +650,7 @@ class Page(CopyrightMixin): | |||
return re.findall(self.re_redirect, content, flags=re.I)[0] | |||
except IndexError: | |||
e = "The page does not appear to have a redirect target." | |||
raise RedirectError(e) | |||
raise exceptions.RedirectError(e) | |||
def edit(self, text, summary, minor=False, bot=True, force=False): | |||
"""Replaces the page's content or creates a new page. | |||
@@ -38,9 +38,9 @@ try: | |||
except ImportError: | |||
oursql = None | |||
from earwigbot import exceptions | |||
from earwigbot.wiki import constants | |||
from earwigbot.wiki.category import Category | |||
from earwigbot.wiki.constants import * | |||
from earwigbot.wiki.exceptions import * | |||
from earwigbot.wiki.page import Page | |||
from earwigbot.wiki.user import User | |||
@@ -128,7 +128,7 @@ class Site(object): | |||
else: | |||
self._cookiejar = CookieJar() | |||
if not user_agent: | |||
user_agent = USER_AGENT # Set default UA from wiki.constants | |||
user_agent = constants.USER_AGENT # Set default UA | |||
self._opener = build_opener(HTTPCookieProcessor(self._cookiejar)) | |||
self._opener.addheaders = [("User-Agent", user_agent), | |||
("Accept-Encoding", "gzip")] | |||
@@ -232,7 +232,7 @@ class Site(object): | |||
e = e.format(error.code) | |||
else: | |||
e = "API query failed." | |||
raise SiteAPIError(e) | |||
raise exceptions.SiteAPIError(e) | |||
result = response.read() | |||
if response.headers.get("Content-Encoding") == "gzip": | |||
@@ -246,7 +246,7 @@ class Site(object): | |||
"""Given API query params, return the URL to query and POST data.""" | |||
if not self._base_url or self._script_path is None: | |||
e = "Tried to do an API query, but no API URL is known." | |||
raise SiteAPIError(e) | |||
raise exceptions.SiteAPIError(e) | |||
base_url = self._base_url | |||
if base_url.startswith("//"): # Protocol-relative URLs from 1.18 | |||
@@ -271,7 +271,7 @@ class Site(object): | |||
res = loads(result) # Try to parse as a JSON object | |||
except ValueError: | |||
e = "API query failed: JSON could not be decoded." | |||
raise SiteAPIError(e) | |||
raise exceptions.SiteAPIError(e) | |||
try: | |||
code = res["error"]["code"] | |||
@@ -282,7 +282,7 @@ class Site(object): | |||
if code == "maxlag": # We've been throttled by the server | |||
if tries >= self._max_retries: | |||
e = "Maximum number of retries reached ({0})." | |||
raise SiteAPIError(e.format(self._max_retries)) | |||
raise exceptions.SiteAPIError(e.format(self._max_retries)) | |||
tries += 1 | |||
msg = 'Server says "{0}"; retrying in {1} seconds ({2}/{3})' | |||
self._logger.info(msg.format(info, wait, tries, self._max_retries)) | |||
@@ -290,7 +290,7 @@ class Site(object): | |||
return self._api_query(params, tries=tries, wait=wait*3) | |||
else: # Some unknown error occurred | |||
e = 'API query failed: got error "{0}"; server says: "{1}".' | |||
error = SiteAPIError(e.format(code, info)) | |||
error = earwigbot.SiteAPIError(e.format(code, info)) | |||
error.code, error.info = code, info | |||
raise error | |||
@@ -491,7 +491,7 @@ class Site(object): | |||
e = "The given password is incorrect." | |||
else: | |||
e = "Couldn't login; server says '{0}'.".format(res) | |||
raise LoginError(e) | |||
raise exceptions.LoginError(e) | |||
def _logout(self): | |||
"""Safely logout through the API. | |||
@@ -518,7 +518,7 @@ class Site(object): | |||
""" | |||
if not oursql: | |||
e = "Module 'oursql' is required for SQL queries." | |||
raise SQLError(e) | |||
raise exceptions.SQLError(e) | |||
args = self._sql_data | |||
for key, value in kwargs.iteritems(): | |||
@@ -638,7 +638,7 @@ class Site(object): | |||
return self._namespaces[ns_id][0] | |||
except KeyError: | |||
e = "There is no namespace with id {0}.".format(ns_id) | |||
raise NamespaceNotFoundError(e) | |||
raise exceptions.NamespaceNotFoundError(e) | |||
def namespace_name_to_id(self, name): | |||
"""Given a namespace name, returns the associated ID. | |||
@@ -655,7 +655,7 @@ class Site(object): | |||
return ns_id | |||
e = "There is no namespace with name '{0}'.".format(name) | |||
raise NamespaceNotFoundError(e) | |||
raise exceptions.NamespaceNotFoundError(e) | |||
def get_page(self, title, follow_redirects=False): | |||
"""Returns a Page object for the given title (pagename). | |||
@@ -667,7 +667,7 @@ class Site(object): | |||
Note that this doesn't do any direct checks for existence or | |||
redirect-following - Page's methods provide that. | |||
""" | |||
prefixes = self.namespace_id_to_name(NS_CATEGORY, all=True) | |||
prefixes = self.namespace_id_to_name(constants.NS_CATEGORY, all=True) | |||
prefix = title.split(":", 1)[0] | |||
if prefix != title: # Avoid a page that is simply "Category" | |||
if prefix in prefixes: | |||
@@ -680,7 +680,7 @@ class Site(object): | |||
`catname` should be given *without* a namespace prefix. This method is | |||
really just shorthand for get_page("Category:" + catname). | |||
""" | |||
prefix = self.namespace_id_to_name(NS_CATEGORY) | |||
prefix = self.namespace_id_to_name(constants.NS_CATEGORY) | |||
pagename = ':'.join((prefix, catname)) | |||
return Category(self, pagename, follow_redirects) | |||
@@ -28,7 +28,7 @@ import stat | |||
import sqlite3 as sqlite | |||
from earwigbot import __version__ | |||
from earwigbot.wiki.exceptions import SiteNotFoundError | |||
from earwigbot.exceptions import SiteNotFoundError | |||
from earwigbot.wiki.site import Site | |||
__all__ = ["SitesDB"] | |||
@@ -22,8 +22,8 @@ | |||
from time import gmtime, strptime | |||
from earwigbot.wiki.constants import * | |||
from earwigbot.wiki.exceptions import UserNotFoundError | |||
from earwigbot.exceptions import UserNotFoundError | |||
from earwigbot.wiki import constants | |||
from earwigbot.wiki.page import Page | |||
__all__ = ["User"] | |||
@@ -252,7 +252,7 @@ class User(object): | |||
No checks are made to see if it exists or not. Proper site namespace | |||
conventions are followed. | |||
""" | |||
prefix = self._site.namespace_id_to_name(NS_USER) | |||
prefix = self._site.namespace_id_to_name(constants.NS_USER) | |||
pagename = ':'.join((prefix, self._name)) | |||
return Page(self._site, pagename) | |||
@@ -262,6 +262,6 @@ class User(object): | |||
No checks are made to see if it exists or not. Proper site namespace | |||
conventions are followed. | |||
""" | |||
prefix = self._site.namespace_id_to_name(NS_USER_TALK) | |||
prefix = self._site.namespace_id_to_name(constants.NS_USER_TALK) | |||
pagename = ':'.join((prefix, self._name)) | |||
return Page(self._site, pagename) |