Repository: Pycord-Development/pycord

Issue:
Error while trying to edit webhook messages
### Summary

An error is raised when trying to edit a webhook's message 

### Reproduction Steps

* Send a message with a webhook
* Get the webhook using from_url
* Use that webhook to edit the message

### Minimal Reproducible Code

```python
async with aiohttp.ClientSession() as session:
    webhook = discord.Webhook.from_url(url=webhook_url, session=session, bot_token=config.TOKEN)
    await webhook.edit_message(message_id, content=content, embed=embed)
```


### Expected Results

The message to be edited

### Actual Results

Traceback (most recent call last):
...
await webhook.edit_message(message_id, content=content, embed=embed)
  File "C:\Users\10cri\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\webhook\async_.py", line 1599, in edit_message
    thread_id = thread.id
AttributeError: '_MissingSentinel' object has no attribute 'id'

### Intents

members

### System Information

- Python v3.9.7-final
- py-cord v2.0.0-alpha
    - py-cord pkg_resources: v2.0.0a4225+gc098ca5
- aiohttp v3.7.4.post0
- system info: Windows 10 10.0.19043

### 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/webhook/async_.py b/discord/webhook/async_.py
--- a/discord/webhook/async_.py
+++ b/discord/webhook/async_.py
@@ -37,6 +37,7 @@
 import aiohttp
 
 from .. import utils
+from ..object import Object
 from ..errors import InvalidArgument, HTTPException, Forbidden, NotFound, DiscordServerError
 from ..message import Message
 from ..enums import try_enum, WebhookType
@@ -45,6 +46,7 @@
 from ..http import Route
 from ..mixins import Hashable
 from ..channel import PartialMessageable
+from ..threads import Thread
 
 __all__ = (
     'Webhook',
@@ -744,6 +746,12 @@ async def edit(
         :class:`WebhookMessage`
             The newly edited message.
         """
+        thread = MISSING
+        if hasattr(self, '_thread_id'):
+            thread = Object(self._thread_id)
+        elif isinstance(self.channel, Thread):
+            thread = Object(self.channel.id)
+
         return await self._state._webhook.edit_message(
             self.id,
             content=content,
@@ -753,6 +761,7 @@ async def edit(
             files=files,
             view=view,
             allowed_mentions=allowed_mentions,
+            thread=thread
         )
 
     async def delete(self, *, delay: Optional[float] = None) -> None:
@@ -775,19 +784,24 @@ async def delete(self, *, delay: Optional[float] = None) -> None:
         HTTPException
             Deleting the message failed.
         """
+        thread_id: Optional[int] = None
+        if hasattr(self, '_thread_id'):
+            thread_id = self._thread_id
+        elif isinstance(self.channel, Thread):
+            thread_id = self.channel.id
 
         if delay is not None:
 
             async def inner_call(delay: float = delay):
                 await asyncio.sleep(delay)
                 try:
-                    await self._state._webhook.delete_message(self.id)
+                    await self._state._webhook.delete_message(self.id, thread_id=thread_id)
                 except HTTPException:
                     pass
 
             asyncio.create_task(inner_call())
         else:
-            await self._state._webhook.delete_message(self.id)
+            await self._state._webhook.delete_message(self.id, thread_id=thread_id)
 
 
 class BaseWebhook(Hashable):
@@ -1494,7 +1508,11 @@ async def fetch_message(
             session=self.session,
             thread_id=thread_id,
         )
-        return self._create_message(data)
+        msg = self._create_message(data)
+        if isinstance(msg.channel, PartialMessageable):
+            msg._thread_id = thread_id
+        
+        return msg
 
     async def edit_message(
         self,
@@ -1595,7 +1613,7 @@ async def edit_message(
         )
 
         thread_id: Optional[int] = None
-        if thread_id is not MISSING:
+        if thread is not MISSING:
             thread_id = thread.id
 
         adapter = async_context.get()
diff --git a/discord/webhook/sync.py b/discord/webhook/sync.py
--- a/discord/webhook/sync.py
+++ b/discord/webhook/sync.py
@@ -45,6 +45,8 @@
 from ..message import Message
 from ..http import Route
 from ..channel import PartialMessageable
+from ..threads import Thread
+from ..object import Object
 
 from .async_ import BaseWebhook, handle_message_parameters, _WebhookState
 
@@ -441,6 +443,12 @@ def edit(
         :class:`SyncWebhookMessage`
             The newly edited message.
         """
+        thread = MISSING
+        if hasattr(self, '_thread_id'):
+            thread = Object(self._thread_id)
+        elif isinstance(self.channel, Thread):
+            thread = Object(self.channel.id)
+
         return self._state._webhook.edit_message(
             self.id,
             content=content,
@@ -449,6 +457,7 @@ def edit(
             file=file,
             files=files,
             allowed_mentions=allowed_mentions,
+            thread=thread
         )
 
     def delete(self, *, delay: Optional[float] = None) -> None:
@@ -470,9 +479,16 @@ def delete(self, *, delay: Optional[float] = None) -> None:
             Deleting the message failed.
         """
 
+        thread_id: Optional[int] = None
+        if hasattr(self, '_thread_id'):
+            thread_id = self._thread_id
+        elif isinstance(self.channel, Thread):
+            thread_id = self.channel.id
+
         if delay is not None:
             time.sleep(delay)
-        self._state._webhook.delete_message(self.id)
+
+        self._state._webhook.delete_message(self.id, thread_id=thread_id)
 
 
 class SyncWebhook(BaseWebhook):
@@ -796,6 +812,7 @@ def send(
         embed: Embed = MISSING,
         embeds: List[Embed] = MISSING,
         allowed_mentions: AllowedMentions = MISSING,
+        thread: Snowflake = MISSING,
         wait: Literal[True],
     ) -> SyncWebhookMessage:
         ...
@@ -813,6 +830,7 @@ def send(
         embed: Embed = MISSING,
         embeds: List[Embed] = MISSING,
         allowed_mentions: AllowedMentions = MISSING,
+        thread: Snowflake = MISSING,
         wait: Literal[False] = ...,
     ) -> None:
         ...
@@ -983,7 +1001,11 @@ def fetch_message(
             session=self.session,
             thread_id=thread_id,
         )
-        return self._create_message(data)
+        msg = self._create_message(data)
+        if isinstance(msg.channel, PartialMessageable):
+            msg._thread_id = thread_id
+        
+        return msg
 
     def edit_message(
         self,


Test patch: