From 7492adc6d01b571495d94dec61172ff0e96b39d0 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 31 Aug 2012 02:37:59 -0400 Subject: [PATCH 001/207] Version bump for 0.2.dev. --- .gitignore | 2 ++ docs/conf.py | 4 ++-- earwigbot/__init__.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 4984243..d70b37d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ *.egg *.egg-info .DS_Store +__pycache__ build +dist docs/_build diff --git a/docs/conf.py b/docs/conf.py index bd18ce3..747d5c8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ copyright = u'2009, 2010, 2011, 2012 Ben Kurtovic' # built documents. # # The short X.Y version. -version = '0.1' +version = '0.2' # The full version, including alpha/beta/rc tags. -release = '0.1' +release = '0.2.dev' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/earwigbot/__init__.py b/earwigbot/__init__.py index 696ce3f..8dca99f 100644 --- a/earwigbot/__init__.py +++ b/earwigbot/__init__.py @@ -32,9 +32,9 @@ details. This documentation is also available `online __author__ = "Ben Kurtovic" __copyright__ = "Copyright (C) 2009, 2010, 2011, 2012 Ben Kurtovic" __license__ = "MIT License" -__version__ = "0.1" +__version__ = "0.2.dev" __email__ = "ben.kurtovic@verizon.net" -__release__ = True +__release__ = False if not __release__: def _get_git_commit_id(): From 0ca84ab9bced68ff8296fb26bc86f3ec44a7b5c3 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 1 Sep 2012 22:28:30 -0400 Subject: [PATCH 002/207] Implement lazy-importing of oauth2, nltk, and bs4. --- earwigbot/__init__.py | 2 -- earwigbot/lazy.py | 11 +++++++++-- earwigbot/wiki/copyvios/__init__.py | 10 ++++++---- earwigbot/wiki/copyvios/parsers.py | 7 +++++-- earwigbot/wiki/copyvios/search.py | 5 +++-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/earwigbot/__init__.py b/earwigbot/__init__.py index 8dca99f..256837c 100644 --- a/earwigbot/__init__.py +++ b/earwigbot/__init__.py @@ -64,5 +64,3 @@ managers = importer.new("earwigbot.managers") tasks = importer.new("earwigbot.tasks") util = importer.new("earwigbot.util") wiki = importer.new("earwigbot.wiki") - -del importer diff --git a/earwigbot/lazy.py b/earwigbot/lazy.py index 555f039..f9214e0 100644 --- a/earwigbot/lazy.py +++ b/earwigbot/lazy.py @@ -21,8 +21,10 @@ # SOFTWARE. """ -Implements a hierarchy of importing classes as defined in PEP 302 to load -modules in a safe yet lazy manner. +Implements a hierarchy of importing classes as defined in `PEP 302 +`_ to load modules in a safe yet lazy +manner, so that they can be referred to by name but are not actually loaded +until they are used (i.e. their attributes are read or modified). """ from imp import acquire_lock, release_lock @@ -64,6 +66,11 @@ class _LazyModule(type): class LazyImporter(object): + """An importer for modules that are loaded lazily. + + This inserts itself into :py:data:`sys.meta_path`, storing a dictionary of + :py:class:`_LazyModule`\ s (which is added to with :py:meth:`new`). + """ def __init__(self): self._modules = {} sys.meta_path.append(self) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index cd643f3..425d99a 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -26,14 +26,14 @@ from StringIO import StringIO from time import sleep, time from urllib2 import build_opener, URLError -import oauth2 as oauth - -from earwigbot import exceptions +from earwigbot import exceptions, importer from earwigbot.wiki.copyvios.markov import MarkovChain, MarkovChainIntersection from earwigbot.wiki.copyvios.parsers import ArticleTextParser, HTMLTextParser from earwigbot.wiki.copyvios.result import CopyvioCheckResult from earwigbot.wiki.copyvios.search import YahooBOSSSearchEngine +oauth = importer.new("oauth2") + __all__ = ["CopyvioMixIn"] class CopyvioMixIn(object): @@ -93,7 +93,9 @@ class CopyvioMixIn(object): credentials = self._search_config["credentials"] if engine == "Yahoo! BOSS": - if not oauth: + try: + oauth.__version__ # Force-load the lazy module + except (ImportError, AttributeError): e = "The package 'oauth2' could not be imported" raise exceptions.UnsupportedSearchEngineError(e) return YahooBOSSSearchEngine(credentials) diff --git a/earwigbot/wiki/copyvios/parsers.py b/earwigbot/wiki/copyvios/parsers.py index 798b2a7..4f8e981 100644 --- a/earwigbot/wiki/copyvios/parsers.py +++ b/earwigbot/wiki/copyvios/parsers.py @@ -22,9 +22,12 @@ from os import path -import bs4 import mwparserfromhell -import nltk + +from earwigbot import importer + +bs4 = importer.new("bs4") +nltk = importer.new("nltk") __all__ = ["BaseTextParser", "ArticleTextParser", "HTMLTextParser"] diff --git a/earwigbot/wiki/copyvios/search.py b/earwigbot/wiki/copyvios/search.py index 0834885..a9afcfb 100644 --- a/earwigbot/wiki/copyvios/search.py +++ b/earwigbot/wiki/copyvios/search.py @@ -23,10 +23,11 @@ from json import loads from urllib import quote_plus, urlencode -import oauth2 as oauth - +from earwigbot import importer from earwigbot.exceptions import SearchQueryError +oauth = importer.new("oauth2") + __all__ = ["BaseSearchEngine", "YahooBOSSSearchEngine"] class BaseSearchEngine(object): From ac6de461bb7c06329f00be24fd2c36365a545417 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 2 Sep 2012 14:37:04 -0400 Subject: [PATCH 003/207] Implement lazy-importing of oursql and pytz. --- earwigbot/commands/time_command.py | 11 ++++++----- earwigbot/wiki/site.py | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index a172a43..f110d1a 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -24,10 +24,11 @@ from datetime import datetime from math import floor from time import time -import pytz - +from earwigbot import importer from earwigbot.commands import Command +pytz = importer.new("pytz") + class Time(Command): """Report the current time in any timezone (UTC default), or in beats.""" name = "time" @@ -52,12 +53,12 @@ class Time(Command): self.reply(data, "@{0:0>3}".format(beats)) def do_time(self, data, timezone): - if not pytz: + try: + tzinfo = pytz.timezone(timezone) + except ImportError: msg = "This command requires the 'pytz' module: http://pytz.sourceforge.net/" self.reply(data, msg) return - try: - tzinfo = pytz.timezone(timezone) except pytz.exceptions.UnknownTimeZoneError: self.reply(data, "Unknown timezone: {0}.".format(timezone)) return diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 6043675..765ea81 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -32,14 +32,14 @@ from urllib import quote_plus, unquote_plus from urllib2 import build_opener, HTTPCookieProcessor, URLError from urlparse import urlparse -import oursql - -from earwigbot import exceptions +from earwigbot import exceptions, importer from earwigbot.wiki import constants from earwigbot.wiki.category import Category from earwigbot.wiki.page import Page from earwigbot.wiki.user import User +oursql = importer.new("oursql") + __all__ = ["Site"] class Site(object): @@ -514,10 +514,6 @@ class Site(object): may raise its own exceptions (e.g. oursql.InterfaceError) if it cannot establish a connection. """ - if not oursql: - e = "Module 'oursql' is required for SQL queries." - raise exceptions.SQLError(e) - args = self._sql_data for key, value in kwargs.iteritems(): args[key] = value @@ -531,7 +527,11 @@ class Site(object): if "autoreconnect" not in args: args["autoreconnect"] = True - self._sql_conn = oursql.connect(**args) + try: + self._sql_conn = oursql.connect(**args) + except ImportError: + e = "Module 'oursql' is required for SQL queries." + raise exceptions.SQLError(e) def _get_service_order(self): """Return a preferred order for using services (e.g. the API and SQL). From 655624c2cfcfcb79306facc79cec66d81829f178 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 2 Sep 2012 15:15:43 -0400 Subject: [PATCH 004/207] Lazy-importing of py-bcrypt and pycrypto; restructured deps in setup. --- earwigbot/commands/crypt.py | 11 ++++++++++- earwigbot/commands/time_command.py | 2 +- earwigbot/config/__init__.py | 6 ++++-- earwigbot/config/script.py | 34 ++++++++++++++++++++++++---------- earwigbot/wiki/copyvios/__init__.py | 4 ++-- earwigbot/wiki/site.py | 2 +- setup.py | 36 ++++++++++++++++++++++-------------- 7 files changed, 64 insertions(+), 31 deletions(-) diff --git a/earwigbot/commands/crypt.py b/earwigbot/commands/crypt.py index 0123be1..92f458c 100644 --- a/earwigbot/commands/crypt.py +++ b/earwigbot/commands/crypt.py @@ -24,8 +24,11 @@ import hashlib from Crypto.Cipher import Blowfish +from earwigbot import importer from earwigbot.commands import Command +Blowfish = importer.new("Crypto.Cipher.Blowfish") + class Crypt(Command): """Provides hash functions with !hash (!hash list for supported algorithms) and Blowfish encryption with !encrypt and !decrypt.""" @@ -66,7 +69,13 @@ class Crypt(Command): self.reply(data, msg.format(data.command)) return - cipher = Blowfish.new(hashlib.sha256(key).digest()) + try: + cipher = Blowfish.new(hashlib.sha256(key).digest()) + except ImportError: + msg = "This command requires the 'pycrypto' package: https://www.dlitz.net/software/pycrypto/" + self.reply(data, msg) + return + try: if data.command == "encrypt": if len(text) % 8: diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index f110d1a..b0dc657 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -56,7 +56,7 @@ class Time(Command): try: tzinfo = pytz.timezone(timezone) except ImportError: - msg = "This command requires the 'pytz' module: http://pytz.sourceforge.net/" + msg = "This command requires the 'pytz' package: http://pytz.sourceforge.net/" self.reply(data, msg) return except pytz.exceptions.UnknownTimeZoneError: diff --git a/earwigbot/config/__init__.py b/earwigbot/config/__init__.py index b0d7fae..911a496 100644 --- a/earwigbot/config/__init__.py +++ b/earwigbot/config/__init__.py @@ -28,10 +28,9 @@ import logging.handlers from os import mkdir, path import stat -from Crypto.Cipher import Blowfish -import bcrypt import yaml +from earwigbot import importer from earwigbot.config.formatter import BotFormatter from earwigbot.config.node import ConfigNode from earwigbot.config.ordered_yaml import OrderedLoader @@ -39,6 +38,9 @@ from earwigbot.config.permissions import PermissionsDB from earwigbot.config.script import ConfigScript from earwigbot.exceptions import NoConfigError +Blowfish = importer.new("Crypto.Cipher.Blowfish") +bcrypt = importer.new("bcrypt") + __all__ = ["BotConfig"] class BotConfig(object): diff --git a/earwigbot/config/script.py b/earwigbot/config/script.py index 9d953e9..0b35aed 100644 --- a/earwigbot/config/script.py +++ b/earwigbot/config/script.py @@ -29,13 +29,14 @@ import stat import sys from textwrap import fill, wrap -from Crypto.Cipher import Blowfish -import bcrypt import yaml -from earwigbot import exceptions +from earwigbot import exceptions, importer from earwigbot.config.ordered_yaml import OrderedDumper +Blowfish = importer.new("Crypto.Cipher.Blowfish") +bcrypt = importer.new("bcrypt") + __all__ = ["ConfigScript"] RULES_TEMPLATE = """# -*- coding: utf-8 -*- @@ -145,17 +146,30 @@ class ConfigScript(object): is to run on a public computer like the Toolserver, but otherwise the need to enter a key everytime you start the bot may be annoying.""") + self.data["metadata"]["encryptPasswords"] = False if self._ask_bool("Encrypt stored passwords?"): - self.data["metadata"]["encryptPasswords"] = True key = getpass(self.PROMPT + "Enter an encryption key: ") msg = "Running {0} rounds of bcrypt...".format(self.BCRYPT_ROUNDS) self._print_no_nl(msg) - signature = bcrypt.hashpw(key, bcrypt.gensalt(self.BCRYPT_ROUNDS)) - self.data["metadata"]["signature"] = signature - self._cipher = Blowfish.new(sha256(key).digest()) - print " done." - else: - self.data["metadata"]["encryptPasswords"] = False + try: + salt = bcrypt.gensalt(self.BCRYPT_ROUNDS) + signature = bcrypt.hashpw(key, salt) + self._cipher = Blowfish.new(sha256(key).digest()) + except ImportError: + print " error!" + self._print("""Encryption requires the 'py-bcrypt' and + 'pycrypto' packages:""") + strt, end = " * \x1b[36m", "\x1b[0m" + print strt + "http://www.mindrot.org/projects/py-bcrypt/" + end + print strt + "https://www.dlitz.net/software/pycrypto/" + end + self._print("""I will disable encryption for now; restart + configuration after installing these packages if + you want it.""") + self._pause() + else: + self.data["metadata"]["encryptPasswords"] = True + self.data["metadata"]["signature"] = signature + print " done." print self._print("""The bot can temporarily store its logs in the logs/ diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 425d99a..59e0dcb 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -95,8 +95,8 @@ class CopyvioMixIn(object): if engine == "Yahoo! BOSS": try: oauth.__version__ # Force-load the lazy module - except (ImportError, AttributeError): - e = "The package 'oauth2' could not be imported" + except ImportError: + e = "Yahoo! BOSS requires the 'oauth2' package: https://github.com/simplegeo/python-oauth2" raise exceptions.UnsupportedSearchEngineError(e) return YahooBOSSSearchEngine(credentials) diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 765ea81..0d0cb0c 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -530,7 +530,7 @@ class Site(object): try: self._sql_conn = oursql.connect(**args) except ImportError: - e = "Module 'oursql' is required for SQL queries." + e = "SQL querying requires the 'oursql' package: http://packages.python.org/oursql/" raise exceptions.SQLError(e) def _get_service_order(self): diff --git a/setup.py b/setup.py index 3bbc638..d2cddb0 100644 --- a/setup.py +++ b/setup.py @@ -25,24 +25,32 @@ from setuptools import setup, find_packages from earwigbot import __version__ -# Not all of these dependencies are required, particularly the copyvio-specific -# ones (bs4, lxml, nltk, and oauth2) and the command-specific one (pytz). The -# bot should run fine without them, but will raise an exception if you try to -# detect copyvios or run a command that requries one. - -dependencies = [ +required_deps = [ "PyYAML >= 3.10", # Parsing config files - "beautifulsoup4 >= 4.1.1", # Parsing/scraping HTML for copyvios - "lxml >= 2.3.5", # Faster parser for BeautifulSoup "mwparserfromhell >= 0.1", # Parsing wikicode for manipulation - "nltk >= 2.0.2", # Parsing sentences to split article content for copyvios - "oauth2 >= 1.5.211", # Interfacing with Yahoo! BOSS Search for copyvios - "oursql >= 0.9.3.1", # Interfacing with MediaWiki databases - "py-bcrypt >= 0.2", # Hashing the bot key in the config file - "pycrypto >= 2.6", # Storing bot passwords and keys in the config file - "pytz >= 2012d", # Handling timezones for the !time IRC command ] +extra_deps = { + "crypto": [ + "py-bcrypt >= 0.2", # Hashing the bot key in the config file + "pycrypto >= 2.6", # Storing bot passwords and keys in the config file + ], + "sql": [ + "oursql >= 0.9.3.1", # Interfacing with MediaWiki databases + ], + "copyvios": [ + "beautifulsoup4 >= 4.1.1", # Parsing/scraping HTML + "lxml >= 2.3.5", # Faster parser for BeautifulSoup + "nltk >= 2.0.2", # Parsing sentences to split article content + "oauth2 >= 1.5.211", # Interfacing with Yahoo! BOSS Search + ], + "time": [ + "pytz >= 2012d", # Handling timezones for the !time IRC command + ], +} + +dependencies = required_deps + sum(extra_deps.values(), []) + with open("README.rst") as fp: long_docs = fp.read() From 1b999a1206528e27c777967024a4d6638ba33843 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 2 Sep 2012 15:29:37 -0400 Subject: [PATCH 005/207] Finish lazy-importing of py-bcrypt and pycrypto in config.__init__ --- earwigbot/commands/crypt.py | 2 -- earwigbot/config/__init__.py | 12 ++++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/earwigbot/commands/crypt.py b/earwigbot/commands/crypt.py index 92f458c..2072743 100644 --- a/earwigbot/commands/crypt.py +++ b/earwigbot/commands/crypt.py @@ -22,8 +22,6 @@ import hashlib -from Crypto.Cipher import Blowfish - from earwigbot import importer from earwigbot.commands import Command diff --git a/earwigbot/config/__init__.py b/earwigbot/config/__init__.py index 911a496..b89d310 100644 --- a/earwigbot/config/__init__.py +++ b/earwigbot/config/__init__.py @@ -282,10 +282,18 @@ class BotConfig(object): self._setup_logging() if self.is_encrypted(): if not self._decryption_cipher: + try: + blowfish_new = Blowfish.new + hashpw = bcrypt.hashpw + except ImportError: + url1 = "http://www.mindrot.org/projects/py-bcrypt" + url2 = "https://www.dlitz.net/software/pycrypto/" + e = "Encryption requires the 'py-bcrypt' and 'pycrypto' packages: {0}, {1}" + raise NoConfigError(e.format(url1, url2)) key = getpass("Enter key to decrypt bot passwords: ") - self._decryption_cipher = Blowfish.new(sha256(key).digest()) + self._decryption_cipher = blowfish_new(sha256(key).digest()) signature = self.metadata["signature"] - if bcrypt.hashpw(key, signature) != signature: + if hashpw(key, signature) != signature: raise RuntimeError("Incorrect password.") for node, nodes in self._decryptable_nodes: self._decrypt(node, nodes) From d709ee00a7ed1ac84e23f5f45f4b21331cd3fb47 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 3 Sep 2012 22:41:48 -0400 Subject: [PATCH 006/207] Better handling when we are blocked from editing . --- earwigbot/exceptions.py | 3 ++- earwigbot/wiki/page.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/earwigbot/exceptions.py b/earwigbot/exceptions.py index 61adf29..c8389aa 100644 --- a/earwigbot/exceptions.py +++ b/earwigbot/exceptions.py @@ -169,7 +169,8 @@ class PermissionsError(EditError): 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. + and AssertEdit enabled. This will also be raised if we have been blocked + from editing. Raised by :py:meth:`Page.edit ` and :py:meth:`Page.add_section `. diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index 7e30cb3..93a881b 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -400,6 +400,15 @@ class Page(CopyvioMixIn): elif error.code in ["emptypage", "emptynewsection"]: raise exceptions.NoContentError(error.info) + elif error.code == "blocked": + if tries > 0 or not all(self.site._login_info): + raise exceptions.PermissionsError(error.info) + else: + # Perhaps we are blocked from being logged-out? Try to log in: + self.site._login(self.site._login_info) + self._token = None # Need a new token; old one is invalid now + return self._edit(params=params, tries=1) + elif error.code == "contenttoobig": raise exceptions.ContentTooBigError(error.info) From d0217d7b8709017ed91d28a0fae4139bb2cd25a2 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 3 Sep 2012 22:54:59 -0400 Subject: [PATCH 007/207] Ensure lazy-loading works with subpackages. --- earwigbot/lazy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/earwigbot/lazy.py b/earwigbot/lazy.py index f9214e0..b123e3c 100644 --- a/earwigbot/lazy.py +++ b/earwigbot/lazy.py @@ -60,6 +60,8 @@ class _LazyModule(type): parents = (ModuleType,) klass = type.__new__(cls, "module", parents, attributes) sys.modules[name] = klass(name) + if "." in name: # Also ensure the parent exists + _LazyModule(name.rsplit(".", 1)[0]) return sys.modules[name] finally: release_lock() From a4dda89a615071ef68e64ea8454367508bae9eec Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 4 Sep 2012 01:05:50 -0400 Subject: [PATCH 008/207] Various fixes for copyvios. - Fix a bug in ExclusionsDB; improve URL regexes. - NLTK's LookupError is actually an IOError. - Fix bug in __repr__ for CopyvioCheckResult. - Rewrite YahooBOSSSearchEngine to actually work with oauth2. - Search engines now take a URL opener in addition to credentials. --- earwigbot/wiki/copyvios/__init__.py | 2 +- earwigbot/wiki/copyvios/exclusions.py | 7 ++--- earwigbot/wiki/copyvios/parsers.py | 5 +++- earwigbot/wiki/copyvios/result.py | 2 +- earwigbot/wiki/copyvios/search.py | 50 +++++++++++++++++++++++------------ 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 59e0dcb..295685c 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -98,7 +98,7 @@ class CopyvioMixIn(object): except ImportError: e = "Yahoo! BOSS requires the 'oauth2' package: https://github.com/simplegeo/python-oauth2" raise exceptions.UnsupportedSearchEngineError(e) - return YahooBOSSSearchEngine(credentials) + return YahooBOSSSearchEngine(credentials, self._opener) raise exceptions.UnknownSearchEngineError(engine) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 3600f97..517a12d 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -88,11 +88,12 @@ class ExclusionsDB(object): return urls regexes = [ - "url\s*=\s*(?:https?:)?(?://)?(.*)", - "\*\s*Site:\s*\[?(?:https?:)?(?://)?(.*)\]?" + r"url\s*=\s*(?:https?:)?(?://)?(.*)", + r"\*\s*Site:\s*(?:\[|\)?(?:https?:)?(?://)?(.*)(?:\]|\)?" ] for regex in regexes: - [urls.add(url.lower()) for (url,) in re.findall(regex, data, re.I)] + find = re.findall(regex, data, re.I) + [urls.add(url.lower().strip()) for url in find if url.strip()] return urls def _update(self, sitename): diff --git a/earwigbot/wiki/copyvios/parsers.py b/earwigbot/wiki/copyvios/parsers.py index 4f8e981..c5e4325 100644 --- a/earwigbot/wiki/copyvios/parsers.py +++ b/earwigbot/wiki/copyvios/parsers.py @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import errno from os import path import mwparserfromhell @@ -83,7 +84,9 @@ class ArticleTextParser(BaseTextParser): datafile = path.join(nltk_dir, "tokenizers", "punkt", "english.pickle") try: tokenizer = nltk.data.load("file:" + datafile) - except LookupError: + except IOError as exc: + if exc.errno != errno.ENOENT: + raise nltk.download("punkt", nltk_dir) tokenizer = nltk.data.load("file:" + datafile) diff --git a/earwigbot/wiki/copyvios/result.py b/earwigbot/wiki/copyvios/result.py index 0c3e98f..7594a41 100644 --- a/earwigbot/wiki/copyvios/result.py +++ b/earwigbot/wiki/copyvios/result.py @@ -50,7 +50,7 @@ class CopyvioCheckResult(object): def __repr__(self): """Return the canonical string representation of the result.""" - res = "CopyvioCheckResult(violation={0!r}, confidence={1!r}, url={2!r}, queries={3|r})" + res = "CopyvioCheckResult(violation={0!r}, confidence={1!r}, url={2!r}, queries={3!r})" return res.format(self.violation, self.confidence, self.url, self.queries) diff --git a/earwigbot/wiki/copyvios/search.py b/earwigbot/wiki/copyvios/search.py index a9afcfb..91db646 100644 --- a/earwigbot/wiki/copyvios/search.py +++ b/earwigbot/wiki/copyvios/search.py @@ -20,8 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from gzip import GzipFile from json import loads -from urllib import quote_plus, urlencode +from StringIO import StringIO +from urllib import quote_plus from earwigbot import importer from earwigbot.exceptions import SearchQueryError @@ -34,9 +36,10 @@ class BaseSearchEngine(object): """Base class for a simple search engine interface.""" name = "Base" - def __init__(self, cred): - """Store credentials *cred* for searching later on.""" + def __init__(self, cred, opener): + """Store credentials (*cred*) and *opener* for searching later on.""" self.cred = cred + self.opener = opener def __repr__(self): """Return the canonical string representation of the search engine.""" @@ -65,22 +68,35 @@ class YahooBOSSSearchEngine(BaseSearchEngine): determined by Yahoo). Raises :py:exc:`~earwigbot.exceptions.SearchQueryError` on errors. """ - base_url = "http://yboss.yahooapis.com/ysearch/web" - query = quote_plus(query.join('"', '"')) - params = {"q": query, "type": "html,text", "format": "json"} - url = "{0}?{1}".format(base_url, urlencode(params)) - - consumer = oauth.Consumer(key=self.cred["key"], - secret=self.cred["secret"]) - client = oauth.Client(consumer) - headers, body = client.request(url, "GET") - - if headers["status"] != "200": + key, secret = self.cred["key"], self.cred["secret"] + consumer = oauth.Consumer(key=key, secret=secret) + + url = "http://yboss.yahooapis.com/ysearch/web" + params = { + "oauth_version": oauth.OAUTH_VERSION, + "oauth_nonce": oauth.generate_nonce(), + "oauth_timestamp": oauth.Request.make_timestamp(), + "oauth_consumer_key": consumer.key, + "q": quote_plus('"' + query.encode("utf8") + '"'), + "type": "html,text", + "format": "json", + } + + req = oauth.Request(method="GET", url=url, parameters=params) + req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None) + response = self.opener.open(req.to_url()) + result = response.read() + + if response.headers.get("Content-Encoding") == "gzip": + stream = StringIO(result) + gzipper = GzipFile(fileobj=stream) + result = gzipper.read() + + if response.getcode() != 200: e = "Yahoo! BOSS Error: got response code '{0}':\n{1}'" - raise SearchQueryError(e.format(headers["status"], body)) - + raise SearchQueryError(e.format(response.getcode(), result)) try: - res = loads(body) + res = loads(result) except ValueError: e = "Yahoo! BOSS Error: JSON could not be decoded" raise SearchQueryError(e) From de23112f439b8cb1b639f46ce5af55fd4c2bf510 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 4 Sep 2012 01:10:07 -0400 Subject: [PATCH 009/207] Bugfix when we can't read HTML. --- earwigbot/wiki/copyvios/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 295685c..09e247b 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -110,7 +110,7 @@ class CopyvioMixIn(object): """ html = self._open_url_ignoring_errors(url) if not html: - return 0 + return 0, () source = MarkovChain(HTMLTextParser(html).strip()) delta = MarkovChainIntersection(article, source) @@ -166,11 +166,11 @@ class CopyvioMixIn(object): if self._exclusions_db: if self._exclusions_db.check(self.site.name, url): continue - conf, chains = self._copyvio_compare_content(article_chain, url) + conf, chns = self._copyvio_compare_content(article_chain, url) if conf > best_confidence: best_confidence = conf best_match = url - best_chains = chains + best_chains = chns num_queries += 1 diff = time() - last_query if diff < interquery_sleep: From bcf9b701070a5bd521103a6e88cd6077937d15a4 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 4 Sep 2012 01:44:41 -0400 Subject: [PATCH 010/207] Keep track of how long generating results takes; support 'max_time'. --- earwigbot/wiki/copyvios/__init__.py | 36 +++++++++++++++++++++++++----------- earwigbot/wiki/copyvios/result.py | 5 ++++- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 09e247b..59b0dab 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -116,7 +116,7 @@ class CopyvioMixIn(object): delta = MarkovChainIntersection(article, source) return float(delta.size()) / article.size(), (source, delta) - def copyvio_check(self, min_confidence=0.5, max_queries=-1, + def copyvio_check(self, min_confidence=0.5, max_queries=-1, max_time=-1, interquery_sleep=1): """Check the page for copyright violations. @@ -128,6 +128,11 @@ class CopyvioMixIn(object): number of queries in a given check. If it's lower than 0, we will not limit the number of queries. + *max_time* can be set to prevent copyvio checks from taking longer than + a set amount of time (generally around a minute), which can be useful + if checks are called through a web server with timeouts. We will stop + checking new URLs as soon as this limit is reached. + *interquery_sleep* is the minimum amount of time we will sleep between search engine queries, in seconds. @@ -135,6 +140,7 @@ class CopyvioMixIn(object): (:py:exc:`~earwigbot.exceptions.UnknownSearchEngineError`, :py:exc:`~earwigbot.exceptions.SearchQueryError`, ...) on errors. """ + start_time = time() searcher = self._select_search_engine() if self._exclusions_db: self._exclusions_db.sync(self.site.name) @@ -171,25 +177,31 @@ class CopyvioMixIn(object): best_confidence = conf best_match = url best_chains = chns + if time() - start_time > max_time: + break num_queries += 1 + if time() - start_time > max_time: + break diff = time() - last_query if diff < interquery_sleep: sleep(interquery_sleep - diff) last_query = time() + ctime = time() - start_time if best_confidence >= min_confidence: is_violation = True - log = u"Violation detected for [[{0}]] (confidence: {1}; URL: {2}; using {3} queries)" + log = u"Violation detected for [[{0}]] (confidence: {1}; URL: {2}; using {3} queries in {4} seconds)" self._logger.debug(log.format(self.title, best_confidence, - best_match, num_queries)) + best_match, num_queries, ctime)) else: is_violation = False - log = u"No violation for [[{0}]] (confidence: {1}; using {2} queries)" + log = u"No violation for [[{0}]] (confidence: {1}; using {2} queries in {3} seconds)" self._logger.debug(log.format(self.title, best_confidence, - num_queries)) + num_queries, ctime)) return CopyvioCheckResult(is_violation, best_confidence, best_match, - num_queries, article_chain, best_chains) + num_queries, ctime, article_chain, + best_chains) def copyvio_compare(self, url, min_confidence=0.5): """Check the page like :py:meth:`copyvio_check` against a specific URL. @@ -213,19 +225,21 @@ class CopyvioMixIn(object): :py:exc:`~earwigbot.exceptions.UnknownSearchEngineError` nor :py:exc:`~earwigbot.exceptions.SearchQueryError` will be raised. """ + start_time = time() content = self.get() clean = ArticleTextParser(content).strip() article_chain = MarkovChain(clean) confidence, chains = self._copyvio_compare_content(article_chain, url) + ctime = time() - start_time if confidence >= min_confidence: is_violation = True - log = u"Violation detected for [[{0}]] (confidence: {1}; URL: {2})" - self._logger.debug(log.format(self.title, confidence, url)) + log = u"Violation detected for [[{0}]] (confidence: {1}; URL: {2}; {3} seconds)" + self._logger.debug(log.format(self.title, confidence, url, ctime)) else: is_violation = False - log = u"No violation for [[{0}]] (confidence: {1}; URL: {2})" - self._logger.debug(log.format(self.title, confidence, url)) + log = u"No violation for [[{0}]] (confidence: {1}; URL: {2}; {3} seconds)" + self._logger.debug(log.format(self.title, confidence, url, ctime)) - return CopyvioCheckResult(is_violation, confidence, url, 0, + return CopyvioCheckResult(is_violation, confidence, url, 0, ctime, article_chain, chains) diff --git a/earwigbot/wiki/copyvios/result.py b/earwigbot/wiki/copyvios/result.py index 7594a41..d8da78f 100644 --- a/earwigbot/wiki/copyvios/result.py +++ b/earwigbot/wiki/copyvios/result.py @@ -34,16 +34,19 @@ class CopyvioCheckResult(object): - :py:attr:`confidence`: a float between 0 and 1 indicating accuracy - :py:attr:`url`: the URL of the violated page - :py:attr:`queries`: the number of queries used to reach a result + - :py:attr:`time`: the amount of time the check took to complete - :py:attr:`article_chain`: the MarkovChain of the article text - :py:attr:`source_chain`: the MarkovChain of the violated page text - :py:attr:`delta_chain`: the MarkovChainIntersection comparing the two """ - def __init__(self, violation, confidence, url, queries, article, chains): + def __init__(self, violation, confidence, url, queries, time, article, + chains): self.violation = violation self.confidence = confidence self.url = url self.queries = queries + self.time = time self.article_chain = article self.source_chain = chains[0] self.delta_chain = chains[1] From 8862bec3d98e95f9e2f94006a28ab77d43d26029 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 4 Sep 2012 01:50:54 -0400 Subject: [PATCH 011/207] Fix statements assigned to nothing. --- earwigbot/wiki/copyvios/parsers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/earwigbot/wiki/copyvios/parsers.py b/earwigbot/wiki/copyvios/parsers.py index c5e4325..ec7fe68 100644 --- a/earwigbot/wiki/copyvios/parsers.py +++ b/earwigbot/wiki/copyvios/parsers.py @@ -137,8 +137,10 @@ class HTMLTextParser(BaseTextParser): soup = bs4.BeautifulSoup(self.text).body is_comment = lambda text: isinstance(text, bs4.element.Comment) - [comment.extract() for comment in soup.find_all(text=is_comment)] + for comment in soup.find_all(text=is_comment): + comment.extract() for tag in self.hidden_tags: - [element.extract() for element in soup.find_all(tag)] + for element in soup.find_all(tag): + element.extract() return "\n".join(soup.stripped_strings) From 25d75c5d115eac93ececba5e57f25f19b98dbee0 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 5 Sep 2012 10:00:01 -0400 Subject: [PATCH 012/207] Forgot to give process_time param to CopyvioCheckResult. --- earwigbot/wiki/copyvios/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 59b0dab..906c2f5 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -158,7 +158,8 @@ class CopyvioMixIn(object): if article_chain.size() < 20: # Auto-fail very small articles return CopyvioCheckResult(False, best_confidence, best_match, - num_queries, article_chain, best_chains) + num_queries, 0, article_chain, + best_chains) while (chunks and best_confidence < min_confidence and (max_queries < 0 or num_queries < max_queries)): From 4ff7612a27065047b17ff96560d88334c3988f58 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 5 Sep 2012 10:10:18 -0400 Subject: [PATCH 013/207] Fix when we've cached None as a url. --- earwigbot/wiki/copyvios/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 906c2f5..cd0d143 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -230,8 +230,13 @@ class CopyvioMixIn(object): content = self.get() clean = ArticleTextParser(content).strip() article_chain = MarkovChain(clean) - confidence, chains = self._copyvio_compare_content(article_chain, url) + if not url: + empty = MarkovChain("") + chns = (empty, MarkovChainIntersection(empty, empty)) + return CopyvioCheckResult(False, 0, url, 0, 0, article_chain, chns) + + confidence, chains = self._copyvio_compare_content(article_chain, url) ctime = time() - start_time if confidence >= min_confidence: is_violation = True From c36b45771a8d4b352123d1eea19e87d757b7afcc Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 7 Sep 2012 21:00:23 -0400 Subject: [PATCH 014/207] Make [[User:EarwigBot/Copyvios/Exclusions]] project-insensitive. --- earwigbot/wiki/copyvios/exclusions.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 517a12d..2a0fb28 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -31,12 +31,14 @@ from earwigbot import exceptions __all__ = ["ExclusionsDB"] default_sources = { + "all": [ + "User:EarwigBot/Copyvios/Exclusions" + ], "enwiki": [ "Wikipedia:Mirrors and forks/Abc", "Wikipedia:Mirrors and forks/Def", "Wikipedia:Mirrors and forks/Ghi", "Wikipedia:Mirrors and forks/Jkl", "Wikipedia:Mirrors and forks/Mno", "Wikipedia:Mirrors and forks/Pqr", - "Wikipedia:Mirrors and forks/Stu", "Wikipedia:Mirrors and forks/Vwxyz", - "User:EarwigBot/Copyvios/Exclusions" + "Wikipedia:Mirrors and forks/Stu", "Wikipedia:Mirrors and forks/Vwxyz" ] } @@ -73,7 +75,8 @@ class ExclusionsDB(object): query = "INSERT INTO sources VALUES (?, ?);" sources = [] for sitename, pages in default_sources.iteritems(): - [sources.append((sitename, page)) for page in pages] + for page in pages: + sources.append((sitename, page)) with sqlite.connect(self._dbfile) as conn: conn.executescript(script) @@ -147,6 +150,8 @@ class ExclusionsDB(object): else: log = u"Database for {0} is still fresh (last updated {1} seconds ago)" self._logger.debug(log.format(sitename, time_since_update)) + if sitename != "all": + self.sync("all") def check(self, sitename, url): """Check whether a given URL is in the exclusions database. @@ -154,9 +159,10 @@ class ExclusionsDB(object): Return ``True`` if the URL is in the database, or ``False`` otherwise. """ normalized = re.sub("https?://", "", url.lower()) - query = "SELECT exclusion_url FROM exclusions WHERE exclusion_sitename = ?" + query = """SELECT exclusion_url FROM exclusions + WHERE exclusion_sitename = ? OR exclusion_sitename = ?""" with sqlite.connect(self._dbfile) as conn, self._db_access_lock: - for (excl,) in conn.execute(query, (sitename,)): + for (excl,) in conn.execute(query, (sitename, "all")): if excl.startswith("*."): netloc = urlparse(url.lower()).netloc matches = True if excl[2:] in netloc else False From 6a381c66f17a8ddbe6ee8a1e91e42d2c826c3166 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 5 Dec 2012 16:55:17 -0500 Subject: [PATCH 015/207] Fix a bug regarding updating the 'all' site. --- earwigbot/wiki/copyvios/exclusions.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 2a0fb28..590f6ef 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -31,7 +31,7 @@ from earwigbot import exceptions __all__ = ["ExclusionsDB"] default_sources = { - "all": [ + "all": [ # Applies to all, but located on enwiki "User:EarwigBot/Copyvios/Exclusions" ], "enwiki": [ @@ -109,7 +109,10 @@ class ExclusionsDB(object): query6 = "UPDATE updates SET update_time = ? WHERE update_sitename = ?;" query7 = "INSERT INTO updates VALUES (?, ?);" - site = self._sitesdb.get_site(sitename) + if sitename == "all": + site = self._sitesdb.get_site("enwiki") + else: + site = self._sitesdb.get_site(sitename) with sqlite.connect(self._dbfile) as conn, self._db_access_lock: urls = set() for (source,) in conn.execute(query1, (sitename,)): From 0b7a13eca5042e814cd04d18abfbb5a37093c42b Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 17 Jan 2013 02:13:04 -0500 Subject: [PATCH 016/207] Update copyright notices for 2013. --- docs/conf.py | 2 +- earwigbot/__init__.py | 4 ++-- earwigbot/bot.py | 2 +- earwigbot/commands/__init__.py | 2 +- earwigbot/commands/access.py | 2 +- earwigbot/commands/calc.py | 2 +- earwigbot/commands/chanops.py | 2 +- earwigbot/commands/crypt.py | 2 +- earwigbot/commands/ctcp.py | 2 +- earwigbot/commands/dictionary.py | 2 +- earwigbot/commands/editcount.py | 2 +- earwigbot/commands/help.py | 2 +- earwigbot/commands/lag.py | 2 +- earwigbot/commands/langcode.py | 2 +- earwigbot/commands/link.py | 2 +- earwigbot/commands/notes.py | 2 +- earwigbot/commands/quit.py | 2 +- earwigbot/commands/registration.py | 2 +- earwigbot/commands/remind.py | 2 +- earwigbot/commands/rights.py | 2 +- earwigbot/commands/test.py | 2 +- earwigbot/commands/threads.py | 2 +- earwigbot/commands/time_command.py | 2 +- earwigbot/commands/trout.py | 2 +- earwigbot/config/__init__.py | 2 +- earwigbot/config/formatter.py | 2 +- earwigbot/config/node.py | 2 +- earwigbot/config/ordered_yaml.py | 2 +- earwigbot/config/permissions.py | 2 +- earwigbot/config/script.py | 2 +- earwigbot/exceptions.py | 2 +- earwigbot/irc/__init__.py | 2 +- earwigbot/irc/connection.py | 2 +- earwigbot/irc/data.py | 2 +- earwigbot/irc/frontend.py | 2 +- earwigbot/irc/rc.py | 2 +- earwigbot/irc/watcher.py | 2 +- earwigbot/lazy.py | 2 +- earwigbot/managers.py | 2 +- earwigbot/tasks/__init__.py | 2 +- earwigbot/tasks/wikiproject_tagger.py | 2 +- earwigbot/util.py | 2 +- earwigbot/wiki/__init__.py | 2 +- earwigbot/wiki/category.py | 2 +- earwigbot/wiki/constants.py | 2 +- earwigbot/wiki/copyvios/__init__.py | 2 +- earwigbot/wiki/copyvios/exclusions.py | 2 +- earwigbot/wiki/copyvios/markov.py | 2 +- earwigbot/wiki/copyvios/parsers.py | 2 +- earwigbot/wiki/copyvios/result.py | 2 +- earwigbot/wiki/copyvios/search.py | 2 +- earwigbot/wiki/page.py | 2 +- earwigbot/wiki/site.py | 2 +- earwigbot/wiki/sitesdb.py | 2 +- earwigbot/wiki/user.py | 2 +- 55 files changed, 56 insertions(+), 56 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 747d5c8..1a13c78 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,7 +41,7 @@ master_doc = 'index' # General information about the project. project = u'EarwigBot' -copyright = u'2009, 2010, 2011, 2012 Ben Kurtovic' +copyright = u'2009, 2010, 2011, 2012, 2013 Ben Kurtovic' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/earwigbot/__init__.py b/earwigbot/__init__.py index 256837c..15dfc94 100644 --- a/earwigbot/__init__.py +++ b/earwigbot/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ details. This documentation is also available `online """ __author__ = "Ben Kurtovic" -__copyright__ = "Copyright (C) 2009, 2010, 2011, 2012 Ben Kurtovic" +__copyright__ = "Copyright (C) 2009, 2010, 2011, 2012, 2013 Ben Kurtovic" __license__ = "MIT License" __version__ = "0.2.dev" __email__ = "ben.kurtovic@verizon.net" diff --git a/earwigbot/bot.py b/earwigbot/bot.py index 27dd9c0..9d95645 100644 --- a/earwigbot/bot.py +++ b/earwigbot/bot.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/__init__.py b/earwigbot/commands/__init__.py index ecb299c..3ebca25 100644 --- a/earwigbot/commands/__init__.py +++ b/earwigbot/commands/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/access.py b/earwigbot/commands/access.py index 1132348..0ca75c1 100644 --- a/earwigbot/commands/access.py +++ b/earwigbot/commands/access.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/calc.py b/earwigbot/commands/calc.py index de16202..1c7d532 100644 --- a/earwigbot/commands/calc.py +++ b/earwigbot/commands/calc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/chanops.py b/earwigbot/commands/chanops.py index ea54500..ac2e300 100644 --- a/earwigbot/commands/chanops.py +++ b/earwigbot/commands/chanops.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/crypt.py b/earwigbot/commands/crypt.py index 2072743..bd6222d 100644 --- a/earwigbot/commands/crypt.py +++ b/earwigbot/commands/crypt.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/ctcp.py b/earwigbot/commands/ctcp.py index 0ed6412..a3ef267 100644 --- a/earwigbot/commands/ctcp.py +++ b/earwigbot/commands/ctcp.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/dictionary.py b/earwigbot/commands/dictionary.py index 407f5f3..54e68ea 100644 --- a/earwigbot/commands/dictionary.py +++ b/earwigbot/commands/dictionary.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/editcount.py b/earwigbot/commands/editcount.py index 2adea14..be902cc 100644 --- a/earwigbot/commands/editcount.py +++ b/earwigbot/commands/editcount.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/help.py b/earwigbot/commands/help.py index 7c9bd7f..6de7a3b 100644 --- a/earwigbot/commands/help.py +++ b/earwigbot/commands/help.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/lag.py b/earwigbot/commands/lag.py index cee0ee1..c2e8330 100644 --- a/earwigbot/commands/lag.py +++ b/earwigbot/commands/lag.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/langcode.py b/earwigbot/commands/langcode.py index 860c32e..d05736b 100644 --- a/earwigbot/commands/langcode.py +++ b/earwigbot/commands/langcode.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/link.py b/earwigbot/commands/link.py index 858ff35..1f4c9a4 100644 --- a/earwigbot/commands/link.py +++ b/earwigbot/commands/link.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/notes.py b/earwigbot/commands/notes.py index a430ae7..d275561 100644 --- a/earwigbot/commands/notes.py +++ b/earwigbot/commands/notes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/quit.py b/earwigbot/commands/quit.py index 0331d08..d5954b3 100644 --- a/earwigbot/commands/quit.py +++ b/earwigbot/commands/quit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/registration.py b/earwigbot/commands/registration.py index 74d2ce0..f45501c 100644 --- a/earwigbot/commands/registration.py +++ b/earwigbot/commands/registration.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/remind.py b/earwigbot/commands/remind.py index e8470cb..6018c16 100644 --- a/earwigbot/commands/remind.py +++ b/earwigbot/commands/remind.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/rights.py b/earwigbot/commands/rights.py index a54093a..749ee3c 100644 --- a/earwigbot/commands/rights.py +++ b/earwigbot/commands/rights.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/test.py b/earwigbot/commands/test.py index 305ba74..32224ff 100644 --- a/earwigbot/commands/test.py +++ b/earwigbot/commands/test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/threads.py b/earwigbot/commands/threads.py index e878d09..9ac8b09 100644 --- a/earwigbot/commands/threads.py +++ b/earwigbot/commands/threads.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index b0dc657..3754986 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/trout.py b/earwigbot/commands/trout.py index eb05db8..b8ea465 100644 --- a/earwigbot/commands/trout.py +++ b/earwigbot/commands/trout.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/__init__.py b/earwigbot/config/__init__.py index b89d310..9a91583 100644 --- a/earwigbot/config/__init__.py +++ b/earwigbot/config/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/formatter.py b/earwigbot/config/formatter.py index 561db21..cb74c0c 100644 --- a/earwigbot/config/formatter.py +++ b/earwigbot/config/formatter.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/node.py b/earwigbot/config/node.py index 82ffaa7..d3be3e5 100644 --- a/earwigbot/config/node.py +++ b/earwigbot/config/node.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/ordered_yaml.py b/earwigbot/config/ordered_yaml.py index 2c07b93..0fc1df6 100644 --- a/earwigbot/config/ordered_yaml.py +++ b/earwigbot/config/ordered_yaml.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/permissions.py b/earwigbot/config/permissions.py index 975f041..131fae2 100644 --- a/earwigbot/config/permissions.py +++ b/earwigbot/config/permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/script.py b/earwigbot/config/script.py index 0b35aed..35dfc38 100644 --- a/earwigbot/config/script.py +++ b/earwigbot/config/script.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/exceptions.py b/earwigbot/exceptions.py index c8389aa..546a9f9 100644 --- a/earwigbot/exceptions.py +++ b/earwigbot/exceptions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/__init__.py b/earwigbot/irc/__init__.py index 4923c75..3fe86e9 100644 --- a/earwigbot/irc/__init__.py +++ b/earwigbot/irc/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/connection.py b/earwigbot/irc/connection.py index 228b6a4..943823d 100644 --- a/earwigbot/irc/connection.py +++ b/earwigbot/irc/connection.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/data.py b/earwigbot/irc/data.py index 2cf2dc8..6ff3213 100644 --- a/earwigbot/irc/data.py +++ b/earwigbot/irc/data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/frontend.py b/earwigbot/irc/frontend.py index b8582b0..ce63a6e 100644 --- a/earwigbot/irc/frontend.py +++ b/earwigbot/irc/frontend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/rc.py b/earwigbot/irc/rc.py index b913e7d..1c526b0 100644 --- a/earwigbot/irc/rc.py +++ b/earwigbot/irc/rc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/watcher.py b/earwigbot/irc/watcher.py index 22d15eb..469914f 100644 --- a/earwigbot/irc/watcher.py +++ b/earwigbot/irc/watcher.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/lazy.py b/earwigbot/lazy.py index b123e3c..5526478 100644 --- a/earwigbot/lazy.py +++ b/earwigbot/lazy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/managers.py b/earwigbot/managers.py index c700e19..d72df54 100644 --- a/earwigbot/managers.py +++ b/earwigbot/managers.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/tasks/__init__.py b/earwigbot/tasks/__init__.py index 5e32f05..d3590a4 100644 --- a/earwigbot/tasks/__init__.py +++ b/earwigbot/tasks/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/tasks/wikiproject_tagger.py b/earwigbot/tasks/wikiproject_tagger.py index 1d7d30f..eecbff7 100644 --- a/earwigbot/tasks/wikiproject_tagger.py +++ b/earwigbot/tasks/wikiproject_tagger.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/util.py b/earwigbot/util.py index 2042f96..41f9eb6 100755 --- a/earwigbot/util.py +++ b/earwigbot/util.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/__init__.py b/earwigbot/wiki/__init__.py index ba80570..7e1d0be 100644 --- a/earwigbot/wiki/__init__.py +++ b/earwigbot/wiki/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/category.py b/earwigbot/wiki/category.py index 33f4fd0..b8561a3 100644 --- a/earwigbot/wiki/category.py +++ b/earwigbot/wiki/category.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/constants.py b/earwigbot/wiki/constants.py index b4adc36..39f1400 100644 --- a/earwigbot/wiki/constants.py +++ b/earwigbot/wiki/constants.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index cd0d143..759f43c 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 590f6ef..0cab1e3 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/markov.py b/earwigbot/wiki/copyvios/markov.py index 6cf14ff..a785b6c 100644 --- a/earwigbot/wiki/copyvios/markov.py +++ b/earwigbot/wiki/copyvios/markov.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/parsers.py b/earwigbot/wiki/copyvios/parsers.py index ec7fe68..30f0c7f 100644 --- a/earwigbot/wiki/copyvios/parsers.py +++ b/earwigbot/wiki/copyvios/parsers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/result.py b/earwigbot/wiki/copyvios/result.py index d8da78f..94b2775 100644 --- a/earwigbot/wiki/copyvios/result.py +++ b/earwigbot/wiki/copyvios/result.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/search.py b/earwigbot/wiki/copyvios/search.py index 91db646..1f2ac8c 100644 --- a/earwigbot/wiki/copyvios/search.py +++ b/earwigbot/wiki/copyvios/search.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index 93a881b..ffcde15 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 0d0cb0c..ec6002b 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/sitesdb.py b/earwigbot/wiki/sitesdb.py index 5b37f78..75cca0f 100644 --- a/earwigbot/wiki/sitesdb.py +++ b/earwigbot/wiki/sitesdb.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/user.py b/earwigbot/wiki/user.py index 039b845..91bb523 100644 --- a/earwigbot/wiki/user.py +++ b/earwigbot/wiki/user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From c3dbc9cc8450f1a7a60e0a904035475a6f0ebe69 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 17 Jan 2013 02:18:17 -0500 Subject: [PATCH 017/207] Missed a few years. --- LICENSE | 2 +- setup.py | 2 +- tests/__init__.py | 2 +- tests/test_calc.py | 2 +- tests/test_test.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index 104339b..c34d909 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2009-2012 Ben Kurtovic +Copyright (C) 2009-2013 Ben Kurtovic Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/setup.py b/setup.py index d2cddb0..8e0931c 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/__init__.py b/tests/__init__.py index 77992bd..6ab010f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/test_calc.py b/tests/test_calc.py index 45e3c9b..b2ce1f7 100644 --- a/tests/test_calc.py +++ b/tests/test_calc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/test_test.py b/tests/test_test.py index 67bb4fa..9e5d054 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2012 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From ab216fb834f6a3c89e04dc34da768fc8f4ba27d0 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 17 Jan 2013 17:30:57 -0500 Subject: [PATCH 018/207] tags in exclusion lists are optional. --- earwigbot/wiki/copyvios/exclusions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 0cab1e3..227265e 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -91,7 +91,7 @@ class ExclusionsDB(object): return urls regexes = [ - r"url\s*=\s*(?:https?:)?(?://)?(.*)", + r"url\s*=\s*()?(?:https?:)?(?://)?(.*)()?", r"\*\s*Site:\s*(?:\[|\)?(?:https?:)?(?://)?(.*)(?:\]|\)?" ] for regex in regexes: From 8c524d9c30ab5efe0cba064d1f217c9a100d7e50 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 17 Jan 2013 17:34:56 -0500 Subject: [PATCH 019/207] Whoops, those patterns are supposed to be ignored. --- earwigbot/wiki/copyvios/exclusions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 227265e..a026517 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -91,7 +91,7 @@ class ExclusionsDB(object): return urls regexes = [ - r"url\s*=\s*()?(?:https?:)?(?://)?(.*)()?", + r"url\s*=\s*(?:)?(?:https?:)?(?://)?(.*)(?:)?", r"\*\s*Site:\s*(?:\[|\)?(?:https?:)?(?://)?(.*)(?:\]|\)?" ] for regex in regexes: From 333201226b1498a10aa4ab826c05884bd2ba4bbd Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 18 Jan 2013 23:15:37 -0500 Subject: [PATCH 020/207] Once again, reengineer regexes. --- earwigbot/wiki/copyvios/exclusions.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index a026517..d62087e 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -91,8 +91,8 @@ class ExclusionsDB(object): return urls regexes = [ - r"url\s*=\s*(?:)?(?:https?:)?(?://)?(.*)(?:)?", - r"\*\s*Site:\s*(?:\[|\)?(?:https?:)?(?://)?(.*)(?:\]|\)?" + r"url\s*=\s*(?:\)?(?:https?:)?(?://)?(.*?)(?:\.*?)?\s*$", + r"\*\s*Site:\s*(?:\[|\)?(?:https?:)?(?://)?(.*?)(?:\].*?|\.*?)?\s*$" ] for regex in regexes: find = re.findall(regex, data, re.I) @@ -101,13 +101,13 @@ class ExclusionsDB(object): def _update(self, sitename): """Update the database from listed sources in the index.""" - query1 = "SELECT source_page FROM sources WHERE source_sitename = ?;" + query1 = "SELECT source_page FROM sources WHERE source_sitename = ?" query2 = "SELECT exclusion_url FROM exclusions WHERE exclusion_sitename = ?" query3 = "DELETE FROM exclusions WHERE exclusion_sitename = ? AND exclusion_url = ?" - query4 = "INSERT INTO exclusions VALUES (?, ?);" - query5 = "SELECT 1 FROM updates WHERE update_sitename = ?;" - query6 = "UPDATE updates SET update_time = ? WHERE update_sitename = ?;" - query7 = "INSERT INTO updates VALUES (?, ?);" + query4 = "INSERT INTO exclusions VALUES (?, ?)" + query5 = "SELECT 1 FROM updates WHERE update_sitename = ?" + query6 = "UPDATE updates SET update_time = ? WHERE update_sitename = ?" + query7 = "INSERT INTO updates VALUES (?, ?)" if sitename == "all": site = self._sitesdb.get_site("enwiki") @@ -130,7 +130,7 @@ class ExclusionsDB(object): def _get_last_update(self, sitename): """Return the UNIX timestamp of the last time the db was updated.""" - query = "SELECT update_time FROM updates WHERE update_sitename = ?;" + query = "SELECT update_time FROM updates WHERE update_sitename = ?" with sqlite.connect(self._dbfile) as conn, self._db_access_lock: try: result = conn.execute(query, (sitename,)).fetchone() @@ -140,11 +140,11 @@ class ExclusionsDB(object): return result[0] if result else 0 def sync(self, sitename): - """Update the database if it hasn't been updated in the past week. + """Update the database if it hasn't been updated in the past day. This only updates the exclusions database for the *sitename* site. """ - max_staleness = 60 * 60 * 24 * 7 + max_staleness = 60 * 60 * 24 time_since_update = int(time() - self._get_last_update(sitename)) if time_since_update > max_staleness: log = u"Updating stale database: {0} (last updated {1} seconds ago)" From f082fca720e11e9c4b78756c595af8861e32dd1e Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 18 Jan 2013 23:42:43 -0500 Subject: [PATCH 021/207] So re.MULTILINE is necessary for those rules. --- earwigbot/wiki/copyvios/exclusions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index d62087e..dbbe0c9 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -95,7 +95,7 @@ class ExclusionsDB(object): r"\*\s*Site:\s*(?:\[|\)?(?:https?:)?(?://)?(.*?)(?:\].*?|\.*?)?\s*$" ] for regex in regexes: - find = re.findall(regex, data, re.I) + find = re.findall(regex, data, re.I|re.M) [urls.add(url.lower().strip()) for url in find if url.strip()] return urls From 9ad03589a443fd56fb513d57f88875747b48c505 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 10 Mar 2013 16:34:53 -0400 Subject: [PATCH 022/207] Make default !access behavior more reasonable. --- earwigbot/commands/access.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/earwigbot/commands/access.py b/earwigbot/commands/access.py index 0ca75c1..f738b21 100644 --- a/earwigbot/commands/access.py +++ b/earwigbot/commands/access.py @@ -30,11 +30,8 @@ class Access(Command): commands = ["access", "permission", "permissions", "perm", "perms"] def process(self, data): - if not data.args: - self.reply(data, "Subcommands are self, list, add, remove.") - return permdb = self.config.irc["permissions"] - if data.args[0] == "self": + if not data.args or data.args[0] == "self": self.do_self(data, permdb) elif data.args[0] == "list": self.do_list(data, permdb) @@ -42,9 +39,11 @@ class Access(Command): self.do_add(data, permdb) elif data.args[0] == "remove": self.do_remove(data, permdb) + elif data.args[0] == "help": + self.reply(data, "Subcommands are self, list, add, and remove.") else: - msg = "Unknown subcommand \x0303{0}\x0F.".format(data.args[0]) - self.reply(data, msg) + msg = "Unknown subcommand \x0303{0}\x0F. Subcommands are self, list, add, remove." + self.reply(data, msg.format(data.args[0])) def do_self(self, data, permdb): if permdb.is_owner(data): From a9051f353598ec7f25b9b8164f1c998859fca03c Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 1 Apr 2013 19:30:56 -0400 Subject: [PATCH 023/207] Bold! --- earwigbot/commands/access.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/commands/access.py b/earwigbot/commands/access.py index f738b21..de562fe 100644 --- a/earwigbot/commands/access.py +++ b/earwigbot/commands/access.py @@ -73,7 +73,7 @@ class Access(Command): else: owners = len(permdb.data.get(permdb.OWNER, [])) admins = len(permdb.data.get(permdb.ADMIN, [])) - msg = "There are {0} bot owners and {1} bot admins. Use '!{2} list owners' or '!{2} list admins' for details." + msg = "There are \x02{0}\x0F bot owners and \x02{1}\x0F bot admins. Use '!{2} list owners' or '!{2} list admins' for details." self.reply(data, msg.format(owners, admins, data.command)) def do_add(self, data, permdb): From dd5a9427f0958586a1cc7166ae5027f5b15a66be Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 14 Apr 2013 00:52:08 -0400 Subject: [PATCH 024/207] Expand the permissions db to store attributes for users. --- earwigbot/config/permissions.py | 78 ++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/earwigbot/config/permissions.py b/earwigbot/config/permissions.py index 131fae2..eb8c7ad 100644 --- a/earwigbot/config/permissions.py +++ b/earwigbot/config/permissions.py @@ -39,7 +39,8 @@ class PermissionsDB(object): def __init__(self, dbfile): self._dbfile = dbfile self._db_access_lock = Lock() - self._data = {} + self._users = {} + self._attributes = {} def __repr__(self): """Return the canonical string representation of the PermissionsDB.""" @@ -53,13 +54,14 @@ class PermissionsDB(object): def _create(self, conn): """Initialize the permissions database with its necessary tables.""" query = """CREATE TABLE users (user_nick, user_ident, user_host, - user_rank)""" + user_rank); + CREATE TABLE attributes (attr_uid, attr_key, attr_value);""" conn.execute(query) def _is_rank(self, user, rank): """Return True if the given user has the given rank, else False.""" try: - for rule in self._data[rank]: + for rule in self._users[rank]: if user in rule: return rule except KeyError: @@ -73,9 +75,9 @@ class PermissionsDB(object): with sqlite.connect(self._dbfile) as conn: conn.execute(query, (user.nick, user.ident, user.host, rank)) try: - self._data[rank].append(user) + self._users[rank].append(user) except KeyError: - self._data[rank] = [user] + self._users[rank] = [user] return user def _del_rank(self, user, rank): @@ -84,40 +86,51 @@ class PermissionsDB(object): user_host = ? AND user_rank = ?""" with self._db_access_lock: try: - for rule in self._data[rank]: + for rule in self._users[rank]: if user in rule: with sqlite.connect(self._dbfile) as conn: args = (user.nick, user.ident, user.host, rank) conn.execute(query, args) - self._data[rank].remove(rule) + self._users[rank].remove(rule) return rule except KeyError: pass return None @property - def data(self): - """A dict of all entries in the permissions database.""" - return self._data + def users(self): + """A dict of all users in the permissions database.""" + return self._users + + @property + def attributes(self): + """A dict of all attributes in the permissions database.""" + return self._attributes def load(self): """Load permissions from an existing database, or create a new one.""" - query = "SELECT user_nick, user_ident, user_host, user_rank FROM users" - self._data = {} + qry1 = "SELECT user_nick, user_ident, user_host, user_rank FROM users" + qry2 = "SELECT attr_uid, attr_key, attr_value FROM attributes" + self._users = {} with sqlite.connect(self._dbfile) as conn, self._db_access_lock: try: - for nick, ident, host, rank in conn.execute(query): + for nick, ident, host, rank in conn.execute(qry1): + try: + self._users[rank].append(_User(nick, ident, host)) + except KeyError: + self._users[rank] = [_User(nick, ident, host)] + for user, key, value in conn.execute(qry2): try: - self._data[rank].append(_User(nick, ident, host)) + self._attributes[user][key] = value except KeyError: - self._data[rank] = [_User(nick, ident, host)] + self._attributes[user] = {key: value} except sqlite.OperationalError: self._create(conn) def has_exact(self, rank, nick="*", ident="*", host="*"): """Return ``True`` if there is an exact match for this rule.""" try: - for usr in self._data[rank]: + for usr in self._users[rank]: if nick != usr.nick or ident != usr.ident or host != usr.host: continue return usr @@ -151,6 +164,39 @@ class PermissionsDB(object): """Remove a nick/ident/host combo to the bot owners list.""" return self._del_rank(_User(nick, ident, host), rank=self.OWNER) + def has_attr(self, user, key): + """Return ``True`` if a given user has a certain attribute, *key*.""" + return user in self._attributes and key in self._attributes[user] + + def get_attr(self, user, key): + """Get the value of the attribute *key* of a given *user*. + + Raises :py:exc:`KeyError` if the *key* or *user* is not found. + """ + return self._attributes[user][key] + + def set_attr(self, user, key, value): + """Set the *value* of the attribute *key* of a given *user*.""" + query1 = """SELECT attr_value FROM attributes WHERE attr_uid = ? + AND attr_key = ?""" + query2 = "INSERT INTO attributes VALUES (?, ?, ?)" + query3 = """UPDATE attributes SET attr_value = ? WHERE attr_uid = ? + AND attr_key = ?""" + with self._db_access_lock, sqlite.connect(self._dbfile) as conn: + if conn.execute(query1, (user, key)): + conn.execute(query2, (user, key, value)) + else: + conn.execute(query3, (value, user, key)) + try: + self._attributes[user][key] = value + except KeyError: + self.attributes[user] = {key: value} + + def remove_attr(self, user, key): + """Remove the attribute *key* of a given *user*.""" + query = "DELETE FROM attributes WHERE attr_uid = ? AND attr_key = ?" + with self._db_access_lock, sqlite.connect(self._dbfile) as conn: + conn.execute(query, (user, key)) class _User(object): """A class that represents an IRC user for the purpose of testing rules.""" From ca7cbceb4a2ee537861bd136950c68f96fc9cf9d Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 14 Apr 2013 01:44:37 -0400 Subject: [PATCH 025/207] Silly SQL, that's not what I told you to do. --- earwigbot/config/permissions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/earwigbot/config/permissions.py b/earwigbot/config/permissions.py index eb8c7ad..d3acb88 100644 --- a/earwigbot/config/permissions.py +++ b/earwigbot/config/permissions.py @@ -183,10 +183,10 @@ class PermissionsDB(object): query3 = """UPDATE attributes SET attr_value = ? WHERE attr_uid = ? AND attr_key = ?""" with self._db_access_lock, sqlite.connect(self._dbfile) as conn: - if conn.execute(query1, (user, key)): - conn.execute(query2, (user, key, value)) - else: + if conn.execute(query1, (user, key)).fetchone(): conn.execute(query3, (value, user, key)) + else: + conn.execute(query2, (user, key, value)) try: self._attributes[user][key] = value except KeyError: From 5931f375debb858d83047727c45e64cb2d835e67 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 11 Jun 2013 21:03:17 -0400 Subject: [PATCH 026/207] Put response.read() in the try:, since that's what throws the timeout. --- earwigbot/wiki/copyvios/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 759f43c..8b906f9 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -63,9 +63,9 @@ class CopyvioMixIn(object): """ try: response = self._opener.open(url.encode("utf8"), timeout=5) + result = response.read() except (URLError, timeout): return None - result = response.read() if response.headers.get("Content-Encoding") == "gzip": stream = StringIO(result) From 8ef0642e08f78da76ab339decda4ab086848c0c3 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 28 Jun 2013 18:27:44 -0400 Subject: [PATCH 027/207] Fix PermissionsDB.data -> PermissionsDB.users. --- earwigbot/commands/access.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/earwigbot/commands/access.py b/earwigbot/commands/access.py index de562fe..b4671ca 100644 --- a/earwigbot/commands/access.py +++ b/earwigbot/commands/access.py @@ -58,9 +58,9 @@ class Access(Command): def do_list(self, data, permdb): if len(data.args) > 1: if data.args[1] in ["owner", "owners"]: - name, rules = "owners", permdb.data.get(permdb.OWNER) + name, rules = "owners", permdb.users.get(permdb.OWNER) elif data.args[1] in ["admin", "admins"]: - name, rules = "admins", permdb.data.get(permdb.ADMIN) + name, rules = "admins", permdb.users.get(permdb.ADMIN) else: msg = "Unknown access level \x0302{0}\x0F." self.reply(data, msg.format(data.args[1])) @@ -71,8 +71,8 @@ class Access(Command): msg = "No bot {0}.".format(name) self.reply(data, msg) else: - owners = len(permdb.data.get(permdb.OWNER, [])) - admins = len(permdb.data.get(permdb.ADMIN, [])) + owners = len(permdb.users.get(permdb.OWNER, [])) + admins = len(permdb.users.get(permdb.ADMIN, [])) msg = "There are \x02{0}\x0F bot owners and \x02{1}\x0F bot admins. Use '!{2} list owners' or '!{2} list admins' for details." self.reply(data, msg.format(owners, admins, data.command)) From af9f6a56fb3a450f02fdb849d0429bedbb88eb56 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 1 Jul 2013 02:44:07 -0400 Subject: [PATCH 028/207] Improve help for !langcode. --- earwigbot/commands/langcode.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/earwigbot/commands/langcode.py b/earwigbot/commands/langcode.py index d05736b..a6534c3 100644 --- a/earwigbot/commands/langcode.py +++ b/earwigbot/commands/langcode.py @@ -23,14 +23,14 @@ from earwigbot.commands import Command class Langcode(Command): - """Convert a language code into its name and a list of WMF sites in that - language, or a name into its code.""" + """Convert a language code into its name (or vice versa), and give a list + of WMF sites in that language.""" name = "langcode" commands = ["langcode", "lang", "language"] def process(self, data): if not data.args: - self.reply(data, "Please specify a language code.") + self.reply(data, "Please specify a language code or name.") return code, lcase = data.args[0], data.args[0].lower() From 58066402afde7a09acadc164d470a9b8e845783e Mon Sep 17 00:00:00 2001 From: justinkim Date: Mon, 15 Jul 2013 19:14:34 -0700 Subject: [PATCH 029/207] Add def to possible !dict aliases --- earwigbot/commands/dictionary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/commands/dictionary.py b/earwigbot/commands/dictionary.py index 54e68ea..4a1715b 100644 --- a/earwigbot/commands/dictionary.py +++ b/earwigbot/commands/dictionary.py @@ -28,7 +28,7 @@ from earwigbot.commands import Command class Dictionary(Command): """Define words and stuff.""" name = "dictionary" - commands = ["dict", "dictionary", "define"] + commands = ["dict", "dictionary", "define", "def"] def process(self, data): if not data.args: From fd5852a6d0729f72e42899d195799934ceba30c2 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 25 Aug 2013 05:10:10 -0400 Subject: [PATCH 030/207] RIP Toolserver. (Some fixes for Labs compatibilty.) --- earwigbot/commands/lag.py | 4 ++-- earwigbot/config/script.py | 17 +++++++++++++---- earwigbot/wiki/site.py | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/earwigbot/commands/lag.py b/earwigbot/commands/lag.py index c2e8330..cefafcc 100644 --- a/earwigbot/commands/lag.py +++ b/earwigbot/commands/lag.py @@ -24,7 +24,7 @@ from earwigbot import exceptions from earwigbot.commands import Command class Lag(Command): - """Return the replag for a specific database on the Toolserver.""" + """Return replag or maxlag information on specific databases.""" name = "lag" commands = ["lag", "replag", "maxlag"] @@ -45,7 +45,7 @@ class Lag(Command): self.reply(data, msg) def get_replag(self, site): - return "Toolserver replag is {0}".format(self.time(site.get_replag())) + return "replag is {0}".format(self.time(site.get_replag())) def get_maxlag(self, site): return "database maxlag is {0}".format(self.time(site.get_maxlag())) diff --git a/earwigbot/config/script.py b/earwigbot/config/script.py index 35dfc38..7bc54c5 100644 --- a/earwigbot/config/script.py +++ b/earwigbot/config/script.py @@ -279,11 +279,20 @@ class ConfigScript(object): self.data["wiki"]["sql"] = {} if self._wmf: - msg = "Will this bot run from the Wikimedia Toolserver?" - toolserver = self._ask_bool(msg, default=False) - if toolserver: - args = [("host", "$1-p.rrdb.toolserver.org"), ("db", "$1_p")] + msg = "Will this bot run from the Wikimedia Tool Labs?" + labs = self._ask_bool(msg, default=False) + if labs: + args = [("host", "$1.labsdb"), ("db", "$1_p"), + ("read_default_file", + "/data/project/earwigbot/replica.my.cnf")] self.data["wiki"]["sql"] = OrderedDict(args) + else: + msg = "Will this bot run from the Wikimedia Toolserver?" + toolserver = self._ask_bool(msg, default=False) + if toolserver: + args = [("host", "$1-p.rrdb.toolserver.org"), + ("db", "$1_p")] + self.data["wiki"]["sql"] = OrderedDict(args) self.data["wiki"]["shutoff"] = {} msg = "Would you like to enable an automatic shutoff page for the bot?" diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index ec6002b..772dfe7 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -729,7 +729,7 @@ class Site(object): query = """SELECT UNIX_TIMESTAMP() - UNIX_TIMESTAMP(rc_timestamp) FROM recentchanges ORDER BY rc_timestamp DESC LIMIT 1""" result = list(self.sql_query(query)) - return result[0][0] + return int(result[0][0]) def namespace_id_to_name(self, ns_id, all=False): """Given a namespace ID, returns associated namespace names. From 8a88988a02313bbe24c564d7d932e98c85fdb802 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 25 Aug 2013 05:14:23 -0400 Subject: [PATCH 031/207] WHOOPS. --- earwigbot/config/script.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/earwigbot/config/script.py b/earwigbot/config/script.py index 7bc54c5..afdb41a 100644 --- a/earwigbot/config/script.py +++ b/earwigbot/config/script.py @@ -283,8 +283,7 @@ class ConfigScript(object): labs = self._ask_bool(msg, default=False) if labs: args = [("host", "$1.labsdb"), ("db", "$1_p"), - ("read_default_file", - "/data/project/earwigbot/replica.my.cnf")] + ("read_default_file", "~/replica.my.cnf")] self.data["wiki"]["sql"] = OrderedDict(args) else: msg = "Will this bot run from the Wikimedia Toolserver?" From 48e6c14ab8835ad5ade82e10d66f4e8dcb54671c Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 25 Aug 2013 05:14:49 -0400 Subject: [PATCH 032/207] WHOOPS X2. --- earwigbot/wiki/site.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 772dfe7..dd06ea6 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -520,6 +520,8 @@ class Site(object): if "read_default_file" not in args and "user" not in args and "passwd" not in args: args["read_default_file"] = expanduser("~/.my.cnf") + elif "read_default_file" in args: + args["read_default_file"] = expanduser(args["read_default_file"]) if "autoping" not in args: args["autoping"] = True From e67833a39f83ec42da6537f0906ed07a50dc8747 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 25 Aug 2013 05:55:10 -0400 Subject: [PATCH 033/207] Mod thread.ident by 10,000 for when they're absurdly large. --- earwigbot/commands/threads.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/earwigbot/commands/threads.py b/earwigbot/commands/threads.py index 9ac8b09..564ab7e 100644 --- a/earwigbot/commands/threads.py +++ b/earwigbot/commands/threads.py @@ -71,10 +71,10 @@ class Threads(Command): tname = thread.name if tname == "MainThread": t = "\x0302MainThread\x0F (id {0})" - normal_threads.append(t.format(thread.ident)) + normal_threads.append(t.format(thread.ident % 10000)) elif tname in self.config.components: t = "\x0302{0}\x0F (id {1})" - normal_threads.append(t.format(tname, thread.ident)) + normal_threads.append(t.format(tname, thread.ident % 10000)) elif tname.startswith("reminder"): tname = tname.replace("reminder ", "") t = "\x0302reminder\x0F (until {0})" @@ -82,7 +82,7 @@ class Threads(Command): else: tname, start_time = re.findall("^(.*?) \((.*?)\)$", tname)[0] t = "\x0302{0}\x0F (id {1}, since {2})" - daemon_threads.append(t.format(tname, thread.ident, + daemon_threads.append(t.format(tname, thread.ident % 10000, start_time)) if daemon_threads: From 71befb120900f52c63906655b45ab2be40cb7aba Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 25 Aug 2013 19:55:24 -0400 Subject: [PATCH 034/207] Schedule jobs more reasonably. --- earwigbot/bot.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/earwigbot/bot.py b/earwigbot/bot.py index 9d95645..952657c 100644 --- a/earwigbot/bot.py +++ b/earwigbot/bot.py @@ -22,7 +22,7 @@ import logging from threading import Lock, Thread, enumerate as enumerate_threads -from time import sleep, time +from time import gmtime, sleep from earwigbot import __version__ from earwigbot.config import BotConfig @@ -101,13 +101,10 @@ class Bot(object): def _start_wiki_scheduler(self): """Start the wiki scheduler in a separate thread if enabled.""" def wiki_scheduler(): + run_at = 15 while self._keep_looping: - time_start = time() self.tasks.schedule() - time_end = time() - time_diff = time_start - time_end - if time_diff < 60: # Sleep until the next minute - sleep(60 - time_diff) + sleep(60 + run_at - gmtime().tm_sec) if self.config.components.get("wiki_scheduler"): self.logger.info("Starting wiki scheduler") From b88181bb24ffb93931612c7ac702a7df5320d456 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 25 Aug 2013 22:17:45 -0400 Subject: [PATCH 035/207] Make exclusion check a bit smarter. --- earwigbot/wiki/copyvios/exclusions.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index dbbe0c9..7b36d2a 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -161,16 +161,15 @@ class ExclusionsDB(object): Return ``True`` if the URL is in the database, or ``False`` otherwise. """ - normalized = re.sub("https?://", "", url.lower()) + normalized = re.sub(r"https?://(www\.)?", "", url.lower()) query = """SELECT exclusion_url FROM exclusions WHERE exclusion_sitename = ? OR exclusion_sitename = ?""" with sqlite.connect(self._dbfile) as conn, self._db_access_lock: for (excl,) in conn.execute(query, (sitename, "all")): if excl.startswith("*."): - netloc = urlparse(url.lower()).netloc - matches = True if excl[2:] in netloc else False + matches = excl[2:] in urlparse(url.lower()).netloc else: - matches = True if normalized.startswith(excl) else False + matches = normalized.startswith(excl) if matches: log = u"Exclusion detected in {0} for {1}" self._logger.debug(log.format(sitename, url)) From a926431754c1c3194d28d2a2afbfd30fdfb87ff2 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 1 Sep 2013 01:40:59 -0400 Subject: [PATCH 036/207] Better client-side buffering of SQL results. --- earwigbot/wiki/category.py | 4 ++-- earwigbot/wiki/site.py | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/earwigbot/wiki/category.py b/earwigbot/wiki/category.py index b8561a3..5422528 100644 --- a/earwigbot/wiki/category.py +++ b/earwigbot/wiki/category.py @@ -87,9 +87,9 @@ class Category(Page): if limit: query += " LIMIT ?" - result = self.site.sql_query(query, (title, limit)) + result = self.site.sql_query(query, (title, limit), buffsize=0) else: - result = self.site.sql_query(query, (title,)) + result = self.site.sql_query(query, (title,), buffsize=0) members = list(result) for row in members: diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index dd06ea6..e94b4c7 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -517,15 +517,12 @@ class Site(object): args = self._sql_data for key, value in kwargs.iteritems(): args[key] = value - if "read_default_file" not in args and "user" not in args and "passwd" not in args: args["read_default_file"] = expanduser("~/.my.cnf") elif "read_default_file" in args: args["read_default_file"] = expanduser(args["read_default_file"]) - if "autoping" not in args: args["autoping"] = True - if "autoreconnect" not in args: args["autoreconnect"] = True @@ -647,7 +644,7 @@ class Site(object): return self._api_query(kwargs) def sql_query(self, query, params=(), plain_query=False, dict_cursor=False, - cursor_class=None, show_table=False): + cursor_class=None, show_table=False, buffsize=1024): """Do an SQL query and yield its results. If *plain_query* is ``True``, we will force an unparameterized query. @@ -658,6 +655,13 @@ class Site(object): is True, the name of the table will be prepended to the name of the column. This will mainly affect an :py:class:`~oursql.DictCursor`. + *buffsize* is the size of each memory-buffered group of results, to + reduce the number of conversations with the database; it is passed to + :py:meth:`cursor.fetchmany() `. If set to + ``0```, all results will be buffered in memory at once (this uses + :py:meth:`fetchall() `). If set to ``1``, it is + equivalent to using :py:meth:`fetchone() `. + Example usage:: >>> query = "SELECT user_id, user_registration FROM user WHERE user_name = ?" @@ -690,7 +694,14 @@ class Site(object): self._sql_connect() with self._sql_conn.cursor(klass, show_table=show_table) as cur: cur.execute(query, params, plain_query) - for result in cur: + if buffsize: + while True: + group = cur.fetchmany(buffsize) + if not group: + return + for result in group: + yield result + for result in cur.fetchall(): yield result def get_maxlag(self, showall=False): @@ -828,7 +839,7 @@ class Site(object): (:py:attr:`self.SERVICE_API ` or :py:attr:`self.SERVICE_SQL `), and the value is the function to call for this service. All functions will be passed the - same arguments the tuple *args* and the dict **kwargs**, which are both + same arguments the tuple *args* and the dict *kwargs*, which are both empty by default. The service order is determined by :py:meth:`_get_service_order`. From 346e7a55482dfe63e4fea7a4865c7d5354910aba Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Sun, 29 Sep 2013 18:46:56 -0700 Subject: [PATCH 037/207] Add !epoch --- earwigbot/commands/time_command.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index 3754986..4ca91bd 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -32,12 +32,15 @@ pytz = importer.new("pytz") class Time(Command): """Report the current time in any timezone (UTC default), or in beats.""" name = "time" - commands = ["time", "beats", "swatch"] + commands = ["time", "beats", "swatch", "epoch"] def process(self, data): if data.command in ["beats", "swatch"]: self.do_beats(data) return + if data.command == "epoch": + self.reply(data, time()) + return if data.args: timezone = data.args[0] else: From 7e1882a24adaf46a45b6301fd1b4923d5fe8021c Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 30 Sep 2013 22:06:47 -0400 Subject: [PATCH 038/207] Update !help for !time. --- earwigbot/commands/time_command.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index 4ca91bd..e52087c 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -30,7 +30,8 @@ from earwigbot.commands import Command pytz = importer.new("pytz") class Time(Command): - """Report the current time in any timezone (UTC default), or in beats.""" + """Report the current time in any timezone (UTC default), UNIX epoch time, + or beat time.""" name = "time" commands = ["time", "beats", "swatch", "epoch"] From a3eee798f9b84ba5beab2d3978e9727a7f96d601 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 13 Oct 2013 01:49:04 -0400 Subject: [PATCH 039/207] Implement Category.__iter__() --- earwigbot/wiki/category.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/earwigbot/wiki/category.py b/earwigbot/wiki/category.py index 5422528..6707c43 100644 --- a/earwigbot/wiki/category.py +++ b/earwigbot/wiki/category.py @@ -58,6 +58,10 @@ class Category(Page): """Return a nice string representation of the Category.""" return ''.format(self.title, str(self.site)) + def __iter__(self): + """Iterate over all members of the category.""" + return self.get_members() + def _get_members_via_api(self, limit, follow): """Iterate over Pages in the category using the API.""" params = {"action": "query", "list": "categorymembers", From ed95c99f0e8453d78516445f6d29caf6726637e8 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 21 Oct 2013 20:56:05 -0400 Subject: [PATCH 040/207] Update email address. --- LICENSE | 2 +- README.rst | 2 +- docs/tips.rst | 2 +- earwigbot/__init__.py | 4 ++-- earwigbot/bot.py | 2 +- earwigbot/commands/__init__.py | 2 +- earwigbot/commands/access.py | 2 +- earwigbot/commands/calc.py | 2 +- earwigbot/commands/chanops.py | 2 +- earwigbot/commands/crypt.py | 2 +- earwigbot/commands/ctcp.py | 2 +- earwigbot/commands/dictionary.py | 2 +- earwigbot/commands/editcount.py | 2 +- earwigbot/commands/help.py | 2 +- earwigbot/commands/lag.py | 2 +- earwigbot/commands/langcode.py | 2 +- earwigbot/commands/link.py | 2 +- earwigbot/commands/notes.py | 2 +- earwigbot/commands/quit.py | 2 +- earwigbot/commands/registration.py | 2 +- earwigbot/commands/remind.py | 2 +- earwigbot/commands/rights.py | 2 +- earwigbot/commands/test.py | 2 +- earwigbot/commands/threads.py | 2 +- earwigbot/commands/time_command.py | 2 +- earwigbot/commands/trout.py | 2 +- earwigbot/config/__init__.py | 2 +- earwigbot/config/formatter.py | 2 +- earwigbot/config/node.py | 2 +- earwigbot/config/ordered_yaml.py | 2 +- earwigbot/config/permissions.py | 2 +- earwigbot/config/script.py | 2 +- earwigbot/exceptions.py | 2 +- earwigbot/irc/__init__.py | 2 +- earwigbot/irc/connection.py | 2 +- earwigbot/irc/data.py | 2 +- earwigbot/irc/frontend.py | 2 +- earwigbot/irc/rc.py | 2 +- earwigbot/irc/watcher.py | 2 +- earwigbot/lazy.py | 2 +- earwigbot/managers.py | 2 +- earwigbot/tasks/__init__.py | 2 +- earwigbot/tasks/wikiproject_tagger.py | 2 +- earwigbot/util.py | 2 +- earwigbot/wiki/__init__.py | 2 +- earwigbot/wiki/category.py | 2 +- earwigbot/wiki/constants.py | 2 +- earwigbot/wiki/copyvios/__init__.py | 2 +- earwigbot/wiki/copyvios/exclusions.py | 2 +- earwigbot/wiki/copyvios/markov.py | 2 +- earwigbot/wiki/copyvios/parsers.py | 2 +- earwigbot/wiki/copyvios/result.py | 2 +- earwigbot/wiki/copyvios/search.py | 2 +- earwigbot/wiki/page.py | 2 +- earwigbot/wiki/site.py | 2 +- earwigbot/wiki/sitesdb.py | 2 +- earwigbot/wiki/user.py | 2 +- setup.py | 4 ++-- tests/__init__.py | 2 +- tests/test_calc.py | 2 +- tests/test_test.py | 2 +- 61 files changed, 63 insertions(+), 63 deletions(-) diff --git a/LICENSE b/LICENSE index c34d909..66dfee1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2009-2013 Ben Kurtovic +Copyright (C) 2009-2013 Ben Kurtovic Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.rst b/README.rst index 4a9e3b0..9dd40f5 100644 --- a/README.rst +++ b/README.rst @@ -202,4 +202,4 @@ Footnotes .. _wikiproject_tagger: https://github.com/earwig/earwigbot/blob/develop/earwigbot/tasks/wikiproject_tagger.py .. _afc_statistics: https://github.com/earwig/earwigbot-plugins/blob/develop/tasks/afc_statistics.py .. _its code and docstrings: https://github.com/earwig/earwigbot/tree/develop/earwigbot/wiki -.. _Let me know: ben.kurtovic@verizon.net +.. _Let me know: ben.kurtovic@gmail.com diff --git a/docs/tips.rst b/docs/tips.rst index 4f4052e..00a648f 100644 --- a/docs/tips.rst +++ b/docs/tips.rst @@ -42,5 +42,5 @@ Tips .. _logging: http://docs.python.org/library/logging.html .. _!git plugin: https://github.com/earwig/earwigbot-plugins/blob/develop/commands/git.py -.. _Let me know: ben.kurtovic@verizon.net +.. _Let me know: ben.kurtovic@gmail.com .. _create an issue: https://github.com/earwig/earwigbot/issues diff --git a/earwigbot/__init__.py b/earwigbot/__init__.py index 15dfc94..9bace8d 100644 --- a/earwigbot/__init__.py +++ b/earwigbot/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -33,7 +33,7 @@ __author__ = "Ben Kurtovic" __copyright__ = "Copyright (C) 2009, 2010, 2011, 2012, 2013 Ben Kurtovic" __license__ = "MIT License" __version__ = "0.2.dev" -__email__ = "ben.kurtovic@verizon.net" +__email__ = "ben.kurtovic@gmail.com" __release__ = False if not __release__: diff --git a/earwigbot/bot.py b/earwigbot/bot.py index 952657c..966ed41 100644 --- a/earwigbot/bot.py +++ b/earwigbot/bot.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/__init__.py b/earwigbot/commands/__init__.py index 3ebca25..3f4de91 100644 --- a/earwigbot/commands/__init__.py +++ b/earwigbot/commands/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/access.py b/earwigbot/commands/access.py index b4671ca..6d0ea7d 100644 --- a/earwigbot/commands/access.py +++ b/earwigbot/commands/access.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/calc.py b/earwigbot/commands/calc.py index 1c7d532..720b437 100644 --- a/earwigbot/commands/calc.py +++ b/earwigbot/commands/calc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/chanops.py b/earwigbot/commands/chanops.py index ac2e300..5f9a12e 100644 --- a/earwigbot/commands/chanops.py +++ b/earwigbot/commands/chanops.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/crypt.py b/earwigbot/commands/crypt.py index bd6222d..6dcb07b 100644 --- a/earwigbot/commands/crypt.py +++ b/earwigbot/commands/crypt.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/ctcp.py b/earwigbot/commands/ctcp.py index a3ef267..1b78f03 100644 --- a/earwigbot/commands/ctcp.py +++ b/earwigbot/commands/ctcp.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/dictionary.py b/earwigbot/commands/dictionary.py index 4a1715b..d2c9626 100644 --- a/earwigbot/commands/dictionary.py +++ b/earwigbot/commands/dictionary.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/editcount.py b/earwigbot/commands/editcount.py index be902cc..e199944 100644 --- a/earwigbot/commands/editcount.py +++ b/earwigbot/commands/editcount.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/help.py b/earwigbot/commands/help.py index 6de7a3b..cdf7e24 100644 --- a/earwigbot/commands/help.py +++ b/earwigbot/commands/help.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/lag.py b/earwigbot/commands/lag.py index cefafcc..fe76f39 100644 --- a/earwigbot/commands/lag.py +++ b/earwigbot/commands/lag.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/langcode.py b/earwigbot/commands/langcode.py index a6534c3..e12d6fe 100644 --- a/earwigbot/commands/langcode.py +++ b/earwigbot/commands/langcode.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/link.py b/earwigbot/commands/link.py index 1f4c9a4..927fcf8 100644 --- a/earwigbot/commands/link.py +++ b/earwigbot/commands/link.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/notes.py b/earwigbot/commands/notes.py index d275561..584389a 100644 --- a/earwigbot/commands/notes.py +++ b/earwigbot/commands/notes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/quit.py b/earwigbot/commands/quit.py index d5954b3..6dee210 100644 --- a/earwigbot/commands/quit.py +++ b/earwigbot/commands/quit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/registration.py b/earwigbot/commands/registration.py index f45501c..d56bc98 100644 --- a/earwigbot/commands/registration.py +++ b/earwigbot/commands/registration.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/remind.py b/earwigbot/commands/remind.py index 6018c16..756991a 100644 --- a/earwigbot/commands/remind.py +++ b/earwigbot/commands/remind.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/rights.py b/earwigbot/commands/rights.py index 749ee3c..4193b32 100644 --- a/earwigbot/commands/rights.py +++ b/earwigbot/commands/rights.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/test.py b/earwigbot/commands/test.py index 32224ff..e823386 100644 --- a/earwigbot/commands/test.py +++ b/earwigbot/commands/test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/threads.py b/earwigbot/commands/threads.py index 564ab7e..255ce63 100644 --- a/earwigbot/commands/threads.py +++ b/earwigbot/commands/threads.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index e52087c..8b1864c 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/trout.py b/earwigbot/commands/trout.py index b8ea465..d32ffae 100644 --- a/earwigbot/commands/trout.py +++ b/earwigbot/commands/trout.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/__init__.py b/earwigbot/config/__init__.py index 9a91583..9b3d147 100644 --- a/earwigbot/config/__init__.py +++ b/earwigbot/config/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/formatter.py b/earwigbot/config/formatter.py index cb74c0c..ec822fe 100644 --- a/earwigbot/config/formatter.py +++ b/earwigbot/config/formatter.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/node.py b/earwigbot/config/node.py index d3be3e5..de2c6fa 100644 --- a/earwigbot/config/node.py +++ b/earwigbot/config/node.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/ordered_yaml.py b/earwigbot/config/ordered_yaml.py index 0fc1df6..6d08af4 100644 --- a/earwigbot/config/ordered_yaml.py +++ b/earwigbot/config/ordered_yaml.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/permissions.py b/earwigbot/config/permissions.py index d3acb88..0b97eba 100644 --- a/earwigbot/config/permissions.py +++ b/earwigbot/config/permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/script.py b/earwigbot/config/script.py index afdb41a..6f3e9cb 100644 --- a/earwigbot/config/script.py +++ b/earwigbot/config/script.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/exceptions.py b/earwigbot/exceptions.py index 546a9f9..27f926e 100644 --- a/earwigbot/exceptions.py +++ b/earwigbot/exceptions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/__init__.py b/earwigbot/irc/__init__.py index 3fe86e9..f3f799c 100644 --- a/earwigbot/irc/__init__.py +++ b/earwigbot/irc/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/connection.py b/earwigbot/irc/connection.py index 943823d..f68028e 100644 --- a/earwigbot/irc/connection.py +++ b/earwigbot/irc/connection.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/data.py b/earwigbot/irc/data.py index 6ff3213..d41da94 100644 --- a/earwigbot/irc/data.py +++ b/earwigbot/irc/data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/frontend.py b/earwigbot/irc/frontend.py index ce63a6e..2c71fca 100644 --- a/earwigbot/irc/frontend.py +++ b/earwigbot/irc/frontend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/rc.py b/earwigbot/irc/rc.py index 1c526b0..7dc17b0 100644 --- a/earwigbot/irc/rc.py +++ b/earwigbot/irc/rc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/watcher.py b/earwigbot/irc/watcher.py index 469914f..7745f2f 100644 --- a/earwigbot/irc/watcher.py +++ b/earwigbot/irc/watcher.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/lazy.py b/earwigbot/lazy.py index 5526478..350462e 100644 --- a/earwigbot/lazy.py +++ b/earwigbot/lazy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/managers.py b/earwigbot/managers.py index d72df54..08a809d 100644 --- a/earwigbot/managers.py +++ b/earwigbot/managers.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/tasks/__init__.py b/earwigbot/tasks/__init__.py index d3590a4..8d04c2e 100644 --- a/earwigbot/tasks/__init__.py +++ b/earwigbot/tasks/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/tasks/wikiproject_tagger.py b/earwigbot/tasks/wikiproject_tagger.py index eecbff7..5ae3018 100644 --- a/earwigbot/tasks/wikiproject_tagger.py +++ b/earwigbot/tasks/wikiproject_tagger.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/util.py b/earwigbot/util.py index 41f9eb6..c7bfdba 100755 --- a/earwigbot/util.py +++ b/earwigbot/util.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/__init__.py b/earwigbot/wiki/__init__.py index 7e1d0be..5977e4d 100644 --- a/earwigbot/wiki/__init__.py +++ b/earwigbot/wiki/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/category.py b/earwigbot/wiki/category.py index 6707c43..d889bed 100644 --- a/earwigbot/wiki/category.py +++ b/earwigbot/wiki/category.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/constants.py b/earwigbot/wiki/constants.py index 39f1400..70db213 100644 --- a/earwigbot/wiki/constants.py +++ b/earwigbot/wiki/constants.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 8b906f9..89532f8 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 7b36d2a..c8d5e4c 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/markov.py b/earwigbot/wiki/copyvios/markov.py index a785b6c..c5e881d 100644 --- a/earwigbot/wiki/copyvios/markov.py +++ b/earwigbot/wiki/copyvios/markov.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/parsers.py b/earwigbot/wiki/copyvios/parsers.py index 30f0c7f..bfd3ebc 100644 --- a/earwigbot/wiki/copyvios/parsers.py +++ b/earwigbot/wiki/copyvios/parsers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/result.py b/earwigbot/wiki/copyvios/result.py index 94b2775..70d30fc 100644 --- a/earwigbot/wiki/copyvios/result.py +++ b/earwigbot/wiki/copyvios/result.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/search.py b/earwigbot/wiki/copyvios/search.py index 1f2ac8c..1d0f01d 100644 --- a/earwigbot/wiki/copyvios/search.py +++ b/earwigbot/wiki/copyvios/search.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index ffcde15..45f629f 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index e94b4c7..ad0d660 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/sitesdb.py b/earwigbot/wiki/sitesdb.py index 75cca0f..07cac02 100644 --- a/earwigbot/wiki/sitesdb.py +++ b/earwigbot/wiki/sitesdb.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/user.py b/earwigbot/wiki/user.py index 91bb523..53fc5a7 100644 --- a/earwigbot/wiki/user.py +++ b/earwigbot/wiki/user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/setup.py b/setup.py index 8e0931c..7ba2375 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -62,7 +62,7 @@ setup( test_suite = "tests", version = __version__, author = "Ben Kurtovic", - author_email = "ben.kurtovic@verizon.net", + author_email = "ben.kurtovic@gmail.com", url = "https://github.com/earwig/earwigbot", description = "EarwigBot is a Python robot that edits Wikipedia and interacts with people over IRC.", long_description = long_docs, diff --git a/tests/__init__.py b/tests/__init__.py index 6ab010f..81fcc93 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/test_calc.py b/tests/test_calc.py index b2ce1f7..fb4cc04 100644 --- a/tests/test_calc.py +++ b/tests/test_calc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/test_test.py b/tests/test_test.py index 9e5d054..e93e159 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2013 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From 39d5c7c149465c066448119f16ef826d0ff1591a Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 3 Jan 2014 20:22:23 -0500 Subject: [PATCH 041/207] Update copyright notices for 2014. --- LICENSE | 2 +- docs/conf.py | 2 +- earwigbot/__init__.py | 4 ++-- earwigbot/bot.py | 2 +- earwigbot/commands/__init__.py | 2 +- earwigbot/commands/access.py | 2 +- earwigbot/commands/calc.py | 2 +- earwigbot/commands/chanops.py | 2 +- earwigbot/commands/crypt.py | 2 +- earwigbot/commands/ctcp.py | 2 +- earwigbot/commands/dictionary.py | 2 +- earwigbot/commands/editcount.py | 2 +- earwigbot/commands/help.py | 2 +- earwigbot/commands/lag.py | 2 +- earwigbot/commands/langcode.py | 2 +- earwigbot/commands/link.py | 2 +- earwigbot/commands/notes.py | 2 +- earwigbot/commands/quit.py | 2 +- earwigbot/commands/registration.py | 2 +- earwigbot/commands/remind.py | 2 +- earwigbot/commands/rights.py | 2 +- earwigbot/commands/test.py | 2 +- earwigbot/commands/threads.py | 2 +- earwigbot/commands/time_command.py | 2 +- earwigbot/commands/trout.py | 2 +- earwigbot/config/__init__.py | 2 +- earwigbot/config/formatter.py | 2 +- earwigbot/config/node.py | 2 +- earwigbot/config/ordered_yaml.py | 2 +- earwigbot/config/permissions.py | 2 +- earwigbot/config/script.py | 2 +- earwigbot/exceptions.py | 2 +- earwigbot/irc/__init__.py | 2 +- earwigbot/irc/connection.py | 2 +- earwigbot/irc/data.py | 2 +- earwigbot/irc/frontend.py | 2 +- earwigbot/irc/rc.py | 2 +- earwigbot/irc/watcher.py | 2 +- earwigbot/lazy.py | 2 +- earwigbot/managers.py | 2 +- earwigbot/tasks/__init__.py | 2 +- earwigbot/tasks/wikiproject_tagger.py | 2 +- earwigbot/util.py | 2 +- earwigbot/wiki/__init__.py | 2 +- earwigbot/wiki/category.py | 2 +- earwigbot/wiki/constants.py | 2 +- earwigbot/wiki/copyvios/__init__.py | 2 +- earwigbot/wiki/copyvios/exclusions.py | 2 +- earwigbot/wiki/copyvios/markov.py | 2 +- earwigbot/wiki/copyvios/parsers.py | 2 +- earwigbot/wiki/copyvios/result.py | 2 +- earwigbot/wiki/copyvios/search.py | 2 +- earwigbot/wiki/page.py | 2 +- earwigbot/wiki/site.py | 2 +- earwigbot/wiki/sitesdb.py | 2 +- earwigbot/wiki/user.py | 2 +- setup.py | 2 +- tests/__init__.py | 2 +- tests/test_calc.py | 2 +- tests/test_test.py | 2 +- 60 files changed, 61 insertions(+), 61 deletions(-) diff --git a/LICENSE b/LICENSE index 66dfee1..614a82e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2009-2013 Ben Kurtovic +Copyright (C) 2009-2014 Ben Kurtovic Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/conf.py b/docs/conf.py index 1a13c78..af988c1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,7 +41,7 @@ master_doc = 'index' # General information about the project. project = u'EarwigBot' -copyright = u'2009, 2010, 2011, 2012, 2013 Ben Kurtovic' +copyright = u'2009, 2010, 2011, 2012, 2013, 2014 Ben Kurtovic' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/earwigbot/__init__.py b/earwigbot/__init__.py index 9bace8d..2b0f8c6 100644 --- a/earwigbot/__init__.py +++ b/earwigbot/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ details. This documentation is also available `online """ __author__ = "Ben Kurtovic" -__copyright__ = "Copyright (C) 2009, 2010, 2011, 2012, 2013 Ben Kurtovic" +__copyright__ = "Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Ben Kurtovic" __license__ = "MIT License" __version__ = "0.2.dev" __email__ = "ben.kurtovic@gmail.com" diff --git a/earwigbot/bot.py b/earwigbot/bot.py index 966ed41..a1d421f 100644 --- a/earwigbot/bot.py +++ b/earwigbot/bot.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/__init__.py b/earwigbot/commands/__init__.py index 3f4de91..47feb7f 100644 --- a/earwigbot/commands/__init__.py +++ b/earwigbot/commands/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/access.py b/earwigbot/commands/access.py index 6d0ea7d..078f782 100644 --- a/earwigbot/commands/access.py +++ b/earwigbot/commands/access.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/calc.py b/earwigbot/commands/calc.py index 720b437..772a6cf 100644 --- a/earwigbot/commands/calc.py +++ b/earwigbot/commands/calc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/chanops.py b/earwigbot/commands/chanops.py index 5f9a12e..2ceb7e3 100644 --- a/earwigbot/commands/chanops.py +++ b/earwigbot/commands/chanops.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/crypt.py b/earwigbot/commands/crypt.py index 6dcb07b..005206a 100644 --- a/earwigbot/commands/crypt.py +++ b/earwigbot/commands/crypt.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/ctcp.py b/earwigbot/commands/ctcp.py index 1b78f03..ac6caf8 100644 --- a/earwigbot/commands/ctcp.py +++ b/earwigbot/commands/ctcp.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/dictionary.py b/earwigbot/commands/dictionary.py index d2c9626..6223461 100644 --- a/earwigbot/commands/dictionary.py +++ b/earwigbot/commands/dictionary.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/editcount.py b/earwigbot/commands/editcount.py index e199944..529232a 100644 --- a/earwigbot/commands/editcount.py +++ b/earwigbot/commands/editcount.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/help.py b/earwigbot/commands/help.py index cdf7e24..24b07b3 100644 --- a/earwigbot/commands/help.py +++ b/earwigbot/commands/help.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/lag.py b/earwigbot/commands/lag.py index fe76f39..c180727 100644 --- a/earwigbot/commands/lag.py +++ b/earwigbot/commands/lag.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/langcode.py b/earwigbot/commands/langcode.py index e12d6fe..69406b1 100644 --- a/earwigbot/commands/langcode.py +++ b/earwigbot/commands/langcode.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/link.py b/earwigbot/commands/link.py index 927fcf8..9165a43 100644 --- a/earwigbot/commands/link.py +++ b/earwigbot/commands/link.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/notes.py b/earwigbot/commands/notes.py index 584389a..9850000 100644 --- a/earwigbot/commands/notes.py +++ b/earwigbot/commands/notes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/quit.py b/earwigbot/commands/quit.py index 6dee210..5ec480f 100644 --- a/earwigbot/commands/quit.py +++ b/earwigbot/commands/quit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/registration.py b/earwigbot/commands/registration.py index d56bc98..5d6748c 100644 --- a/earwigbot/commands/registration.py +++ b/earwigbot/commands/registration.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/remind.py b/earwigbot/commands/remind.py index 756991a..bb0c873 100644 --- a/earwigbot/commands/remind.py +++ b/earwigbot/commands/remind.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/rights.py b/earwigbot/commands/rights.py index 4193b32..532e3c6 100644 --- a/earwigbot/commands/rights.py +++ b/earwigbot/commands/rights.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/test.py b/earwigbot/commands/test.py index e823386..4b02a6c 100644 --- a/earwigbot/commands/test.py +++ b/earwigbot/commands/test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/threads.py b/earwigbot/commands/threads.py index 255ce63..b384be4 100644 --- a/earwigbot/commands/threads.py +++ b/earwigbot/commands/threads.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/time_command.py b/earwigbot/commands/time_command.py index 8b1864c..6316de6 100644 --- a/earwigbot/commands/time_command.py +++ b/earwigbot/commands/time_command.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/commands/trout.py b/earwigbot/commands/trout.py index d32ffae..28e3fe8 100644 --- a/earwigbot/commands/trout.py +++ b/earwigbot/commands/trout.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/__init__.py b/earwigbot/config/__init__.py index 9b3d147..d076de5 100644 --- a/earwigbot/config/__init__.py +++ b/earwigbot/config/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/formatter.py b/earwigbot/config/formatter.py index ec822fe..5d599f1 100644 --- a/earwigbot/config/formatter.py +++ b/earwigbot/config/formatter.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/node.py b/earwigbot/config/node.py index de2c6fa..b1c3cc5 100644 --- a/earwigbot/config/node.py +++ b/earwigbot/config/node.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/ordered_yaml.py b/earwigbot/config/ordered_yaml.py index 6d08af4..c0ffd8e 100644 --- a/earwigbot/config/ordered_yaml.py +++ b/earwigbot/config/ordered_yaml.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/permissions.py b/earwigbot/config/permissions.py index 0b97eba..54e36f1 100644 --- a/earwigbot/config/permissions.py +++ b/earwigbot/config/permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/config/script.py b/earwigbot/config/script.py index 6f3e9cb..96b62fe 100644 --- a/earwigbot/config/script.py +++ b/earwigbot/config/script.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/exceptions.py b/earwigbot/exceptions.py index 27f926e..3016f74 100644 --- a/earwigbot/exceptions.py +++ b/earwigbot/exceptions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/__init__.py b/earwigbot/irc/__init__.py index f3f799c..400248b 100644 --- a/earwigbot/irc/__init__.py +++ b/earwigbot/irc/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/connection.py b/earwigbot/irc/connection.py index f68028e..bdf08ea 100644 --- a/earwigbot/irc/connection.py +++ b/earwigbot/irc/connection.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/data.py b/earwigbot/irc/data.py index d41da94..5813410 100644 --- a/earwigbot/irc/data.py +++ b/earwigbot/irc/data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/frontend.py b/earwigbot/irc/frontend.py index 2c71fca..3955184 100644 --- a/earwigbot/irc/frontend.py +++ b/earwigbot/irc/frontend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/rc.py b/earwigbot/irc/rc.py index 7dc17b0..98e5798 100644 --- a/earwigbot/irc/rc.py +++ b/earwigbot/irc/rc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/irc/watcher.py b/earwigbot/irc/watcher.py index 7745f2f..b00265f 100644 --- a/earwigbot/irc/watcher.py +++ b/earwigbot/irc/watcher.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/lazy.py b/earwigbot/lazy.py index 350462e..c58f8c0 100644 --- a/earwigbot/lazy.py +++ b/earwigbot/lazy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/managers.py b/earwigbot/managers.py index 08a809d..db01aa9 100644 --- a/earwigbot/managers.py +++ b/earwigbot/managers.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/tasks/__init__.py b/earwigbot/tasks/__init__.py index 8d04c2e..cffc1a4 100644 --- a/earwigbot/tasks/__init__.py +++ b/earwigbot/tasks/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/tasks/wikiproject_tagger.py b/earwigbot/tasks/wikiproject_tagger.py index 5ae3018..59429ff 100644 --- a/earwigbot/tasks/wikiproject_tagger.py +++ b/earwigbot/tasks/wikiproject_tagger.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/util.py b/earwigbot/util.py index c7bfdba..9657e7e 100755 --- a/earwigbot/util.py +++ b/earwigbot/util.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/__init__.py b/earwigbot/wiki/__init__.py index 5977e4d..df814c5 100644 --- a/earwigbot/wiki/__init__.py +++ b/earwigbot/wiki/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/category.py b/earwigbot/wiki/category.py index d889bed..aa4edcd 100644 --- a/earwigbot/wiki/category.py +++ b/earwigbot/wiki/category.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/constants.py b/earwigbot/wiki/constants.py index 70db213..8e56d9f 100644 --- a/earwigbot/wiki/constants.py +++ b/earwigbot/wiki/constants.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/__init__.py b/earwigbot/wiki/copyvios/__init__.py index 89532f8..55b9f91 100644 --- a/earwigbot/wiki/copyvios/__init__.py +++ b/earwigbot/wiki/copyvios/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index c8d5e4c..b6ff56c 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/markov.py b/earwigbot/wiki/copyvios/markov.py index c5e881d..065d6f1 100644 --- a/earwigbot/wiki/copyvios/markov.py +++ b/earwigbot/wiki/copyvios/markov.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/parsers.py b/earwigbot/wiki/copyvios/parsers.py index bfd3ebc..29a49f5 100644 --- a/earwigbot/wiki/copyvios/parsers.py +++ b/earwigbot/wiki/copyvios/parsers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/result.py b/earwigbot/wiki/copyvios/result.py index 70d30fc..521c810 100644 --- a/earwigbot/wiki/copyvios/result.py +++ b/earwigbot/wiki/copyvios/result.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/copyvios/search.py b/earwigbot/wiki/copyvios/search.py index 1d0f01d..2a875cc 100644 --- a/earwigbot/wiki/copyvios/search.py +++ b/earwigbot/wiki/copyvios/search.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index 45f629f..af047dd 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index ad0d660..31f5f39 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/sitesdb.py b/earwigbot/wiki/sitesdb.py index 07cac02..e773c75 100644 --- a/earwigbot/wiki/sitesdb.py +++ b/earwigbot/wiki/sitesdb.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/earwigbot/wiki/user.py b/earwigbot/wiki/user.py index 53fc5a7..96c9dc0 100644 --- a/earwigbot/wiki/user.py +++ b/earwigbot/wiki/user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/setup.py b/setup.py index 7ba2375..c6c73dd 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/__init__.py b/tests/__init__.py index 81fcc93..dc1585f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/test_calc.py b/tests/test_calc.py index fb4cc04..fa5b0ed 100644 --- a/tests/test_calc.py +++ b/tests/test_calc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/tests/test_test.py b/tests/test_test.py index e93e159..3ceea58 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009-2013 Ben Kurtovic +# Copyright (C) 2009-2014 Ben Kurtovic # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From 08af8828417fde12c5fe22db05edb9c5b4a3c43b Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 7 Jan 2014 03:21:55 -0500 Subject: [PATCH 042/207] Update AssertEdit behavior now that it's been merged into MW core. Note: don't deploy until January 14. --- earwigbot/exceptions.py | 27 ++++++++-------- earwigbot/wiki/page.py | 86 ++++--------------------------------------------- earwigbot/wiki/site.py | 34 ++++++++++++++----- 3 files changed, 47 insertions(+), 100 deletions(-) diff --git a/earwigbot/exceptions.py b/earwigbot/exceptions.py index 3016f74..e92935e 100644 --- a/earwigbot/exceptions.py +++ b/earwigbot/exceptions.py @@ -36,13 +36,13 @@ This module contains all exceptions used by EarwigBot:: | +-- SQLError +-- NoServiceError +-- LoginError + +-- PermissionsError +-- NamespaceNotFoundError +-- PageNotFoundError +-- InvalidPageError +-- RedirectError +-- UserNotFoundError +-- EditError - | +-- PermissionsError | +-- EditConflictError | +-- NoContentError | +-- ContentTooBigError @@ -120,6 +120,19 @@ class LoginError(WikiToolsetError): Raised by :py:meth:`Site._login `. """ +class PermissionsError(WikiToolsetError): + """A permissions error ocurred. + + 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. This will also be raised if we have been blocked + from editing. + + Raised by :py:meth:`Page.edit `, + :py:meth:`Page.add_section `, and + other API methods depending on settings. + """ + class NamespaceNotFoundError(WikiToolsetError): """A requested namespace name or namespace ID does not exist. @@ -164,18 +177,6 @@ class EditError(WikiToolsetError): :py:meth:`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. This will also be raised if we have been blocked - from editing. - - Raised by :py:meth:`Page.edit ` and - :py:meth:`Page.add_section `. - """ - class EditConflictError(EditError): """We gotten an edit conflict or a (rarer) delete/recreate conflict. diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index af047dd..eacb221 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -308,6 +308,7 @@ class Page(CopyvioMixIn): section, captcha_id, captcha_word) else: # Make sure we have the right token: params["token"] = self._token + self._token = None # Token now invalid # Try the API query, catching most errors with our handler: try: @@ -324,13 +325,8 @@ class Page(CopyvioMixIn): self._exists = self.PAGE_UNKNOWN return - # If we're here, then the edit failed. If it's because of AssertEdit, - # handle that. Otherwise, die - something odd is going on: - try: - assertion = result["edit"]["assert"] - except KeyError: - raise exceptions.EditError(result["edit"]) - self._handle_assert_edit(assertion, params, tries) + # Otherwise, there was some kind of problem. Throw an exception: + raise exceptions.EditError(result["edit"]) def _build_edit_params(self, text, summary, minor, bot, force, section, captcha_id, captcha_word): @@ -371,95 +367,27 @@ class Page(CopyvioMixIn): is protected), or we'll try to fix it (for example, if we can't edit due to being logged out, we'll try to log in). """ - if error.code in ["noedit", "cantcreate", "protectedtitle", - "noimageredirect"]: + perms = ["noedit", "noedit-anon", "cantcreate", "cantcreate-anon", + "protectedtitle", "noimageredirect", "noimageredirect-anon", + "blocked"] + if error.code in perms: 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 exceptions.PermissionsError(error.info) - if tries == 0: - # We have login info; try to login: - self.site._login(self.site._login_info) - self._token = None # Need a new token; old one is invalid now - return self._edit(params=params, tries=1) - 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 exceptions.LoginError(e) - elif error.code in ["editconflict", "pagedeleted", "articleexists"]: # These attributes are now invalidated: self._content = None self._basetimestamp = None self._exists = self.PAGE_UNKNOWN raise exceptions.EditConflictError(error.info) - elif error.code in ["emptypage", "emptynewsection"]: raise exceptions.NoContentError(error.info) - - elif error.code == "blocked": - if tries > 0 or not all(self.site._login_info): - raise exceptions.PermissionsError(error.info) - else: - # Perhaps we are blocked from being logged-out? Try to log in: - self.site._login(self.site._login_info) - self._token = None # Need a new token; old one is invalid now - return self._edit(params=params, tries=1) - elif error.code == "contenttoobig": raise exceptions.ContentTooBigError(error.info) - elif error.code == "spamdetected": raise exceptions.SpamDetectedError(error.info) - elif error.code == "filtered": raise exceptions.FilteredError(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. - - If the assertion was 'user' and we have valid login information, try to - log in. Otherwise, raise PermissionsError with details. - """ - if assertion == "user": - if not all(self.site._login_info): - # Insufficient login info: - e = "AssertEdit: user assertion failed, and no login info was provided." - raise exceptions.PermissionsError(e) - if tries == 0: - # We have login info; try to login: - self.site._login(self.site._login_info) - self._token = None # Need a new token; old one is invalid now - return self._edit(params=params, tries=1) - 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 exceptions.LoginError(e) - - elif assertion == "bot": - if not all(self.site._login_info): - # Insufficient login info: - e = "AssertEdit: bot assertion failed, and no login info was provided." - raise exceptions.PermissionsError(e) - if tries == 0: - # Try to log in if we got logged out: - self.site._login(self.site._login_info) - self._token = None # Need a new token; old one is invalid now - return self._edit(params=params, tries=1) - else: - # We already tried to log in, so we don't have a bot flag: - e = "AssertEdit: bot assertion failed: we don't have a bot flag!" - raise exceptions.PermissionsError(e) - - # Unknown assertion, maybe "true", "false", or "exists": - e = "AssertEdit: assertion '{0}' failed.".format(assertion) - raise exceptions.PermissionsError(e) - @property def site(self): """The page's corresponding Site object.""" diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 31f5f39..1947f13 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -209,11 +209,13 @@ class Site(object): args.append(key + "=" + val) return "&".join(args) - def _api_query(self, params, tries=0, wait=5, ignore_maxlag=False): + def _api_query(self, params, tries=0, wait=5, ignore_maxlag=False, + ae_retry=True): """Do an API query with *params* as a dict of parameters. See the documentation for :py:meth:`api_query` for full implementation - details. + details. *tries*, *wait*, and *ignore_maxlag* are for maxlag; + *ae_retry* is for AssertEdit. """ since_last_query = time() - self._last_query_time # Throttling support if since_last_query < self._wait_between_queries: @@ -247,7 +249,7 @@ class Site(object): gzipper = GzipFile(fileobj=stream) result = gzipper.read() - return self._handle_api_query_result(result, params, tries, wait) + return self._handle_api_result(result, params, tries, wait, ae_retry) def _build_api_query(self, params, ignore_maxlag): """Given API query params, return the URL to query and POST data.""" @@ -257,7 +259,8 @@ class Site(object): url = ''.join((self.url, self._script_path, "/api.php")) params["format"] = "json" # This is the only format we understand - if self._assert_edit: # If requested, ensure that we're logged in + if self._assert_edit and params.get("action") != "login": + # If requested, ensure that we're logged in params["assert"] = self._assert_edit if self._maxlag and not ignore_maxlag: # If requested, don't overload the servers: @@ -266,7 +269,7 @@ class Site(object): data = self._urlencode_utf8(params) return url, data - def _handle_api_query_result(self, result, params, tries, wait): + def _handle_api_result(self, result, params, tries, wait, ae_retry): """Given the result of an API query, attempt to return useful data.""" try: res = loads(result) # Try to parse as a JSON object @@ -277,8 +280,8 @@ class Site(object): try: code = res["error"]["code"] info = res["error"]["info"] - except (TypeError, KeyError): # Having these keys indicates a problem - return res # All is well; return the decoded JSON + except (TypeError, KeyError): # If there's no error code/info, return + return res if code == "maxlag": # We've been throttled by the server if tries >= self._max_retries: @@ -288,7 +291,22 @@ class Site(object): msg = 'Server says "{0}"; retrying in {1} seconds ({2}/{3})' self._logger.info(msg.format(info, wait, tries, self._max_retries)) sleep(wait) - return self._api_query(params, tries=tries, wait=wait*2) + return self._api_query(params, tries, wait * 2, ae_retry=ae_retry) + elif code in ["assertuserfailed", "assertbotfailed"]: # AssertEdit + if ae_retry and all(self._login_info): + # Try to log in if we got logged out: + self._login(self._login_info) + if "token" in params: # Fetch a new one; this is invalid now + tparams = {"action": "tokens", "type": params["action"]} + params["token"] = self._api_query(tparams, ae_retry=False) + return self._api_query(params, tries, wait, ae_retry=False) + if not all(self._login_info): + e = "Assertion failed, and no login info was provided." + elif code == "assertbotfailed": + e = "Bot assertion failed: we don't have a bot flag!" + else: + e = "User assertion failed due to an unknown issue. Cookie problem?" + raise exceptions.PermissionsError("AssertEdit: " + e) else: # Some unknown error occurred e = 'API query failed: got error "{0}"; server says: "{1}".' error = exceptions.APIError(e.format(code, info)) From 3d5be6c627eb2f8eccf3303a3f1f4a453fc18382 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 10 Jan 2014 04:59:09 -0500 Subject: [PATCH 043/207] Fix token-getter code and refactor into a get_token() function. --- earwigbot/wiki/site.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 1947f13..390ff04 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -73,6 +73,7 @@ class Site(object): - :py:meth:`sql_query`: does an SQL query and yields its results - :py:meth:`get_maxlag`: returns the internal database lag - :py:meth:`get_replag`: estimates the external database lag + - :py:meth:`get_token`: gets a token for a specific API action - :py:meth:`namespace_id_to_name`: returns names associated with an NS id - :py:meth:`namespace_name_to_id`: returns the ID associated with a NS name - :py:meth:`get_page`: returns a Page for the given title @@ -297,8 +298,7 @@ class Site(object): # Try to log in if we got logged out: self._login(self._login_info) if "token" in params: # Fetch a new one; this is invalid now - tparams = {"action": "tokens", "type": params["action"]} - params["token"] = self._api_query(tparams, ae_retry=False) + params["token"] = self.get_token(params["action"], False) return self._api_query(params, tries, wait, ae_retry=False) if not all(self._login_info): e = "Assertion failed, and no login info was provided." @@ -656,7 +656,7 @@ class Site(object): query until we exceed :py:attr:`self._max_retries`. There is helpful MediaWiki API documentation at `MediaWiki.org - `_. + `_. """ with self._api_lock: return self._api_query(kwargs) @@ -762,6 +762,33 @@ class Site(object): result = list(self.sql_query(query)) return int(result[0][0]) + def get_token(self, action, lock=True): + """Return a token for a data-modifying API action. + + *action* must be one of the types listed on + . If it's given as a union + of types separated by |, then the function will return a dictionary + of tokens instead of a single one. *lock* is for internal usage; + setting it to ``False`` prevents the query from acquiring the internal + API access lock. + + Raises :py:exc:`~earwigbot.exceptions.PermissionsError` if we don't + have permissions for the requested action(s), or they are invalid. + Raises :py:exc:`~earwigbot.exceptions.APIError` if there was some other + API issue. + """ + if lock: + result = self.api_query(action="tokens", type=action) + else: + params = {"action": "tokens", "type": action} + result = self._api_query(params, ae_retry=False) + + if "warnings" in result and "token" in result["warnings"]: + raise exceptions.PermissionsError(result["warnings"]["token"]["*"]) + if "|" in action: + return result["tokens"] + return result["tokens"].values()[0] + def namespace_id_to_name(self, ns_id, all=False): """Given a namespace ID, returns associated namespace names. From 1bfe5c2ee71676002abee9cc73469f057fd82ccd Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 18 Jan 2014 23:58:18 -0500 Subject: [PATCH 044/207] Fix error handling in get_token(). --- earwigbot/wiki/site.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 390ff04..015ba7c 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -778,16 +778,16 @@ class Site(object): API issue. """ if lock: - result = self.api_query(action="tokens", type=action) + res = self.api_query(action="tokens", type=action) else: params = {"action": "tokens", "type": action} - result = self._api_query(params, ae_retry=False) + res = self._api_query(params, ae_retry=False) - if "warnings" in result and "token" in result["warnings"]: - raise exceptions.PermissionsError(result["warnings"]["token"]["*"]) + if "warnings" in res and "tokens" in res["warnings"]: + raise exceptions.PermissionsError(res["warnings"]["tokens"]["*"]) if "|" in action: - return result["tokens"] - return result["tokens"].values()[0] + return res["tokens"] + return res["tokens"].values()[0] def namespace_id_to_name(self, ns_id, all=False): """Given a namespace ID, returns associated namespace names. From 4fff9089125757e1898c99d19f0f9048c7c1bb4e Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 19 Jan 2014 01:06:48 -0500 Subject: [PATCH 045/207] Cleanup; fix site locking mechanism; badtoken handling. --- earwigbot/wiki/page.py | 19 +++++++++++++------ earwigbot/wiki/site.py | 21 +++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index eacb221..175505a 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -280,8 +280,7 @@ class Page(CopyvioMixIn): self._assert_existence() def _edit(self, params=None, text=None, summary=None, minor=None, bot=None, - force=None, section=None, captcha_id=None, captcha_word=None, - tries=0): + force=None, section=None, captcha_id=None, captcha_word=None): """Edit the page! If *params* is given, we'll use it as our API query parameters. @@ -316,7 +315,7 @@ class Page(CopyvioMixIn): except exceptions.APIError as error: if not hasattr(error, "code"): raise # We can only handle errors with a code attribute - result = self._handle_edit_errors(error, params, tries) + result = self._handle_edit_errors(error, params) # If everything was successful, reset invalidated attributes: if result["edit"]["result"] == "Success": @@ -360,12 +359,12 @@ class Page(CopyvioMixIn): return params - def _handle_edit_errors(self, error, params, tries): + def _handle_edit_errors(self, error, params, retry=True): """If our edit fails due to some error, try to handle it. We'll either raise an appropriate exception (for example, if the page - is protected), or we'll try to fix it (for example, if we can't edit - due to being logged out, we'll try to log in). + is protected), or we'll try to fix it (for example, if the token is + invalid, we'll try to get a new one). """ perms = ["noedit", "noedit-anon", "cantcreate", "cantcreate-anon", "protectedtitle", "noimageredirect", "noimageredirect-anon", @@ -378,6 +377,14 @@ class Page(CopyvioMixIn): self._basetimestamp = None self._exists = self.PAGE_UNKNOWN raise exceptions.EditConflictError(error.info) + elif error.code == "badtoken" and retry: + params["token"] = self.site.get_token("edit") + try: + return self.site.api_query(**params) + except exceptions.APIError as error: + if not hasattr(error, "code"): + raise # We can only handle errors with a code attribute + result = self._handle_edit_errors(error, params, retry=False) elif error.code in ["emptypage", "emptynewsection"]: raise exceptions.NoContentError(error.info) elif error.code == "contenttoobig": diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 015ba7c..9874f1a 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -26,7 +26,7 @@ from json import loads from logging import getLogger, NullHandler from os.path import expanduser from StringIO import StringIO -from threading import Lock +from threading import RLock from time import sleep, time from urllib import quote_plus, unquote_plus from urllib2 import build_opener, HTTPCookieProcessor, URLError @@ -124,7 +124,7 @@ class Site(object): self._wait_between_queries = wait_between_queries self._max_retries = 6 self._last_query_time = 0 - self._api_lock = Lock() + self._api_lock = RLock() self._api_info_cache = {"maxlag": 0, "lastcheck": 0} # Attributes used for SQL queries: @@ -133,7 +133,7 @@ class Site(object): else: self._sql_data = {} self._sql_conn = None - self._sql_lock = Lock() + self._sql_lock = RLock() self._sql_info_cache = {"replag": 0, "lastcheck": 0, "usable": None} # Attribute used in copyright violation checks (see CopyrightMixIn): @@ -298,7 +298,7 @@ class Site(object): # Try to log in if we got logged out: self._login(self._login_info) if "token" in params: # Fetch a new one; this is invalid now - params["token"] = self.get_token(params["action"], False) + params["token"] = self.get_token(params["action"]) return self._api_query(params, tries, wait, ae_retry=False) if not all(self._login_info): e = "Assertion failed, and no login info was provided." @@ -762,27 +762,20 @@ class Site(object): result = list(self.sql_query(query)) return int(result[0][0]) - def get_token(self, action, lock=True): + def get_token(self, action): """Return a token for a data-modifying API action. *action* must be one of the types listed on . If it's given as a union of types separated by |, then the function will return a dictionary - of tokens instead of a single one. *lock* is for internal usage; - setting it to ``False`` prevents the query from acquiring the internal - API access lock. + of tokens instead of a single one. Raises :py:exc:`~earwigbot.exceptions.PermissionsError` if we don't have permissions for the requested action(s), or they are invalid. Raises :py:exc:`~earwigbot.exceptions.APIError` if there was some other API issue. """ - if lock: - res = self.api_query(action="tokens", type=action) - else: - params = {"action": "tokens", "type": action} - res = self._api_query(params, ae_retry=False) - + res = self.api_query(action="tokens", type=action) if "warnings" in res and "tokens" in res["warnings"]: raise exceptions.PermissionsError(res["warnings"]["tokens"]["*"]) if "|" in action: From 0d4a09902fc8ee17798f5257a667dd703c7da572 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 19 Jan 2014 01:08:24 -0500 Subject: [PATCH 046/207] Missed a line. --- earwigbot/wiki/page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index 175505a..2c8cba2 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -384,7 +384,7 @@ class Page(CopyvioMixIn): except exceptions.APIError as error: if not hasattr(error, "code"): raise # We can only handle errors with a code attribute - result = self._handle_edit_errors(error, params, retry=False) + return self._handle_edit_errors(error, params, retry=False) elif error.code in ["emptypage", "emptynewsection"]: raise exceptions.NoContentError(error.info) elif error.code == "contenttoobig": From 202ea9385442db1c33bba989a3c8c8742a7534ce Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 19 Feb 2014 17:20:51 -0500 Subject: [PATCH 047/207] Add a bunch of functionality to !remind (#43). --- earwigbot/commands/remind.py | 250 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 226 insertions(+), 24 deletions(-) diff --git a/earwigbot/commands/remind.py b/earwigbot/commands/remind.py index bb0c873..2ecbacb 100644 --- a/earwigbot/commands/remind.py +++ b/earwigbot/commands/remind.py @@ -20,43 +20,245 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from threading import Timer +from itertools import chain +import random +from threading import Thread import time from earwigbot.commands import Command +DISPLAY = ["display", "show", "list", "info"] +CANCEL = ["cancel", "stop", "delete", "del"] +SNOOZE = ["snooze", "delay", "reset", "adjust"] + class Remind(Command): """Set a message to be repeated to you in a certain amount of time.""" name = "remind" - commands = ["remind", "reminder"] + commands = ["remind", "reminder", "reminders", "snooze"] - def process(self, data): - if not data.args: - msg = "Please specify a time (in seconds) and a message in the following format: !remind