We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Bugzilla] Error calling shutdown method for module bugzilla:None
Noticed this in my logs. Bugzilla shutdown throwing none. On Sopel 6.5.3, Python 3.5.3.

```
Ping timeout reached after 120 seconds, closing connection
Calling shutdown for 2 modules.
calling reddit.shutdown
calling bugzilla.shutdown
Error calling shutdown method for module bugzilla:None
Closed!
Warning: Disconnected. Reconnecting in 20 seconds...
 
Welcome to Sopel. Loading modules...
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sopel/modules/bugzilla.py`
Content:
```
1 # coding=utf-8
2 """Bugzilla issue reporting module
3 
4 Copyright 2013-2015, Embolalia, embolalia.com
5 Licensed under the Eiffel Forum License 2.
6 """
7 from __future__ import unicode_literals, absolute_import, print_function, division
8 
9 import re
10 
11 import xmltodict
12 
13 from sopel import web, tools
14 from sopel.config.types import StaticSection, ListAttribute
15 from sopel.logger import get_logger
16 from sopel.module import rule
17 
18 
19 regex = None
20 LOGGER = get_logger(__name__)
21 
22 
23 class BugzillaSection(StaticSection):
24     domains = ListAttribute('domains')
25     """The domains of the Bugzilla instances from which to get information."""
26 
27 
28 def configure(config):
29     config.define_section('bugzilla', BugzillaSection)
30     config.bugzilla.configure_setting(
31         'domains',
32         'Enter the domains of the Bugzillas you want extra information '
33         'from (e.g. bugzilla.gnome.org)'
34     )
35 
36 
37 def setup(bot):
38     global regex
39     bot.config.define_section('bugzilla', BugzillaSection)
40 
41     if not bot.config.bugzilla.domains:
42         return
43     if not bot.memory.contains('url_callbacks'):
44         bot.memory['url_callbacks'] = tools.SopelMemory()
45 
46     domains = '|'.join(bot.config.bugzilla.domains)
47     regex = re.compile((r'https?://(%s)'
48                         '(/show_bug.cgi\?\S*?)'
49                         '(id=\d+)')
50                        % domains)
51     bot.memory['url_callbacks'][regex] = show_bug
52 
53 
54 def shutdown(bot):
55     del bot.memory['url_callbacks'][regex]
56 
57 
58 @rule(r'.*https?://(\S+?)'
59       '(/show_bug.cgi\?\S*?)'
60       '(id=\d+).*')
61 def show_bug(bot, trigger, match=None):
62     """Show information about a Bugzilla bug."""
63     match = match or trigger
64     domain = match.group(1)
65     if domain not in bot.config.bugzilla.domains:
66         return
67     url = 'https://%s%sctype=xml&%s' % match.groups()
68     data = web.get(url, dont_decode=True)
69     bug = xmltodict.parse(data).get('bugzilla').get('bug')
70     error = bug.get('@error', None)  # error="NotPermitted"
71 
72     if error:
73         LOGGER.warning('Bugzilla error: %s' % error)
74         bot.say('[BUGZILLA] Unable to get infomation for '
75                 'linked bug (%s)' % error)
76         return
77 
78     message = ('[BUGZILLA] %s | Product: %s | Component: %s | Version: %s | ' +
79                'Importance: %s |  Status: %s | Assigned to: %s | ' +
80                'Reported: %s | Modified: %s')
81 
82     resolution = bug.get('resolution')
83     if resolution is not None:
84         status = bug.get('bug_status') + ' ' + resolution
85     else:
86         status = bug.get('bug_status')
87 
88     assigned_to = bug.get('assigned_to')
89     if isinstance(assigned_to, dict):
90         assigned_to = assigned_to.get('@name')
91 
92     message = message % (
93         bug.get('short_desc'), bug.get('product'),
94         bug.get('component'), bug.get('version'),
95         (bug.get('priority') + ' ' + bug.get('bug_severity')),
96         status, assigned_to, bug.get('creation_ts'),
97         bug.get('delta_ts'))
98     bot.say(message)
99
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sopel/modules/bugzilla.py b/sopel/modules/bugzilla.py
--- a/sopel/modules/bugzilla.py
+++ b/sopel/modules/bugzilla.py
@@ -52,7 +52,12 @@
 
 
 def shutdown(bot):
-    del bot.memory['url_callbacks'][regex]
+    try:
+        del bot.memory['url_callbacks'][regex]
+    except KeyError:
+        # bot.config.bugzilla.domains was probably just empty on startup
+        # everything's daijoubu
+        pass
 
 
 @rule(r'.*https?://(\S+?)'

{"golden_diff": "diff --git a/sopel/modules/bugzilla.py b/sopel/modules/bugzilla.py\n--- a/sopel/modules/bugzilla.py\n+++ b/sopel/modules/bugzilla.py\n@@ -52,7 +52,12 @@\n \n \n def shutdown(bot):\n-    del bot.memory['url_callbacks'][regex]\n+    try:\n+        del bot.memory['url_callbacks'][regex]\n+    except KeyError:\n+        # bot.config.bugzilla.domains was probably just empty on startup\n+        # everything's daijoubu\n+        pass\n \n \n @rule(r'.*https?://(\\S+?)'\n", "issue": "[Bugzilla] Error calling shutdown method for module bugzilla:None\nNoticed this in my logs. Bugzilla shutdown throwing none. On Sopel 6.5.3, Python 3.5.3.\r\n\r\n```\r\nPing timeout reached after 120 seconds, closing connection\r\nCalling shutdown for 2 modules.\r\ncalling reddit.shutdown\r\ncalling bugzilla.shutdown\r\nError calling shutdown method for module bugzilla:None\r\nClosed!\r\nWarning: Disconnected. Reconnecting in 20 seconds...\r\n \r\nWelcome to Sopel. Loading modules...\r\n```\n", "before_files": [{"content": "# coding=utf-8\n\"\"\"Bugzilla issue reporting module\n\nCopyright 2013-2015, Embolalia, embolalia.com\nLicensed under the Eiffel Forum License 2.\n\"\"\"\nfrom __future__ import unicode_literals, absolute_import, print_function, division\n\nimport re\n\nimport xmltodict\n\nfrom sopel import web, tools\nfrom sopel.config.types import StaticSection, ListAttribute\nfrom sopel.logger import get_logger\nfrom sopel.module import rule\n\n\nregex = None\nLOGGER = get_logger(__name__)\n\n\nclass BugzillaSection(StaticSection):\n    domains = ListAttribute('domains')\n    \"\"\"The domains of the Bugzilla instances from which to get information.\"\"\"\n\n\ndef configure(config):\n    config.define_section('bugzilla', BugzillaSection)\n    config.bugzilla.configure_setting(\n        'domains',\n        'Enter the domains of the Bugzillas you want extra information '\n        'from (e.g. bugzilla.gnome.org)'\n    )\n\n\ndef setup(bot):\n    global regex\n    bot.config.define_section('bugzilla', BugzillaSection)\n\n    if not bot.config.bugzilla.domains:\n        return\n    if not bot.memory.contains('url_callbacks'):\n        bot.memory['url_callbacks'] = tools.SopelMemory()\n\n    domains = '|'.join(bot.config.bugzilla.domains)\n    regex = re.compile((r'https?://(%s)'\n                        '(/show_bug.cgi\\?\\S*?)'\n                        '(id=\\d+)')\n                       % domains)\n    bot.memory['url_callbacks'][regex] = show_bug\n\n\ndef shutdown(bot):\n    del bot.memory['url_callbacks'][regex]\n\n\n@rule(r'.*https?://(\\S+?)'\n      '(/show_bug.cgi\\?\\S*?)'\n      '(id=\\d+).*')\ndef show_bug(bot, trigger, match=None):\n    \"\"\"Show information about a Bugzilla bug.\"\"\"\n    match = match or trigger\n    domain = match.group(1)\n    if domain not in bot.config.bugzilla.domains:\n        return\n    url = 'https://%s%sctype=xml&%s' % match.groups()\n    data = web.get(url, dont_decode=True)\n    bug = xmltodict.parse(data).get('bugzilla').get('bug')\n    error = bug.get('@error', None)  # error=\"NotPermitted\"\n\n    if error:\n        LOGGER.warning('Bugzilla error: %s' % error)\n        bot.say('[BUGZILLA] Unable to get infomation for '\n                'linked bug (%s)' % error)\n        return\n\n    message = ('[BUGZILLA] %s | Product: %s | Component: %s | Version: %s | ' +\n               'Importance: %s |  Status: %s | Assigned to: %s | ' +\n               'Reported: %s | Modified: %s')\n\n    resolution = bug.get('resolution')\n    if resolution is not None:\n        status = bug.get('bug_status') + ' ' + resolution\n    else:\n        status = bug.get('bug_status')\n\n    assigned_to = bug.get('assigned_to')\n    if isinstance(assigned_to, dict):\n        assigned_to = assigned_to.get('@name')\n\n    message = message % (\n        bug.get('short_desc'), bug.get('product'),\n        bug.get('component'), bug.get('version'),\n        (bug.get('priority') + ' ' + bug.get('bug_severity')),\n        status, assigned_to, bug.get('creation_ts'),\n        bug.get('delta_ts'))\n    bot.say(message)\n", "path": "sopel/modules/bugzilla.py"}], "after_files": [{"content": "# coding=utf-8\n\"\"\"Bugzilla issue reporting module\n\nCopyright 2013-2015, Embolalia, embolalia.com\nLicensed under the Eiffel Forum License 2.\n\"\"\"\nfrom __future__ import unicode_literals, absolute_import, print_function, division\n\nimport re\n\nimport xmltodict\n\nfrom sopel import web, tools\nfrom sopel.config.types import StaticSection, ListAttribute\nfrom sopel.logger import get_logger\nfrom sopel.module import rule\n\n\nregex = None\nLOGGER = get_logger(__name__)\n\n\nclass BugzillaSection(StaticSection):\n    domains = ListAttribute('domains')\n    \"\"\"The domains of the Bugzilla instances from which to get information.\"\"\"\n\n\ndef configure(config):\n    config.define_section('bugzilla', BugzillaSection)\n    config.bugzilla.configure_setting(\n        'domains',\n        'Enter the domains of the Bugzillas you want extra information '\n        'from (e.g. bugzilla.gnome.org)'\n    )\n\n\ndef setup(bot):\n    global regex\n    bot.config.define_section('bugzilla', BugzillaSection)\n\n    if not bot.config.bugzilla.domains:\n        return\n    if not bot.memory.contains('url_callbacks'):\n        bot.memory['url_callbacks'] = tools.SopelMemory()\n\n    domains = '|'.join(bot.config.bugzilla.domains)\n    regex = re.compile((r'https?://(%s)'\n                        '(/show_bug.cgi\\?\\S*?)'\n                        '(id=\\d+)')\n                       % domains)\n    bot.memory['url_callbacks'][regex] = show_bug\n\n\ndef shutdown(bot):\n    try:\n        del bot.memory['url_callbacks'][regex]\n    except KeyError:\n        # bot.config.bugzilla.domains was probably just empty on startup\n        # everything's daijoubu\n        pass\n\n\n@rule(r'.*https?://(\\S+?)'\n      '(/show_bug.cgi\\?\\S*?)'\n      '(id=\\d+).*')\ndef show_bug(bot, trigger, match=None):\n    \"\"\"Show information about a Bugzilla bug.\"\"\"\n    match = match or trigger\n    domain = match.group(1)\n    if domain not in bot.config.bugzilla.domains:\n        return\n    url = 'https://%s%sctype=xml&%s' % match.groups()\n    data = web.get(url, dont_decode=True)\n    bug = xmltodict.parse(data).get('bugzilla').get('bug')\n    error = bug.get('@error', None)  # error=\"NotPermitted\"\n\n    if error:\n        LOGGER.warning('Bugzilla error: %s' % error)\n        bot.say('[BUGZILLA] Unable to get infomation for '\n                'linked bug (%s)' % error)\n        return\n\n    message = ('[BUGZILLA] %s | Product: %s | Component: %s | Version: %s | ' +\n               'Importance: %s |  Status: %s | Assigned to: %s | ' +\n               'Reported: %s | Modified: %s')\n\n    resolution = bug.get('resolution')\n    if resolution is not None:\n        status = bug.get('bug_status') + ' ' + resolution\n    else:\n        status = bug.get('bug_status')\n\n    assigned_to = bug.get('assigned_to')\n    if isinstance(assigned_to, dict):\n        assigned_to = assigned_to.get('@name')\n\n    message = message % (\n        bug.get('short_desc'), bug.get('product'),\n        bug.get('component'), bug.get('version'),\n        (bug.get('priority') + ' ' + bug.get('bug_severity')),\n        status, assigned_to, bug.get('creation_ts'),\n        bug.get('delta_ts'))\n    bot.say(message)\n", "path": "sopel/modules/bugzilla.py"}]}