Skip to content

Commit

Permalink
Migration to discord.py 2.0 (#5600)
Browse files Browse the repository at this point in the history
* Temporarily set d.py to use latest git revision

* Remove `bot` param to Client.start

* Switch to aware datetimes

A lot of this is removing `.replace(...)` which while not technically
needed, simplifies the code base. There's only a few changes that are
actually necessary here.

* Update to work with new Asset design

* [threads] Update core ModLog API to support threads

- Added proper support for passing `Thread` to `channel`
  when creating/editing case
- Added `parent_channel_id` attribute to Modlog API's Case
    - Added `parent_channel` property that tries to get parent channel
- Updated case's content to show both thread and parent information

* [threads] Disallow usage of threads in some of the commands

- announceset channel
- filter channel clear
- filter channel add
- filter channel remove
- GlobalUniqueObjectFinder converter
    - permissions addglobalrule
    - permissions removeglobalrule
    - permissions removeserverrule
    - Permissions cog does not perform any validation for IDs
      when setting through YAML so that has not been touched
- streamalert twitch/youtube/picarto
- embedset channel
- set ownernotifications adddestination

* [threads] Handle threads in Red's permissions system (Requires)

- Made permissions system apply rules of (only) parent in threads

* [threads] Update embed_requested to support threads

- Threads don't have their own embed settings and inherit from parent

* [threads] Update Red.message_eligible_as_command to support threads

* [threads] Properly handle invocation of [p](un)mutechannel in threads

Usage of a (un)mutechannel will mute/unmute user in the parent channel
if it's invoked in a thread.

* [threads] Update Filter cog to properly handle threads

- `[p]filter channel list` in a threads sends list for parent channel
- Checking for filter hits for a message in a thread checks its parent
  channel's word list. There's no separate word list for threads.

* [threads] Support threads in Audio cog

- Handle threads being notify channels
- Update type hint for `is_query_allowed()`

* [threads] Update type hints and documentation to reflect thread support

- Documented that `{channel}` in CCs might be a thread
- Allowed (documented) usage of threads with `Config.channel()`
    - Separate thread scope is still in the picture though
      if it were to be done, it's going to be in separate in PR
- GuildContext.channel might be Thread

* Use less costy channel check in customcom's on_message_without_command

This isn't needed for d.py 2.0 but whatever...

* Update for in-place edits

* Embed's bool changed behavior, I'm hoping it doesn't affect us

* Address User.permissions_in() removal

* Swap VerificationLevel.extreme with VerificationLevel.highest

* Change to keyword-only parameters

* Change of `Guild.vanity_invite()` return type

* avatar -> display_avatar

* Fix metaclass shenanigans with Converter

* Update Red.add_cog() to be inline with `dpy_commands.Bot.add_cog()`

This means adding `override` keyword-only parameter and causing
small breakage by swapping RuntimeError with discord.ClientException.

* Address all DEP-WARNs

* Remove Context.clean_prefix and use upstream implementation instead

* Remove commands.Literal and use upstream implementation instead

Honestly, this was a rather bad implementation anyway...

Breaking but actually not really - it was provisional.

* Update Command.callback's setter

Support for functools.partial is now built into d.py

* Add new perms in HUMANIZED_PERM mapping (some from d.py 1.7 it seems)

BTW, that should really be in core instead of what we have now...

* Remove the part of do_conversion that has not worked for a long while

* Stop wrapping BadArgument in ConversionFailure

This is breaking but it's best to resolve it like this.

The functionality of ConversionFailure can be replicated with
Context.current_parameter and Context.current_argument.

* Add custom errors for int and float converters

* Remove Command.__call__ as it's now implemented in d.py

* Get rid of _dpy_reimplements

These were reimplemented for the purpose of typing
so it is no longer needed now that d.py is type hinted.

* Add return to Red.remove_cog

* Ensure we don't delete messages that differ only by used sticker

* discord.InvalidArgument->ValueError

* Move from raw <t:...> syntax to discord.utils.format_dt()

* Address AsyncIter removal

* Swap to pos-only for params that are pos-only in upstream

* Update for changes to Command.params

* [threads] Support threads in ignore checks and allow ignoring them

- Updated `[p](un)ignore channel` to accept threads
- Updated `[p]ignore list` to list ignored threads
- Updated logic in `Red.ignored_channel_or_guild()`

Ignores for guild channels now work as follows (only changes for threads):
- if channel is not a thread:
    - check if user has manage channels perm in channel
      and allow command usage if so
    - check if channel is ignored and disallow command usage if so
    - allow command usage if none of the conditions above happened
- if channel is a thread:
    - check if user has manage channels perm in parent channel
      and allow command usage if so
    - check if parent channel is ignored and disallow command usage
      if so
    - check if user has manage thread perm in parent channel
      and allow command usage if so
    - check if thread is ignored and disallow command usage if so
    - allow command usage if none of the conditions above happened

* [partial] Raise TypeError when channel is of PartialMessageable type

- Red.embed_requested
- Red.ignored_channel_or_guild

* [partial] Discard command messages when channel is PartialMessageable

* [threads] Add utilities for checking appropriate perms in both channels & threads

* [threads] Update code to use can_react_in() and @bot_can_react()

* [threads] Update code to use can_send_messages_in

* [threads] Add send_messages_in_threads perm to mute role and overrides

* [threads] Update code to use (bot/user)_can_manage_channel

* [threads] Update [p]diagnoseissues to work with threads

* Type hint fix

* [threads] Patch vendored discord.ext.menus to check proper perms in threads

I guess we've reached time when we have to patch the lib we vendor...

* Make docs generation work with non-final d.py releases

* Update discord.utils.oauth_url() usage

* Swap usage of discord.Embed.Empty/discord.embeds.EmptyEmbed to None

* Update usage of Guild.member_count to work with `None`

* Switch from Guild.vanity_invite() to Guild.vanity_url

* Update startup process to work with d.py's new asynchronous startup

* Use setup_hook() for pre-connect actions

* Update core's add_cog, remove_cog, and load_extension methods

* Update all setup functions to async and add awaits to bot.add_cog calls

* Modernize cogs by using async cog_load and cog_unload

* Address StoreChannel removal

* [partial] Disallow passing PartialMessageable to Case.channel

* [partial] Update cogs and utils to work better with PartialMessageable

- Ignore messages with PartialMessageable channel in CustomCommands cog
- In Filter cog, don't pass channel to modlog.create_case()
  if it's PartialMessageable
- In Trivia cog, only compare channel IDs
- Make `.utils.menus.menu()` work for messages
  with PartialMessageable channel
- Make checks in `.utils.tunnel.Tunnel.communicate()` more rigid

* Add few missing DEP-WARNs
  • Loading branch information
Jackenmen authored Apr 3, 2022
1 parent c9a0971 commit febca8c
Show file tree
Hide file tree
Showing 104 changed files with 1,427 additions and 999 deletions.
30 changes: 15 additions & 15 deletions docs/cog_customcom.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ Cooldowns

You can set cooldowns for your custom commands. If a command is on cooldown, it will not be triggered.

You can set cooldowns per member or per channel, or set a cooldown guild-wide. You can also set multiple types of cooldown on a single custom command. All cooldowns must pass before the command will trigger.
You can set cooldowns per member or per thread/channel, or set a cooldown guild-wide. You can also set multiple types of cooldown on a single custom command. All cooldowns must pass before the command will trigger.

------------------
Context Parameters
------------------

You can enhance your custom command's response by leaving spaces for the bot to substitute.

+-----------+----------------------------------------+
| Argument | Substitute |
+===========+========================================+
| {message} | The message the bot is responding to. |
+-----------+----------------------------------------+
| {author} | The user who called the command. |
+-----------+----------------------------------------+
| {channel} | The channel the command was called in. |
+-----------+----------------------------------------+
| {server} | The server the command was called in. |
+-----------+----------------------------------------+
| {guild} | Same as with {server}. |
+-----------+----------------------------------------+
+-----------+--------------------------------------------------+
| Argument | Substitute |
+===========+==================================================+
| {message} | The message the bot is responding to. |
+-----------+--------------------------------------------------+
| {author} | The user who called the command. |
+-----------+--------------------------------------------------+
| {channel} | The channel or thread the command was called in. |
+-----------+--------------------------------------------------+
| {server} | The server the command was called in. |
+-----------+--------------------------------------------------+
| {guild} | Same as with {server}. |
+-----------+--------------------------------------------------+

You can further refine the response with dot notation. For example, {author.mention} will mention the user who called the command.

Expand Down Expand Up @@ -81,7 +81,7 @@ Showing your own avatar

.. code-block:: none
[p]customcom add simple avatar {author.avatar_url}
[p]customcom add simple avatar {author.display_avatar}
[p]avatar
https://cdn.discordapp.com/avatars/133801473317404673/be4c4a4fe47cb3e74c31a0504e7a295e.webp?size=1024
Expand Down
6 changes: 3 additions & 3 deletions docs/cog_guides/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -389,16 +389,16 @@ announceset channel

.. code-block:: none
[p]announceset channel [channel]
[p]announceset channel <channel>
**Description**

Sets the channel where the bot owner announcements will be sent.

**Arguments**

* ``[channel]``: The channel that will be used for bot announcements.
|channel-input| Defaults to where you typed the command.
* ``<channel>``: The channel that will be used for bot announcements.
|channel-input|

.. _admin-command-announceset-clearchannel:

Expand Down
12 changes: 6 additions & 6 deletions docs/cog_guides/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1842,9 +1842,9 @@ ignore channel
**Description**

Ignore commands in the channel or category.
Ignore commands in the channel, thread, or category.

Defaults to the current channel.
Defaults to the current thread or channel.

.. Note:: Owners, Admins, and those with Manage Channel permissions override ignored channels.

Expand All @@ -1856,7 +1856,7 @@ Defaults to the current channel.
- ``[p]ignore channel 356236713347252226`` - Also accepts IDs.

**Arguments:**
- ``<channel>`` - The channel to ignore. Can be a category channel.
- ``<channel>`` - The channel to ignore. This can also be a thread or category channel.

.. _core-command-ignore-list:

Expand Down Expand Up @@ -4045,9 +4045,9 @@ unignore channel
**Description**

Remove a channel or category from the ignore list.
Remove a channel, thread, or category from the ignore list.

Defaults to the current channel.
Defaults to the current thread or channel.

**Examples:**
- ``[p]unignore channel #general`` - Unignores commands in the #general channel.
Expand All @@ -4056,7 +4056,7 @@ Defaults to the current channel.
- ``[p]unignore channel 356236713347252226`` - Also accepts IDs. Use this method to unignore categories.

**Arguments:**
- ``<channel>`` - The channel to unignore. This can be a category channel.
- ``<channel>`` - The channel to unignore. This can also be a thread or category channel.

.. _core-command-unignore-server:

Expand Down
2 changes: 1 addition & 1 deletion docs/cog_guides/customcommands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ customcom cooldown

Set, edit, or view the cooldown for a custom command.

You may set cooldowns per member, channel, or guild. Multiple
You may set cooldowns per member, thread/channel, or guild. Multiple
cooldowns may be set. All cooldowns must be cooled to call the
custom command.

Expand Down
4 changes: 2 additions & 2 deletions docs/cog_guides/mod.rst
Original file line number Diff line number Diff line change
Expand Up @@ -574,14 +574,14 @@ slowmode
**Description**

Changes channel's slowmode setting.
Changes thread's or channel's slowmode setting.

Interval can be anything from 0 seconds to 6 hours.
Use without parameters to disable.

**Arguments**

* ``[interval=0:00:00]``: The time for the channel's slowmode settings.
* ``[interval=0:00:00]``: The time for the thread's/channel's slowmode settings.

.. note::
Interval can be anything from 0 seconds to 6 hours.
Expand Down
4 changes: 2 additions & 2 deletions docs/cog_guides/mutes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ mutechannel

**Description**

Mute a user in the current text channel.
Mute a user in the current text channel (or in the parent of the current thread).

Examples:

Expand Down Expand Up @@ -355,7 +355,7 @@ unmutechannel

**Description**

Unmute a user in this channel.
Unmute a user in this channel (or in the parent of this thread).

**Arguments**

Expand Down
2 changes: 1 addition & 1 deletion docs/cog_guides/permissions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Global rules (set by the owner) are checked first, then rules set for servers. I

1. Rules about a user.
2. Rules about the voice channel a user is in.
3. Rules about the text channel a command was issued in.
3. Rules about the text channel or a parent of the thread a command was issued in.
4. Rules about a role the user has (The highest role they have with a rule will be used).
5. Rules about the server a user is in (Global rules only).

Expand Down
2 changes: 1 addition & 1 deletion docs/cog_guides/reports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ report interact

Open a message tunnel.

This tunnel will forward things you say in this channel
This tunnel will forward things you say in this channel or thread
to the ticket opener's direct messages.

Tunnels do not persist across bot restarts.
Expand Down
2 changes: 1 addition & 1 deletion docs/cog_permissions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ For each of those, the first rule pertaining to one of the following models will

1. User
2. Voice channel
3. Text channel
3. Text channel (parent text channel in case of invocations in threads)
4. Channel category
5. Roles, highest to lowest
6. Server (can only be in global rules)
Expand Down
16 changes: 13 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
# built documents.
#
from redbot.core import __version__
from discord import __version__ as dpy_version
from discord import __version__ as dpy_version, version_info as dpy_version_info

# The short X.Y version.
version = __version__
Expand Down Expand Up @@ -225,10 +225,20 @@

# -- Options for extensions -----------------------------------------------

if dpy_version_info.releaselevel == "final":
# final release - versioned docs should be available
dpy_docs_url = f"https://discordpy.readthedocs.io/en/v{dpy_version}/"
elif dpy_version_info.minor == dpy_version_info.micro == 0:
# alpha release of a new major version - `master` version of docs should be used
dpy_docs_url = "https://discordpy.readthedocs.io/en/master/"
else:
# alpha release of a new minor or micro version - `latest` version of docs should be used
dpy_docs_url = "https://discordpy.readthedocs.io/en/latest/"

# Intersphinx
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"dpy": (f"https://discordpy.readthedocs.io/en/v{dpy_version}/", None),
"dpy": (dpy_docs_url, None),
"motor": ("https://motor.readthedocs.io/en/stable/", None),
"babel": ("http://babel.pocoo.org/en/stable/", None),
"dateutil": ("https://dateutil.readthedocs.io/en/stable/", None),
Expand All @@ -238,7 +248,7 @@
# This allows to create links to d.py docs with
# :dpy_docs:`link text <site_name.html>`
extlinks = {
"dpy_docs": (f"https://discordpy.readthedocs.io/en/v{dpy_version}/%s", None),
"dpy_docs": (f"{dpy_docs_url}/%s", None),
"issue": ("https://github.com/Cog-Creators/Red-DiscordBot/issues/%s", "#"),
"ghuser": ("https://github.com/%s", "@"),
}
Expand Down
2 changes: 1 addition & 1 deletion docs/framework_checks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ The following are all decorators for commands, which add restrictions to where a
run.

.. automodule:: redbot.core.commands
:members: permissions_check, bot_has_permissions, bot_in_a_guild, has_permissions, has_guild_permissions, is_owner, guildowner, guildowner_or_permissions, admin, admin_or_permissions, mod, mod_or_permissions
:members: permissions_check, bot_has_permissions, bot_in_a_guild, bot_can_manage_channel, bot_can_react, has_permissions, can_manage_channel, has_guild_permissions, is_owner, guildowner, guildowner_or_can_manage_channel, guildowner_or_permissions, admin, admin_or_can_manage_channel, admin_or_permissions, mod, mod_or_can_manage_channel, mod_or_permissions
4 changes: 2 additions & 2 deletions docs/framework_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ Here is an example of the :code:`async with` syntax:
* :py:meth:`Config.member` which takes :py:class:`discord.Member`.
* :py:meth:`Config.user` which takes :py:class:`discord.User`.
* :py:meth:`Config.role` which takes :py:class:`discord.Role`.
* :py:meth:`Config.channel` which takes :py:class:`discord.TextChannel`.
* :py:meth:`Config.channel` which takes :py:class:`discord.abc.GuildChannel` or :py:class:`discord.Thread`.

If you need to wipe data from the config, you want to look at :py:meth:`Group.clear`, or :py:meth:`Config.clear_all`
and similar methods, such as :py:meth:`Config.clear_all_guilds`.
Expand Down Expand Up @@ -467,7 +467,7 @@ much the same way they would in V2. The following examples will demonstrate how
async def setup(bot):
cog = ExampleCog()
await cog.load_data()
bot.add_cog(cog)
await bot.add_cog(cog)
************************************
Best practices and performance notes
Expand Down
8 changes: 3 additions & 5 deletions docs/framework_modlog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ Basic Usage
Registering Case types
**********************

To register case types, use an asynchronous ``initialize()`` method and call
it from your setup function:
To register case types, use a special ``cog_load()`` method which is called when you add a cog:

.. code-block:: python
Expand All @@ -46,7 +45,7 @@ it from your setup function:
class MyCog(commands.Cog):
async def initialize(self):
async def cog_load(self):
await self.register_casetypes()
@staticmethod
Expand Down Expand Up @@ -87,8 +86,7 @@ it from your setup function:
async def setup(bot):
cog = MyCog()
await cog.initialize()
bot.add_cog(cog)
await bot.add_cog(cog)
.. important::
Image should be the emoji you want to represent your case type with.
Expand Down
4 changes: 2 additions & 2 deletions docs/framework_rpc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Examples

.. code-block:: Python
def setup(bot):
async def setup(bot):
c = Cog()
bot.add_cog(c)
await bot.add_cog(c)
bot.register_rpc_handler(c.rpc_method)
*******************************
Expand Down
2 changes: 1 addition & 1 deletion docs/framework_utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ General Utility
===============

.. automodule:: redbot.core.utils
:members: deduplicate_iterables, bounded_gather, bounded_gather_iter, get_end_user_data_statement, get_end_user_data_statement_or_raise
:members: deduplicate_iterables, bounded_gather, bounded_gather_iter, get_end_user_data_statement, get_end_user_data_statement_or_raise, can_user_send_messages_in, can_user_manage_channel, can_user_react_in

.. autoclass:: AsyncIter
:members:
Expand Down
4 changes: 2 additions & 2 deletions docs/guide_cog_creation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ Open :code:`__init__.py`. In that file, place the following:
from .mycog import MyCog
def setup(bot):
bot.add_cog(MyCog(bot))
async def setup(bot):
await bot.add_cog(MyCog(bot))
Make sure that both files are saved.

Expand Down
7 changes: 4 additions & 3 deletions redbot/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,10 @@ async def run_bot(red: Red, cli_flags: Namespace) -> None:
sys.exit(1)

if cli_flags.dry_run:
await red.http.close()
sys.exit(0)
try:
await red.start(token, bot=True)
# `async with red:` is unnecessary here because we call red.close() in shutdown handler
await red.start(token)
except discord.LoginFailure:
log.critical("This token doesn't seem to be valid.")
db_token = await red._config.token()
Expand Down Expand Up @@ -451,7 +451,8 @@ async def shutdown_handler(red, signal_type=None, exit_code=None):
red._shutdown_mode = exit_code

try:
await red.close()
if not red.is_closed():
await red.close()
finally:
# Then cancels all outstanding tasks other than ourselves
pending = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
Expand Down
6 changes: 4 additions & 2 deletions redbot/cogs/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from redbot.core.bot import Red

from .admin import Admin


def setup(bot):
bot.add_cog(Admin(bot))
async def setup(bot: Red) -> None:
await bot.add_cog(Admin(bot))
21 changes: 5 additions & 16 deletions redbot/cogs/admin/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,9 @@ def __init__(self, bot):
)

self.__current_announcer = None
self._ready = asyncio.Event()
asyncio.create_task(self.handle_migrations())
# As this is a data migration, don't store this for cancelation.

async def cog_before_invoke(self, ctx: commands.Context):
await self._ready.wait()
async def cog_load(self) -> None:
await self.handle_migrations()

async def red_delete_data_for_user(self, **kwargs):
"""Nothing to delete"""
Expand All @@ -106,9 +103,7 @@ async def handle_migrations(self):
await self.migrate_config_from_0_to_1()
await self.config.schema_version.set(1)

self._ready.set()

async def migrate_config_from_0_to_1(self):
async def migrate_config_from_0_to_1(self) -> None:
all_guilds = await self.config.all_guilds()

for guild_id, guild_data in all_guilds.items():
Expand Down Expand Up @@ -354,14 +349,8 @@ async def announceset(self, ctx):
pass

@announceset.command(name="channel")
async def announceset_channel(self, ctx, *, channel: discord.TextChannel = None):
"""
Change the channel where the bot will send announcements.
If channel is left blank it defaults to the current channel.
"""
if channel is None:
channel = ctx.channel
async def announceset_channel(self, ctx, *, channel: discord.TextChannel):
"""Change the channel where the bot will send announcements."""
await self.config.guild(ctx.guild).announce_channel.set(channel.id)
await ctx.send(
_("The announcement channel has been set to {channel.mention}").format(channel=channel)
Expand Down
6 changes: 2 additions & 4 deletions redbot/cogs/alias/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@
from redbot.core.bot import Red


async def setup(bot: Red):
cog = Alias(bot)
bot.add_cog(cog)
cog.sync_init()
async def setup(bot: Red) -> None:
await bot.add_cog(Alias(bot))
Loading

0 comments on commit febca8c

Please sign in to comment.