diff --git a/sopel/modules/bugzilla.py b/sopel/modules/bugzilla.py index 675c5109ce..1eca770663 100644 --- a/sopel/modules/bugzilla.py +++ b/sopel/modules/bugzilla.py @@ -14,11 +14,9 @@ import requests import xmltodict +from sopel import plugin, plugins from sopel.config.types import ListAttribute, StaticSection -from sopel.module import rule - -regex = None LOGGER = logging.getLogger(__name__) @@ -42,34 +40,35 @@ def configure(config): def setup(bot): - global regex bot.config.define_section('bugzilla', BugzillaSection) - if not bot.config.bugzilla.domains: - return - domains = '|'.join(bot.config.bugzilla.domains) - regex = re.compile((r'https?://(%s)' - r'(/show_bug.cgi\?\S*?)' - r'(id=\d+)') - % domains) - bot.register_url_callback(regex, show_bug) +def _bugzilla_loader(settings): + if not settings.bugzilla.domains: + raise plugins.exceptions.ImproperlyConfigured( + 'Bugzilla URL callback requires ' + '"bugzilla.domains" to be configured; check your config file.') + + domain_pattern = '|'.join( + re.escape(domain) + for domain in settings.bugzilla.domains) + pattern = ( + r'https?://(%s)' + r'(/show_bug.cgi\?\S*?)' + r'(id=\d+).*' + ) % domain_pattern -def shutdown(bot): - bot.unregister_url_callback(regex, show_bug) + return [re.compile(pattern)] -@rule(r'.*https?://(\S+?)' - r'(/show_bug.cgi\?\S*?)' - r'(id=\d+).*') +@plugin.url_lazy(_bugzilla_loader) def show_bug(bot, trigger, match=None): """Show information about a Bugzilla bug.""" - match = match or trigger - domain = match.group(1) + domain = trigger.group(1) if domain not in bot.config.bugzilla.domains: return - url = 'https://%s%sctype=xml&%s' % match.groups() + url = 'https://%s%sctype=xml&%s' % trigger.groups() data = requests.get(url).content bug = xmltodict.parse(data).get('bugzilla').get('bug') error = bug.get('@error', None) # error="NotPermitted" diff --git a/sopel/modules/wikipedia.py b/sopel/modules/wikipedia.py index ecbde88082..2f69b5be0a 100644 --- a/sopel/modules/wikipedia.py +++ b/sopel/modules/wikipedia.py @@ -13,7 +13,7 @@ from requests import get from sopel.config.types import StaticSection, ValidatedAttribute -from sopel.module import commands, example, NOLIMIT, url +from sopel.module import commands, example, NOLIMIT, output_prefix, url from sopel.tools.web import quote, unquote try: # TODO: Remove fallback when dropping py2 @@ -133,9 +133,9 @@ def say_snippet(bot, trigger, server, query, show_url=True): snippet = mw_snippet(server, query) except KeyError: if show_url: - bot.say("[WIKIPEDIA] Error fetching snippet for \"{}\".".format(page_name)) + bot.say("Error fetching snippet for \"{}\".".format(page_name)) return - msg = '[WIKIPEDIA] {} | "{}"'.format(page_name, snippet) + msg = '{} | "{}"'.format(page_name, snippet) msg_url = msg + ' | https://{}/wiki/{}'.format(server, query) if msg_url == trigger: # prevents triggering on another instance of Sopel return @@ -166,10 +166,10 @@ def say_section(bot, trigger, server, query, section): snippet = mw_section(server, query, section) if not snippet: - bot.say("[WIKIPEDIA] Error fetching section \"{}\" for page \"{}\".".format(section, page_name)) + bot.say("Error fetching section \"{}\" for page \"{}\".".format(section, page_name)) return - msg = '[WIKIPEDIA] {} - {} | "{}"'.format(page_name, section.replace('_', ' '), snippet) + msg = '{} - {} | "{}"'.format(page_name, section.replace('_', ' '), snippet) bot.say(msg) @@ -217,6 +217,7 @@ def mw_section(server, query, section): # Matches a wikipedia page (excluding spaces and #, but not /File: links), with a separate optional field for the section @url(r'https?:\/\/([a-z]+\.wikipedia\.org)\/wiki\/((?!File\:)[^ #]+)#?([^ ]*)') +@output_prefix('[WIKIPEDIA] ') def mw_info(bot, trigger, match=None): """Retrieves and outputs a snippet of the linked page.""" if match.group(3): @@ -230,6 +231,7 @@ def mw_info(bot, trigger, match=None): @commands('w', 'wiki', 'wik') @example('.w San Francisco') +@output_prefix('[WIKIPEDIA] ') def wikipedia(bot, trigger): lang = bot.config.wikipedia.default_lang diff --git a/sopel/plugins/exceptions.py b/sopel/plugins/exceptions.py index 8fa2e890f0..5d3ae15f25 100644 --- a/sopel/plugins/exceptions.py +++ b/sopel/plugins/exceptions.py @@ -16,3 +16,12 @@ def __init__(self, name): message = 'Plugin "%s" not registered' % name self.plugin_name = name super(PluginNotRegistered, self).__init__(message) + + +class ImproperlyConfigured(PluginError): + """Exception raised when a plugin is not properly configured. + + This can be used in any place where a plugin requires a specific config, + for example in its ``setup`` function, in any of its rules or commands, + and in the loader function for the :func:`sopel.plugin.url_lazy` decorator. + """