We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
find_updates: Unexpected error (local variable 'info' referenced before assignment)
### Description
An error is logged, errors shouldn't happen.

### Reproduction steps
Seen in log channel, unknown, run the bot for long enough???

### Expected behavior
No error

### Logs
```
[2021-03-31 22:00:24,531] sopel.tools.jobs     ERROR    - Error while processing job: local variable 'info' referenced before assignment
[2021-03-31 22:00:24,538] sopel.bot            ERROR    - Unexpected error (local variable 'info' referenced before assignment)
Traceback (most recent call last):
  File "/srv/sopelbots/devvenv/lib/python3.7/site-packages/sopel/tools/jobs.py", line 191, in _call
    job.execute(self.manager)
  File "/srv/sopelbots/devvenv/lib/python3.7/site-packages/sopel/tools/jobs.py", line 463, in execute
    return self._handler(manager)
  File "/srv/sopelbots/devvenv/lib/python3.7/site-packages/sopel/modules/find_updates.py", line 86, in check_version
    latest = info['version']
UnboundLocalError: local variable 'info' referenced before assignment

```

### Environment
- Sopel `.version`: https://github.com/sopel-irc/sopel/commit/96c55aff852bf40bca56de49b2bc30378bf1c819
- Sopel installed via: pip/wheel
- Python version: 3.7.3
- Operating system: Debian 10.9
- IRCd `/version`: freenode
- Relevant plugins: find_updates


--- 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/find_updates.py`
Content:
```
1 # coding=utf-8
2 """
3 find_updates.py - Sopel Update Check Plugin
4 This is separated from version.py, so that it can be easily overridden by
5 distribution packagers, and they can check their repositories rather than the
6 Sopel website.
7 Copyright 2014, Elsie Powell, embolalia.com
8 Licensed under the Eiffel Forum License 2.
9 
10 https://sopel.chat
11 """
12 from __future__ import absolute_import, division, print_function, unicode_literals
13 
14 import requests
15 
16 from sopel import (
17     __version__ as current_version,
18     _version_info,
19     plugin,
20     tools,
21     version_info,
22 )
23 
24 
25 wait_time = 24 * 60 * 60  # check once per day
26 version_url = 'https://sopel.chat/latest.json'
27 stable_message = (
28     'A new Sopel version, {}, is available; I am running {}. Please update '
29     'me. Full release notes at {}'
30 )
31 unstable_message = (
32     'A new pre-release version, {}, is available; I am running {}. Please '
33     'update me.{}'
34 )
35 
36 
37 @plugin.event(tools.events.RPL_LUSERCLIENT)
38 def startup_version_check(bot, trigger):
39     if not bot.memory.get('update_startup_check_run', False):
40         bot.memory['update_startup_check_run'] = True
41         check_version(bot)
42 
43 
44 def _check_succeeded(bot):
45     bot.memory['update_failures'] = 0
46 
47 
48 def _check_failed(bot):
49     bot.memory['update_failures'] = 1 + bot.memory.get('update_failures', 0)
50 
51 
52 @plugin.interval(wait_time)
53 def check_version(bot):
54     version = version_info
55     success = False
56 
57     try:
58         r = requests.get(version_url, timeout=(5, 5))
59     except requests.exceptions.RequestException:
60         _check_failed(bot)
61     else:
62         success = True
63 
64     try:
65         if success:
66             info = r.json()
67     except ValueError:
68         # TODO: use JSONDecodeError when dropping Pythons < 3.5
69         _check_failed(bot)
70 
71     if not success and bot.memory.get('update_failures', 0) > 4:
72         bot.say(
73             "[update] I haven't been able to check for updates in a while. "
74             "Please verify that {} is working and I can reach it."
75             .format(version_url), bot.config.core.owner)
76         bot.say(
77             "[update] If this issue persists, please alert the Sopel dev team "
78             "in #sopel on freenode, or open a GitHub issue: "
79             "https://github.com/sopel-irc/sopel/issues",
80             bot.config.core.owner)
81         return
82 
83     _check_succeeded(bot)
84 
85     if version.releaselevel == 'final':
86         latest = info['version']
87         notes = info['release_notes']
88         message = stable_message
89     else:
90         latest = info['unstable']
91         notes = info.get('unstable_notes', '')
92         if notes:
93             notes = ' Full release notes at ' + notes
94         message = unstable_message
95     latest_version = _version_info(latest)
96 
97     if version < latest_version:
98         msg = message.format(latest, current_version, notes)
99         bot.say('[update] ' + msg, bot.config.core.owner)
100
```
--- 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/find_updates.py b/sopel/modules/find_updates.py
--- a/sopel/modules/find_updates.py
+++ b/sopel/modules/find_updates.py
@@ -67,8 +67,14 @@
     except ValueError:
         # TODO: use JSONDecodeError when dropping Pythons < 3.5
         _check_failed(bot)
+        success = False
 
-    if not success and bot.memory.get('update_failures', 0) > 4:
+    if not success:
+        if bot.memory.get('update_failures', 0) <= 4:
+            # not enough failures to worry; silently ignore this one
+            return
+
+        # too many failures to ignore; notify owner
         bot.say(
             "[update] I haven't been able to check for updates in a while. "
             "Please verify that {} is working and I can reach it."

{"golden_diff": "diff --git a/sopel/modules/find_updates.py b/sopel/modules/find_updates.py\n--- a/sopel/modules/find_updates.py\n+++ b/sopel/modules/find_updates.py\n@@ -67,8 +67,14 @@\n     except ValueError:\n         # TODO: use JSONDecodeError when dropping Pythons < 3.5\n         _check_failed(bot)\n+        success = False\n \n-    if not success and bot.memory.get('update_failures', 0) > 4:\n+    if not success:\n+        if bot.memory.get('update_failures', 0) <= 4:\n+            # not enough failures to worry; silently ignore this one\n+            return\n+\n+        # too many failures to ignore; notify owner\n         bot.say(\n             \"[update] I haven't been able to check for updates in a while. \"\n             \"Please verify that {} is working and I can reach it.\"\n", "issue": "find_updates: Unexpected error (local variable 'info' referenced before assignment)\n### Description\r\nAn error is logged, errors shouldn't happen.\r\n\r\n### Reproduction steps\r\nSeen in log channel, unknown, run the bot for long enough???\r\n\r\n### Expected behavior\r\nNo error\r\n\r\n### Logs\r\n```\r\n[2021-03-31 22:00:24,531] sopel.tools.jobs     ERROR    - Error while processing job: local variable 'info' referenced before assignment\r\n[2021-03-31 22:00:24,538] sopel.bot            ERROR    - Unexpected error (local variable 'info' referenced before assignment)\r\nTraceback (most recent call last):\r\n  File \"/srv/sopelbots/devvenv/lib/python3.7/site-packages/sopel/tools/jobs.py\", line 191, in _call\r\n    job.execute(self.manager)\r\n  File \"/srv/sopelbots/devvenv/lib/python3.7/site-packages/sopel/tools/jobs.py\", line 463, in execute\r\n    return self._handler(manager)\r\n  File \"/srv/sopelbots/devvenv/lib/python3.7/site-packages/sopel/modules/find_updates.py\", line 86, in check_version\r\n    latest = info['version']\r\nUnboundLocalError: local variable 'info' referenced before assignment\r\n\r\n```\r\n\r\n### Environment\r\n- Sopel `.version`: https://github.com/sopel-irc/sopel/commit/96c55aff852bf40bca56de49b2bc30378bf1c819\r\n- Sopel installed via: pip/wheel\r\n- Python version: 3.7.3\r\n- Operating system: Debian 10.9\r\n- IRCd `/version`: freenode\r\n- Relevant plugins: find_updates\r\n\n", "before_files": [{"content": "# coding=utf-8\n\"\"\"\nfind_updates.py - Sopel Update Check Plugin\nThis is separated from version.py, so that it can be easily overridden by\ndistribution packagers, and they can check their repositories rather than the\nSopel website.\nCopyright 2014, Elsie Powell, embolalia.com\nLicensed under the Eiffel Forum License 2.\n\nhttps://sopel.chat\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport requests\n\nfrom sopel import (\n    __version__ as current_version,\n    _version_info,\n    plugin,\n    tools,\n    version_info,\n)\n\n\nwait_time = 24 * 60 * 60  # check once per day\nversion_url = 'https://sopel.chat/latest.json'\nstable_message = (\n    'A new Sopel version, {}, is available; I am running {}. Please update '\n    'me. Full release notes at {}'\n)\nunstable_message = (\n    'A new pre-release version, {}, is available; I am running {}. Please '\n    'update me.{}'\n)\n\n\n@plugin.event(tools.events.RPL_LUSERCLIENT)\ndef startup_version_check(bot, trigger):\n    if not bot.memory.get('update_startup_check_run', False):\n        bot.memory['update_startup_check_run'] = True\n        check_version(bot)\n\n\ndef _check_succeeded(bot):\n    bot.memory['update_failures'] = 0\n\n\ndef _check_failed(bot):\n    bot.memory['update_failures'] = 1 + bot.memory.get('update_failures', 0)\n\n\n@plugin.interval(wait_time)\ndef check_version(bot):\n    version = version_info\n    success = False\n\n    try:\n        r = requests.get(version_url, timeout=(5, 5))\n    except requests.exceptions.RequestException:\n        _check_failed(bot)\n    else:\n        success = True\n\n    try:\n        if success:\n            info = r.json()\n    except ValueError:\n        # TODO: use JSONDecodeError when dropping Pythons < 3.5\n        _check_failed(bot)\n\n    if not success and bot.memory.get('update_failures', 0) > 4:\n        bot.say(\n            \"[update] I haven't been able to check for updates in a while. \"\n            \"Please verify that {} is working and I can reach it.\"\n            .format(version_url), bot.config.core.owner)\n        bot.say(\n            \"[update] If this issue persists, please alert the Sopel dev team \"\n            \"in #sopel on freenode, or open a GitHub issue: \"\n            \"https://github.com/sopel-irc/sopel/issues\",\n            bot.config.core.owner)\n        return\n\n    _check_succeeded(bot)\n\n    if version.releaselevel == 'final':\n        latest = info['version']\n        notes = info['release_notes']\n        message = stable_message\n    else:\n        latest = info['unstable']\n        notes = info.get('unstable_notes', '')\n        if notes:\n            notes = ' Full release notes at ' + notes\n        message = unstable_message\n    latest_version = _version_info(latest)\n\n    if version < latest_version:\n        msg = message.format(latest, current_version, notes)\n        bot.say('[update] ' + msg, bot.config.core.owner)\n", "path": "sopel/modules/find_updates.py"}], "after_files": [{"content": "# coding=utf-8\n\"\"\"\nfind_updates.py - Sopel Update Check Plugin\nThis is separated from version.py, so that it can be easily overridden by\ndistribution packagers, and they can check their repositories rather than the\nSopel website.\nCopyright 2014, Elsie Powell, embolalia.com\nLicensed under the Eiffel Forum License 2.\n\nhttps://sopel.chat\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport requests\n\nfrom sopel import (\n    __version__ as current_version,\n    _version_info,\n    plugin,\n    tools,\n    version_info,\n)\n\n\nwait_time = 24 * 60 * 60  # check once per day\nversion_url = 'https://sopel.chat/latest.json'\nstable_message = (\n    'A new Sopel version, {}, is available; I am running {}. Please update '\n    'me. Full release notes at {}'\n)\nunstable_message = (\n    'A new pre-release version, {}, is available; I am running {}. Please '\n    'update me.{}'\n)\n\n\n@plugin.event(tools.events.RPL_LUSERCLIENT)\ndef startup_version_check(bot, trigger):\n    if not bot.memory.get('update_startup_check_run', False):\n        bot.memory['update_startup_check_run'] = True\n        check_version(bot)\n\n\ndef _check_succeeded(bot):\n    bot.memory['update_failures'] = 0\n\n\ndef _check_failed(bot):\n    bot.memory['update_failures'] = 1 + bot.memory.get('update_failures', 0)\n\n\n@plugin.interval(wait_time)\ndef check_version(bot):\n    version = version_info\n    success = False\n\n    try:\n        r = requests.get(version_url, timeout=(5, 5))\n    except requests.exceptions.RequestException:\n        _check_failed(bot)\n    else:\n        success = True\n\n    try:\n        if success:\n            info = r.json()\n    except ValueError:\n        # TODO: use JSONDecodeError when dropping Pythons < 3.5\n        _check_failed(bot)\n        success = False\n\n    if not success:\n        if bot.memory.get('update_failures', 0) <= 4:\n            # not enough failures to worry; silently ignore this one\n            return\n\n        # too many failures to ignore; notify owner\n        bot.say(\n            \"[update] I haven't been able to check for updates in a while. \"\n            \"Please verify that {} is working and I can reach it.\"\n            .format(version_url), bot.config.core.owner)\n        bot.say(\n            \"[update] If this issue persists, please alert the Sopel dev team \"\n            \"in #sopel on freenode, or open a GitHub issue: \"\n            \"https://github.com/sopel-irc/sopel/issues\",\n            bot.config.core.owner)\n        return\n\n    _check_succeeded(bot)\n\n    if version.releaselevel == 'final':\n        latest = info['version']\n        notes = info['release_notes']\n        message = stable_message\n    else:\n        latest = info['unstable']\n        notes = info.get('unstable_notes', '')\n        if notes:\n            notes = ' Full release notes at ' + notes\n        message = unstable_message\n    latest_version = _version_info(latest)\n\n    if version < latest_version:\n        msg = message.format(latest, current_version, notes)\n        bot.say('[update] ' + msg, bot.config.core.owner)\n", "path": "sopel/modules/find_updates.py"}]}