Repository: Cog-Creators/Red-DiscordBot

Issue:
[Core] `redbot --edit` exits with a traceback (regression from shutdown PR)
# Other bugs

#### What were you trying to do?

Edit instance's data with `redbot instancename --edit`

#### What were you expecting to happen?

Graceful shutdown after editing what I need to edit

#### What actually happened?

Got console noise (first 2 lines) and traceback:
```
[2020-01-09 14:03:17] [INFO] red.main: Shutting down with exit code: 0
[2020-01-09 14:03:17] [INFO] red.main: Please wait, cleaning up a bit more
Traceback (most recent call last):
  File "C:\Users\Jakub\OneDrive\Dokumenty\Red-DiscordBot\.venv\Scripts\redbot-script.py", line 11, in <module>
    load_entry_point('Red-DiscordBot', 'console_scripts', 'redbot')()
  File "c:\users\jakub\onedrive\dokumenty\red-discordbot\redbot\__main__.py", line 465, in main
    sys.exit(red._shutdown_mode.value)
AttributeError: 'int' object has no attribute 'value'
```

#### How can we reproduce this issue?

Use `redbot instancename --edit` and just enter through everything, you don't even have to change anything.

// IMO there should be none of this `[INFO]` logging in `redbot --edit`


Discussion:

Resolving patch:
diff --git a/redbot/__main__.py b/redbot/__main__.py
--- a/redbot/__main__.py
+++ b/redbot/__main__.py
@@ -266,6 +266,27 @@ def _copy_data(data):
     return True
 
 
+def handle_edit(cli_flags: Namespace):
+    """
+    This one exists to not log all the things like it's a full run of the bot.
+    """
+    loop = asyncio.get_event_loop()
+    data_manager.load_basic_configuration(cli_flags.instance_name)
+    red = Red(cli_flags=cli_flags, description="Red V3", dm_help=None, fetch_offline_members=True)
+    try:
+        driver_cls = drivers.get_driver_class()
+        loop.run_until_complete(driver_cls.initialize(**data_manager.storage_details()))
+        loop.run_until_complete(edit_instance(red, cli_flags))
+        loop.run_until_complete(driver_cls.teardown())
+    except (KeyboardInterrupt, EOFError):
+        print("Aborted!")
+    finally:
+        loop.run_until_complete(asyncio.sleep(1))
+        loop.stop()
+        loop.close()
+        sys.exit(0)
+
+
 async def run_bot(red: Red, cli_flags: Namespace):
 
     driver_cls = drivers.get_driver_class()
@@ -280,15 +301,6 @@ async def run_bot(red: Red, cli_flags: Namespace):
     log.debug("Data Path: %s", data_manager._base_data_path())
     log.debug("Storage Type: %s", data_manager.storage_type())
 
-    if cli_flags.edit:
-        try:
-            await edit_instance(red, cli_flags)
-        except (KeyboardInterrupt, EOFError):
-            print("Aborted!")
-        finally:
-            await driver_cls.teardown()
-        sys.exit(0)
-
     # lib folder has to be in sys.path before trying to load any 3rd-party cog (GH-3061)
     # We might want to change handling of requirements in Downloader at later date
     LIB_PATH = data_manager.cog_data_path(raw_name="Downloader") / "lib"
@@ -398,8 +410,12 @@ def red_exception_handler(red, red_task: asyncio.Future):
 
 
 def main():
+    red = None  # Error handling for users misusing the bot
     cli_flags = parse_cli_flags(sys.argv[1:])
     handle_early_exit_flags(cli_flags)
+    if cli_flags.edit:
+        handle_edit(cli_flags)
+        return
     try:
         loop = asyncio.get_event_loop()
 
@@ -441,13 +457,15 @@ def main():
         # We still have to catch this here too. (*joy*)
         log.warning("Please do not use Ctrl+C to Shutdown Red! (attempting to die gracefully...)")
         log.error("Received KeyboardInterrupt, treating as interrupt")
-        loop.run_until_complete(shutdown_handler(red, signal.SIGINT))
+        if red is not None:
+            loop.run_until_complete(shutdown_handler(red, signal.SIGINT))
     except SystemExit as exc:
         # We also have to catch this one here. Basically any exception which normally
         # Kills the python interpreter (Base Exceptions minus asyncio.cancelled)
         # We need to do something with prior to having the loop close
         log.info("Shutting down with exit code: %s", exc.code)
-        loop.run_until_complete(shutdown_handler(red, None, exc.code))
+        if red is not None:
+            loop.run_until_complete(shutdown_handler(red, None, exc.code))
     finally:
         # Allows transports to close properly, and prevent new ones from being opened.
         # Transports may still not be closed correcly on windows, see below
@@ -462,7 +480,8 @@ def main():
             loop.run_until_complete(asyncio.sleep(1))
         loop.stop()
         loop.close()
-        sys.exit(red._shutdown_mode.value)
+        exit_code = red._shutdown_mode if red is not None else 1
+        sys.exit(exit_code)
 
 
 if __name__ == "__main__":


Test patch: