Repository: hikari-py/hikari
Pull request #637 (2021-06-01 18:11:37)

Add channel methods
### Summary
This pr adds the methods specified #35

### Checklist
- [x] I have run `nox` and all the pipelines have passed.
- [x] I have made unittests according to the code I have added/modified/deleted.

### Related issues
#35
<!--
To mention an issue use `#issue-id` and to mention a merge request use `!merge-request-id`
To close/fix an issue use `Close #issue-id` or `Fix #issue-id` (depending on the merge request)
-->


FasterSpeeding: Needs rebasing but otherwise LGTM
ashwinvin: Rebased everything. 

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 17a4942f..671aaaf9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -165,10 +165,22 @@ jobs:
           retention-days: 2
           if-no-files-found: error
 
+  # This job is only used to mark the CI as being done
+  #
+  # Allows us to add this as a required check in Github branch rules, as all the
+  # other jobs are subject to change
+  ci-done:
+    needs: [upload-coverage, linting, twemoji, pages]
+
+    runs-on: ubuntu-20.04
+
+    steps:
+      - name: Completed
+        run: echo "CI Completed"
+
   deploy:
-    # Only run on releases and if everything passes
     if: github.event_name == 'release'
-    needs: [upload-coverage, linting, twemoji, pages]
+    needs: [ci-done]
 
     runs-on: ubuntu-20.04
 
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index b4097697..e541e35a 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
 ## Enforcement
 
 Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at nekoka.tt@outlook.com. All
+reported by contacting the project team at davfsa@gmail.com. All
 complaints will be reviewed and investigated and will result in a response that
 is deemed necessary and appropriate to the circumstances. The project team is
 obligated to maintain confidentiality with regard to the reporter of an incident.
diff --git a/README.md b/README.md
index 1a59a4cc..a7a99a16 100644
--- a/README.md
+++ b/README.md
@@ -176,9 +176,9 @@ and `ciso8601`, which will provide you with a small performance boost.
 
 ### `uvloop`
 
-**If you use Linux**, you will get additional performance benefits from using
-a library called `uvloop`. This replaces the default `asyncio` event loop with
-one that uses `libuv` internally. You can run `pip install uvloop` and then
+**If you use a UNIX-like system**, you will get additional performance benefits
+from using a library called `uvloop`. This replaces the default `asyncio` event
+loop with one that uses `libuv` internally. You can run `pip install uvloop` and then
 amend your script to be something similar to the following example to utilise it
 in your application:
 
@@ -190,7 +190,7 @@ if os.name != "nt":
     import uvloop
     uvloop.install()
 
-bot = hikari.Bot(...)
+bot = hikari.BotApp(...)
 ...
 ```
 
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 5cddde4d..e2fc684a 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -28,7 +28,7 @@ sphobjinv==2.1
 # TYPE CHECKING #
 #################
 
-mypy==0.902
+mypy==0.910
 
 #######################
 # DEPENDENCY CHECKING #
@@ -41,4 +41,4 @@ safety~=1.10.3
 #############
 
 black==21.6b0
-isort==5.8.0
+isort==5.9.1
diff --git a/flake8-requirements.txt b/flake8-requirements.txt
index 237167f6..cbda3c18 100644
--- a/flake8-requirements.txt
+++ b/flake8-requirements.txt
@@ -22,6 +22,6 @@ flake8-mutable==1.2.0                   # mutable default argument detection
 flake8-pep3101==1.3.0                   # new-style format strings only
 flake8-print==4.0.0                     # complain about print statements in code
 flake8-printf-formatting==1.1.2         # forbey printf-style python2 string formatting
-flake8-pytest-style==1.4.2              # pytest checks
+flake8-pytest-style==1.5.0              # pytest checks
 flake8-raise==0.0.5                     # exception raising linting
 flake8-use-fstring==1.1                 # format string checking
diff --git a/hikari/api/event_manager.py b/hikari/api/event_manager.py
index 90a0c2c2..6208ba1e 100644
--- a/hikari/api/event_manager.py
+++ b/hikari/api/event_manager.py
@@ -161,7 +161,7 @@ async def on_everyone_mentioned(event):
     # For the sake of UX, I will check this at runtime instead and let the
     # user use a static type checker.
     @abc.abstractmethod
-    def subscribe(self, event_type: typing.Type[typing.Any], callback: CallbackT[typing.Any]) -> CallbackT[typing.Any]:
+    def subscribe(self, event_type: typing.Type[typing.Any], callback: CallbackT[typing.Any]) -> None:
         """Subscribe a given callback to a given event type.
 
         Parameters
@@ -189,11 +189,6 @@ async def on_message(event):
         bot.subscribe(MessageCreateEvent, on_message)
         ```
 
-        Returns
-        -------
-        typing.Callable[[T], typing.Coroutine[typing.Any, typing.Any, builtins.None]
-            The event callback that was passed in.
-
         See Also
         --------
         Listen: `hikari.api.event_manager.EventManager.listen`
diff --git a/hikari/api/rest.py b/hikari/api/rest.py
index 34f53d53..b24f1b09 100644
--- a/hikari/api/rest.py
+++ b/hikari/api/rest.py
@@ -513,7 +513,7 @@ async def edit_permission_overwrites(
         channel: snowflakes.SnowflakeishOr[channels_.GuildChannel],
         target: snowflakes.Snowflakeish,
         *,
-        target_type: channels_.PermissionOverwriteType,
+        target_type: typing.Union[channels_.PermissionOverwriteType, int],
         allow: undefined.UndefinedOr[permissions_.Permissions] = undefined.UNDEFINED,
         deny: undefined.UndefinedOr[permissions_.Permissions] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
@@ -528,7 +528,7 @@ async def edit_permission_overwrites(
             snowflakes.Snowflakeish, users.PartialUser, guilds.PartialRole, channels_.PermissionOverwrite
         ],
         *,
-        target_type: undefined.UndefinedOr[channels_.PermissionOverwriteType] = undefined.UNDEFINED,
+        target_type: undefined.UndefinedOr[typing.Union[channels_.PermissionOverwriteType, int]] = undefined.UNDEFINED,
         allow: undefined.UndefinedOr[permissions_.Permissions] = undefined.UNDEFINED,
         deny: undefined.UndefinedOr[permissions_.Permissions] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
@@ -546,7 +546,7 @@ async def edit_permission_overwrites(
 
         Other Parameters
         ----------------
-        target_type : hikari.undefined.UndefinedOr[hikari.channels.PermissionOverwriteType]
+        target_type : hikari.undefined.UndefinedOr[typing.Union[hikari.channels.PermissionOverwriteType, int]]
             If provided, the type of the target to update. If unset, will attempt to get
             the type from `target`.
         allow : hikari.undefined.UndefinedOr[hikari.permissions.Permissions]
@@ -1053,6 +1053,7 @@ async def create_message(
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -1079,9 +1080,9 @@ async def create_message(
             in the content. Any other value here will be cast to a
             `builtins.str`.
 
-            If this is a `hikari.embeds.Embed` and no `embed` kwarg is
-            provided, then this will instead update the embed. This allows for
-            simpler syntax when sending an embed alone.
+            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
+            is provided, then this will instead update the embed. This allows
+            for simpler syntax when sending an embed alone.
 
             Likewise, if this is a `hikari.files.Resource`, then the
             content is instead treated as an attachment if no `attachment` and
@@ -1091,6 +1092,8 @@ async def create_message(
         ----------------
         embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
             If provided, the message embed.
+        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
+            If provided, the message embeds.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
             If provided, the message attachment. This can be a resource,
             or string of a path on your computer or a URL.
@@ -1177,10 +1180,8 @@ async def create_message(
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
             limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content; if `reply` is
-            not found or not in the same channel as `channel`.
+            invalid image URLs in embeds; if `reply` is ot found or not in the
+            same channel as `channel`.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.ForbiddenError
@@ -1259,6 +1260,7 @@ async def edit_message(
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
         embed: undefined.UndefinedNoneOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedNoneOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         replace_attachments: bool = False,
@@ -1289,8 +1291,9 @@ async def edit_message(
 
             Any other value will be cast to a `builtins.str` before sending.
 
-            If this is a `hikari.embeds.Embed` and no `embed` kwarg is
-            provided or if this is a `hikari.files.Resourceish` and neither the
+            If this is a `hikari.embeds.Embed` and neither the `embed` or
+            `embeds` kwargs are provided or if this is a
+            `hikari.files.Resourceish` and neither the
             `attachment` or `attachments` kwargs are provided, the values will
             be overwritten. This allows for simpler syntax when sending an
             embed or an attachment alone.
@@ -1299,10 +1302,16 @@ async def edit_message(
         ----------------
         embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed]
             If provided, the embed to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous embed, if
-            present, is not changed. If this is `builtins.None`, then the embed
-            is removed, if present. Otherwise, the new embed that was provided
-            will be used as the replacement.
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embed that was provided will be used as the
+            replacement.
+        embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]]
+            If provided, the embeds to set on the message. If
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embeds that were provided will be used as the
+            replacement.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish]
             If provided, the attachment to set on the message. If
             `hikari.undefined.UNDEFINED`, the previous attachment, if
@@ -1398,9 +1407,7 @@ async def edit_message(
             This may be raised in several discrete situations, such as messages
             being empty with no embeds; messages with more than 2000 characters
             in them, embeds that exceed one of the many embed
-            limits; invalid image URLs in embeds; users in `user_mentions` not
-            being mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content.
+            limits; invalid image URLs in embeds.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.ForbiddenError
@@ -2162,7 +2169,7 @@ async def execute_webhook(
         ----------------
         embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
             If provided, the message embed.
-        embeds : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
+        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the message embeds.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
             If provided, the message attachment. This can be a resource,
@@ -2244,9 +2251,7 @@ async def execute_webhook(
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
             limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content.
+            invalid image URLs in embeds.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.NotFoundError
@@ -2363,16 +2368,16 @@ async def edit_webhook_message(
         ----------------
         embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed]
             If provided, the embed to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous embed, if
-            present, is not changed. If this is `builtins.None`, then the embed
-            is removed, if present. Otherwise, the new embed that was provided
-            will be used as the replacement.
-        embeds : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed]
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embed that was provided will be used as the
+            replacement.
+        embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the embeds to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous embeds if
-            present are not changed. If this is `builtins.None`, then the embeds
-            are removed ,if present. Otherwise, the new embeds that were provided
-            will be used as the replacement.
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embeds that were provided will be used as the
+            replacement.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish]
             If provided, the attachment to set on the message. If
             `hikari.undefined.UNDEFINED`, the previous attachment, if
@@ -2453,9 +2458,7 @@ async def edit_webhook_message(
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
             limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content.
+            invalid image URLs in embeds.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.NotFoundError
diff --git a/hikari/channels.py b/hikari/channels.py
index d0c748fd..30cad18c 100644
--- a/hikari/channels.py
+++ b/hikari/channels.py
@@ -61,14 +61,16 @@
 if typing.TYPE_CHECKING:
     import datetime
 
-    from hikari import embeds
+    from hikari import embeds as embeds_
     from hikari import files
     from hikari import guilds
     from hikari import iterators
     from hikari import messages
     from hikari import users
+    from hikari import voices
     from hikari import webhooks
     from hikari.api import special_endpoints
+    from hikari.internal import time
 
 
 @typing.final
@@ -287,7 +289,7 @@ class PermissionOverwrite(snowflakes.Unique):
     )
     """The ID of this entity."""
 
-    type: typing.Union[PermissionOverwriteType, str] = attr.field(
+    type: typing.Union[PermissionOverwriteType, int] = attr.field(
         converter=PermissionOverwriteType, hash=True, repr=True
     )
     """The type of entity this overwrite targets."""
@@ -338,6 +340,42 @@ class PartialChannel(snowflakes.Unique):
     def __str__(self) -> str:
         return self.name if self.name is not None else f"Unnamed {self.__class__.__name__} ID {self.id}"
 
+    async def delete(self) -> PartialChannel:
+        """Delete a channel in a guild, or close a DM.
+
+        Returns
+        -------
+        hikari.channels.PartialChannel
+            Object of the channel that was deleted.
+
+        Raises
+        ------
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `MANAGE_CHANNEL` permission in the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+
+        !!! note
+            For Public servers, the set 'Rules' or 'Guidelines' channels and the
+            'Public Server Updates' channel cannot be deleted.
+        """
+        return await self.app.rest.delete_channel(self.id)
+
 
 class TextChannel(PartialChannel, abc.ABC):
     """A channel that can have text messages in it."""
@@ -346,7 +384,7 @@ class TextChannel(PartialChannel, abc.ABC):
     __slots__: typing.Sequence[str] = ()
 
     # TODO: add examples to this and the REST method this invokes.
-    def history(
+    def fetch_history(
         self,
         *,
         before: undefined.UndefinedOr[snowflakes.SearchableSnowflakeishOr[snowflakes.Unique]] = undefined.UNDEFINED,
@@ -400,11 +438,51 @@ def history(
         """  # noqa: E501 - Line too long
         return self.app.rest.fetch_messages(self.id, before=before, after=after, around=around)
 
+    async def fetch_message(self, message: snowflakes.SnowflakeishOr[messages.PartialMessage]) -> messages.Message:
+        """Fetch a specific message in the given text channel.
+
+        Parameters
+        ----------
+        message : hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]
+            The message to fetch. This may be the object or the ID of an
+            existing channel.
+
+        Returns
+        -------
+        hikari.messages.Message
+            The requested message.
+
+        Raises
+        ------
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `READ_MESSAGE_HISTORY` in the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found or the message is not found in the
+            given text channel.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """
+        return await self.app.rest.fetch_message(self.id, message)
+
     async def send(
         self,
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
-        embed: undefined.UndefinedOr[embeds.Embed] = undefined.UNDEFINED,
+        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
@@ -429,9 +507,9 @@ async def send(
             in the content. Any other value here will be cast to a
             `builtins.str`.
 
-            If this is a `hikari.embeds.Embed` and no `embed` kwarg is
-            provided, then this will instead update the embed. This allows for
-            simpler syntax when sending an embed alone.
+            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
+            is provided, then this will instead update the embed. This allows
+            for simpler syntax when sending an embed alone.
 
             Likewise, if this is a `hikari.files.Resource`, then the
             content is instead treated as an attachment if no `attachment` and
@@ -441,6 +519,8 @@ async def send(
         ----------------
         embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
             If provided, the message embed.
+        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
+            If provided, the message embeds.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
             If provided, the message attachment. This can be a resource,
             or string of a path on your computer or a URL.
@@ -516,10 +596,8 @@ async def send(
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
             limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content; `reply` not found
-            or not in the same channel.
+            invalid image URLs in embeds; `reply` not found or not in the same
+            channel.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.ForbiddenError
@@ -538,6 +616,7 @@ async def send(
             channel=self.id,
             content=content,
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce=nonce,
@@ -575,6 +654,159 @@ def trigger_typing(self) -> special_endpoints.TypingIndicator:
         """
         return self.app.rest.trigger_typing(self.id)
 
+    async def fetch_pins(self) -> typing.Sequence[messages.Message]:
+        """Fetch the pinned messages in this text channel.
+
+        Returns
+        -------
+        typing.Sequence[hikari.messages.Message]
+            The pinned messages in this text channel.
+
+        Raises
+        ------
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `READ_MESSAGES` in the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """
+        return await self.app.rest.fetch_pins(self.id)
+
+    async def pin_message(self, message: snowflakes.SnowflakeishOr[messages.PartialMessage]) -> None:
+        """Pin an existing message in the text channel.
+
+        Parameters
+        ----------
+        message : hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]
+            The message to pin. This may be the object or the ID
+            of an existing message.
+
+        Raises
+        ------
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `MANAGE_MESSAGES` in the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found, or if the message does not exist in
+            the given channel.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """
+        return await self.app.rest.pin_message(self.id, message)
+
+    async def unpin_message(self, message: snowflakes.SnowflakeishOr[messages.PartialMessage]) -> None:
+        """Unpin a given message from the text channel.
+
+        Parameters
+        ----------
+        message : hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]
+            The message to unpin. This may be the object or the ID of an
+            existing message.
+
+        Raises
+        ------
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `MANAGE_MESSAGES` permission.
+        hikari.errors.NotFoundError
+            If the channel is not found or the message is not a pinned message
+            in the given channel.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """
+        return await self.app.rest.unpin_message(self.id, message)
+
+    async def delete_messages(
+        self,
+        messages: typing.Union[
+            snowflakes.SnowflakeishOr[messages.PartialMessage],
+            snowflakes.SnowflakeishIterable[messages.PartialMessage],
+        ],
+        /,
+        *other_messages: snowflakes.SnowflakeishOr[messages.PartialMessage],
+    ) -> None:
+        """Bulk-delete messages from the channel.
+
+        Parameters
+        ----------
+        messages : typing.Union[hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage], hikari.snowflakes.SnowflakeishIterable[hikari.messages.PartialMessage]]
+            Either the object/ID of an existing message to delete or an iterable
+            of the objects and/or IDs of existing messages to delete.
+
+        Other Parameters
+        ----------------
+        *other_messages : hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]
+            The objects and/or IDs of other existing messages to delete.
+
+        !!! note
+            This API endpoint will only be able to delete 100 messages
+            at a time. For anything more than this, multiple requests will
+            be executed one-after-the-other, since the rate limits for this
+            endpoint do not favour more than one request per bucket.
+
+            If one message is left over from chunking per 100 messages, or
+            only one message is passed to this coroutine function, then the
+            logic is expected to defer to `delete_message`. The implication
+            of this is that the `delete_message` endpoint is ratelimited
+            by a different bucket with different usage rates.
+
+        !!! warning
+            This endpoint is not atomic. If an error occurs midway through
+            a bulk delete, you will **not** be able to revert any changes made
+            up to this point.
+
+        !!! warning
+            Specifying any messages more than 14 days old will cause the call
+            to fail, potentially with partial completion.
+
+        Raises
+        ------
+        hikari.errors.BulkDeleteError
+            An error containing the messages successfully deleted, and the
+            messages that were not removed. The
+            `builtins.BaseException.__cause__` of the exception will be the
+            original error that terminated this process.
+        """  # noqa: E501 - Line too long
+        return await self.app.rest.delete_messages(self.id, messages, *other_messages)
+
 
 @attr.define(hash=True, kw_only=True, weakref_slot=False)
 class PrivateChannel(PartialChannel):
@@ -739,6 +971,247 @@ def shard_id(self) -> typing.Optional[int]:
 
         return None
 
+    async def fetch_guild(self) -> guilds.PartialGuild:
+        """Fetch the guild linked to this channel.
+
+        Parameters
+        ----------
+        guild : hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]
+            The guild to fetch. This can be the object
+            or the ID of an existing guild.
+
+        Returns
+        -------
+        hikari.guilds.RESTGuild
+            The requested guild.
+
+        Raises
+        ------
+        hikari.errors.ForbiddenError
+            If you are not part of the guild.
+        hikari.errors.NotFoundError
+            If the guild is not found.
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """
+        return await self.app.rest.fetch_guild(self.guild_id)
+
+    async def edit_overwrite(
+        self,
+        target: typing.Union[snowflakes.Snowflakeish, users.PartialUser, guilds.PartialRole, PermissionOverwrite],
+        *,
+        target_type: undefined.UndefinedOr[typing.Union[PermissionOverwriteType, int]] = undefined.UNDEFINED,
+        allow: undefined.UndefinedOr[permissions.Permissions] = undefined.UNDEFINED,
+        deny: undefined.UndefinedOr[permissions.Permissions] = undefined.UNDEFINED,
+        reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
+    ) -> None:
+        """Edit permissions for a specific entity in the given guild channel.
+
+           This creates new overwrite for the channel, if there no other overwrites present.
+
+        Parameters
+        ----------
+        target : typing.Union[hikari.users.PartialUser, hikari.guilds.PartialRole, hikari.channels.PermissionOverwrite, hikari.snowflakes.Snowflakeish]
+            The channel overwrite to edit. This may be the object or the ID of an
+            existing overwrite.
+
+        Other Parameters
+        ----------------
+        target_type : hikari.undefined.UndefinedOr[typing.Union[hikari.channels.PermissionOverwriteType, int]]
+            If provided, the type of the target to update. If unset, will attempt to get
+            the type from `target`.
+        allow : hikari.undefined.UndefinedOr[hikari.permissions.Permissions]
+            If provided, the new vale of all allowed permissions.
+        deny : hikari.undefined.UndefinedOr[hikari.permissions.Permissions]
+            If provided, the new vale of all disallowed permissions.
+        reason : hikari.undefined.UndefinedOr[builtins.str]
+            If provided, the reason that will be recorded in the audit logs.
+            Maximum of 512 characters.
+
+        Raises
+        ------
+        builtins.TypeError
+            If `target_type` is unset and we were unable to determine the type
+            from `target`.
+        hikari.errors.BadRequestError
+            If any of the fields that are passed have an invalid value.
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `MANAGE_PERMISSIONS` permission in the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found or the target is not found if it is
+            a role.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """  # noqa: E501 - Line too long
+        if target_type is undefined.UNDEFINED:
+            assert not isinstance(
+                target, int
+            ), "Cannot determine the type of the target to update. Try specifying 'target_type' manually."
+            return await self.app.rest.edit_permission_overwrites(
+                self.id, target, allow=allow, deny=deny, reason=reason
+            )
+
+        return await self.app.rest.edit_permission_overwrites(
+            self.id, typing.cast(int, target), target_type=target_type, allow=allow, deny=deny, reason=reason
+        )
+
+    async def remove_overwrite(
+        self,
+        target: snowflakes.SnowflakeishOr[
+            typing.Union[PermissionOverwrite, guilds.PartialRole, users.PartialUser, snowflakes.Snowflakeish]
+        ],
+    ) -> None:
+        """Delete a custom permission for an entity in a given guild channel.
+
+        Parameters
+        ----------
+        target : typing.Union[hikari.users.PartialUser, hikari.guilds.PartialRole, hikari.channels.PermissionOverwrite, hikari.snowflakes.Snowflakeish]
+            The channel overwrite to delete.
+
+        Raises
+        ------
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing the `MANAGE_PERMISSIONS` permission in the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found or the target is not found.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """  # noqa: E501 - Line too long
+        return await self.app.rest.delete_permission_overwrite(self.id, target)
+
+    async def edit(
+        self,
+        *,
+        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
+        position: undefined.UndefinedOr[int] = undefined.UNDEFINED,
+        topic: undefined.UndefinedOr[str] = undefined.UNDEFINED,
+        nsfw: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
+        bitrate: undefined.UndefinedOr[int] = undefined.UNDEFINED,
+        video_quality_mode: undefined.UndefinedOr[typing.Union[VideoQualityMode, int]] = undefined.UNDEFINED,
+        user_limit: undefined.UndefinedOr[int] = undefined.UNDEFINED,
+        rate_limit_per_user: undefined.UndefinedOr[time.Intervalish] = undefined.UNDEFINED,
+        region: undefined.UndefinedOr[voices.VoiceRegionish] = undefined.UNDEFINED,
+        permission_overwrites: undefined.UndefinedOr[typing.Sequence[PermissionOverwrite]] = undefined.UNDEFINED,
+        parent_category: undefined.UndefinedOr[snowflakes.SnowflakeishOr[GuildCategory]] = undefined.UNDEFINED,
+        reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
+    ) -> PartialChannel:
+        """Edit the text channel.
+
+        Other Parameters
+        ----------------
+        name : hikari.undefined.UndefinedOr[[builtins.str]
+            If provided, the new name for the channel.
+        position : hikari.undefined.UndefinedOr[[builtins.int]
+            If provided, the new position for the channel.
+        topic : hikari.undefined.UndefinedOr[builtins.str]
+            If provided, the new topic for the channel.
+        nsfw : hikari.undefined.UndefinedOr[builtins.bool]
+            If provided, whether the channel should be marked as NSFW or not.
+        bitrate : hikari.undefined.UndefinedOr[builtins.int]
+            If provided, the new bitrate for the channel.
+        video_quality_mode: hikari.undefined.UndefinedOr[typing.Union[hikari.channels.VideoQualityMode, builtins.int]]
+            If provided, the new video quality mode for the channel.
+        user_limit : hikari.undefined.UndefinedOr[builtins.int]
+            If provided, the new user limit in the channel.
+        rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
+            If provided, the new rate limit per user in the channel.
+        region : hikari.undefined.UndefinedOr[hikari.voices.VoiceRegionish]
+            If provided, the voice region to set for this channel. Passing
+            `builtins.None` here will set it to "auto" mode where the used
+            region will be decided based on the first person who connects to it
+            when it's empty.
+        permission_overwrites : hikari.undefined.UndefinedOr[typing.Sequence[hikari.channels.PermissionOverwrite]]
+            If provided, the new permission overwrites for the channel.
+        parent_category : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildCategory]]
+            If provided, the new guild category for the channel.
+        reason : hikari.undefined.UndefinedOr[builtins.str]
+            If provided, the reason that will be recorded in the audit logs.
+            Maximum of 512 characters.
+
+        Returns
+        -------
+        hikari.channels.PartialChannel
+            The edited channel.
+
+        Raises
+        ------
+        hikari.errors.BadRequestError
+            If any of the fields that are passed have an invalid value.
+        hikari.errors.UnauthorizedError
+            If you are unauthorized to make the request (invalid/missing token).
+        hikari.errors.ForbiddenError
+            If you are missing permissions to edit the channel.
+        hikari.errors.NotFoundError
+            If the channel is not found.
+        hikari.errors.RateLimitTooLongError
+            Raised in the event that a rate limit occurs that is
+            longer than `max_rate_limit` when making a request.
+        hikari.errors.RateLimitedError
+            Usually, Hikari will handle and retry on hitting
+            rate-limits automatically. This includes most bucket-specific
+            rate-limits and global rate-limits. In some rare edge cases,
+            however, Discord implements other undocumented rules for
+            rate-limiting, such as limits per attribute. These cannot be
+            detected or handled normally by Hikari due to their undocumented
+            nature, and will trigger this exception if they occur.
+        hikari.errors.InternalServerError
+            If an internal error occurs on Discord while handling the request.
+        """  # noqa: E501 - Line too long
+        return await self.app.rest.edit_channel(
+            self.id,
+            name=name,
+            position=position,
+            topic=topic,
+            nsfw=nsfw,
+            bitrate=bitrate,
+            video_quality_mode=video_quality_mode,
+            user_limit=user_limit,
+            rate_limit_per_user=rate_limit_per_user,
+            region=region,
+            permission_overwrites=permission_overwrites,
+            parent_category=parent_category,
+            reason=reason,
+        )
+
 
 @attr.define(hash=True, kw_only=True, weakref_slot=False)
 class GuildCategory(GuildChannel):
diff --git a/hikari/errors.py b/hikari/errors.py
index 68942432..f3ee80d7 100644
--- a/hikari/errors.py
+++ b/hikari/errors.py
@@ -313,6 +313,12 @@ class RESTErrorCode(int, enums.Enum):
     MAXIMUM_INVITES = 30_016
     """Maximum number of invites reached (1000)."""
 
+    MAXIMUM_ANIMATED_EMOJIS = 30_018
+    """Maximum number of animated emojis reached."""
+
+    MAXIMUM_NUMBER_OF_SERVER_MEMBERS_REACHED = 30_019
+    """Maximum number of server members reached."""
+
     GUILD_ALREADY_HAS_TEMPLATE = 30_031
     """Guild already has a template."""
 
diff --git a/hikari/files.py b/hikari/files.py
index 2b17562f..c027eccd 100644
--- a/hikari/files.py
+++ b/hikari/files.py
@@ -174,17 +174,17 @@ def ensure_resource(url_or_resource: Resourceish, /) -> Resource[AsyncReader]:
 
     Returns
     -------
-    typing.Optional[Resource]
-        The resource to use, or `builtins.None` if `builtins.None` was input.
+    Resource
+        The resource to use.
     """
+    if isinstance(url_or_resource, Resource):
+        return url_or_resource
+
     if isinstance(url_or_resource, RAWISH_TYPES):
         data = unwrap_bytes(url_or_resource)
         filename = generate_filename_from_details(mimetype=None, extension=None, data=data)
         return typing.cast("Resource[AsyncReader]", Bytes(data, filename))
 
-    if isinstance(url_or_resource, Resource):
-        return url_or_resource
-
     url_or_resource = str(url_or_resource)
 
     if url_or_resource.startswith(("https://", "http://")):
@@ -953,7 +953,7 @@ async def __aiter__(self) -> typing.AsyncGenerator[typing.Any, bytes]:
     async def _wrap_iter(self) -> typing.AsyncGenerator[typing.Any, bytes]:
         if isinstance(self.data, bytes):
             for i in range(0, len(self.data), _MAGIC):
-                yield self.data[i : i + _MAGIC]  # noqa: E203
+                yield self.data[i : i + _MAGIC]  # noqa: E203 - Whitespace before ":"
 
         elif aio.is_async_iterator(self.data) or inspect.isasyncgen(self.data):
             try:
diff --git a/hikari/guilds.py b/hikari/guilds.py
index c5c84638..3eccca5e 100644
--- a/hikari/guilds.py
+++ b/hikari/guilds.py
@@ -161,6 +161,15 @@ class GuildFeature(str, enums.Enum):
     PREVIEW_ENABLED = "PREVIEW_ENABLED"
     """Guild can be viewed before Membership Screening is complete."""
 
+    TICKETED_EVENTS_ENABLED = "TICKETED_EVENTS_ENABLED"
+    """Guild has enabled ticketed events."""
+
+    MONETIZATION_ENABLED = "MONETIZATION_ENABLED"
+    """Guild has enabled monetization."""
+
+    MORE_STICKERS = "MONETIZATION_ENABLED"
+    """Guild has an increased custom stickers slots."""
+
 
 GuildFeatureish = typing.Union[str, GuildFeature]
 """Type hint for possible guild features.
diff --git a/hikari/impl/bot.py b/hikari/impl/bot.py
index ab839623..e35fafa0 100644
--- a/hikari/impl/bot.py
+++ b/hikari/impl/bot.py
@@ -213,6 +213,7 @@ class BotApp(traits.BotAware):
     __slots__: typing.Sequence[str] = (
         "_cache",
         "_closing_event",
+        "_closed_event",
         "_entity_factory",
         "_event_manager",
         "_event_factory",
@@ -250,6 +251,7 @@ def __init__(
 
         # Settings and state
         self._closing_event: typing.Optional[asyncio.Event] = None
+        self._closed_event: typing.Optional[asyncio.Event] = None
         self._is_alive = False
         self._executor = executor
         self._http_settings = http_settings if http_settings is not None else config.HTTPSettings()
@@ -356,25 +358,30 @@ def _check_if_alive(self) -> None:
         if not self._is_alive:
             raise errors.ComponentStateConflictError("bot is not running so it cannot be interacted with")
 
-    async def close(self, force: bool = True) -> None:
+    async def close(self) -> None:
         """Kill the application by shutting all components down."""
-        if self._closing_event and not self._closing_event.is_set():
-            _LOGGER.debug("bot requested to shutdown [force:%s]", force)
-            self._closing_event.set()
+        self._check_if_alive()
+
+        if self._closed_event:  # Closing is in progress from another call, wait for that to complete.
+            await self._closed_event.wait()
+            return
 
-        if not self._closing_event or not force:  # If closing event is None then this is already closing.
+        if self._closing_event is None:  # If closing event is None then this is already closed.
             return
 
+        _LOGGER.debug("bot requested to shutdown")
+        self._closed_event = asyncio.Event()
+        self._closing_event.set()
         self._closing_event = None
 
+        loop = asyncio.get_running_loop()
+
         async def handle(name: str, awaitable: typing.Awaitable[typing.Any]) -> None:
             future = asyncio.ensure_future(awaitable)
 
             try:
                 await future
             except Exception as ex:
-                loop = asyncio.get_running_loop()
-
                 loop.call_exception_handler(
                     {
                         "message": f"{name} raised an exception during shutdown",
@@ -396,15 +403,14 @@ async def handle(name: str, awaitable: typing.Awaitable[typing.Any]) -> None:
         for coro in asyncio.as_completed([handle(*pair) for pair in calls]):
             await coro
 
-        # Join any shards until they finish
-        await aio.all_of(*(s.join() for s in self._shards.values()), timeout=len(self._shards))
-
         # Clear out cache and shard map
         self._cache.clear()
         self._shards.clear()
         self._is_alive = False
 
         await self._event_manager.dispatch(self._event_factory.deserialize_stopped_event())
+        self._closed_event.set()
+        self._closed_event = None
 
     def dispatch(self, event: event_manager_.EventT_inv) -> asyncio.Future[typing.Any]:
         return self._event_manager.dispatch(event)
@@ -574,7 +580,7 @@ def run(
         if shard_ids is not None and shard_count is None:
             raise TypeError("'shard_ids' must be passed with 'shard_count'")
 
-        loop = asyncio.get_event_loop()
+        loop = aio.get_or_make_loop()
         signals = ("SIGINT", "SIGTERM")
 
         if asyncio_debug:
@@ -862,10 +868,8 @@ def stream(
         self._check_if_alive()
         return self._event_manager.stream(event_type, timeout=timeout, limit=limit)
 
-    def subscribe(
-        self, event_type: typing.Type[typing.Any], callback: event_manager_.CallbackT[typing.Any]
-    ) -> event_manager_.CallbackT[typing.Any]:
-        return self._event_manager.subscribe(event_type, callback)
+    def subscribe(self, event_type: typing.Type[typing.Any], callback: event_manager_.CallbackT[typing.Any]) -> None:
+        self._event_manager.subscribe(event_type, callback)
 
     def unsubscribe(self, event_type: typing.Type[typing.Any], callback: event_manager_.CallbackT[typing.Any]) -> None:
         self._event_manager.unsubscribe(event_type, callback)
@@ -941,7 +945,7 @@ async def _set_close_flag(self, signame: str, signum: int) -> None:
         # solution.
         _LOGGER.debug("received interrupt %s (%s), will start shutting down shortly", signame, signum)
 
-        await self.close(force=False)
+        await self.close()
 
     async def _start_one_shard(
         self,
@@ -1025,6 +1029,8 @@ async def murder(future: asyncio.Future[typing.Any]) -> None:
 
         _LOGGER.debug("closing event loop")
         loop.close()
+        # Closed loops cannot be re-used so it should also be un-set.
+        asyncio.set_event_loop(None)
 
     @staticmethod
     def _validate_activity(activity: undefined.UndefinedNoneOr[presences.Activity]) -> None:
diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py
index 6bb69b5a..8f876965 100644
--- a/hikari/impl/entity_factory.py
+++ b/hikari/impl/entity_factory.py
@@ -1739,6 +1739,10 @@ def deserialize_partial_message(  # noqa CFQ001 - Function too long
         if "stickers" in payload:
             stickers = [self._deserialize_sticker(sticker) for sticker in payload["stickers"]]
 
+        content = payload.get("content", undefined.UNDEFINED)
+        if content is not undefined.UNDEFINED:
+            content = content or None  # Default to None if content is an empty string
+
         message = message_models.PartialMessage(
             app=self._app,
             id=snowflakes.Snowflake(payload["id"]),
@@ -1746,14 +1750,14 @@ def deserialize_partial_message(  # noqa CFQ001 - Function too long
             guild_id=guild_id,
             author=author,
             member=member,
-            content=payload["content"] if "content" in payload else undefined.UNDEFINED,
+            content=content,
             timestamp=timestamp,
             edited_timestamp=edited_timestamp,
-            is_tts=payload["tts"] if "tts" in payload else undefined.UNDEFINED,
+            is_tts=payload.get("tts", undefined.UNDEFINED),
             attachments=attachments,
             embeds=embeds,
             reactions=reactions,
-            is_pinned=payload["pinned"] if "pinned" in payload else undefined.UNDEFINED,
+            is_pinned=payload.get("pinned", undefined.UNDEFINED),
             webhook_id=snowflakes.Snowflake(payload["webhook_id"]) if "webhook_id" in payload else undefined.UNDEFINED,
             type=message_models.MessageType(payload["type"]) if "type" in payload else undefined.UNDEFINED,
             activity=activity,
@@ -1762,7 +1766,7 @@ def deserialize_partial_message(  # noqa CFQ001 - Function too long
             referenced_message=referenced_message,
             flags=message_models.MessageFlag(payload["flags"]) if "flags" in payload else undefined.UNDEFINED,
             stickers=stickers,
-            nonce=payload["nonce"] if "nonce" in payload else undefined.UNDEFINED,
+            nonce=payload.get("nonce", undefined.UNDEFINED),
             # We initialize these next.
             mentions=NotImplemented,
         )
@@ -1850,7 +1854,7 @@ def deserialize_message(  # noqa CFQ001 - Function too long
             guild_id=guild_id,
             author=author,
             member=member,
-            content=payload["content"],
+            content=payload["content"] or None,
             timestamp=time.iso8601_datetime_string_to_datetime(payload["timestamp"]),
             edited_timestamp=edited_timestamp,
             is_tts=payload["tts"],
diff --git a/hikari/impl/event_manager_base.py b/hikari/impl/event_manager_base.py
index 33266a7f..f20220a7 100644
--- a/hikari/impl/event_manager_base.py
+++ b/hikari/impl/event_manager_base.py
@@ -97,7 +97,7 @@ def subscribe(
         callback: event_manager.CallbackT[event_manager.EventT_co],
         *,
         _nested: int = 0,
-    ) -> event_manager.CallbackT[event_manager.EventT_co]:
+    ) -> None:
         if not issubclass(event_type, base_events.Event):
             raise TypeError("Cannot subscribe to a non-Event type")
 
@@ -121,8 +121,6 @@ def subscribe(
 
         self._listeners[event_type].append(callback)  # type: ignore[arg-type]
 
-        return callback
-
     def _check_intents(self, event_type: typing.Type[event_manager.EventT_co], nested: int) -> None:
         # Collection of combined bitfield combinations of intents that
         # could be enabled to receive this event.
@@ -268,7 +266,7 @@ async def wait_for(
 
         self._check_intents(event_type, 1)
 
-        future: asyncio.Future[event_manager.EventT_co] = asyncio.get_event_loop().create_future()
+        future: asyncio.Future[event_manager.EventT_co] = asyncio.get_running_loop().create_future()
 
         try:
             waiter_set = self._waiters[event_type]
diff --git a/hikari/impl/rest.py b/hikari/impl/rest.py
index 77a01f4a..110a65cd 100644
--- a/hikari/impl/rest.py
+++ b/hikari/impl/rest.py
@@ -263,6 +263,9 @@ def proxy_settings(self) -> config.ProxySettings:
         return self._rest().proxy_settings
 
 
+_NONE_OR_UNDEFINED: typing.Final[typing.Set[undefined.UndefinedOr[None]]] = {None, undefined.UNDEFINED}
+
+
 class RESTApp(traits.ExecutorAware):
     """The base for a HTTP-only Discord application.
 
@@ -998,7 +1001,7 @@ async def edit_permission_overwrites(
             snowflakes.Snowflakeish, users.PartialUser, guilds.PartialRole, channels_.PermissionOverwrite
         ],
         *,
-        target_type: undefined.UndefinedOr[typing.Union[channels_.PermissionOverwriteType, str]] = undefined.UNDEFINED,
+        target_type: undefined.UndefinedOr[typing.Union[channels_.PermissionOverwriteType, int]] = undefined.UNDEFINED,
         allow: undefined.UndefinedOr[permissions_.Permissions] = undefined.UNDEFINED,
         deny: undefined.UndefinedOr[permissions_.Permissions] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
@@ -1148,38 +1151,42 @@ async def fetch_message(
         assert isinstance(response, dict)
         return self._entity_factory.deserialize_message(response)
 
-    async def create_message(
+    async def _create_message(
         self,
-        channel: snowflakes.SnowflakeishOr[channels_.TextChannel],
-        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
+        route: routes.CompiledRoute,
+        body: data_binding.JSONObjectBuilder,
+        query: typing.Optional[data_binding.StringMapBuilder] = None,
         *,
-        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
-        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
-        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
-        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
-        nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
-        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages_.PartialMessage]] = undefined.UNDEFINED,
-        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
-        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
-        user_mentions: undefined.UndefinedOr[
-            typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]
-        ] = undefined.UNDEFINED,
-        role_mentions: undefined.UndefinedOr[
-            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
-        ] = undefined.UNDEFINED,
+        content: undefined.UndefinedOr[typing.Any],
+        embed: undefined.UndefinedOr[embeds_.Embed],
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]],
+        attachment: undefined.UndefinedOr[files.Resourceish],
+        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]],
+        tts: undefined.UndefinedOr[bool],
+        mentions_everyone: undefined.UndefinedOr[bool],
+        mentions_reply: undefined.UndefinedOr[bool],
+        user_mentions: undefined.UndefinedOr[typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]],
+        role_mentions: undefined.UndefinedOr[typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]],
     ) -> messages_.Message:
         if not undefined.count(attachment, attachments):
             raise ValueError("You may only specify one of 'attachment' or 'attachments', not both")
 
-        if not isinstance(attachments, typing.Collection) and attachments is not undefined.UNDEFINED:
+        if not undefined.count(embed, embeds):
+            raise ValueError("You may only specify one of 'embed' or 'embeds', not both")
+
+        if attachments is not undefined.UNDEFINED and not isinstance(attachments, typing.Collection):
             raise ValueError(
                 "You passed a non-collection to 'attachments', but this expects a collection. Maybe you meant to "
                 "use 'attachment' (singular) instead?"
             )
 
-        route = routes.POST_CHANNEL_MESSAGES.compile(channel=channel)
+        if embeds is not undefined.UNDEFINED and not isinstance(embeds, typing.Collection):
+            raise TypeError(
+                "You passed a non collection to 'embeds', but this expects a collection. Maybe you meant to "
+                "use 'embed' (singular) instead?"
+            )
 
-        if embed is undefined.UNDEFINED and isinstance(content, embeds_.Embed):
+        if undefined.count(embed, embeds) == 2 and isinstance(content, embeds_.Embed):
             # Syntatic sugar, common mistake to accidentally send an embed
             # as the content, so lets detect this and fix it for the user.
             embed = content
@@ -1195,26 +1202,32 @@ async def create_message(
             attachment = content
             content = undefined.UNDEFINED
 
-        body = data_binding.JSONObjectBuilder()
-        body.put(
-            "allowed_mentions",
-            self._generate_allowed_mentions(mentions_everyone, mentions_reply, user_mentions, role_mentions),
-        )
-        body.put("content", content, conversion=str)
-        body.put("nonce", nonce)
-        body.put("tts", tts)
-        body.put("message_reference", reply, conversion=lambda m: {"message_id": str(int(m))})
-
         final_attachments: typing.List[files.Resource[files.AsyncReader]] = []
         if attachment is not undefined.UNDEFINED:
             final_attachments.append(files.ensure_resource(attachment))
         if attachments is not undefined.UNDEFINED:
             final_attachments.extend([files.ensure_resource(a) for a in attachments])
 
+        serialized_embeds: undefined.UndefinedOr[data_binding.JSONArray] = undefined.UNDEFINED
+
         if embed is not undefined.UNDEFINED:
             embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
-            body.put("embed", embed_payload)
             final_attachments.extend(embed_attachments)
+            serialized_embeds = [embed_payload]
+        elif embeds is not undefined.UNDEFINED:
+            serialized_embeds = []
+            for embed in embeds:
+                embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
+                final_attachments.extend(embed_attachments)
+                serialized_embeds.append(embed_payload)
+
+        body.put(
+            "allowed_mentions",
+            self._generate_allowed_mentions(mentions_everyone, mentions_reply, user_mentions, role_mentions),
+        )
+        body.put("content", content, conversion=str)
+        body.put("tts", tts)
+        body.put("embeds", serialized_embeds)
 
         if final_attachments:
             form = data_binding.URLEncodedForm()
@@ -1228,37 +1241,27 @@ async def create_message(
                     mimetype = stream.mimetype or _APPLICATION_OCTET_STREAM
                     form.add_field(f"file{i}", stream, filename=stream.filename, content_type=mimetype)
 
-                response = await self._request(route, form=form)
+                response = await self._request(route, form=form, query=query)
             finally:
                 await stack.aclose()
         else:
-            response = await self._request(route, json=body)
-
-        assert isinstance(response, dict)
-        return self._entity_factory.deserialize_message(response)
-
-    async def crosspost_message(
-        self,
-        channel: snowflakes.SnowflakeishOr[channels_.GuildNewsChannel],
-        message: snowflakes.SnowflakeishOr[messages_.PartialMessage],
-    ) -> messages_.Message:
-        route = routes.POST_CHANNEL_CROSSPOST.compile(channel=channel, message=message)
-
-        response = await self._request(route)
+            response = await self._request(route, json=body, query=query)
 
         assert isinstance(response, dict)
         return self._entity_factory.deserialize_message(response)
 
-    async def edit_message(
+    async def create_message(
         self,
         channel: snowflakes.SnowflakeishOr[channels_.TextChannel],
-        message: snowflakes.SnowflakeishOr[messages_.PartialMessage],
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
-        embed: undefined.UndefinedNoneOr[embeds_.Embed] = undefined.UNDEFINED,
+        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
-        replace_attachments: bool = False,
+        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
+        nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
+        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages_.PartialMessage]] = undefined.UNDEFINED,
         mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         user_mentions: undefined.UndefinedOr[
@@ -1267,11 +1270,72 @@ async def edit_message(
         role_mentions: undefined.UndefinedOr[
             typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
         ] = undefined.UNDEFINED,
-        flags: undefined.UndefinedOr[messages_.MessageFlag] = undefined.UNDEFINED,
     ) -> messages_.Message:
-        route = routes.PATCH_CHANNEL_MESSAGE.compile(channel=channel, message=message)
+        route = routes.POST_CHANNEL_MESSAGES.compile(channel=channel)
         body = data_binding.JSONObjectBuilder()
-        body.put("flags", flags)
+        body.put("nonce", nonce)
+        body.put("message_reference", reply, conversion=lambda m: {"message_id": str(int(m))})
+        return await self._create_message(
+            route,
+            body,
+            content=content,
+            embed=embed,
+            embeds=embeds,
+            attachment=attachment,
+            attachments=attachments,
+            tts=tts,
+            mentions_everyone=mentions_everyone,
+            mentions_reply=mentions_reply,
+            user_mentions=user_mentions,
+            role_mentions=role_mentions,
+        )
+
+    async def crosspost_message(
+        self,
+        channel: snowflakes.SnowflakeishOr[channels_.GuildNewsChannel],
+        message: snowflakes.SnowflakeishOr[messages_.PartialMessage],
+    ) -> messages_.Message:
+        route = routes.POST_CHANNEL_CROSSPOST.compile(channel=channel, message=message)
+
+        response = await self._request(route)
+
+        assert isinstance(response, dict)
+        return self._entity_factory.deserialize_message(response)
+
+    async def _edit_message(  # noqa: C901 - Function too complex
+        self,
+        route: routes.CompiledRoute,
+        body: data_binding.JSONObjectBuilder,
+        *,
+        content: undefined.UndefinedOr[typing.Any],
+        embed: undefined.UndefinedNoneOr[embeds_.Embed],
+        embeds: undefined.UndefinedNoneOr[typing.Sequence[embeds_.Embed]],
+        attachment: undefined.UndefinedOr[files.Resourceish],
+        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]],
+        replace_attachments: bool,
+        mentions_everyone: undefined.UndefinedOr[bool],
+        mentions_reply: undefined.UndefinedOr[bool],
+        user_mentions: undefined.UndefinedOr[typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]],
+        role_mentions: undefined.UndefinedOr[typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]],
+    ) -> messages_.Message:
+        if not undefined.count(attachment, attachments):
+            raise ValueError("You may only specify one of 'attachment' or 'attachments', not both")
+
+        if not undefined.count(embed, embeds):
+            raise ValueError("You may only specify one of 'embed' or 'embeds', not both")
+
+        if attachments is not undefined.UNDEFINED and not isinstance(attachments, typing.Collection):
+            raise ValueError(
+                "You passed a non-collection to 'attachments', but this expects a collection. Maybe you meant to "
+                "use 'attachment' (singular) instead?"
+            )
+
+        if embeds not in _NONE_OR_UNDEFINED and not isinstance(embeds, typing.Collection):
+            raise TypeError(
+                "You passed a non collection to 'embeds', but this expects a collection. Maybe you meant to "
+                "use 'embed' (singular) instead?"
+            )
+
         if undefined.count(mentions_everyone, mentions_reply, user_mentions, role_mentions) != 4:
             body.put(
                 "allowed_mentions",
@@ -1301,16 +1365,27 @@ async def edit_message(
         final_attachments: typing.List[files.Resource[files.AsyncReader]] = []
         if attachment is not undefined.UNDEFINED:
             final_attachments.append(files.ensure_resource(attachment))
-        if attachments:
+        if attachments is not undefined.UNDEFINED:
             final_attachments.extend([files.ensure_resource(a) for a in attachments])
 
-        if isinstance(embed, embeds_.Embed):
-            embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
-            body.put("embed", embed_payload)
-            final_attachments.extend(embed_attachments)
+        serialized_embeds: data_binding.JSONArray = []
+        update_embeds: bool = False
+        if embed is not undefined.UNDEFINED:
+            update_embeds = True
+            if embed is not None:
+                embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
+                serialized_embeds.append(embed_payload)
+                final_attachments.extend(embed_attachments)
+        elif embeds is not undefined.UNDEFINED:
+            update_embeds = True
+            if embeds is not None:
+                for embed in embeds:
+                    embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
+                    serialized_embeds.append(embed_payload)
+                    final_attachments.extend(embed_attachments)
 
-        elif embed is None:
-            body.put("embed", None)
+        if update_embeds:
+            body.put("embeds", serialized_embeds)
 
         if replace_attachments:
             body.put("attachments", None)
@@ -1335,6 +1410,45 @@ async def edit_message(
         assert isinstance(response, dict)
         return self._entity_factory.deserialize_message(response)
 
+    async def edit_message(
+        self,
+        channel: snowflakes.SnowflakeishOr[channels_.TextChannel],
+        message: snowflakes.SnowflakeishOr[messages_.PartialMessage],
+        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
+        *,
+        embed: undefined.UndefinedNoneOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedNoneOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
+        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
+        replace_attachments: bool = False,
+        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
+        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
+        user_mentions: undefined.UndefinedOr[
+            typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]
+        ] = undefined.UNDEFINED,
+        role_mentions: undefined.UndefinedOr[
+            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
+        ] = undefined.UNDEFINED,
+        flags: undefined.UndefinedOr[messages_.MessageFlag] = undefined.UNDEFINED,
+    ) -> messages_.Message:
+        route = routes.PATCH_CHANNEL_MESSAGE.compile(channel=channel, message=message)
+        body = data_binding.JSONObjectBuilder()
+        body.put("flags", flags)
+        return await self._edit_message(
+            route,
+            body,
+            content=content,
+            embed=embed,
+            embeds=embeds,
+            attachment=attachment,
+            attachments=attachments,
+            replace_attachments=replace_attachments,
+            mentions_everyone=mentions_everyone,
+            mentions_reply=mentions_reply,
+            user_mentions=user_mentions,
+            role_mentions=role_mentions,
+        )
+
     async def delete_message(
         self,
         channel: snowflakes.SnowflakeishOr[channels_.TextChannel],
@@ -1612,93 +1726,28 @@ async def execute_webhook(
             typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
         ] = undefined.UNDEFINED,
     ) -> messages_.Message:
-        if not undefined.count(attachment, attachments):
-            raise ValueError("You may only specify one of 'attachment' or 'attachments', not both")
-
-        if not undefined.count(embed, embeds):
-            raise ValueError("You may only specify one of 'embed' or 'embeds', not both")
-
-        if not isinstance(embeds, typing.Collection) and embeds is not undefined.UNDEFINED:
-            raise TypeError(
-                "You passed a non collection to 'embeds', but this expects a collection. Maybe you meant to "
-                "use 'embed' (singular) instead?"
-            )
-
-        if not isinstance(attachments, typing.Collection) and attachments is not undefined.UNDEFINED:
-            raise TypeError(
-                "You passed a non collection to 'attachments', but this expects a collection. Maybe you meant to "
-                "use 'attachment' (singular) instead?"
-            )
-
-        if undefined.count(embed, embeds) == 2 and isinstance(content, embeds_.Embed):
-            # Syntatic sugar, common mistake to accidentally send an embed
-            # as the content, so lets detect this and fix it for the user.
-            embed = content
-            content = undefined.UNDEFINED
-
-        elif undefined.count(attachment, attachments) == 2 and isinstance(
-            content, (files.Resource, files.RAWISH_TYPES, os.PathLike)
-        ):
-            # Syntatic sugar, common mistake to accidentally send an attachment
-            # as the content, so lets detect this and fix it for the user. This
-            # will still then work with normal implicit embed attachments as
-            # we work this out later.
-            attachment = content
-            content = undefined.UNDEFINED
-
         route = routes.POST_WEBHOOK_WITH_TOKEN.compile(webhook=webhook, token=token)
 
-        final_attachments: typing.List[files.Resource[files.AsyncReader]] = []
-        if attachment is not undefined.UNDEFINED:
-            final_attachments.append(files.ensure_resource(attachment))
-        if attachments is not undefined.UNDEFINED:
-            final_attachments.extend([files.ensure_resource(a) for a in attachments])
-
-        serialized_embeds: data_binding.JSONArray = []
-
-        if embed is not undefined.UNDEFINED:
-            embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
-            serialized_embeds.append(embed_payload)
-            final_attachments.extend(embed_attachments)
-        elif embeds is not undefined.UNDEFINED:
-            for embed in embeds:
-                embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
-                serialized_embeds.append(embed_payload)
-                final_attachments.extend(embed_attachments)
-
         body = data_binding.JSONObjectBuilder()
-        body.put(
-            "mentions",
-            self._generate_allowed_mentions(mentions_everyone, undefined.UNDEFINED, user_mentions, role_mentions),
-        )
-        body.put("content", content, conversion=str)
-        body.put("embeds", serialized_embeds)
         body.put("username", username)
         body.put("avatar_url", avatar_url)
-        body.put("tts", tts)
         query = data_binding.StringMapBuilder()
         query.put("wait", True)
-
-        if final_attachments:
-            form = data_binding.URLEncodedForm()
-            form.add_field("payload_json", data_binding.dump_json(body), content_type=_APPLICATION_JSON)
-
-            stack = contextlib.AsyncExitStack()
-
-            try:
-                for i, attachment in enumerate(final_attachments):
-                    stream = await stack.enter_async_context(attachment.stream(executor=self._executor))
-                    mimetype = stream.mimetype or _APPLICATION_OCTET_STREAM
-                    form.add_field(f"file{i}", stream, filename=stream.filename, content_type=mimetype)
-
-                response = await self._request(route, query=query, form=form, no_auth=True)
-            finally:
-                await stack.aclose()
-        else:
-            response = await self._request(route, query=query, json=body, no_auth=True)
-
-        assert isinstance(response, dict)
-        return self._entity_factory.deserialize_message(response)
+        return await self._create_message(
+            route,
+            body,
+            query,
+            content=content,
+            embed=embed,
+            embeds=embeds,
+            attachment=attachment,
+            attachments=attachments,
+            tts=tts,
+            mentions_everyone=mentions_everyone,
+            user_mentions=user_mentions,
+            role_mentions=role_mentions,
+            mentions_reply=undefined.UNDEFINED,
+        )
 
     async def fetch_webhook_message(
         self,
@@ -1731,91 +1780,22 @@ async def edit_webhook_message(
             typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
         ] = undefined.UNDEFINED,
     ) -> messages_.Message:
-        if not undefined.count(embed, embeds):
-            raise ValueError("You may only specify one of 'embed' or 'embeds', not both")
-
-        if not isinstance(embeds, typing.Collection) and embeds is not undefined.UNDEFINED:
-            raise TypeError(
-                "You passed a non collection to 'embeds', but this expects a collection. Maybe you meant to "
-                "use 'embed' (singular) instead?"
-            )
-
-        if undefined.count(embed, embeds) == 2 and isinstance(content, embeds_.Embed):
-            # Syntatic sugar, common mistake to accidentally send an embed
-            # as the content, so lets detect this and fix it for the user.
-            embed = content
-            content = undefined.UNDEFINED
-        elif undefined.count(attachment, attachments) == 2 and isinstance(
-            content, (files.Resource, files.RAWISH_TYPES, os.PathLike)
-        ):
-            # Syntatic sugar, common mistake to accidentally send an attachment
-            # as the content, so lets detect this and fix it for the user. This
-            # will still then work with normal implicit embed attachments as
-            # we work this out later.
-            attachment = content
-            content = undefined.UNDEFINED
-
         route = routes.PATCH_WEBHOOK_MESSAGE.compile(webhook=webhook, token=token, message=message)
         body = data_binding.JSONObjectBuilder()
-        if undefined.count(mentions_everyone, user_mentions, role_mentions) != 3:
-            body.put(
-                "allowed_mentions",
-                self._generate_allowed_mentions(mentions_everyone, undefined.UNDEFINED, user_mentions, role_mentions),
-            )
-
-        if content is not None:
-            body.put("content", content, conversion=str)
-        else:
-            body.put("content", None)
-
-        final_attachments: typing.List[files.Resource[files.AsyncReader]] = []
-        if attachment is not undefined.UNDEFINED:
-            final_attachments.append(files.ensure_resource(attachment))
-        if attachments:
-            final_attachments.extend([files.ensure_resource(a) for a in attachments])
-
-        serialized_embeds: data_binding.JSONArray = []
-        update_embeds: bool = False
-        if embed is not undefined.UNDEFINED:
-            update_embeds = True
-            if embed is not None:
-                embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
-                serialized_embeds.append(embed_payload)
-                final_attachments.extend(embed_attachments)
-        elif embeds is not undefined.UNDEFINED:
-            update_embeds = True
-            if embeds is not None:
-                for embed in embeds:
-                    embed_payload, embed_attachments = self._entity_factory.serialize_embed(embed)
-                    serialized_embeds.append(embed_payload)
-                    final_attachments.extend(embed_attachments)
-
-        if update_embeds:
-            body.put("embeds", serialized_embeds)
-
-        if replace_attachments:
-            body.put("attachments", None)
-
-        if final_attachments:
-            form = data_binding.URLEncodedForm()
-            form.add_field("payload_json", data_binding.dump_json(body), content_type=_APPLICATION_JSON)
-
-            stack = contextlib.AsyncExitStack()
-
-            try:
-                for i, attachment in enumerate(final_attachments):
-                    stream = await stack.enter_async_context(attachment.stream(executor=self._executor))
-                    mimetype = stream.mimetype or _APPLICATION_OCTET_STREAM
-                    form.add_field(f"file{i}", stream, filename=stream.filename, content_type=mimetype)
-
-                response = await self._request(route, form=form, no_auth=True)
-            finally:
-                await stack.aclose()
-        else:
-            response = await self._request(route, json=body, no_auth=True)
-
-        assert isinstance(response, dict)
-        return self._entity_factory.deserialize_message(response)
+        return await self._edit_message(
+            route,
+            body,
+            content=content,
+            embed=embed,
+            embeds=embeds,
+            attachment=attachment,
+            attachments=attachments,
+            replace_attachments=replace_attachments,
+            mentions_everyone=mentions_everyone,
+            mentions_reply=undefined.UNDEFINED,
+            user_mentions=user_mentions,
+            role_mentions=role_mentions,
+        )
 
     async def delete_webhook_message(
         self,
diff --git a/hikari/impl/shard.py b/hikari/impl/shard.py
index ae314152..539ace5f 100644
--- a/hikari/impl/shard.py
+++ b/hikari/impl/shard.py
@@ -385,8 +385,8 @@ class GatewayShardImpl(shard.GatewayShard):
 
     __slots__: typing.Sequence[str] = (
         "_activity",
-        "_closed",
-        "_closing",
+        "_closed_event",
+        "_closing_event",
         "_chunking_rate_limit",
         "_event_manager",
         "_event_factory",
@@ -450,8 +450,8 @@ def __init__(
         new_query = urllib.parse.urlencode(query)
 
         self._activity = initial_activity
-        self._closing = asyncio.Event()
-        self._closed = asyncio.Event()
+        self._closing_event = asyncio.Event()
+        self._closed_event = asyncio.Event()
         self._chunking_rate_limit = rate_limits.WindowedBurstRateLimiter(
             f"shard {shard_id} chunking rate limit",
             *_CHUNKING_RATELIMIT,
@@ -505,7 +505,7 @@ def shard_count(self) -> int:
         return self._shard_count
 
     async def close(self) -> None:
-        if not self._closing.is_set():
+        if not self._closing_event.is_set():
             try:
                 if self._ws is not None:
                     self._logger.debug(
@@ -513,11 +513,14 @@ async def close(self) -> None:
                         "disconnecting immediately with GOING AWAY"
                     )
                     await self._ws.send_close(code=errors.ShardCloseCode.GOING_AWAY, message=b"shard disconnecting")
-                self._closing.set()
+                self._closing_event.set()
             finally:
                 self._chunking_rate_limit.close()
                 self._total_rate_limit.close()
 
+        # Wait for the shard to fully close
+        await self._closed_event.wait()
+
     async def get_user_id(self) -> snowflakes.Snowflake:
         await self._handshake_completed.wait()
         if self._user_id is None:
@@ -526,7 +529,7 @@ async def get_user_id(self) -> snowflakes.Snowflake:
 
     async def join(self) -> None:
         """Wait for this shard to close, if running."""
-        await self._closed.wait()
+        await self._closed_event.wait()
 
     async def _send_json(
         self,
@@ -701,7 +704,7 @@ async def _heartbeat(self, heartbeat_interval: float) -> bool:
         self._last_heartbeat_ack_received = time.monotonic()
         self._logger.debug("starting heartbeat with interval %ss", heartbeat_interval)
 
-        while not self._closing.is_set() and not self._closed.is_set():
+        while not self._closing_event.is_set() and not self._closed_event.is_set():
             if self._last_heartbeat_ack_received <= self._last_heartbeat_sent:
                 # Gateway is zombie, close and request reconnect.
                 self._logger.warning(
@@ -718,7 +721,7 @@ async def _heartbeat(self, heartbeat_interval: float) -> bool:
             await self._send_heartbeat()
 
             try:
-                await asyncio.wait_for(self._closing.wait(), timeout=heartbeat_interval)
+                await asyncio.wait_for(self._closing_event.wait(), timeout=heartbeat_interval)
                 # We are closing
                 break
             except asyncio.TimeoutError:
@@ -774,8 +777,8 @@ async def _resume(self) -> None:
         )
 
     async def _run(self) -> None:
-        self._closed.clear()
-        self._closing.clear()
+        self._closed_event.clear()
+        self._closing_event.clear()
         last_started_at = -float("inf")
 
         backoff = rate_limits.ExponentialBackOff(
@@ -785,13 +788,13 @@ async def _run(self) -> None:
         )
 
         try:
-            while not self._closing.is_set() and not self._closed.is_set():
+            while not self._closing_event.is_set() and not self._closed_event.is_set():
                 if time.monotonic() - last_started_at < _BACKOFF_WINDOW:
                     backoff_time = next(backoff)
                     self._logger.info("backing off reconnecting for %.2fs", backoff_time)
 
                     try:
-                        await asyncio.wait_for(self._closing.wait(), timeout=backoff_time)
+                        await asyncio.wait_for(self._closing_event.wait(), timeout=backoff_time)
                         # We were told to close.
                         return
                     except asyncio.TimeoutError:
@@ -837,8 +840,8 @@ async def _run(self) -> None:
                     self._logger.error("encountered some unhandled error", exc_info=ex)
                     raise
         finally:
-            self._closing.set()
-            self._closed.set()
+            self._closing_event.set()
+            self._closed_event.set()
 
     async def _run_once(self) -> bool:
         self._handshake_completed.clear()
@@ -872,7 +875,7 @@ async def _run_once(self) -> bool:
                     self._logger.debug("identifying with new session")
                     await self._identify()
 
-                if self._closing.is_set():
+                if self._closing_event.is_set():
                     self._logger.debug(
                         "closing flag was set during handshake, disconnecting with GOING AWAY "
                         "(_run_once => do not reconnect)"
@@ -883,7 +886,7 @@ async def _run_once(self) -> bool:
                     return False
 
                 # Event polling.
-                while not self._closing.is_set() and not heartbeat_task.done() and not heartbeat_task.cancelled():
+                while not self._closing_event.is_set() and not heartbeat_task.done() and not heartbeat_task.cancelled():
                     try:
                         result = await self._poll_events()
 
@@ -932,7 +935,7 @@ async def _run_once(self) -> bool:
                 self._event_manager.dispatch(self._event_factory.deserialize_disconnected_event(self))
 
             # Ignore errors if we are closing
-            if self._closing.is_set() or self._closed.is_set():
+            if self._closing_event.is_set() or self._closed_event.is_set():
                 return False
 
             # Check if we made the socket close or handled it. If we didn't, we should always try to
@@ -1013,7 +1016,7 @@ async def _wait_for_hello(self) -> asyncio.Task[bool]:
             )
             raise errors.GatewayError(f"Expected opcode {_HELLO}, but received {payload[_OP]}")
 
-        if self._closing.is_set():
+        if self._closing_event.is_set():
             self._logger.debug(
                 "closing flag was set before we could handshake, disconnecting with GOING AWAY "
                 "(_run_once => do not reconnect)"
diff --git a/hikari/internal/aio.py b/hikari/internal/aio.py
index 33a39df0..977844cb 100644
--- a/hikari/internal/aio.py
+++ b/hikari/internal/aio.py
@@ -26,6 +26,7 @@
 
 __all__: typing.List[str] = [
     "completed_future",
+    "get_or_make_loop",
     "is_async_iterator",
     "is_async_iterable",
     "first_completed",
@@ -55,12 +56,15 @@ def completed_future(result: typing.Optional[T_inv] = None, /) -> asyncio.Future
     -------
     asyncio.Future[T]
         The completed future.
+
+    Raises
+    ------
+    RuntimeError
+        When called in an environment with no running event loop.
     """
-    future = asyncio.get_event_loop().create_future()
+    future = asyncio.get_running_loop().create_future()
     future.set_result(result)
-    # MyPy pretends this type hint is valid when it is not. Probably should be
-    # in the standard lib but whatever.
-    return typing.cast("asyncio.Future[typing.Optional[T_inv]]", future)
+    return future
 
 
 # On Python3.8.2, there appears to be a bug with the typing module:
@@ -185,3 +189,27 @@ async def all_of(
             await gatherer  # pragma: no cover
         except asyncio.CancelledError:
             pass
+
+
+def get_or_make_loop() -> asyncio.AbstractEventLoop:
+    """Get the current usable event loop or create a new one.
+
+    Returns
+    -------
+    asyncio.AbstractEventLoop
+    """
+    # get_event_loop will error under oddly specific cases such as if set_event_loop has been called before even
+    # if it was just called with None or if it's called on a thread which isn't the main Thread.
+    try:
+        loop = asyncio.get_event_loop()
+
+        # Closed loops cannot be re-used.
+        if not loop.is_closed():
+            return loop
+
+    except RuntimeError:
+        pass
+
+    loop = asyncio.new_event_loop()
+    asyncio.set_event_loop(loop)
+    return loop
diff --git a/hikari/internal/attr_extensions.py b/hikari/internal/attr_extensions.py
index ea703136..eaf965ab 100644
--- a/hikari/internal/attr_extensions.py
+++ b/hikari/internal/attr_extensions.py
@@ -113,7 +113,7 @@ def generate_shallow_copier(cls: typing.Type[ModelT]) -> typing.Callable[[ModelT
     globals_ = {"cls": cls}
     _LOGGER.log(ux.TRACE, "generating shallow copy function for %r: %r", cls, code)
     exec(code, globals_)  # noqa: S102 - Use of exec detected.
-    return typing.cast("typing.Callable[[ModelT], ModelT]", globals_["copy"])
+    return globals_["copy"]
 
 
 def get_or_generate_shallow_copier(cls: typing.Type[ModelT]) -> typing.Callable[[ModelT], ModelT]:
diff --git a/hikari/internal/ux.py b/hikari/internal/ux.py
index c14aa81d..1c584cae 100644
--- a/hikari/internal/ux.py
+++ b/hikari/internal/ux.py
@@ -136,6 +136,10 @@ def init_logging(
     logging.captureWarnings(True)
 
 
+_UNCONDITIONAL_ANSI_FLAGS: typing.Final[typing.FrozenSet[str]] = frozenset(("PYCHARM_HOSTED", "WT_SESSION"))
+"""Set of env variables which always indicate that ANSI flags should be included."""
+
+
 def print_banner(package: typing.Optional[str], allow_color: bool, force_color: bool) -> None:
     """Print a banner of choice to `sys.stdout`.
 
@@ -223,30 +227,34 @@ def supports_color(allow_color: bool, force_color: bool) -> bool:
     # isatty is not always implemented, https://code.djangoproject.com/ticket/6223
     is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
 
-    if os.getenv("CLICOLOR_FORCE", "0") != "0" or force_color:
+    clicolor = os.environ.get("CLICOLOR")
+    if os.environ.get("CLICOLOR_FORCE", "0") != "0" or force_color:
         # https://bixense.com/clicolors/
         return True
-    elif os.getenv("CLICOLOR", "0") != "0" and is_a_tty:
+    if clicolor is not None and clicolor != "0" and is_a_tty:
         # https://bixense.com/clicolors/
         return True
-    elif os.getenv("COLORTERM", "").casefold() in ("truecolor", "24bit"):
+    if clicolor == "0":
+        # https://bixense.com/clicolors/
+        return False
+    if os.environ.get("COLORTERM", "").casefold() in ("truecolor", "24bit"):
         # Seems to be used by Gnome Terminal, and Tmpod will beat me if I don't add it.
         # https://gist.github.com/XVilka/8346728#true-color-detection
         return True
 
     plat = sys.platform
-    color_support = False
-
-    if plat != "Pocket PC":
-        if plat == "win32":
-            color_support |= os.getenv("TERM_PROGRAM", None) in ("mintty", "Terminus")
-            color_support |= "ANSICON" in os.environ
-            color_support &= is_a_tty
-        else:
-            color_support = is_a_tty
+    if plat == "Pocket PC":
+        return False
 
-        color_support |= bool(os.getenv("PYCHARM_HOSTED", ""))
+    color_support = False
+    if plat == "win32":
+        color_support |= os.environ.get("TERM_PROGRAM") in ("mintty", "Terminus")
+        color_support |= "ANSICON" in os.environ
+        color_support &= is_a_tty
+    else:
+        color_support = is_a_tty
 
+    color_support |= bool(os.environ.keys() & _UNCONDITIONAL_ANSI_FLAGS)
     return color_support
 
 
diff --git a/hikari/iterators.py b/hikari/iterators.py
index dc3831c4..d286fba2 100644
--- a/hikari/iterators.py
+++ b/hikari/iterators.py
@@ -766,8 +766,7 @@ def _next_chunk(self) -> typing.Optional[typing.Generator[ValueT, None, None]]:
     __slots__: typing.Sequence[str] = ("_buffer",)
 
     def __init__(self) -> None:
-        empty_genexp = typing.cast("typing.Generator[ValueT, None, None]", (_ for _ in ()))
-        self._buffer: typing.Optional[typing.Generator[ValueT, None, None]] = empty_genexp
+        self._buffer: typing.Optional[typing.Generator[ValueT, None, None]] = (_ for _ in ())
 
     @abc.abstractmethod
     async def _next_chunk(self) -> typing.Optional[typing.Generator[ValueT, None, None]]:
diff --git a/hikari/messages.py b/hikari/messages.py
index ea1068e8..8988452e 100644
--- a/hikari/messages.py
+++ b/hikari/messages.py
@@ -702,6 +702,7 @@ async def edit(
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
         embed: undefined.UndefinedNoneOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedNoneOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         replace_attachments: bool = False,
@@ -720,33 +721,33 @@ async def edit(
         Parameters
         ----------
         content : hikari.undefined.UndefinedOr[typing.Any]
-            The message content to update with. If
+            If provided, the message content to update with. If
             `hikari.undefined.UNDEFINED`, then the content will not
             be changed. If `builtins.None`, then the content will be removed.
 
             Any other value will be cast to a `builtins.str` before sending.
 
-            If this is a `hikari.embeds.Embed` and neither the
-            `embed` or `embeds` kwargs are provided or if this is a
-            `hikari.files.Resourceish` and neither the `attachment` or
-            `attachments` kwargs are provided, the values will be overwritten.
-            This allows for simpler syntax when sending an embed or an
-            attachment alone.
+            If this is a `hikari.embeds.Embed` and neither the `embed` or
+            `embeds` kwargs are provided or if this is a
+            `hikari.files.Resourceish` and neither the
+            `attachment` or `attachments` kwargs are provided, the values will
+            be overwritten. This allows for simpler syntax when sending an
+            embed or an attachment alone.
 
         Other Parameters
         ----------------
         embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed]
             If provided, the embed to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous embed, if
-            present, is not changed. If this is `builtins.None`, then the embed
-            is removed, if present. Otherwise, the new embed that was provided
-            will be used as the replacement.
-        attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish]
-            If provided, the attachment to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous attachment, if
-            present, is not changed. If this is `builtins.None`, then the
-            attachment is removed, if present. Otherwise, the new attachment
-            that was provided will be attached.
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embed that was provided will be used as the
+            replacement.
+        embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]]
+            If provided, the embeds to set on the message. If
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embeds that were provided will be used as the
+            replacement.
         attachments : hikari.undefined.UndefinedOr[typing.Sequence[hikari.files.Resourceish]]
             If provided, the attachments to set on the message. If
             `hikari.undefined.UNDEFINED`, the previous attachments, if
@@ -836,9 +837,7 @@ async def edit(
             This may be raised in several discrete situations, such as messages
             being empty with no embeds; messages with more than 2000 characters
             in them, embeds that exceed one of the many embed
-            limits; invalid image URLs in embeds; users in `user_mentions` not
-            being mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content.
+            limits; invalid image URLs in embeds.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.ForbiddenError
@@ -856,6 +855,7 @@ async def edit(
             channel=self.channel_id,
             content=content,
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             replace_attachments=replace_attachments,
@@ -871,6 +871,7 @@ async def respond(
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
@@ -897,9 +898,9 @@ async def respond(
             in the content. Any other value here will be cast to a
             `builtins.str`.
 
-            If this is a `hikari.embeds.Embed` and no `embed` kwarg is
-            provided, then this will instead update the embed. This allows for
-            simpler syntax when sending an embed alone.
+            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
+            is provided, then this will instead update the embed. This allows
+            for simpler syntax when sending an embed alone.
 
             Likewise, if this is a `hikari.files.Resource`, then the
             content is instead treated as an attachment if no `attachment` and
@@ -909,6 +910,8 @@ async def respond(
         ----------------
         embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
             If provided, the message embed.
+        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
+            If provided, the message embeds.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
             If provided, the message attachment. This can be a resource,
             or string of a path on your computer or a URL.
@@ -984,10 +987,8 @@ async def respond(
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
             limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content; `reply` not found
-            or not in the same channel.
+            invalid image URLs in embeds; `reply` not found or not in the same
+            channel.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.ForbiddenError
@@ -1005,10 +1006,14 @@ async def respond(
         if reply is True:
             reply = self
 
+        elif reply is False:
+            reply = undefined.UNDEFINED
+
         return await self.app.rest.create_message(
             channel=self.channel_id,
             content=content,
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce=nonce,
diff --git a/hikari/users.py b/hikari/users.py
index 5f8b65c2..2b7f24fe 100644
--- a/hikari/users.py
+++ b/hikari/users.py
@@ -41,7 +41,7 @@
 
 if typing.TYPE_CHECKING:
     from hikari import channels
-    from hikari import embeds
+    from hikari import embeds as embeds_
     from hikari import files
     from hikari import guilds
     from hikari import messages
@@ -242,7 +242,8 @@ async def send(
         self,
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
-        embed: undefined.UndefinedOr[embeds.Embed] = undefined.UNDEFINED,
+        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
@@ -267,18 +268,21 @@ async def send(
             in the content. Any other value here will be cast to a
             `builtins.str`.
 
-            If this is a `hikari.embeds.Embed` and no `embed` kwarg is
-            provided, then this will instead update the embed. This allows for
-            simpler syntax when sending an embed alone.
+            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
+            is provided, then this will instead update the embed. This allows
+            for simpler syntax when sending an embed alone.
 
             Likewise, if this is a `hikari.files.Resource`, then the
             content is instead treated as an attachment if no `attachment` and
             no `attachments` kwargs are provided.
 
+
         Other Parameters
         ----------------
         embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
             If provided, the message embed.
+        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
+            If provided, the message embeds.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
             If provided, the message attachment. This can be a resource,
             or string of a path on your computer or a URL.
@@ -365,10 +369,8 @@ async def send(
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
             limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content; `reply` not found
-            or not in the same channel.
+            invalid image URLs in embeds; `reply` not found or not in the same
+            channel.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.ForbiddenError
@@ -401,6 +403,7 @@ async def send(
             channel=channel_id,
             content=content,
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce=nonce,
@@ -695,7 +698,8 @@ async def send(
         self,
         content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
         *,
-        embed: undefined.UndefinedOr[embeds.Embed] = undefined.UNDEFINED,
+        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
+        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
         attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
         attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
         nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
diff --git a/hikari/webhooks.py b/hikari/webhooks.py
index f9c2eb6a..7197fb72 100644
--- a/hikari/webhooks.py
+++ b/hikari/webhooks.py
@@ -351,16 +351,16 @@ async def edit_message(
         ----------------
         embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed]
             If provided, the embed to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous embed, if
-            present, is not changed. If this is `builtins.None`, then the embed
-            is removed, if present. Otherwise, the new embed that was provided
-            will be used as the replacement.
-        embeds : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed]
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embed that was provided will be used as the
+            replacement.
+        embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the embeds to set on the message. If
-            `hikari.undefined.UNDEFINED`, the previous embeds if
-            present are not changed. If this is `builtins.None`, then the embeds
-            are removed ,if present. Otherwise, the new embeds that were provided
-            will be used as the replacement.
+            `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed.
+            If this is `builtins.None` then any present embeds are removed.
+            Otherwise, the new embeds that were provided will be used as the
+            replacement.
         attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish]
             If provided, the attachment to set on the message. If
             `hikari.undefined.UNDEFINED`, the previous attachment, if
@@ -440,10 +440,7 @@ async def edit_message(
             This may be raised in several discrete situations, such as messages
             being empty with no attachments or embeds; messages with more than
             2000 characters in them, embeds that exceed one of the many embed
-            limits; too many attachments; attachments that are too large;
-            invalid image URLs in embeds; users in `user_mentions` not being
-            mentioned in the message content; roles in `role_mentions` not
-            being mentioned in the message content.
+            limits; too many attachments; attachments that are too large.
         hikari.errors.UnauthorizedError
             If you are unauthorized to make the request (invalid/missing token).
         hikari.errors.NotFoundError


Test patch:
diff --git a/tests/hikari/__init__.py b/tests/hikari/__init__.py
index 9439d83f..e9272020 100644
--- a/tests/hikari/__init__.py
+++ b/tests/hikari/__init__.py
@@ -21,6 +21,7 @@
 # SOFTWARE.
 import asyncio
 import sys
+import typing
 
 import pytest
 
@@ -28,8 +29,10 @@
 
 
 class TestingPolicy(asyncio.DefaultEventLoopPolicy):
-    def set_event_loop(self, loop) -> None:
-        loop.set_debug(True)
+    def set_event_loop(self, loop: typing.Optional[asyncio.AbstractEventLoop]) -> None:
+        if loop:
+            loop.set_debug(True)
+
         super().set_event_loop(loop)
 
 
diff --git a/tests/hikari/events/test_base_events.py b/tests/hikari/events/test_base_events.py
index d6d9df42..8c26553c 100644
--- a/tests/hikari/events/test_base_events.py
+++ b/tests/hikari/events/test_base_events.py
@@ -139,7 +139,7 @@ def test_shard_property(self, has_shard, event):
     def test_exc_info_property(self, event, error):
         assert event.exc_info == (type(error), error, error.__traceback__)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_retry(self, event):
         await event.retry()
         event.failed_callback.assert_awaited_once_with(event.failed_event)
diff --git a/tests/hikari/events/test_channel_events.py b/tests/hikari/events/test_channel_events.py
index a07a38a2..4981c388 100644
--- a/tests/hikari/events/test_channel_events.py
+++ b/tests/hikari/events/test_channel_events.py
@@ -54,7 +54,7 @@ def test_guild_when_unavailable(self, event):
         event.app.cache.get_available_guild.assert_called_once_with(929292929)
         event.app.cache.get_unavailable_guild.assert_called_once_with(929292929)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_guild(self, event):
         event.app.rest.fetch_guild = mock.AsyncMock()
         result = await event.fetch_guild()
@@ -68,7 +68,7 @@ def test_channel(self, event):
         assert result is event.app.cache.get_guild_channel.return_value
         event.app.cache.get_guild_channel.assert_called_once_with(432432432)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_channel(self, event):
         event.app.rest.fetch_channel = mock.AsyncMock(return_value=mock.MagicMock(spec=channels.GuildChannel))
         result = await event.fetch_channel()
diff --git a/tests/hikari/events/test_guild_events.py b/tests/hikari/events/test_guild_events.py
index 267a0a9a..695e4a06 100644
--- a/tests/hikari/events/test_guild_events.py
+++ b/tests/hikari/events/test_guild_events.py
@@ -53,7 +53,7 @@ def test_guild_when_unavailable(self, event):
         event.app.cache.get_unavailable_guild.assert_called_once_with(534123123)
         event.app.cache.get_available_guild.assert_called_once_with(534123123)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_guild(self, event):
         event.app.rest.fetch_guild = mock.AsyncMock()
         result = await event.fetch_guild()
@@ -61,7 +61,7 @@ async def test_fetch_guild(self, event):
         assert result is event.app.rest.fetch_guild.return_value
         event.app.rest.fetch_guild.assert_called_once_with(534123123)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_guild_preview(self, event):
         event.app.rest.fetch_guild_preview = mock.AsyncMock()
         result = await event.fetch_guild_preview()
diff --git a/tests/hikari/impl/test_bot.py b/tests/hikari/impl/test_bot.py
index 3eec2512..6af30a94 100644
--- a/tests/hikari/impl/test_bot.py
+++ b/tests/hikari/impl/test_bot.py
@@ -277,41 +277,33 @@ def test_check_if_alive(self, bot):
 
         bot._check_if_alive()
 
-    @pytest.mark.asyncio
-    async def test_close_when_not_force(self, bot, event_manager):
-        bot._closing_event = mock.Mock(is_set=mock.Mock(return_value=False))
-        bot._is_alive = True
-
-        await bot.close(force=False)
-
-        bot._closing_event.set.assert_called_once_with()
-        assert bot._is_alive is True
-
-    @pytest.mark.asyncio
-    async def test_close_when_not_force_and_closing_event_set(self, bot, event_manager):
-        bot._closing_event = mock.Mock(is_set=mock.Mock(return_value=True))
+    @pytest.mark.asyncio()
+    async def test_close_when_already_closed(self, bot, event_manager):
+        bot._closing_event = None
+        bot._closed_event = None
         bot._is_alive = True
 
-        await bot.close(force=False)
+        await bot.close()
 
-        bot._closing_event.set.assert_not_called()
         assert bot._is_alive is True
 
-    @pytest.mark.asyncio
-    async def test_close_when_already_closed(self, bot, event_manager):
-        bot._closing_event = None
+    @pytest.mark.asyncio()
+    async def test_close_when_already_closing(self, bot, event_manager):
+        bot._closing_event = object()
+        bot._closed_event = mock.AsyncMock()
         bot._is_alive = True
 
-        await bot.close(force=True)
+        await bot.close()
 
+        bot._closed_event.wait.assert_awaited_once_with()
         assert bot._is_alive is True
 
-    @pytest.mark.asyncio
-    async def test_close_when_force(self, bot, event_manager, event_factory, rest, voice, cache):
+    @pytest.mark.asyncio()
+    async def test_close(self, bot, event_manager, event_factory, rest, voice, cache):
         def null_call(arg):
             return arg
 
-        class AwaitMock:
+        class AwaitableMock:
             def __init__(self, error=None):
                 self._awaited_count = 0
                 self._error = error
@@ -335,25 +327,30 @@ def assert_awaited_once(self):
         stack.enter_context(mock.patch.object(asyncio, "as_completed", side_effect=null_call))
         ensure_future = stack.enter_context(mock.patch.object(asyncio, "ensure_future", side_effect=null_call))
         get_running_loop = stack.enter_context(mock.patch.object(asyncio, "get_running_loop"))
-        all_of = stack.enter_context(mock.patch.object(aio, "all_of", new=mock.AsyncMock()))
+        new_event = stack.enter_context(mock.patch.object(asyncio, "Event"))
+        mock_future = mock.Mock()
+        get_running_loop.return_value.create_future.return_value = mock_future
 
         event_manager.dispatch = mock.AsyncMock()
-        rest.close = AwaitMock()
-        voice.close = AwaitMock()
+        rest.close = AwaitableMock()
+        voice.close = AwaitableMock()
         bot._closing_event = closing_event = mock.Mock(is_set=mock.Mock(return_value=False))
+        bot._closed_event = None
         bot._is_alive = True
         error = RuntimeError()
-        shard0 = mock.Mock(id=0, close=AwaitMock())
-        shard1 = mock.Mock(id=1, close=AwaitMock(error=error))
-        shard2 = mock.Mock(id=2, close=AwaitMock())
+        shard0 = mock.Mock(id=0, close=AwaitableMock())
+        shard1 = mock.Mock(id=1, close=AwaitableMock(error))
+        shard2 = mock.Mock(id=2, close=AwaitableMock())
         bot._shards = {0: shard0, 1: shard1, 2: shard2}
 
         with stack:
-            await bot.close(force=True)
+            await bot.close()
 
-        # Closing event and args
+        # Events and args
         closing_event.set.assert_called_once_with()
         assert bot._closing_event is None
+        new_event.return_value.set.assert_called_once_with()
+        assert bot._closed_event is None
         assert bot._is_alive is False
 
         # Closing components
@@ -384,9 +381,6 @@ def assert_awaited_once(self):
             }
         )
 
-        # Joining shards
-        all_of.assert_awaited_once_with(*(shard0.join(), shard1.join(), shard2.join()), timeout=3)
-
         # Clear out maps
         assert bot._shards == {}
         cache.clear.assert_called_once_with()
@@ -414,7 +408,7 @@ def test_get_listeners(self, bot, event_manager):
 
         event_manager.get_listeners.assert_called_once_with(event, polymorphic=False)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_join_when_not_until_close(self, bot, event_manager):
         shard0 = mock.Mock()
         shard1 = mock.Mock()
@@ -430,7 +424,7 @@ async def test_join_when_not_until_close(self, bot, event_manager):
             *(shard0.join.return_value, shard1.join.return_value, shard2.join.return_value)
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_join_when_until_close(self, bot):
         shard0 = mock.Mock()
         shard1 = mock.Mock()
@@ -480,7 +474,7 @@ def test_run_with_asyncio_debug(self, bot):
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "start", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
-        loop = stack.enter_context(mock.patch.object(asyncio, "get_event_loop")).return_value
+        loop = stack.enter_context(mock.patch.object(aio, "get_or_make_loop")).return_value
 
         with stack:
             bot.run(close_loop=False, asyncio_debug=True)
@@ -492,7 +486,7 @@ def test_run_with_coroutine_tracking_depth(self, bot):
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "start", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
-        stack.enter_context(mock.patch.object(asyncio, "get_event_loop"))
+        stack.enter_context(mock.patch.object(aio, "get_or_make_loop"))
         coroutine_tracking_depth = stack.enter_context(
             mock.patch.object(sys, "set_coroutine_origin_tracking_depth", side_effect=AttributeError)
         )
@@ -507,7 +501,7 @@ def test_run_with_enable_signal_handlers(self, bot):
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "start", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
-        stack.enter_context(mock.patch.object(asyncio, "get_event_loop"))
+        stack.enter_context(mock.patch.object(aio, "get_or_make_loop"))
         signal_function = stack.enter_context(
             mock.patch.object(signal, "signal", side_effect=[None, AttributeError, None, AttributeError])
         )
@@ -534,7 +528,7 @@ def raise_signal(*args, **kwargs):
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=raise_signal))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl, "_LOGGER", isEnabledFor=mock.Mock(return_value=logging)))
-        loop = stack.enter_context(mock.patch.object(asyncio, "get_event_loop")).return_value
+        loop = stack.enter_context(mock.patch.object(aio, "get_or_make_loop")).return_value
         set_close_flag = stack.enter_context(mock.patch.object(bot_impl.BotApp, "_set_close_flag", new=mock.Mock()))
         run_coroutine_threadsafe = stack.enter_context(mock.patch.object(asyncio, "run_coroutine_threadsafe"))
 
@@ -550,7 +544,7 @@ def test_run_with_close_passed_executor(self, bot):
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "start", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
-        stack.enter_context(mock.patch.object(asyncio, "get_event_loop"))
+        stack.enter_context(mock.patch.object(aio, "get_or_make_loop"))
         executor = mock.Mock()
         bot._executor = executor
 
@@ -566,7 +560,7 @@ def test_run_with_close_loop(self, bot):
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=mock.Mock()))
         stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
         destroy_loop = stack.enter_context(mock.patch.object(bot_impl.BotApp, "_destroy_loop"))
-        loop = stack.enter_context(mock.patch.object(asyncio, "get_event_loop")).return_value
+        loop = stack.enter_context(mock.patch.object(aio, "get_or_make_loop")).return_value
 
         with stack:
             bot.run(close_loop=True)
@@ -588,7 +582,7 @@ def test_run(self, bot):
         start_function = stack.enter_context(mock.patch.object(bot_impl.BotApp, "start", new=mock.Mock()))
         join_function = stack.enter_context(mock.patch.object(bot_impl.BotApp, "join", new=mock.Mock()))
         close_function = stack.enter_context(mock.patch.object(bot_impl.BotApp, "close", new=mock.Mock()))
-        loop = stack.enter_context(mock.patch.object(asyncio, "get_event_loop")).return_value
+        loop = stack.enter_context(mock.patch.object(aio, "get_or_make_loop")).return_value
 
         with stack:
             bot.run(
@@ -628,12 +622,12 @@ def test_run(self, bot):
             status=status,
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_start_when_shard_ids_specified_without_shard_count(self, bot):
         with pytest.raises(TypeError, match=r"'shard_ids' must be passed with 'shard_count'"):
             await bot.start(shard_ids={1})
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_start_when_already_running(self, bot):
         bot._is_alive = True
 
@@ -669,7 +663,7 @@ def test_unsubscribe(self, bot):
 
         bot._event_manager.unsubscribe.assert_called_once_with(event_type, callback)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_wait_for(self, bot):
         event_type = object()
         predicate = object()
@@ -702,7 +696,7 @@ def test_get_shard(self, bot):
 
         calculate_shard_id.assert_called_once_with(96, 702763150025556029)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_update_presence(self, bot):
         status = object()
         activity = object()
@@ -730,7 +724,7 @@ async def test_update_presence(self, bot):
         shard1.update_presence.assert_called_once_with(status=status, activity=activity, idle_since=idle_since, afk=afk)
         shard2.update_presence.assert_called_once_with(status=status, activity=activity, idle_since=idle_since, afk=afk)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_update_voice_state(self, bot):
         shard = mock.Mock()
         shard.update_voice_state = mock.AsyncMock()
@@ -745,7 +739,7 @@ async def test_update_voice_state(self, bot):
             guild=115590097100865541, channel=123, self_mute=True, self_deaf=False
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_request_guild_members(self, bot):
         shard = mock.Mock(shard_count=3)
         shard.request_guild_members = mock.AsyncMock()
@@ -772,14 +766,14 @@ async def test_request_guild_members(self, bot):
             nonce="NONCE",
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_set_close_flag(self, bot):
         with mock.patch.object(bot_impl.BotApp, "close") as close:
             await bot._set_close_flag("Terminated", 15)
 
-        close.assert_awaited_once_with(force=False)
+        close.assert_awaited_once_with()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_start_one_shard(self, bot):
         activity = object()
         status = object()
@@ -824,7 +818,7 @@ async def test_start_one_shard(self, bot):
         assert bot._shards == {1: shard_obj}
         first_completed.assert_awaited_once_with(shard_obj.start.return_value, closing_event.wait.return_value)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_start_one_shard_when_not_alive(self, bot):
         activity = object()
         status = object()
diff --git a/tests/hikari/impl/test_buckets.py b/tests/hikari/impl/test_buckets.py
index f6aa33be..86d23b7b 100644
--- a/tests/hikari/impl/test_buckets.py
+++ b/tests/hikari/impl/test_buckets.py
@@ -42,7 +42,7 @@ def template(self):
     def compiled_route(self, template):
         return routes.CompiledRoute("/foo/bar", template, "1a2b3c")
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_async_context_manager(self, compiled_route):
         with mock.patch.object(asyncio, "Lock") as lock:
             lock.return_value.acquire = mock.AsyncMock()
@@ -80,7 +80,7 @@ def test_drip(self, name, compiled_route):
             rl.drip()
             assert rl.remaining == 0 if name != buckets.UNKNOWN_HASH else 1
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_when_unknown_bucket(self, compiled_route):
         with buckets.RESTBucket(buckets.UNKNOWN_HASH, compiled_route, float("inf")) as rl:
             rl._lock = mock.AsyncMock()
@@ -90,7 +90,7 @@ async def test_acquire_when_unknown_bucket(self, compiled_route):
             rl._lock.acquire.assert_awaited_once_with()
             super_acquire.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_when_too_long_ratelimit(self, compiled_route):
         with buckets.RESTBucket("spaghetti", compiled_route, 60) as rl:
             rl.reset_at = time.perf_counter() + 999999999999999999999999999
@@ -98,7 +98,7 @@ async def test_acquire_when_too_long_ratelimit(self, compiled_route):
                 with pytest.raises(errors.RateLimitTooLongError):
                     await rl.acquire()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire(self, compiled_route):
         with buckets.RESTBucket("spaghetti", compiled_route, float("inf")) as rl:
             rl._lock = mock.AsyncMock()
@@ -123,7 +123,7 @@ def test_resolve(self, compiled_route):
 
 
 class TestRESTBucketManager:
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_close_closes_all_buckets(self):
         class MockBucket:
             def __init__(self):
@@ -139,14 +139,14 @@ def __init__(self):
         for i, bucket in enumerate(buckets_array):
             bucket.close.assert_called_once(), i
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_close_sets_closed_event(self):
         mgr = buckets.RESTBucketManager(max_rate_limit=float("inf"))
         assert not mgr.closed_event.is_set()
         mgr.close()
         assert mgr.closed_event.is_set()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_start(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             assert mgr.gc_task is None
@@ -155,7 +155,7 @@ async def test_start(self):
             mgr.start()
             assert mgr.gc_task is not None
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_exit_closes(self):
         with mock.patch.object(buckets.RESTBucketManager, "close") as close:
             with mock.patch.object(buckets.RESTBucketManager, "gc") as gc:
@@ -164,7 +164,7 @@ async def test_exit_closes(self):
                 gc.assert_called_once_with(0.01, 32)
             close.assert_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_gc_polls_until_closed_event_set(self):
         # This is shit, but it is good shit.
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
@@ -183,7 +183,7 @@ async def test_gc_polls_until_closed_event_set(self):
             assert mgr.gc_task is None
             assert task.done()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_gc_calls_do_pass(self):
         with hikari_test_helpers.mock_class_namespace(buckets.RESTBucketManager, slots_=False)(
             max_rate_limit=float("inf")
@@ -196,7 +196,7 @@ async def test_gc_calls_do_pass(self):
             finally:
                 mgr.gc_task.cancel()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_do_gc_pass_any_buckets_that_are_empty_but_still_rate_limited_are_kept_alive(self):
         with hikari_test_helpers.mock_class_namespace(buckets.RESTBucketManager)(max_rate_limit=float("inf")) as mgr:
             bucket = mock.Mock()
@@ -211,7 +211,7 @@ async def test_do_gc_pass_any_buckets_that_are_empty_but_still_rate_limited_are_
             assert "foobar" in mgr.real_hashes_to_buckets
             bucket.close.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_do_gc_pass_any_buckets_that_are_empty_but_not_rate_limited_and_not_expired_are_kept_alive(self):
         with hikari_test_helpers.mock_class_namespace(buckets.RESTBucketManager)(max_rate_limit=float("inf")) as mgr:
             bucket = mock.Mock()
@@ -226,7 +226,7 @@ async def test_do_gc_pass_any_buckets_that_are_empty_but_not_rate_limited_and_no
             assert "foobar" in mgr.real_hashes_to_buckets
             bucket.close.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_do_gc_pass_any_buckets_that_are_empty_but_not_rate_limited_and_expired_are_closed(self):
         with hikari_test_helpers.mock_class_namespace(buckets.RESTBucketManager)(max_rate_limit=float("inf")) as mgr:
             bucket = mock.Mock()
@@ -241,7 +241,7 @@ async def test_do_gc_pass_any_buckets_that_are_empty_but_not_rate_limited_and_ex
             assert "foobar" not in mgr.real_hashes_to_buckets
             bucket.close.assert_called_once()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_do_gc_pass_any_buckets_that_are_not_empty_are_kept_alive(self):
         with hikari_test_helpers.mock_class_namespace(buckets.RESTBucketManager)(max_rate_limit=float("inf")) as mgr:
             bucket = mock.Mock()
@@ -256,7 +256,7 @@ async def test_do_gc_pass_any_buckets_that_are_not_empty_are_kept_alive(self):
             assert "foobar" in mgr.real_hashes_to_buckets
             bucket.close.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_route_when_not_in_routes_to_real_hashes_makes_new_bucket_using_initial_hash(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -268,7 +268,7 @@ async def test_acquire_route_when_not_in_routes_to_real_hashes_makes_new_bucket_
             assert isinstance(mgr.real_hashes_to_buckets["UNKNOWN;bobs"], buckets.RESTBucket)
             create_unknown_hash.assert_called_once_with(route)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_route_when_not_in_routes_to_real_hashes_doesnt_cache_route(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -278,7 +278,7 @@ async def test_acquire_route_when_not_in_routes_to_real_hashes_doesnt_cache_rout
 
             assert mgr.routes_to_hashes.get(route.route) is None
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_route_when_route_cached_already_obtains_hash_from_route_and_bucket_from_hash(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -289,7 +289,7 @@ async def test_acquire_route_when_route_cached_already_obtains_hash_from_route_a
 
             assert mgr.acquire(route) is bucket
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_route_returns_context_manager(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -300,7 +300,7 @@ async def test_acquire_route_returns_context_manager(self):
 
                 assert mgr.acquire(route) is bucket
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_unknown_route_returns_context_manager_for_new_bucket(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -311,7 +311,7 @@ async def test_acquire_unknown_route_returns_context_manager_for_new_bucket(self
 
             assert mgr.acquire(route) is bucket
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_update_rate_limits_if_wrong_bucket_hash_reroutes_route(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -326,7 +326,7 @@ async def test_update_rate_limits_if_wrong_bucket_hash_reroutes_route(self):
             assert mgr.real_hashes_to_buckets["blep;bobs"] is bucket.return_value
             bucket.return_value.update_rate_limit.assert_called_once_with(22, 23, 27 + 3.56)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_update_rate_limits_if_unknown_bucket_hash_reroutes_route(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -345,7 +345,7 @@ async def test_update_rate_limits_if_unknown_bucket_hash_reroutes_route(self):
             bucket.update_rate_limit.assert_called_once_with(22, 23, 27 + 3.56)
             create_unknown_hash.assert_called_once_with(route)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_update_rate_limits_if_right_bucket_hash_does_nothing_to_hash(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
@@ -361,7 +361,7 @@ async def test_update_rate_limits_if_right_bucket_hash_does_nothing_to_hash(self
             assert mgr.real_hashes_to_buckets["123;bobs"] is bucket
             bucket.update_rate_limit.assert_called_once_with(22, 23, 27 + 7.65)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_update_rate_limits_updates_params(self):
         with buckets.RESTBucketManager(max_rate_limit=float("inf")) as mgr:
             route = mock.Mock()
diff --git a/tests/hikari/impl/test_entity_factory.py b/tests/hikari/impl/test_entity_factory.py
index 402b1569..28f7fd19 100644
--- a/tests/hikari/impl/test_entity_factory.py
+++ b/tests/hikari/impl/test_entity_factory.py
@@ -3048,6 +3048,7 @@ def test_deserialize_partial_message(
         assert partial_message.nonce == "171000788183678976"
 
     def test_deserialize_partial_message_with_partial_fields(self, entity_factory_impl, message_payload):
+        message_payload["content"] = ""
         message_payload["edited_timestamp"] = None
         message_payload["member"] = None
         message_payload["application"]["primary_sku_id"] = None
@@ -3056,7 +3057,10 @@ def test_deserialize_partial_message_with_partial_fields(self, entity_factory_im
         del message_payload["message_reference"]["message_id"]
         del message_payload["message_reference"]["guild_id"]
         del message_payload["application"]["cover_image"]
+
         partial_message = entity_factory_impl.deserialize_partial_message(message_payload)
+
+        assert partial_message.content is None
         assert partial_message.edited_timestamp is None
         assert partial_message._guild_id is not None
         assert partial_message.member is None
@@ -3069,6 +3073,7 @@ def test_deserialize_partial_message_with_partial_fields(self, entity_factory_im
 
     def test_deserialize_partial_message_with_unset_fields(self, entity_factory_impl, mock_app):
         partial_message = entity_factory_impl.deserialize_partial_message({"id": 123, "channel_id": 456})
+
         assert partial_message.app is mock_app
         assert partial_message.id == 123
         assert partial_message.channel_id == 456
@@ -3213,7 +3218,7 @@ def test_deserialize_message_with_null_and_unset_fields(
             "id": "123",
             "channel_id": "456",
             "author": user_payload,
-            "content": "some info",
+            "content": "",
             "timestamp": "2020-03-21T21:20:16.510000+00:00",
             "edited_timestamp": None,
             "tts": True,
@@ -3228,6 +3233,7 @@ def test_deserialize_message_with_null_and_unset_fields(
 
         message = entity_factory_impl.deserialize_message(message_payload)
         assert message.app is mock_app
+        assert message.content is None
         assert message._guild_id is None
         assert message.member is None
         assert message.edited_timestamp is None
diff --git a/tests/hikari/impl/test_event_manager.py b/tests/hikari/impl/test_event_manager.py
index c3da1bf0..95a57bd8 100644
--- a/tests/hikari/impl/test_event_manager.py
+++ b/tests/hikari/impl/test_event_manager.py
@@ -85,7 +85,7 @@ def stateless_event_manager(self, app):
         obj.dispatch = mock.AsyncMock()
         return obj
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_ready_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(my_user=mock.Mock())
@@ -98,7 +98,7 @@ async def test_on_ready_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_ready_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_ready_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -109,7 +109,7 @@ async def test_on_ready_stateless(self, stateless_event_manager, shard, app):
             stateless_event_manager._app.event_factory.deserialize_ready_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_resumed(self, event_manager, shard, app):
         payload = {}
 
@@ -120,7 +120,7 @@ async def test_on_resumed(self, event_manager, shard, app):
             event_manager._app.event_factory.deserialize_resumed_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_create_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(channel=mock.Mock(channels.GuildChannel))
@@ -133,7 +133,7 @@ async def test_on_channel_create_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_channel_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_create_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -146,7 +146,7 @@ async def test_on_channel_create_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_channel_create_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_update_stateful(self, event_manager, shard, app):
         payload = {"id": 123}
         old_channel = object()
@@ -164,7 +164,7 @@ async def test_on_channel_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"id": 123}
 
@@ -177,7 +177,7 @@ async def test_on_channel_update_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_channel_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_delete_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(channel=mock.Mock(id=123))
@@ -190,7 +190,7 @@ async def test_on_channel_delete_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_channel_delete_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_delete_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -203,7 +203,7 @@ async def test_on_channel_delete_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_channel_delete_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_channel_pins_update(self, stateless_event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -217,7 +217,7 @@ async def test_on_channel_pins_update(self, stateless_event_manager, shard, app)
         )
         stateless_event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_create_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(
@@ -262,7 +262,7 @@ async def test_on_guild_create_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_guild_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_create_when_request_chunks(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(
@@ -312,7 +312,7 @@ async def test_on_guild_create_when_request_chunks(self, event_manager, shard, a
         event_manager._app.event_factory.deserialize_guild_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_create_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -327,7 +327,7 @@ async def test_on_guild_create_stateless(self, stateless_event_manager, shard, a
             stateless_event_manager._app.event_factory.deserialize_guild_create_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_update_stateful(self, event_manager, shard, app):
         payload = {"id": 123}
         old_guild = object()
@@ -351,7 +351,7 @@ async def test_on_guild_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"id": 123}
 
@@ -364,7 +364,7 @@ async def test_on_guild_update_stateless(self, stateless_event_manager, shard, a
             stateless_event_manager._app.event_factory.deserialize_guild_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_delete_stateful_when_available(self, event_manager, shard, app):
         payload = {"unavailable": False}
         event = mock.Mock(guild_id=123)
@@ -384,7 +384,7 @@ async def test_on_guild_delete_stateful_when_available(self, event_manager, shar
         event_manager._app.event_factory.deserialize_guild_leave_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_delete_stateful_when_unavailable(self, event_manager, shard, app):
         payload = {"unavailable": True}
         event = mock.Mock(guild_id=123)
@@ -397,7 +397,7 @@ async def test_on_guild_delete_stateful_when_unavailable(self, event_manager, sh
         event_manager._app.event_factory.deserialize_guild_unavailable_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_delete_stateless_when_available(self, stateless_event_manager, shard, app):
         payload = {"unavailable": False}
 
@@ -408,7 +408,7 @@ async def test_on_guild_delete_stateless_when_available(self, stateless_event_ma
             stateless_event_manager._app.event_factory.deserialize_guild_leave_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_delete_stateless_when_unavailable(self, stateless_event_manager, shard, app):
         payload = {"unavailable": True}
 
@@ -421,7 +421,7 @@ async def test_on_guild_delete_stateless_when_unavailable(self, stateless_event_
             stateless_event_manager._app.event_factory.deserialize_guild_unavailable_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_ban_add(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -433,7 +433,7 @@ async def test_on_guild_ban_add(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_guild_ban_add_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_ban_remove(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -445,7 +445,7 @@ async def test_on_guild_ban_remove(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_guild_ban_remove_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_emojis_update_stateful(self, event_manager, shard, app):
         payload = {"guild_id": 123}
         old_emojis = {"Test": 123}
@@ -464,7 +464,7 @@ async def test_on_guild_emojis_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_emojis_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"guild_id": 123}
 
@@ -477,13 +477,13 @@ async def test_on_guild_emojis_update_stateless(self, stateless_event_manager, s
             stateless_event_manager._app.event_factory.deserialize_guild_emojis_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_integrations_update(self, event_manager, shard):
         assert await event_manager.on_guild_integrations_update(shard, {}) is None
 
         event_manager.dispatch.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_integration_create(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -495,7 +495,7 @@ async def test_on_integration_create(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_integration_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_integration_delete(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -507,7 +507,7 @@ async def test_on_integration_delete(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_integration_delete_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_integration_update(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -519,7 +519,7 @@ async def test_on_integration_update(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_integration_update_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_member_add_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(user=object(), member=object())
@@ -532,7 +532,7 @@ async def test_on_guild_member_add_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_guild_member_add_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_member_add_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -545,7 +545,7 @@ async def test_on_guild_member_add_stateless(self, stateless_event_manager, shar
             stateless_event_manager._app.event_factory.deserialize_guild_member_add_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_member_remove_stateful(self, event_manager, shard, app):
         payload = {"guild_id": "456", "user": {"id": "123"}}
 
@@ -559,7 +559,7 @@ async def test_on_guild_member_remove_stateful(self, event_manager, shard, app):
             event_manager._app.event_factory.deserialize_guild_member_remove_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_member_remove_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -572,7 +572,7 @@ async def test_on_guild_member_remove_stateless(self, stateless_event_manager, s
             stateless_event_manager._app.event_factory.deserialize_guild_member_remove_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_member_update_stateful(self, event_manager, shard, app):
         payload = {"user": {"id": 123}, "guild_id": 456}
         old_member = object()
@@ -590,7 +590,7 @@ async def test_on_guild_member_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_member_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"user": {"id": 123}, "guild_id": 456}
 
@@ -603,7 +603,7 @@ async def test_on_guild_member_update_stateless(self, stateless_event_manager, s
             stateless_event_manager._app.event_factory.deserialize_guild_member_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_members_chunk_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(members={"TestMember": 123}, presences={"TestPresences": 456})
@@ -616,7 +616,7 @@ async def test_on_guild_members_chunk_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_guild_member_chunk_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_members_chunk_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -629,7 +629,7 @@ async def test_on_guild_members_chunk_stateless(self, stateless_event_manager, s
             stateless_event_manager._app.event_factory.deserialize_guild_member_chunk_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_role_create_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(role=object())
@@ -642,7 +642,7 @@ async def test_on_guild_role_create_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_guild_role_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_role_create_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -655,7 +655,7 @@ async def test_on_guild_role_create_stateless(self, stateless_event_manager, sha
             stateless_event_manager._app.event_factory.deserialize_guild_role_create_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_role_update_stateful(self, event_manager, shard, app):
         payload = {"role": {"id": 123}}
         old_role = object()
@@ -673,7 +673,7 @@ async def test_on_guild_role_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_role_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"role": {"id": 123}}
 
@@ -686,7 +686,7 @@ async def test_on_guild_role_update_stateless(self, stateless_event_manager, sha
             stateless_event_manager._app.event_factory.deserialize_guild_role_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_role_delete_stateful(self, event_manager, shard, app):
         payload = {"role_id": "123"}
 
@@ -700,7 +700,7 @@ async def test_on_guild_role_delete_stateful(self, event_manager, shard, app):
             event_manager._app.event_factory.deserialize_guild_role_delete_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_guild_role_delete_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -713,7 +713,7 @@ async def test_on_guild_role_delete_stateless(self, stateless_event_manager, sha
             stateless_event_manager._app.event_factory.deserialize_guild_role_delete_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_invite_create_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(invite="qwerty")
@@ -726,7 +726,7 @@ async def test_on_invite_create_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_invite_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_invite_create_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -739,7 +739,7 @@ async def test_on_invite_create_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_invite_create_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_invite_delete_stateful(self, event_manager, shard, app):
         payload = {"code": "qwerty"}
 
@@ -753,7 +753,7 @@ async def test_on_invite_delete_stateful(self, event_manager, shard, app):
             event_manager._app.event_factory.deserialize_invite_delete_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_invite_delete_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -766,7 +766,7 @@ async def test_on_invite_delete_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_invite_delete_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_create_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(message=object())
@@ -779,7 +779,7 @@ async def test_on_message_create_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_message_create_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_create_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -792,7 +792,7 @@ async def test_on_message_create_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_message_create_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_update_stateful(self, event_manager, shard, app):
         payload = {"id": 123}
         old_message = object()
@@ -810,7 +810,7 @@ async def test_on_message_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"id": 123}
 
@@ -823,7 +823,7 @@ async def test_on_message_update_stateless(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_message_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_delete_stateless(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(message_id=123)
@@ -836,7 +836,7 @@ async def test_on_message_delete_stateless(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_message_delete_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_delete_stateful(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -849,7 +849,7 @@ async def test_on_message_delete_stateful(self, stateless_event_manager, shard,
             stateless_event_manager._app.event_factory.deserialize_message_delete_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_delete_bulk_stateful(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock(message_ids=[123, 456, 789])
@@ -862,7 +862,7 @@ async def test_on_message_delete_bulk_stateful(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_message_delete_bulk_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_delete_bulk_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -875,7 +875,7 @@ async def test_on_message_delete_bulk_stateless(self, stateless_event_manager, s
             stateless_event_manager._app.event_factory.deserialize_message_delete_bulk_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_reaction_add(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -887,7 +887,7 @@ async def test_on_message_reaction_add(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_message_reaction_add_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_reaction_remove(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -901,7 +901,7 @@ async def test_on_message_reaction_remove(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_reaction_remove_all(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -915,7 +915,7 @@ async def test_on_message_reaction_remove_all(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_message_reaction_remove_emoji(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -929,7 +929,7 @@ async def test_on_message_reaction_remove_emoji(self, event_manager, shard, app)
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_presence_update_stateful_update(self, event_manager, shard, app):
         payload = {"user": {"id": 123}, "guild_id": 456}
         old_presence = object()
@@ -947,7 +947,7 @@ async def test_on_presence_update_stateful_update(self, event_manager, shard, ap
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_presence_update_stateful_delete(self, event_manager, shard, app):
         payload = {"user": {"id": 123}, "guild_id": 456}
         old_presence = object()
@@ -965,7 +965,7 @@ async def test_on_presence_update_stateful_delete(self, event_manager, shard, ap
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_presence_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"user": {"id": 123}, "guild_id": 456}
 
@@ -978,7 +978,7 @@ async def test_on_presence_update_stateless(self, stateless_event_manager, shard
             stateless_event_manager._app.event_factory.deserialize_presence_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_typing_start(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -990,7 +990,7 @@ async def test_on_typing_start(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_typing_start_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_user_update_stateful(self, event_manager, shard, app):
         payload = {}
         old_user = object()
@@ -1007,7 +1007,7 @@ async def test_on_user_update_stateful(self, event_manager, shard, app):
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_user_update_stateless(self, stateless_event_manager, shard, app):
         payload = {}
 
@@ -1020,7 +1020,7 @@ async def test_on_user_update_stateless(self, stateless_event_manager, shard, ap
             stateless_event_manager._app.event_factory.deserialize_own_user_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_voice_state_update_stateful_update(self, event_manager, shard, app):
         payload = {"user_id": 123, "guild_id": 456}
         old_state = object()
@@ -1038,7 +1038,7 @@ async def test_on_voice_state_update_stateful_update(self, event_manager, shard,
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_voice_state_update_stateful_delete(self, event_manager, shard, app):
         payload = {"user_id": 123, "guild_id": 456}
         old_state = object()
@@ -1056,7 +1056,7 @@ async def test_on_voice_state_update_stateful_delete(self, event_manager, shard,
         )
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_voice_state_update_stateless(self, stateless_event_manager, shard, app):
         payload = {"user_id": 123, "guild_id": 456}
 
@@ -1069,7 +1069,7 @@ async def test_on_voice_state_update_stateless(self, stateless_event_manager, sh
             stateless_event_manager._app.event_factory.deserialize_voice_state_update_event.return_value
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_voice_server_update(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
@@ -1081,7 +1081,7 @@ async def test_on_voice_server_update(self, event_manager, shard, app):
         event_manager._app.event_factory.deserialize_voice_server_update_event.assert_called_once_with(shard, payload)
         event_manager.dispatch.assert_awaited_once_with(event)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_webhooks_update(self, event_manager, shard, app):
         payload = {}
         event = mock.Mock()
diff --git a/tests/hikari/impl/test_event_manager_base.py b/tests/hikari/impl/test_event_manager_base.py
index 00f427bd..dc487bd8 100644
--- a/tests/hikari/impl/test_event_manager_base.py
+++ b/tests/hikari/impl/test_event_manager_base.py
@@ -58,7 +58,7 @@ async def not_a_listener(self):
         manager = StubManager(mock.Mock(intents=42))
         assert manager._consumers == {"foo": manager.on_foo, "bar": manager.on_bar}
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_consume_raw_event_when_KeyError(self, event_manager):
         mock_payload = {"id": "3123123123"}
         mock_shard = mock.Mock(id=123)
@@ -76,7 +76,7 @@ async def test_consume_raw_event_when_KeyError(self, event_manager):
             mock_shard, mock_payload, name="UNEXISTING_EVENT"
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_consume_raw_event_when_found(self, event_manager):
         event_manager._handle_dispatch = mock.Mock()
         event_manager.dispatch = mock.Mock()
@@ -100,7 +100,7 @@ async def test_consume_raw_event_when_found(self, event_manager):
             shard, payload, name="EXISTING_EVENT"
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_handle_dispatch_invokes_callback(self, event_manager, event_loop):
         callback = mock.AsyncMock()
         error_handler = mock.MagicMock()
@@ -113,7 +113,7 @@ async def test_handle_dispatch_invokes_callback(self, event_manager, event_loop)
         callback.assert_awaited_once_with(shard, pl)
         error_handler.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_handle_dispatch_ignores_cancelled_errors(self, event_manager, event_loop):
         callback = mock.AsyncMock(side_effect=asyncio.CancelledError)
         error_handler = mock.MagicMock()
@@ -125,7 +125,7 @@ async def test_handle_dispatch_ignores_cancelled_errors(self, event_manager, eve
 
         error_handler.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_handle_dispatch_handles_exceptions(self, event_manager, event_loop):
         exc = Exception("aaaa!")
         callback = mock.AsyncMock(side_effect=exc)
@@ -165,7 +165,7 @@ async def test():
             ...
 
         with mock.patch.object(event_manager_base.EventManagerBase, "_check_intents") as check:
-            assert event_manager.subscribe(member_events.MemberCreateEvent, test, _nested=1) == test
+            event_manager.subscribe(member_events.MemberCreateEvent, test, _nested=1)
 
         assert event_manager._listeners == {member_events.MemberCreateEvent: [test]}
         check.assert_called_once_with(member_events.MemberCreateEvent, 1)
@@ -180,7 +180,7 @@ async def test2():
         event_manager._listeners[member_events.MemberCreateEvent] = [test2]
 
         with mock.patch.object(event_manager_base.EventManagerBase, "_check_intents") as check:
-            assert event_manager.subscribe(member_events.MemberCreateEvent, test, _nested=2) == test
+            event_manager.subscribe(member_events.MemberCreateEvent, test, _nested=2)
 
         assert event_manager._listeners == {member_events.MemberCreateEvent: [test2, test]}
         check.assert_called_once_with(member_events.MemberCreateEvent, 2)
diff --git a/tests/hikari/impl/test_rate_limits.py b/tests/hikari/impl/test_rate_limits.py
index 6cfffc17..7952e824 100644
--- a/tests/hikari/impl/test_rate_limits.py
+++ b/tests/hikari/impl/test_rate_limits.py
@@ -103,7 +103,7 @@ def test_close_when_closed(self, mock_burst_limiter):
 
 
 class TestManualRateLimiter:
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_returns_completed_future_if_throttle_task_is_None(self, event_loop):
         with rate_limits.ManualRateLimiter() as limiter:
             limiter.throttle_task = None
@@ -113,7 +113,7 @@ async def test_acquire_returns_completed_future_if_throttle_task_is_None(self, e
             await limiter.acquire()
             future.set_result.assert_called_once_with(None)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_returns_incomplete_future_if_throttle_task_is_not_None(self, event_loop):
         with rate_limits.ManualRateLimiter() as limiter:
             limiter.throttle_task = event_loop.create_future()
@@ -123,7 +123,7 @@ async def test_acquire_returns_incomplete_future_if_throttle_task_is_not_None(se
             await limiter.acquire()
             future.set_result.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_acquire_places_future_on_queue_if_throttle_task_is_not_None(self, event_loop):
         with rate_limits.ManualRateLimiter() as limiter:
             limiter.throttle_task = event_loop.create_future()
@@ -138,7 +138,7 @@ async def test_acquire_places_future_on_queue_if_throttle_task_is_not_None(self,
             assert future in limiter.queue
             future.set_result.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_cancels_existing_task(self):
         with rate_limits.ManualRateLimiter() as limiter:
             limiter.throttle_task = asyncio.get_running_loop().create_future()
@@ -147,7 +147,7 @@ async def test_throttle_cancels_existing_task(self):
             assert old_task.cancelled()
             assert old_task is not limiter.throttle_task
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_schedules_throttle(self):
         with hikari_test_helpers.mock_class_namespace(rate_limits.ManualRateLimiter, slots_=False)() as limiter:
             limiter.unlock_later = mock.AsyncMock()
@@ -155,7 +155,7 @@ async def test_throttle_schedules_throttle(self):
             await limiter.throttle_task
             limiter.unlock_later.assert_called_once_with(0)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_chews_queue_completing_futures(self, event_loop):
         with rate_limits.ManualRateLimiter() as limiter:
             futures = [event_loop.create_future() for _ in range(10)]
@@ -164,7 +164,7 @@ async def test_throttle_chews_queue_completing_futures(self, event_loop):
             for i, future in enumerate(futures):
                 assert future.done(), f"future {i} was not done"
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_sleeps_before_popping_queue(self, event_loop):
         # GIVEN
         slept_at = float("nan")
@@ -190,7 +190,7 @@ def pop(self, _=-1):
         for i, pop_time in enumerate(popped_at):
             assert slept_at < pop_time, f"future {i} popped before initial sleep"
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_clears_throttle_task(self, event_loop):
         with rate_limits.ManualRateLimiter() as limiter:
             limiter.throttle_task = event_loop.create_future()
@@ -208,7 +208,7 @@ def ratelimiter(self):
         with contextlib.suppress(Exception):
             inst.close()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_drip_if_not_throttled_and_not_ratelimited(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = None
@@ -221,7 +221,7 @@ async def test_drip_if_not_throttled_and_not_ratelimited(self, ratelimiter, even
         ratelimiter.drip.assert_called_once_with()
         future.set_result.assert_called_once_with(None)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_no_drip_if_throttle_task_is_not_None(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = asyncio.get_running_loop().create_future()
@@ -233,7 +233,7 @@ async def test_no_drip_if_throttle_task_is_not_None(self, ratelimiter, event_loo
 
         ratelimiter.drip.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_no_drip_if_rate_limited(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = False
@@ -245,7 +245,7 @@ async def test_no_drip_if_rate_limited(self, ratelimiter, event_loop):
 
         ratelimiter.drip.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_task_scheduled_if_rate_limited_and_throttle_task_is_None(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = None
@@ -259,7 +259,7 @@ async def test_task_scheduled_if_rate_limited_and_throttle_task_is_None(self, ra
 
         ratelimiter.throttle.assert_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_task_not_scheduled_if_rate_limited_and_throttle_task_not_None(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = event_loop.create_future()
@@ -271,7 +271,7 @@ async def test_task_not_scheduled_if_rate_limited_and_throttle_task_not_None(sel
         await ratelimiter.acquire()
         assert old_task is ratelimiter.throttle_task, "task was rescheduled, that shouldn't happen :("
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_future_is_added_to_queue_if_throttle_task_is_not_None(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = asyncio.get_running_loop().create_future()
@@ -284,7 +284,7 @@ async def test_future_is_added_to_queue_if_throttle_task_is_not_None(self, ratel
         # use slice to prevent aborting test with index error rather than assertion error if this fails.
         assert ratelimiter.queue[-1:] == [future]
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_future_is_added_to_queue_if_rate_limited(self, ratelimiter, event_loop):
         ratelimiter.drip = mock.Mock()
         ratelimiter.throttle_task = None
@@ -299,7 +299,7 @@ async def test_future_is_added_to_queue_if_rate_limited(self, ratelimiter, event
         finally:
             ratelimiter.throttle_task.cancel()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_consumes_queue(self, event_loop):
         with rate_limits.WindowedBurstRateLimiter(__name__, 0.01, 1) as rl:
             rl.queue = [event_loop.create_future() for _ in range(15)]
@@ -310,7 +310,7 @@ async def test_throttle_consumes_queue(self, event_loop):
         for i, future in enumerate(old_queue):
             assert future.done(), f"future {i} was incomplete!"
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout(20)
     @hikari_test_helpers.retry(5)
     async def test_throttle_when_limited_sleeps_then_bursts_repeatedly(self, event_loop):
@@ -398,7 +398,7 @@ def create_task(i):
                 f"max diff = {max_distance_within_window}"
             )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_throttle_resets_throttle_task(self, event_loop):
         with rate_limits.WindowedBurstRateLimiter(__name__, 0.01, 1) as rl:
             rl.queue = [event_loop.create_future() for _ in range(15)]
diff --git a/tests/hikari/impl/test_shard.py b/tests/hikari/impl/test_shard.py
index 75b05633..8eacae5d 100644
--- a/tests/hikari/impl/test_shard.py
+++ b/tests/hikari/impl/test_shard.py
@@ -626,17 +626,19 @@ def test_intents_property(self, client):
         client._intents = intents
         assert client.intents is intents
 
-    @pytest.mark.parametrize(
-        ("run_task", "expected"),
-        [
-            (None, False),
-            (asyncio.get_event_loop().create_future(), True),
-            (aio.completed_future(), False),
-        ],
-    )
-    def test_is_alive_property(self, run_task, expected, client):
-        client._run_task = run_task
-        assert client.is_alive is expected
+    def test_is_alive_property(self, client):
+        client._run_task = None
+        assert client.is_alive is False
+
+    @pytest.mark.asyncio()
+    async def test_is_alive_property_with_active_future(self, client):
+        client._run_task = asyncio.get_running_loop().create_future()
+        assert client.is_alive is True
+
+    @pytest.mark.asyncio()
+    async def test_is_alive_property_with_finished_future(self, client):
+        client._run_task = aio.completed_future()
+        assert client.is_alive is False
 
     def test_shard_count_property(self, client):
         client._shard_count = 69
@@ -651,45 +653,51 @@ def test_shard__check_if_alive_when_alive(self, client):
         with mock.patch.object(shard.GatewayShardImpl, "is_alive", new=True):
             client._check_if_alive()
 
-    async def test_close_when_closing_set(self, client):
-        client._closing = mock.Mock(is_set=mock.Mock(return_value=True))
+    async def test_close_when_closing_event_set(self, client):
+        client._closing_event = mock.Mock(is_set=mock.Mock(return_value=True))
+        client._closed_event = mock.Mock(wait=mock.AsyncMock())
         client._send_close = mock.Mock()
         client._chunking_rate_limit = mock.Mock()
         client._total_rate_limit = mock.Mock()
 
         await client.close()
 
-        client._closing.set.assert_not_called()
+        client._closing_event.set.assert_not_called()
         client._send_close.assert_not_called()
         client._chunking_rate_limit.close.assert_not_called()
         client._total_rate_limit.close.assert_not_called()
+        client._closed_event.wait.assert_awaited_once_with()
 
-    async def test_close_when_closing_not_set(self, client):
-        client._closing = mock.Mock(is_set=mock.Mock(return_value=False))
+    async def test_close_when_closing_event_not_set(self, client):
+        client._closing_event = mock.Mock(is_set=mock.Mock(return_value=False))
+        client._closed_event = mock.Mock(wait=mock.AsyncMock())
         client._ws = mock.Mock(send_close=mock.AsyncMock())
         client._chunking_rate_limit = mock.Mock()
         client._total_rate_limit = mock.Mock()
 
         await client.close()
 
-        client._closing.set.assert_called_once_with()
+        client._closing_event.set.assert_called_once_with()
         client._ws.send_close.assert_awaited_once_with(
             code=errors.ShardCloseCode.GOING_AWAY, message=b"shard disconnecting"
         )
         client._chunking_rate_limit.close.assert_called_once_with()
         client._total_rate_limit.close.assert_called_once_with()
+        client._closed_event.wait.assert_awaited_once_with()
 
-    async def test_close_when_closing_not_set_and_ws_is_None(self, client):
-        client._closing = mock.Mock(is_set=mock.Mock(return_value=False))
+    async def test_close_when_closing_event_not_set_and_ws_is_None(self, client):
+        client._closing_event = mock.Mock(is_set=mock.Mock(return_value=False))
+        client._closed_event = mock.Mock(wait=mock.AsyncMock())
         client._ws = None
         client._chunking_rate_limit = mock.Mock()
         client._total_rate_limit = mock.Mock()
 
         await client.close()
 
-        client._closing.set.assert_called_once_with()
+        client._closing_event.set.assert_called_once_with()
         client._chunking_rate_limit.close.assert_called_once_with()
         client._total_rate_limit.close.assert_called_once_with()
+        client._closed_event.wait.assert_awaited_once_with()
 
     async def test_when__user_id_is_None(self, client):
         client._handshake_completed = mock.Mock(wait=mock.AsyncMock())
@@ -703,11 +711,11 @@ async def test_when__user_id_is_not_None(self, client):
         assert await client.get_user_id() == 123
 
     async def test_join(self, client):
-        client._closed = mock.Mock(wait=mock.AsyncMock())
+        client._closed_event = mock.Mock(wait=mock.AsyncMock())
 
         await client.join()
 
-        client._closed.wait.assert_awaited_once_with()
+        client._closed_event.wait.assert_awaited_once_with()
 
     async def test_request_guild_members_when_no_query_and_no_limit_and_GUILD_MEMBERS_not_enabled(self, client):
         client._check_if_alive = mock.Mock()
@@ -1007,15 +1015,15 @@ async def test__identify(self, client):
     async def test__heartbeat(self, client):
         client._last_heartbeat_sent = 5
         client._logger = mock.Mock()
-        client._closing = mock.Mock(is_set=mock.Mock(return_value=False))
-        client._closed = mock.Mock(is_set=mock.Mock(return_value=False))
+        client._closing_event = mock.Mock(is_set=mock.Mock(return_value=False))
+        client._closed_event = mock.Mock(is_set=mock.Mock(return_value=False))
         client._send_heartbeat = mock.AsyncMock()
 
         with mock.patch.object(time, "monotonic", return_value=10):
             with mock.patch.object(asyncio, "wait_for", side_effect=[asyncio.TimeoutError, None]) as wait_for:
                 assert await client._heartbeat(20) is False
 
-        wait_for.assert_awaited_with(client._closing.wait(), timeout=20)
+        wait_for.assert_awaited_with(client._closing_event.wait(), timeout=20)
 
     @hikari_test_helpers.timeout()
     async def test__heartbeat_when_zombie(self, client):
diff --git a/tests/hikari/internal/test_aio.py b/tests/hikari/internal/test_aio.py
index fc480215..aad61eb1 100644
--- a/tests/hikari/internal/test_aio.py
+++ b/tests/hikari/internal/test_aio.py
@@ -21,6 +21,7 @@
 # SOFTWARE.
 import asyncio
 
+import mock.mock
 import pytest
 
 from hikari.internal import aio
@@ -61,22 +62,22 @@ def test_coro_stub_neq(self):
 
 
 class TestCompletedFuture:
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @pytest.mark.parametrize("args", [(), (12,)])
     async def test_is_awaitable(self, args):
         await aio.completed_future(*args)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @pytest.mark.parametrize("args", [(), (12,)])
     async def test_is_completed(self, args):
         future = aio.completed_future(*args)
         assert future.done()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_default_result_is_none(self):
         assert aio.completed_future().result() is None
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_non_default_result(self):
         assert aio.completed_future(...).result() is ...
 
@@ -96,7 +97,7 @@ async def __anext__(self):
 
         assert aio.is_async_iterator(AsyncIterator)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_on_genexp(self):
         async def genexp():
             yield ...
@@ -379,3 +380,34 @@ async def test_cancels_all_if_cancelled(self, event_loop):
             await waiter
         assert waiter.cancelled(), "future was forcefully cancelled?"
         assert waiter.done(), "asyncio.CancelledError not raised?"
+
+
+def test_get_or_make_loop():
+    mock_loop = mock.Mock(asyncio.AbstractEventLoop, is_closed=mock.Mock(return_value=False))
+    asyncio.set_event_loop(mock_loop)
+
+    assert aio.get_or_make_loop() is mock_loop
+
+
+def test_get_or_make_loop_handles_runtime_error():
+    asyncio.set_event_loop(None)
+    mock_loop = mock.Mock(asyncio.AbstractEventLoop)
+
+    with mock.patch.object(asyncio, "new_event_loop", return_value=mock_loop) as new_event_loop:
+        assert aio.get_or_make_loop() is mock_loop
+
+        new_event_loop.assert_called_once_with()
+
+    assert asyncio.get_event_loop() is mock_loop
+
+
+def test_get_or_make_loop_handles_closed_loop():
+    asyncio.set_event_loop(mock.Mock(asyncio.AbstractEventLoop, is_closed=mock.Mock(return_value=True)))
+    mock_loop = mock.Mock(asyncio.AbstractEventLoop)
+
+    with mock.patch.object(asyncio, "new_event_loop", return_value=mock_loop) as new_event_loop:
+        assert aio.get_or_make_loop() is mock_loop
+
+        new_event_loop.assert_called_once_with()
+
+    assert asyncio.get_event_loop() is mock_loop
diff --git a/tests/hikari/internal/test_collections.py b/tests/hikari/internal/test_collections.py
index 5a5ffd89..2746cdaa 100644
--- a/tests/hikari/internal/test_collections.py
+++ b/tests/hikari/internal/test_collections.py
@@ -172,7 +172,7 @@ def test___delitem__(self):
         del mock_map["ok"]
         assert mock_map == {"ayanami": "rei qt"}
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test___delitem___garbage_collection(self):
         mock_map = collections.TimedCacheMap(
             expiry=datetime.timedelta(seconds=hikari_test_helpers.REASONABLE_QUICK_RESPONSE_TIME * 3)
@@ -186,7 +186,7 @@ async def test___delitem___garbage_collection(self):
         del mock_map["ayanami"]
         assert mock_map == {"rei": "aww"}
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test___delitem___garbage_collection_on_expire_set(self):
         expire_call = mock.Mock()
         mock_map = collections.TimedCacheMap(
@@ -239,7 +239,7 @@ def test___setitem___removes_old_entry_instead_of_replacing(self):
         mock_map["ok"] = "foo"
         assert list(mock_map.items())[2] == ("ok", "foo")
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test___setitem___garbage_collection(self):
         mock_map = collections.TimedCacheMap(
             expiry=datetime.timedelta(seconds=hikari_test_helpers.REASONABLE_QUICK_RESPONSE_TIME * 3)
diff --git a/tests/hikari/internal/test_ux.py b/tests/hikari/internal/test_ux.py
index 45672c5d..7c76df4b 100644
--- a/tests/hikari/internal/test_ux.py
+++ b/tests/hikari/internal/test_ux.py
@@ -233,48 +233,36 @@ def test_when_not_allow_color(self):
         assert ux.supports_color(False, True) is False
 
     def test_when_CLICOLOR_FORCE_in_env(self):
-        with mock.patch.object(os, "getenv", return_value="1") as getenv:
+        with mock.patch.dict(os.environ, {"CLICOLOR_FORCE": "1"}, clear=True):
             assert ux.supports_color(True, False) is True
 
-        getenv.assert_called_once_with("CLICOLOR_FORCE", "0")
-
     def test_when_force_color(self):
-        with mock.patch.object(os, "getenv", return_value="0") as getenv:
+        with mock.patch.dict(os.environ, {"CLICOLOR_FORCE": "0"}, clear=True):
             assert ux.supports_color(True, True) is True
 
-        getenv.assert_called_once_with("CLICOLOR_FORCE", "0")
-
     def test_when_CLICOLOR_and_is_a_tty(self):
         with mock.patch.object(sys.stdout, "isatty", return_value=True):
-            with mock.patch.object(os, "getenv", side_effect=["0", "1"]) as getenv:
+            with mock.patch.dict(os.environ, {"CLICOLOR_FORCE": "0", "CLICOLOR": "1"}, clear=True):
                 assert ux.supports_color(True, False) is True
 
-        assert getenv.call_count == 2
-        getenv.assert_has_calls([mock.call("CLICOLOR_FORCE", "0"), mock.call("CLICOLOR", "0")])
+    def test_when_CLICOLOR_is_0(self):
+        with mock.patch.object(sys.stdout, "isatty", return_value=True):
+            with mock.patch.dict(os.environ, {"CLICOLOR_FORCE": "0", "CLICOLOR": "0"}, clear=True):
+                assert ux.supports_color(True, False) is False
 
     @pytest.mark.parametrize("colorterm", ["truecolor", "24bit", "TRUECOLOR", "24BIT"])
     def test_when_COLORTERM_has_correct_value(self, colorterm):
-        with mock.patch.object(os, "getenv", side_effect=["0", "0", colorterm]) as getenv:
+        with mock.patch.dict(os.environ, {"COLORTERM": colorterm}, clear=True):
             assert ux.supports_color(True, False) is True
 
-        assert getenv.call_count == 3
-        getenv.assert_has_calls(
-            [mock.call("CLICOLOR_FORCE", "0"), mock.call("CLICOLOR", "0"), mock.call("COLORTERM", "")]
-        )
-
     def test_when_plat_is_Pocket_PC(self):
         stack = contextlib.ExitStack()
-        getenv = stack.enter_context(mock.patch.object(os, "getenv", return_value="0"))
+        stack.enter_context(mock.patch.dict(os.environ, {}, clear=True))
         stack.enter_context(mock.patch.object(sys, "platform", new="Pocket PC"))
 
         with stack:
             assert ux.supports_color(True, False) is False
 
-        assert getenv.call_count == 3
-        getenv.assert_has_calls(
-            [mock.call("CLICOLOR_FORCE", "0"), mock.call("CLICOLOR", "0"), mock.call("COLORTERM", "")]
-        )
-
     @pytest.mark.parametrize(
         ("term_program", "ansicon", "isatty", "expected"),
         [
@@ -288,78 +276,49 @@ def test_when_plat_is_Pocket_PC(self):
         ],
     )
     def test_when_plat_is_win32(self, term_program, ansicon, isatty, expected):
+        environ = {"TERM_PROGRAM": term_program}
+        if ansicon:
+            environ["ANSICON"] = "ooga booga"
+
         stack = contextlib.ExitStack()
-        getenv = stack.enter_context(mock.patch.object(os, "getenv", side_effect=["0", "0", "", term_program, ""]))
+        stack.enter_context(mock.patch.dict(os.environ, environ, clear=True))
         stack.enter_context(mock.patch.object(sys.stdout, "isatty", return_value=isatty))
         stack.enter_context(mock.patch.object(sys, "platform", new="win32"))
-        stack.enter_context(mock.patch.object(os, "environ", new=["ANSICON"] if ansicon else []))
 
         with stack:
             assert ux.supports_color(True, False) is expected
 
-        assert getenv.call_count == 5
-        getenv.assert_has_calls(
-            [
-                mock.call("CLICOLOR_FORCE", "0"),
-                mock.call("CLICOLOR", "0"),
-                mock.call("COLORTERM", ""),
-                mock.call("TERM_PROGRAM", None),
-                mock.call("PYCHARM_HOSTED", ""),
-            ]
-        )
-
     @pytest.mark.parametrize("isatty", [True, False])
     def test_when_plat_is_not_win32(self, isatty):
         stack = contextlib.ExitStack()
-        getenv = stack.enter_context(mock.patch.object(os, "getenv", side_effect=["0", "0", "", ""]))
+        stack.enter_context(mock.patch.dict(os.environ, {}, clear=True))
         stack.enter_context(mock.patch.object(sys.stdout, "isatty", return_value=isatty))
         stack.enter_context(mock.patch.object(sys, "platform", new="linux"))
 
         with stack:
             assert ux.supports_color(True, False) is isatty
 
-        assert getenv.call_count == 4
-        getenv.assert_has_calls(
-            [
-                mock.call("CLICOLOR_FORCE", "0"),
-                mock.call("CLICOLOR", "0"),
-                mock.call("COLORTERM", ""),
-                mock.call("PYCHARM_HOSTED", ""),
-            ]
-        )
-
     @pytest.mark.parametrize("isatty", [True, False])
     @pytest.mark.parametrize("plat", ["linux", "win32"])
     def test_when_PYCHARM_HOSTED(self, isatty, plat):
         stack = contextlib.ExitStack()
-        getenv = stack.enter_context(mock.patch.object(os, "getenv", return_value="0"))
+        stack.enter_context(mock.patch.dict(os.environ, {"PYCHARM_HOSTED": "OOGA BOOGA"}, clear=True))
         stack.enter_context(mock.patch.object(sys.stdout, "isatty", return_value=isatty))
         stack.enter_context(mock.patch.object(sys, "platform", new=plat))
 
         with stack:
             assert ux.supports_color(True, False) is True
 
-        if plat == "win32":
-            assert getenv.call_count == 5
-            getenv.assert_has_calls(
-                [
-                    mock.call("CLICOLOR_FORCE", "0"),
-                    mock.call("CLICOLOR", "0"),
-                    mock.call("COLORTERM", ""),
-                    mock.call("TERM_PROGRAM", None),
-                    mock.call("PYCHARM_HOSTED", ""),
-                ]
-            )
-        else:
-            assert getenv.call_count == 4
-            getenv.assert_has_calls(
-                [
-                    mock.call("CLICOLOR_FORCE", "0"),
-                    mock.call("CLICOLOR", "0"),
-                    mock.call("COLORTERM", ""),
-                    mock.call("PYCHARM_HOSTED", ""),
-                ]
-            )
+    @pytest.mark.parametrize("isatty", [True, False])
+    @pytest.mark.parametrize("plat", ["linux", "win32"])
+    def test_when_WT_SESSION(self, isatty, plat):
+        stack = contextlib.ExitStack()
+        stack.enter_context(mock.patch.dict(os.environ, {"WT_SESSION": "OOGA BOOGA"}, clear=True))
+        stack.enter_context(mock.patch.object(sys.stdout, "isatty", return_value=isatty))
+        stack.enter_context(mock.patch.object(sys, "platform", new=plat))
+
+        with stack:
+            assert ux.supports_color(True, False) is True
 
 
 class TestHikariVersion:
diff --git a/tests/hikari/test_channels.py b/tests/hikari/test_channels.py
index 8731f224..c21de3eb 100644
--- a/tests/hikari/test_channels.py
+++ b/tests/hikari/test_channels.py
@@ -28,6 +28,7 @@
 from hikari import files
 from hikari import permissions
 from hikari import snowflakes
+from hikari import undefined
 from hikari import users
 from tests.hikari import hikari_test_helpers
 
@@ -194,10 +195,10 @@ def model(self, mock_app):
             type=channels.ChannelType.GUILD_TEXT,
         )
 
-    async def test_history(self, model):
+    async def test_fetch_history(self, model):
         model.app.rest.fetch_messages = mock.AsyncMock()
 
-        await model.history(
+        await model.fetch_history(
             before=datetime.datetime(2020, 4, 1, 1, 0, 0),
             after=datetime.datetime(2020, 4, 1, 0, 0, 0),
             around=datetime.datetime(2020, 4, 1, 0, 30, 0),
@@ -210,10 +211,46 @@ async def test_history(self, model):
             around=datetime.datetime(2020, 4, 1, 0, 30, 0),
         )
 
+    async def test_fetch_message(self, model):
+        model.app.rest.fetch_message = mock.AsyncMock()
+
+        assert await model.fetch_message(133742069) == model.app.rest.fetch_message.return_value
+
+        model.app.rest.fetch_message.assert_awaited_once_with(12345679, 133742069)
+
+    async def test_fetch_pins(self, model):
+        model.app.rest.fetch_pins = mock.AsyncMock()
+
+        await model.fetch_pins()
+
+        model.app.rest.fetch_pins.assert_awaited_once_with(12345679)
+
+    async def test_pin_message(self, model):
+        model.app.rest.pin_message = mock.AsyncMock()
+
+        assert await model.pin_message(77790) == model.app.rest.pin_message.return_value
+
+        model.app.rest.pin_message.assert_awaited_once_with(12345679, 77790)
+
+    async def test_unpin_message(self, model):
+        model.app.rest.unpin_message = mock.AsyncMock()
+
+        assert await model.unpin_message(77790) == model.app.rest.unpin_message.return_value
+
+        model.app.rest.unpin_message.assert_awaited_once_with(12345679, 77790)
+
+    async def test_delete_messages(self, model):
+        model.app.rest.delete_messages = mock.AsyncMock()
+
+        await model.delete_messages([77790, 88890, 1800], 1337)
+
+        model.app.rest.delete_messages.assert_awaited_once_with(12345679, [77790, 88890, 1800], 1337)
+
     async def test_send(self, model):
         model.app.rest.create_message = mock.AsyncMock()
         mock_attachment = object()
         mock_embed = object()
+        mock_embeds = object()
         mock_attachments = [object(), object(), object()]
         mock_reply = object()
 
@@ -224,6 +261,7 @@ async def test_send(self, model):
             attachment=mock_attachment,
             attachments=mock_attachments,
             embed=mock_embed,
+            embeds=mock_embeds,
             reply=mock_reply,
             mentions_everyone=False,
             user_mentions=[123, 456],
@@ -239,6 +277,7 @@ async def test_send(self, model):
             attachment=mock_attachment,
             attachments=mock_attachments,
             embed=mock_embed,
+            embeds=mock_embeds,
             reply=mock_reply,
             mentions_everyone=False,
             user_mentions=[123, 456],
@@ -280,3 +319,84 @@ def test_shard_id_property_when_guild_id_is_not_None(self, model):
 
     def test_mention_property(self, model):
         assert model.mention == "<#69420>"
+
+    @pytest.mark.asyncio()
+    async def test_edit_overwrite(self, model):
+        model.app.rest.edit_permission_overwrites = mock.AsyncMock()
+        user = mock.Mock(users.PartialUser)
+        await model.edit_overwrite(
+            333,
+            target_type=user,
+            allow=permissions.Permissions.BAN_MEMBERS,
+            deny=permissions.Permissions.CONNECT,
+            reason="vrooom vroom",
+        )
+
+        model.app.rest.edit_permission_overwrites.assert_called_once_with(
+            69420,
+            333,
+            target_type=user,
+            allow=permissions.Permissions.BAN_MEMBERS,
+            deny=permissions.Permissions.CONNECT,
+            reason="vrooom vroom",
+        )
+
+    @pytest.mark.asyncio()
+    async def test_edit_overwrite_target_type_none(self, model):
+        model.app.rest.edit_permission_overwrites = mock.AsyncMock()
+        user = mock.Mock(users.PartialUser)
+        await model.edit_overwrite(
+            user, allow=permissions.Permissions.BAN_MEMBERS, deny=permissions.Permissions.CONNECT, reason="vrooom vroom"
+        )
+
+        model.app.rest.edit_permission_overwrites.assert_called_once_with(
+            69420,
+            user,
+            allow=permissions.Permissions.BAN_MEMBERS,
+            deny=permissions.Permissions.CONNECT,
+            reason="vrooom vroom",
+        )
+
+    @pytest.mark.asyncio()
+    async def test_remove_overwrite(self, model):
+        model.app.rest.delete_permission_overwrite = mock.AsyncMock()
+
+        await model.remove_overwrite(333)
+
+        model.app.rest.delete_permission_overwrite.assert_called_once_with(
+            69420,
+            333,
+        )
+
+    @pytest.mark.asyncio()
+    async def test_fetch_guild(self, model):
+        model.app.rest.fetch_guild = mock.AsyncMock()
+
+        assert await model.fetch_guild() == model.app.rest.fetch_guild.return_value
+
+        model.app.rest.fetch_guild.assert_awaited_once_with(123456789)
+
+    @pytest.mark.asyncio()
+    async def test_edit(self, model):
+        model.app.rest.edit_channel = mock.AsyncMock()
+
+        assert (
+            await model.edit(name="Supa fast boike", bitrate=420, reason="left right")
+            == model.app.rest.edit_channel.return_value
+        )
+
+        model.app.rest.edit_channel.assert_awaited_once_with(
+            69420,
+            name="Supa fast boike",
+            position=undefined.UNDEFINED,
+            topic=undefined.UNDEFINED,
+            nsfw=undefined.UNDEFINED,
+            bitrate=420,
+            video_quality_mode=undefined.UNDEFINED,
+            user_limit=undefined.UNDEFINED,
+            rate_limit_per_user=undefined.UNDEFINED,
+            region=undefined.UNDEFINED,
+            permission_overwrites=undefined.UNDEFINED,
+            parent_category=undefined.UNDEFINED,
+            reason="left right",
+        )
diff --git a/tests/hikari/test_event_stream.py b/tests/hikari/test_event_stream.py
index ddb2585a..1c8d6a1a 100644
--- a/tests/hikari/test_event_stream.py
+++ b/tests/hikari/test_event_stream.py
@@ -35,7 +35,7 @@
 
 
 class TestGenerateWeakListener:
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test__generate_weak_listener_when_method_is_None(self):
         def test():
             return None
@@ -48,7 +48,7 @@ def test():
         ):
             await call_weak_method(None)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test__generate_weak_listener(self):
         mock_listener = mock.AsyncMock()
         mock_event = object()
@@ -68,7 +68,7 @@ class TestStreamer:
     def stub_streamer(self):
         return hikari_test_helpers.mock_class_namespace(event_stream.Streamer)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test___aenter___and___aexit__(self, stub_streamer):
         async with stub_streamer():
             stub_streamer.open.assert_awaited_once()
@@ -95,7 +95,7 @@ def mock_app():
 
 
 class TestEventStream:
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test__listener_when_filter_returns_false(self, mock_app):
         stream = event_stream.EventStream(mock_app, events.Event, timeout=None)
         stream.filter(lambda _: False)
@@ -104,7 +104,7 @@ async def test__listener_when_filter_returns_false(self, mock_app):
         assert await stream._listener(mock_event) is None
         assert stream._queue.qsize() == 0
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test__listener_when_filter_passes_and_queue_full(self, mock_app):
         stream = event_stream.EventStream(mock_app, events.Event, timeout=None, limit=2)
         stream._queue.put_nowait(object())
@@ -117,7 +117,7 @@ async def test__listener_when_filter_passes_and_queue_full(self, mock_app):
         assert stream._queue.get_nowait() is not mock_event
         assert stream._queue.get_nowait() is not mock_event
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test__listener_when_filter_passes_and_queue_not_full(self, mock_app):
         stream = event_stream.EventStream(mock_app, events.Event, timeout=None, limit=None)
         stream._queue.put_nowait(object())
@@ -131,7 +131,7 @@ async def test__listener_when_filter_passes_and_queue_not_full(self, mock_app):
         assert stream._queue.get_nowait() is not mock_event
         assert stream._queue.get_nowait() is mock_event
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test___anext___when_stream_closed(self):
         streamer = event_stream.EventStream(mock.Mock(), event_type=events.Event, timeout=float("inf"))
@@ -140,7 +140,7 @@ async def test___anext___when_stream_closed(self):
         with pytest.raises(TypeError):
             await streamer.__anext__()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test___anext___times_out(self):
         streamer = event_stream.EventStream(
@@ -151,7 +151,7 @@ async def test___anext___times_out(self):
             async for _ in streamer:
                 pytest.fail("streamer shouldn't have yielded anything")
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test___anext___waits_for_next_event(self):
         mock_event = object()
@@ -172,7 +172,7 @@ async def add_event():
 
             pytest.fail("streamer should've yielded something")
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test___anext__(self):
         mock_event = object()
@@ -188,7 +188,7 @@ async def test___anext__(self):
 
         pytest.fail("streamer should've yielded something")
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test___await__(self):
         mock_event_0 = object()
         mock_event_1 = object()
@@ -235,13 +235,13 @@ def test___del___for_inactive_stream(self):
 
         close_method.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_close_for_inactive_stream(self, mock_app):
         stream = event_stream.EventStream(mock_app, events.Event, timeout=None, limit=None)
         await stream.close()
         mock_app.event_manager.unsubscribe.assert_not_called()
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test_close_for_active_stream(self, mock_app):
         mock_registered_listener = object()
@@ -254,7 +254,7 @@ async def test_close_for_active_stream(self, mock_app):
         assert stream._active is False
         assert stream._registered_listener is None
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test_close_for_active_stream_handles_value_error(self, mock_app):
         mock_registered_listener = object()
@@ -288,7 +288,7 @@ def predicate(obj):
         assert stream._filters(second_pass) is True
         assert stream._filters(second_fail) is False
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_filter_for_active_stream(self):
         stream = hikari_test_helpers.mock_class_namespace(event_stream.EventStream)(
             app=mock.Mock(), event_type=events.Event, timeout=float("inf")
@@ -305,7 +305,7 @@ async def test_filter_for_active_stream(self):
         # Ensure we don't get a warning or error on del
         stream._active = False
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_open_for_inactive_stream(self, mock_app):
         mock_listener = object()
         stream = hikari_test_helpers.mock_class_namespace(event_stream.EventStream)(
@@ -331,7 +331,7 @@ async def test_open_for_inactive_stream(self, mock_app):
         # Ensure we don't get a warning or error on del
         stream._active = False
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     @hikari_test_helpers.timeout()
     async def test_open_for_active_stream(self, mock_app):
         stream = hikari_test_helpers.mock_class_namespace(event_stream.EventStream)(
diff --git a/tests/hikari/test_guilds.py b/tests/hikari/test_guilds.py
index 37f75218..7170247b 100644
--- a/tests/hikari/test_guilds.py
+++ b/tests/hikari/test_guilds.py
@@ -204,7 +204,7 @@ def test_make_avatar_url(self, model, mock_user):
         mock_user.make_avatar_url.assert_called_once_with(ext="png", size=4096)
         assert result is mock_user.make_avatar_url.return_value
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_self(self, model):
         model.user.app.rest.fetch_member = mock.AsyncMock()
 
@@ -212,7 +212,7 @@ async def test_fetch_self(self, model):
 
         model.user.app.rest.fetch_member.assert_awaited_once_with(456, 123)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_ban(self, model):
         model.app.rest.ban_user = mock.AsyncMock()
 
diff --git a/tests/hikari/test_messages.py b/tests/hikari/test_messages.py
index 7e065683..2e27e7c4 100644
--- a/tests/hikari/test_messages.py
+++ b/tests/hikari/test_messages.py
@@ -28,6 +28,7 @@
 from hikari import guilds
 from hikari import messages
 from hikari import snowflakes
+from hikari import undefined
 from hikari import urls
 from hikari import users
 from hikari.internal import routes
@@ -164,11 +165,13 @@ async def test_edit(self, message):
         message.id = 123
         message.channel_id = 456
         embed = object()
+        embeds = [object(), object()]
         attachment = object()
         roles = [object()]
         await message.edit(
             content="test content",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=[attachment, attachment],
             replace_attachments=True,
@@ -183,6 +186,7 @@ async def test_edit(self, message):
             channel=456,
             content="test content",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=[attachment, attachment],
             replace_attachments=True,
@@ -198,6 +202,7 @@ async def test_respond(self, message):
         message.id = 123
         message.channel_id = 456
         embed = object()
+        embeds = [object(), object()]
         roles = [object()]
         attachment = object()
         attachments = [object()]
@@ -205,6 +210,7 @@ async def test_respond(self, message):
         await message.respond(
             content="test content",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -219,6 +225,7 @@ async def test_respond(self, message):
             channel=456,
             content="test content",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -235,12 +242,14 @@ async def test_respond_when_reply_is_True(self, message):
         message.id = 123
         message.channel_id = 456
         embed = object()
+        embeds = [object()]
         roles = [object()]
         attachment = object()
         attachments = [object()]
         await message.respond(
             content="test content",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -255,6 +264,7 @@ async def test_respond_when_reply_is_True(self, message):
             channel=456,
             content="test content",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -266,6 +276,27 @@ async def test_respond_when_reply_is_True(self, message):
             mentions_reply=True,
         )
 
+    async def test_respond_when_reply_is_False(self, message):
+        message.app = mock.AsyncMock()
+        message.id = 123
+        message.channel_id = 456
+        await message.respond(reply=False)
+        message.app.rest.create_message.assert_awaited_once_with(
+            channel=456,
+            content=undefined.UNDEFINED,
+            embed=undefined.UNDEFINED,
+            embeds=undefined.UNDEFINED,
+            attachment=undefined.UNDEFINED,
+            attachments=undefined.UNDEFINED,
+            nonce=undefined.UNDEFINED,
+            tts=undefined.UNDEFINED,
+            reply=undefined.UNDEFINED,
+            mentions_everyone=undefined.UNDEFINED,
+            user_mentions=undefined.UNDEFINED,
+            role_mentions=undefined.UNDEFINED,
+            mentions_reply=undefined.UNDEFINED,
+        )
+
     async def test_delete(self, message):
         message.app = mock.AsyncMock()
         message.id = 123
diff --git a/tests/hikari/test_users.py b/tests/hikari/test_users.py
index 6ca1776e..4ea713c6 100644
--- a/tests/hikari/test_users.py
+++ b/tests/hikari/test_users.py
@@ -49,6 +49,7 @@ async def test_fetch_self(self, obj):
     async def test_send_uses_cached_id(self, obj):
         obj.id = 4123123
         embed = object()
+        embeds = [object()]
         attachment = object()
         attachments = [object(), object()]
         user_mentions = [object(), object()]
@@ -62,6 +63,7 @@ async def test_send_uses_cached_id(self, obj):
         returned = await obj.send(
             content="test",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -81,6 +83,7 @@ async def test_send_uses_cached_id(self, obj):
             channel=obj.app.cache.get_dm_channel_id.return_value,
             content="test",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -96,6 +99,7 @@ async def test_send_uses_cached_id(self, obj):
     async def test_send_when_not_cached(self, obj):
         obj.id = 522234
         embed = object()
+        embeds = [object(), object()]
         attachment = object()
         attachments = [object(), object()]
         user_mentions = [object(), object()]
@@ -110,6 +114,7 @@ async def test_send_when_not_cached(self, obj):
         returned = await obj.send(
             content="test",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -129,6 +134,7 @@ async def test_send_when_not_cached(self, obj):
             channel=obj.fetch_dm_channel.return_value.id,
             content="test",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -144,6 +150,7 @@ async def test_send_when_not_cached(self, obj):
     async def test_send_when_not_cache_aware(self, obj):
         obj.id = 522234
         embed = object()
+        embeds = [object(), object()]
         attachment = object()
         attachments = [object(), object()]
         user_mentions = [object(), object()]
@@ -157,6 +164,7 @@ async def test_send_when_not_cache_aware(self, obj):
         returned = await obj.send(
             content="test",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
@@ -175,6 +183,7 @@ async def test_send_when_not_cache_aware(self, obj):
             channel=obj.fetch_dm_channel.return_value.id,
             content="test",
             embed=embed,
+            embeds=embeds,
             attachment=attachment,
             attachments=attachments,
             nonce="nonce",
diff --git a/tests/hikari/test_webhooks.py b/tests/hikari/test_webhooks.py
index 00363693..59625311 100644
--- a/tests/hikari/test_webhooks.py
+++ b/tests/hikari/test_webhooks.py
@@ -50,7 +50,7 @@ def test_str_when_name_is_None(self, webhook):
         webhook.name = None
         assert str(webhook) == "Unnamed webhook ID 987654321"
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_message(self, webhook):
         message = object()
         returned_message = object()
@@ -62,13 +62,13 @@ async def test_fetch_message(self, webhook):
 
         webhook.app.rest.fetch_webhook_message.assert_called_once_with(987654321, token="abc123bca", message=message)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_fetch_message_when_no_token(self, webhook):
         webhook.token = None
         with pytest.raises(ValueError, match=r"Cannot fetch a message using a webhook where we don't know the token"):
             await webhook.fetch_message(987)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_edit_message(self, webhook):
         message = object()
         embed = object()
@@ -106,13 +106,13 @@ async def test_edit_message(self, webhook):
             role_mentions=[567, 890],
         )
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_edit_message_when_no_token(self, webhook):
         webhook.token = None
         with pytest.raises(ValueError, match=r"Cannot edit a message using a webhook where we don't know the token"):
             await webhook.edit_message(987)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_delete_message(self, webhook):
         message = object()
         webhook.app.rest.delete_webhook_message = mock.AsyncMock()
@@ -121,7 +121,7 @@ async def test_delete_message(self, webhook):
 
         webhook.app.rest.delete_webhook_message.assert_called_once_with(987654321, token="abc123bca", message=message)
 
-    @pytest.mark.asyncio
+    @pytest.mark.asyncio()
     async def test_delete_message_when_no_token(self, webhook):
         webhook.token = None
         with pytest.raises(ValueError, match=r"Cannot delete a message using a webhook where we don't know the token"):