Repository: Pycord-Development/pycord

Issue:
AttributeError in client.Connect in certain conditions(rare)
### Summary

client.Connect raising AttributeError if the user's internet stopped working after requesting to https://discord.com/api/v10/gateway

### Reproduction Steps

Have an unstable internet and luck

### Minimal Reproducible Code

_No response_

### Expected Results

It should retry to connect

### Actual Results

An error happened and the program terminated

```py
Traceback (most recent call last):
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\tasks.py", line 490, in wait_for
    return fut.result()
           ^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\gateway.py", line 338, in from_client
    socket = await client.http.ws_connect(gateway)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\http.py", line 213, in ws_connect
    return await self.__session.ws_connect(url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\client.py", line 805, in _ws_connect
    resp = await self.request(
           ^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\client.py", line 562, in _request
    conn = await self._connector.connect(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 540, in connect
    proto = await self._create_connection(req, traces, timeout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 901, in _create_connection
    _, proto = await self._create_direct_connection(req, traces, timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 1178, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 980, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore[return-value]  # noqa
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 1112, in create_connection
    transport, protocol = await self._create_connection_transport(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 1145, in _create_connection_transport
    await waiter
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 597, in connect
    self.ws = await asyncio.wait_for(coro, timeout=60.0)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\tasks.py", line 492, in wait_for
    raise exceptions.TimeoutError() from exc
TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Personal\Documents\GitHub\Grass-bot-rewrite\bot\main.py", line 12, in <module>
    bot.bot.run()
  File "D:\Personal\Documents\GitHub\Grass-bot-rewrite\bot\bot.py", line 86, in run
    super().run(token)
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 763, in run
    return future.result()
           ^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 742, in runner
    await self.start(*args, **kwargs)
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 706, in start
    await self.connect(reconnect=reconnect)
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 657, in connect
    sequence=self.ws.sequence, resume=True, session=self.ws.session_id
             ^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'sequence'
```

### Intents

All

### System Information

- Python v3.11.5-final
- py-cord v2.4.1-final
- aiohttp v3.8.6
- system info: Windows 10 10.0.22621

### Checklist

- [X] I have searched the open issues for duplicates.
- [X] I have shown the entire traceback, if possible.
- [X] I have removed my token from display, if visible.

### Additional Context

_No response_
AttributeError in client.Connect in certain conditions(rare)
### Summary

client.Connect raising AttributeError if the user's internet stopped working after requesting to https://discord.com/api/v10/gateway

### Reproduction Steps

Have an unstable internet and luck

### Minimal Reproducible Code

_No response_

### Expected Results

It should retry to connect

### Actual Results

An error happened and the program terminated

```py
Traceback (most recent call last):
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\tasks.py", line 490, in wait_for
    return fut.result()
           ^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\gateway.py", line 338, in from_client
    socket = await client.http.ws_connect(gateway)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\http.py", line 213, in ws_connect
    return await self.__session.ws_connect(url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\client.py", line 805, in _ws_connect
    resp = await self.request(
           ^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\client.py", line 562, in _request
    conn = await self._connector.connect(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 540, in connect
    proto = await self._create_connection(req, traces, timeout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 901, in _create_connection
    _, proto = await self._create_direct_connection(req, traces, timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 1178, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\aiohttp\connector.py", line 980, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore[return-value]  # noqa
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 1112, in create_connection
    transport, protocol = await self._create_connection_transport(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 1145, in _create_connection_transport
    await waiter
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 597, in connect
    self.ws = await asyncio.wait_for(coro, timeout=60.0)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Ethan_1\AppData\Local\Programs\Python\Python311\Lib\asyncio\tasks.py", line 492, in wait_for
    raise exceptions.TimeoutError() from exc
TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Personal\Documents\GitHub\Grass-bot-rewrite\bot\main.py", line 12, in <module>
    bot.bot.run()
  File "D:\Personal\Documents\GitHub\Grass-bot-rewrite\bot\bot.py", line 86, in run
    super().run(token)
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 763, in run
    return future.result()
           ^^^^^^^^^^^^^^^
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 742, in runner
    await self.start(*args, **kwargs)
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 706, in start
    await self.connect(reconnect=reconnect)
  File "d:\Personal\Documents\GitHub\Grass-bot-rewrite\.venv\Lib\site-packages\discord\client.py", line 657, in connect
    sequence=self.ws.sequence, resume=True, session=self.ws.session_id
             ^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'sequence'
```

### Intents

All

### System Information

- Python v3.11.5-final
- py-cord v2.4.1-final
- aiohttp v3.8.6
- system info: Windows 10 10.0.22621

### Checklist

- [X] I have searched the open issues for duplicates.
- [X] I have shown the entire traceback, if possible.
- [X] I have removed my token from display, if visible.

### Additional Context

_No response_


Discussion:

Resolving patch:
diff --git a/discord/client.py b/discord/client.py
--- a/discord/client.py
+++ b/discord/client.py
@@ -653,6 +653,8 @@ async def connect(self, *, reconnect: bool = True) -> None:
                 # Always try to RESUME the connection
                 # If the connection is not RESUME-able then the gateway will invalidate the session.
                 # This is apparently what the official Discord client does.
+                if self.ws is None:
+                    continue
                 ws_params.update(
                     sequence=self.ws.sequence, resume=True, session=self.ws.session_id
                 )


Test patch: