Utility Functions
General Utility
- redbot.core.utils.bounded_gather(*coros_or_futures, return_exceptions=False, limit=4, semaphore=None)[source]
A semaphore-bounded wrapper to
asyncio.gather()
.- Parameters:
*coros_or_futures – The awaitables to run in a bounded concurrent fashion.
return_exceptions (bool) – If true, gather exceptions in the result list instead of raising.
limit (Optional[
int
]) – The maximum number of concurrent tasks. Used when nosemaphore
is passed.semaphore (Optional[
asyncio.Semaphore
]) – The semaphore to use for bounding tasks. IfNone
, create one usingloop
andlimit
.
- Raises:
TypeError – When invalid parameters are passed
- redbot.core.utils.bounded_gather_iter(*coros_or_futures, limit=4, semaphore=None)[source]
An iterator that returns tasks as they are ready, but limits the number of tasks running at a time.
- Parameters:
*coros_or_futures – The awaitables to run in a bounded concurrent fashion.
limit (Optional[
int
]) – The maximum number of concurrent tasks. Used when nosemaphore
is passed.semaphore (Optional[
asyncio.Semaphore
]) – The semaphore to use for bounding tasks. IfNone
, create one usingloop
andlimit
.
- Raises:
TypeError – When invalid parameters are passed
- redbot.core.utils.can_user_manage_channel(obj, channel, /, allow_thread_owner=False)[source]
Checks if a guild member can manage the given channel.
This function properly resolves the permissions for
discord.Thread
as well.- Parameters:
obj (discord.Member) – The guild member to check permissions for. If passed
messageable
resolves to a guild channel/thread, this needs to be an instance ofdiscord.Member
.channel (Union[discord.abc.GuildChannel, discord.Thread]) – The messageable object to check permissions for. If this resolves to a DM/group channel, this function will return
True
.allow_thread_owner (bool) – If
True
, the function will also returnTrue
if the given member is a thread owner. This can, for example, be useful to check if the member can edit a channel/thread’s name as that, in addition to members with manage channel/threads permission, can also be done by the thread owner.
- Returns:
Whether the user can manage the given channel.
- Return type:
- redbot.core.utils.can_user_react_in(obj, messageable, /)[source]
Checks if a user/guild member can react in the given messageable.
This function properly resolves the permissions for
discord.Thread
as well.Note
Without making an API request, it is not possible to reliably detect whether a guild member (who is NOT current bot user) can react in a private thread.
If it’s essential for you to reliably detect this, you will need to try fetching the thread member:
can_react = can_user_react_in(member, thread) if thread.is_private() and not thread.permissions_for(member).manage_threads: try: await thread.fetch_member(member.id) except discord.NotFound: can_react = False
- Parameters:
obj (discord.abc.User) – The user or member to check permissions for. If passed
messageable
resolves to a guild channel/thread, this needs to be an instance ofdiscord.Member
.messageable (discord.abc.Messageable) – The messageable object to check permissions for. If this resolves to a DM/group channel, this function will return
True
.
- Returns:
Whether the user can send messages in the given messageable.
- Return type:
- Raises:
TypeError – When the passed channel is of type
discord.PartialMessageable
.
- redbot.core.utils.can_user_send_messages_in(obj, messageable, /)[source]
Checks if a user/member can send messages in the given messageable.
This function properly resolves the permissions for
discord.Thread
as well.Note
Without making an API request, it is not possible to reliably detect whether a guild member (who is NOT current bot user) can send messages in a private thread.
If it’s essential for you to reliably detect this, you will need to try fetching the thread member:
can_send_messages = can_user_send_messages_in(member, thread) if thread.is_private() and not thread.permissions_for(member).manage_threads: try: await thread.fetch_member(member.id) except discord.NotFound: can_send_messages = False
- Parameters:
obj (discord.abc.User) – The user or member to check permissions for. If passed
messageable
resolves to a guild channel/thread, this needs to be an instance ofdiscord.Member
.messageable (discord.abc.Messageable) – The messageable object to check permissions for. If this resolves to a DM/group channel, this function will return
True
.
- Returns:
Whether the user can send messages in the given messageable.
- Return type:
- Raises:
TypeError – When the passed channel is of type
discord.PartialMessageable
.
- redbot.core.utils.deduplicate_iterables(*iterables)[source]
Returns a list of all unique items in
iterables
, in the order they were first encountered.
- redbot.core.utils.get_end_user_data_statement(file)[source]
This function attempts to get the
end_user_data_statement
key from cog’sinfo.json
. This will log the reason ifNone
is returned.Example
You can use this function in cog package’s top-level
__init__.py
to conveniently reuse end user data statement frominfo.json
file placed in the same directory:from redbot.core.utils import get_end_user_data_statement __red_end_user_data_statement__ = get_end_user_data_statement(__file__) async def setup(bot): ...
To help detect issues with the
info.json
file while still allowing the cog to load, this function logs an error ifinfo.json
file doesn’t exist, can’t be parsed, or doesn’t have anend_user_data_statement
key.- Parameters:
file (Union[pathlib.Path, str]) – The
__file__
variable for the cog’s__init__.py
file.- Returns:
The end user data statement found in the info.json or
None
if there was an issue finding one.- Return type:
Optional[str]
- redbot.core.utils.get_end_user_data_statement_or_raise(file)[source]
This function attempts to get the
end_user_data_statement
key from cog’sinfo.json
.Example
You can use this function in cog package’s top-level
__init__.py
to conveniently reuse end user data statement frominfo.json
file placed in the same directory:from redbot.core.utils import get_end_user_data_statement_or_raise __red_end_user_data_statement__ = get_end_user_data_statement_or_raise(__file__) async def setup(bot): ...
In order to ensure that you won’t end up with no end user data statement, this function raises if
info.json
file doesn’t exist, can’t be parsed, or doesn’t have anend_user_data_statement
key.- Parameters:
file (Union[pathlib.Path, str]) – The
__file__
variable for the cog’s__init__.py
file.- Returns:
The end user data statement found in the info.json.
- Return type:
- Raises:
FileNotFoundError – When
info.json
does not exist.KeyError – When
info.json
does not have theend_user_data_statement
key.json.JSONDecodeError – When
info.json
can’t be decoded withjson.load()
UnicodeError – When
info.json
can’t be decoded due to bad encoding.Exception – Any other exception raised from
pathlib
andjson
modules when attempting to parse theinfo.json
for theend_user_data_statement
key.
- class redbot.core.utils.AsyncIter(iterable, delay=0, steps=1)[source]
Bases:
AsyncIterator
[_T
],Awaitable
[List
[_T
]]Asynchronous iterator yielding items from
iterable
that sleeps fordelay
seconds everysteps
items.- Parameters:
- Raises:
ValueError – When
steps
is lower than 1.
Examples
>>> from redbot.core.utils import AsyncIter >>> async for value in AsyncIter(range(3)): ... print(value) 0 1 2
- async for ... in enumerate(start=0)[source]
Async iterable version of
enumerate
.- Parameters:
start (int) – The index to start from. Defaults to 0.
- Returns:
An async iterator of tuples in the form of
(index, item)
.- Return type:
AsyncIterator[Tuple[int, T]]
Examples
>>> from redbot.core.utils import AsyncIter >>> iterator = AsyncIter(['one', 'two', 'three']) >>> async for i in iterator.enumerate(start=10): ... print(i) (10, 'one') (11, 'two') (12, 'three')
- async for ... in filter(function)[source]
Filter the iterable with an (optionally async) predicate.
- Parameters:
function (Callable[[T], Union[bool, Awaitable[bool]]]) – A function or coroutine function which takes one item of
iterable
as an argument, and returnsTrue
orFalse
.- Returns:
An object which can either be awaited to yield a list of the filtered items, or can also act as an async iterator to yield items one by one.
- Return type:
AsyncFilter[T]
Examples
>>> from redbot.core.utils import AsyncIter >>> def predicate(value): ... return value <= 5 >>> iterator = AsyncIter([1, 10, 5, 100]) >>> async for i in iterator.filter(predicate): ... print(i) 1 5
>>> from redbot.core.utils import AsyncIter >>> def predicate(value): ... return value <= 5 >>> iterator = AsyncIter([1, 10, 5, 100]) >>> await iterator.filter(predicate) [1, 5]
- __await__()[source]
Returns a list of the iterable.
Examples
>>> from redbot.core.utils import AsyncIter >>> iterator = AsyncIter(range(5)) >>> await iterator [0, 1, 2, 3, 4]
- await find(predicate, default=None)[source]
Calls
predicate
over items in iterable and return first value to match.- Parameters:
predicate (Union[Callable, Coroutine]) – A function that returns a boolean-like result. The predicate provided can be a coroutine.
default (Optional[Any]) – The value to return if there are no matches.
- Raises:
TypeError – When
predicate
is not a callable.
Examples
>>> from redbot.core.utils import AsyncIter >>> await AsyncIter(range(3)).find(lambda x: x == 1) 1
- await flatten()[source]
Returns a list of the iterable.
Examples
>>> from redbot.core.utils import AsyncIter >>> iterator = AsyncIter(range(5)) >>> await iterator.flatten() [0, 1, 2, 3, 4]
- map(func)[source]
Set the mapping callable for this instance of
AsyncIter
.Important
This should be called after AsyncIter initialization and before any other of its methods.
- Parameters:
func (Union[Callable, Coroutine]) – The function to map values to. The function provided can be a coroutine.
- Raises:
TypeError – When
func
is not a callable.
Examples
>>> from redbot.core.utils import AsyncIter >>> async for value in AsyncIter(range(3)).map(bool): ... print(value) False True True
- await next(default=Ellipsis)[source]
Returns a next entry of the iterable.
- Parameters:
default (Optional[Any]) – The value to return if the iterator is exhausted.
- Raises:
StopAsyncIteration – When
default
is not specified and the iterator has been exhausted.
Examples
>>> from redbot.core.utils import AsyncIter >>> iterator = AsyncIter(range(5)) >>> await iterator.next() 0 >>> await iterator.next() 1
Chat Formatting
- for ... in redbot.core.utils.chat_formatting.pagify(text, delims=('\n',), *, priority=False, escape_mass_mentions=True, shorten_by=8, page_length=2000)[source]
Generate multiple pages from the given text.
The returned iterator supports length estimation with
operator.length_hint()
.Note
This does not respect code blocks or inline code.
- Parameters:
text (str) – The content to pagify and send.
delims (
sequence
ofstr
, optional) – Characters where page breaks will occur. If no delimiters are found in a page, the page will break afterpage_length
characters. By default this only contains the newline.priority (
bool
) – Set toTrue
to choose the page break delimiter based on the order ofdelims
. Otherwise, the page will always break at the last possible delimiter.escape_mass_mentions (
bool
) – IfTrue
, any mass mentions (here or everyone) will be silenced.shorten_by (
int
) – How much to shorten each page by. Defaults to 8.page_length (
int
) – The maximum length of each page. Defaults to 2000.
- Yields:
str
– Pages of the given text.
- redbot.core.utils.chat_formatting.bold(text, escape_formatting=True)[source]
Get the given text in bold.
Note: By default, this function will escape
text
prior to emboldening.
- redbot.core.utils.chat_formatting.escape(text, *, mass_mentions=False, formatting=False)[source]
Get text with all mass mentions or markdown escaped.
- redbot.core.utils.chat_formatting.format_perms_list(perms)[source]
Format a list of permission names.
This will return a humanized list of the names of all enabled permissions in the provided
discord.Permissions
object.- Parameters:
perms (discord.Permissions) – The permissions object with the requested permissions to list enabled.
- Returns:
The humanized list.
- Return type:
- redbot.core.utils.chat_formatting.humanize_list(items, *, locale=None, style='standard')[source]
Get comma-separated list, with the last element joined with and.
- Parameters:
items (Sequence[str]) – The items of the list to join together.
locale (Optional[str]) – The locale to convert, if not specified it defaults to the bot’s locale.
style (str) –
The style to format the list with.
Note: Not all styles are necessarily available in all locales, see documentation of
babel.lists.format_list
for more details.- standard
A typical ‘and’ list for arbitrary placeholders. eg. “January, February, and March”
- standard-short
A short version of a ‘and’ list, suitable for use with short or abbreviated placeholder values. eg. “Jan., Feb., and Mar.”
- or
A typical ‘or’ list for arbitrary placeholders. eg. “January, February, or March”
- or-short
A short version of an ‘or’ list. eg. “Jan., Feb., or Mar.”
- unit
A list suitable for wide units. eg. “3 feet, 7 inches”
- unit-short
A list suitable for short units eg. “3 ft, 7 in”
- unit-narrow
A list suitable for narrow units, where space on the screen is very limited. eg. “3′ 7″”
- Raises:
ValueError – The locale does not support the specified style.
Examples
>>> humanize_list(['One', 'Two', 'Three']) 'One, Two, and Three' >>> humanize_list(['One']) 'One' >>> humanize_list(['omena', 'peruna', 'aplari'], style='or', locale='fi') 'omena, peruna tai aplari'
- redbot.core.utils.chat_formatting.humanize_number(val, override_locale=None)[source]
Convert an int or float to a str with digit separators based on bot locale.
- Parameters:
- Raises:
decimals.InvalidOperation – If val is greater than 10 x 10^21 for some locales, 10 x 10^24 in others.
- Returns:
Locale-aware formatted number.
- Return type:
- redbot.core.utils.chat_formatting.humanize_timedelta(*, timedelta=None, seconds=None, negative_format=None, maximum_units=None)[source]
Get a locale aware human timedelta representation.
This works with either a timedelta object or a number of seconds.
Fractional values will be omitted.
Values that are less than 1 second but greater than -1 second will be an empty string.
- Parameters:
timedelta (Optional[datetime.timedelta]) – A timedelta object
seconds (Optional[SupportsInt]) – A number of seconds
negative_format (Optional[str]) – How to format negative timedeltas, using %-formatting rules. Defaults to “negative %s”
maximum_units (Optional[int]) – The maximum number of different units to output in the final string.
- Returns:
A locale aware representation of the timedelta or seconds.
- Return type:
- Raises:
ValueError – The function was called with neither a number of seconds nor a timedelta object, or with a maximum_units less than 1.
Examples
>>> humanize_timedelta(seconds=314) '5 minutes, 14 seconds' >>> humanize_timedelta(timedelta=timedelta(minutes=3.14), maximum_units=1) '3 minutes' >>> humanize_timedelta(timedelta=timedelta(days=-3.14), negative_format="%s ago", maximum_units=3) '3 days, 3 hours, 21 minutes ago'
- redbot.core.utils.chat_formatting.hyperlink(text, url)[source]
Create hyperlink markdown with text and a URL.
- redbot.core.utils.chat_formatting.italics(text, escape_formatting=True)[source]
Get the given text in italics.
Note: By default, this function will escape
text
prior to italicising.
- redbot.core.utils.chat_formatting.rich_markup(*objects, crop=True, emoji=True, highlight=True, justify=None, markup=True, no_wrap=None, overflow=None, width=None)[source]
Returns a codeblock with ANSI formatting for colour support.
This supports a limited set of Rich markup, and rich helper functions. (https://rich.readthedocs.io/en/stable/index.html)
- Parameters:
*objects (Any) – The text to convert to ANSI formatting.
crop (Optional[bool]) – Crop output to width of virtual terminal. Defaults to
True
.emoji (Optional[bool]) – Enable emoji code. Defaults to
True
.highlight (Optional[bool]) – Enable automated highlighting. Defaults to
True
.justify (Optional[str]) – Justify method: “default”, “left”, “right”, “center”, or “full”. Defaults to
None
.markup (Optional[bool]) – Boolean to enable Console Markup. Defaults to
True
.no_wrap (Optional[bool]) – Disables word wrapping. Defaults to
None
.overflow (Optional[str]) – Overflow method: “ignore”, “crop”, “fold”, or “ellipsis”. Defaults to None.
width (Optional[int]) – The width of the virtual terminal. Defaults to
80
characters long.
- Returns:
The ANSI formatted text in a codeblock.
- Return type:
- redbot.core.utils.chat_formatting.spoiler(text, escape_formatting=True)[source]
Get the given text as a spoiler.
Note: By default, this function will escape
text
prior to making the text a spoiler.
- redbot.core.utils.chat_formatting.strikethrough(text, escape_formatting=True)[source]
Get the given text with a strikethrough.
Note: By default, this function will escape
text
prior to applying a strikethrough.
- redbot.core.utils.chat_formatting.text_to_file(text, filename='file.txt', *, spoiler=False, encoding='utf-8')[source]
Prepares text to be sent as a file on Discord, without character limit.
This writes text into a bytes object that can be used for the
file
orfiles
parameters ofdiscord.abc.Messageable.send()
.- Parameters:
- Returns:
The file containing your text.
- Return type:
Embed Helpers
- redbot.core.utils.embed.randomize_colour(embed)[source]
Gives the provided embed a random color. There is an alias for this called randomize_color
- Parameters:
embed (discord.Embed) – The embed to add a color to
- Returns:
The embed with the color set to a random color
- Return type:
Event Predicates
MessagePredicate
- class redbot.core.utils.predicates.MessagePredicate(predicate)[source]
Bases:
Callable
[[Message
],bool
]A simple collection of predicates for message events.
These predicates intend to help simplify checks in message events and reduce boilerplate code.
This class should be created through the provided classmethods. Instances of this class are callable message predicates, i.e. they return
True
if a message matches the criteria.All predicates are combined with
MessagePredicate.same_context()
.Examples
Waiting for a response in the same channel and from the same author:
await bot.wait_for("message", check=MessagePredicate.same_context(ctx))
Waiting for a response to a yes or no question:
pred = MessagePredicate.yes_or_no(ctx) await bot.wait_for("message", check=pred) if pred.result is True: # User responded "yes" ...
Getting a member object from a user’s response:
pred = MessagePredicate.valid_member(ctx) await bot.wait_for("message", check=pred) member = pred.result
- result
The object which the message content matched with. This is dependent on the predicate used - see each predicate’s documentation for details, not every method will assign this attribute. Defaults to
None
.- Type:
Any
- classmethod cancelled(ctx=None, channel=None, user=None)[source]
Match if the message is
[p]cancel
.- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod contained_in(collection, ctx=None, channel=None, user=None)[source]
Match if the response is contained in the specified collection.
The index of the response in the
collection
sequence is assigned to theresult
attribute.- Parameters:
collection (Sequence[str]) – The collection containing valid responses.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod equal_to(value, ctx=None, channel=None, user=None)[source]
Match if the response is equal to the specified value.
- Parameters:
value (str) – The value to compare the response with.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod greater(value, ctx=None, channel=None, user=None)[source]
Match if the response is greater than the specified value.
- Parameters:
value (Union[int, float]) – The value to compare the response with.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod has_role(ctx=None, channel=None, user=None)[source]
Match if the response refers to a role which the author has.
Assigns the matching
discord.Role
object toresult
.One of
user
orctx
must be supplied. This predicate cannot be used in DM.- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[Union[
discord.TextChannel
,discord.VoiceChannel
,discord.StageChannel
,discord.Thread
]]) – Same aschannel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod length_greater(length, ctx=None, channel=None, user=None)[source]
Match if the response’s length is greater than the specified length.
- Parameters:
length (int) – The value to compare the response’s length with.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod length_less(length, ctx=None, channel=None, user=None)[source]
Match if the response’s length is less than the specified length.
- Parameters:
length (int) – The value to compare the response’s length with.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod less(value, ctx=None, channel=None, user=None)[source]
Match if the response is less than the specified value.
- Parameters:
value (Union[int, float]) – The value to compare the response with.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod lower_contained_in(collection, ctx=None, channel=None, user=None)[source]
Same as
contained_in()
, but the response is set to lowercase before matching.- Parameters:
collection (Sequence[str]) – The collection containing valid lowercase responses.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod lower_equal_to(value, ctx=None, channel=None, user=None)[source]
Match if the response as lowercase is equal to the specified value.
- Parameters:
value (str) – The value to compare the response with.
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod positive(ctx=None, channel=None, user=None)[source]
Match if the response is a positive number.
Assigns the response to
result
as afloat
.- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod regex(pattern, ctx=None, channel=None, user=None)[source]
Match if the response matches the specified regex pattern.
This predicate will use
re.search
to find a match. The resultingmatch object
will be assigned toresult
.- Parameters:
pattern (Union[
pattern object
, str]) – The pattern to search for in the response.ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod same_context(ctx=None, channel=None, user=None)[source]
Match if the message fits the described context.
- Parameters:
ctx (Optional[Context]) – The current invocation context.
channel (Optional[discord.abc.Messageable]) – The messageable object we expect a message in. If unspecified, defaults to
ctx.channel
. Ifctx
is unspecified too, the message’s channel will be ignored.user (Optional[discord.abc.User]) – The user we expect a message from. If unspecified, defaults to
ctx.author
. Ifctx
is unspecified too, the message’s author will be ignored.
- Returns:
The event predicate.
- Return type:
- classmethod valid_float(ctx=None, channel=None, user=None)[source]
Match if the response is a float.
Assigns the response to
result
as afloat
.- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod valid_int(ctx=None, channel=None, user=None)[source]
Match if the response is an integer.
Assigns the response to
result
as anint
.- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod valid_member(ctx=None, channel=None, user=None)[source]
Match if the response refers to a member in the current guild.
Assigns the matching
discord.Member
object toresult
.This predicate cannot be used in DM.
- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[Union[
discord.TextChannel
,discord.VoiceChannel
,discord.StageChannel
,discord.Thread
]]) – Same aschannel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod valid_role(ctx=None, channel=None, user=None)[source]
Match if the response refers to a role in the current guild.
Assigns the matching
discord.Role
object toresult
.This predicate cannot be used in DM.
- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[Union[
discord.TextChannel
,discord.VoiceChannel
,discord.StageChannel
,discord.Thread
]]) – Same aschannel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod valid_text_channel(ctx=None, channel=None, user=None)[source]
Match if the response refers to a text channel in the current guild.
Assigns the matching
discord.TextChannel
object toresult
.This predicate cannot be used in DM.
- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[Union[
discord.TextChannel
,discord.VoiceChannel
,discord.StageChannel
,discord.Thread
]]) – Same aschannel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod yes_or_no(ctx=None, channel=None, user=None)[source]
Match if the message is “yes”/”y” or “no”/”n”.
This will assign
True
for yes, orFalse
for no to theresult
attribute.- Parameters:
ctx (Optional[Context]) – Same as
ctx
insame_context()
.channel (Optional[discord.abc.Messageable]) – Same as
channel
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
ReactionPredicate
- class redbot.core.utils.predicates.ReactionPredicate(predicate)[source]
Bases:
Callable
[[Reaction
,User
],bool
]A collection of predicates for reaction events.
All checks are combined with
ReactionPredicate.same_context()
.Examples
Confirming a yes/no question with a tick/cross reaction:
from redbot.core.utils.predicates import ReactionPredicate from redbot.core.utils.menus import start_adding_reactions msg = await ctx.send("Yes or no?") start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred) if pred.result is True: # User responded with tick ... else: # User responded with cross ...
Waiting for the first reaction from any user with one of the first 5 letters of the alphabet:
from redbot.core.utils.predicates import ReactionPredicate from redbot.core.utils.menus import start_adding_reactions msg = await ctx.send("React to me!") emojis = ReactionPredicate.ALPHABET_EMOJIS[:5] start_adding_reactions(msg, emojis) pred = ReactionPredicate.with_emojis(emojis, msg) await ctx.bot.wait_for("reaction_add", check=pred) # pred.result is now the index of the letter in `emojis`
- result
The object which the reaction matched with. This is dependent on the predicate used - see each predicate’s documentation for details, not every method will assign this attribute. Defaults to
None
.- Type:
Any
- ALPHABET_EMOJIS = ('🇦', '🇧', '🇨', '🇩', '🇪', '🇫', '🇬', '🇭', '🇮', '🇯', '🇰', '🇱', '🇲', '🇳', '🇴', '🇵', '🇶', '🇷', '🇸', '🇹', '🇺', '🇻', '🇼', '🇽', '🇾', '🇿')
A tuple of all 26 alphabetical letter emojis.
- Type:
Tuple[str, …]
- NUMBER_EMOJIS = ('0⃣', '1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣')
A tuple of all single-digit number emojis, 0 through 9.
- Type:
Tuple[str, …]
- YES_OR_NO_EMOJIS = ('✅', '❎')
A tuple containing the tick emoji and cross emoji, in that order.
- classmethod same_context(message=None, user=None)[source]
Match if a reaction fits the described context.
This will ignore reactions added by the bot user, regardless of whether or not
user
is supplied.- Parameters:
message (Optional[discord.Message]) – The message which we expect a reaction to. If unspecified, the reaction’s message will be ignored.
user (Optional[discord.abc.User]) – The user we expect to react. If unspecified, the user who added the reaction will be ignored.
- Returns:
The event predicate.
- Return type:
- classmethod with_emojis(emojis, message=None, user=None)[source]
Match if the reaction is one of the specified emojis.
- Parameters:
emojis (Sequence[Union[str, discord.Emoji, discord.PartialEmoji]]) – The emojis of which one we expect to be reacted.
message (discord.Message) – Same as
message
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
- classmethod yes_or_no(message=None, user=None)[source]
Match if the reaction is a tick or cross emoji.
The emojis used are in
ReactionPredicate.YES_OR_NO_EMOJIS
.This will assign
True
for yes, orFalse
for no to theresult
attribute.- Parameters:
message (discord.Message) – Same as
message
insame_context()
.user (Optional[discord.abc.User]) – Same as
user
insame_context()
.
- Returns:
The event predicate.
- Return type:
Mod Helpers
- await redbot.core.utils.mod.check_permissions(ctx, perms)[source]
Check if the author has required permissions.
This will always return
True
if the author is a bot owner, or has theadministrator
permission. Ifperms
is empty, this will only check if the user is a bot owner.- Parameters:
ctx (Context) – The command invocation context to check.
perms (Dict[str, bool]) – A dictionary mapping permissions to their required states. Valid permission names are those listed as properties of the
discord.Permissions
class.
- Returns:
True
if the author has the required permissions.- Return type:
- redbot.core.utils.mod.get_audit_reason(author, reason=None, *, shorten=False)[source]
Construct a reason to appear in the audit log.
- Parameters:
author (discord.Member) – The author behind the audit log action.
reason (str) – The reason behind the audit log action.
shorten (bool) – When set to
True
, the returned audit reason string will be shortened to fit the max length allowed by Discord audit logs.
- Returns:
The formatted audit log reason.
- Return type:
- await redbot.core.utils.mod.is_admin_or_superior(bot, obj)[source]
Same as
is_mod_or_superior
except for admin permissions.If a message is passed, its author’s permissions are checked. If a role is passed, it simply checks if it is the admin role.
- Parameters:
bot (redbot.core.bot.Red) – The bot object.
obj (
discord.Message
ordiscord.Member
ordiscord.Role
) – The object to check permissions for.
- Returns:
True
if the object has admin permissions.- Return type:
- Raises:
TypeError – If the wrong type of
obj
was passed.
- await redbot.core.utils.mod.is_mod_or_superior(bot, obj)[source]
Check if an object has mod or superior permissions.
If a message is passed, its author’s permissions are checked. If a role is passed, it simply checks if it is one of either the admin or mod roles.
- Parameters:
bot (redbot.core.bot.Red) – The bot object.
obj (
discord.Message
ordiscord.Member
ordiscord.Role
) – The object to check permissions for.
- Returns:
True
if the object has mod permissions.- Return type:
- Raises:
TypeError – If the wrong type of
obj
was passed.
- await redbot.core.utils.mod.mass_purge(messages, channel, *, reason=None)[source]
Bulk delete messages from a channel.
If more than 100 messages are supplied, the bot will delete 100 messages at a time, sleeping between each action.
Note
Messages must not be older than 14 days, and the bot must not be a user account.
- Parameters:
messages (
list
ofdiscord.Message
) – The messages to bulk delete.channel (
discord.TextChannel
,discord.VoiceChannel
,discord.StageChannel
, ordiscord.Thread
) – The channel to delete messages from.reason (
str
, optional) – The reason for bulk deletion, which will appear in the audit log.
- Raises:
discord.Forbidden – You do not have proper permissions to delete the messages or you’re not using a bot account.
discord.HTTPException – Deleting the messages failed.
- await redbot.core.utils.mod.slow_deletion(messages)[source]
Delete a list of messages one at a time.
Any exceptions raised when trying to delete the message will be silenced.
- Parameters:
messages (
iterable
ofdiscord.Message
) – The messages to delete.
- redbot.core.utils.mod.strfdelta(delta)[source]
Format a timedelta object to a message with time units.
- Parameters:
delta (datetime.timedelta) – The duration to parse.
- Returns:
A message representing the timedelta with units.
- Return type:
Tunnel
- class redbot.core.utils.tunnel.Tunnel(*args, **kwargs)[source]
Bases:
object
A tunnel interface for messages
This will return None on init if the destination or source + origin pair is already in use, or the existing tunnel object if one exists for the designated parameters
- sender
The person who opened the tunnel
- Type:
- origin
The channel in which it was opened
- recipient
The user on the other end of the tunnel
- Type:
- await close_because_disabled(close_message)[source]
Sends a message to both ends of the tunnel that the tunnel is now closed.
- Parameters:
close_message (str) – The message to send to both ends of the tunnel.
- await communicate(*, message, topic=None, skip_message_content=False)[source]
Forwards a message.
- Parameters:
message (
discord.Message
) – The message to forwardtopic (
str
) – A string to prependskip_message_content (
bool
) – If this flag is set, only the topic will be sent
- Returns:
a pair of ints matching the ids of the message which was forwarded and the last message the bot sent to do that. useful if waiting for reactions.
- Return type:
- Raises:
discord.Forbidden – This should only happen if the user’s DMs are disabled the bot can’t upload at the origin channel or can’t add reactions there.
- staticmethod await files_from_attach(m, *, use_cached=False, images_only=False)[source]
makes a list of file objects from a message returns an empty list if none, or if the sum of file sizes is too large for the bot to send
- Parameters:
m (
discord.Message
) – A message to get attachments fromuse_cached (
bool
) – Whether to useproxy_url
rather thanurl
when downloading the attachmentimages_only (
bool
) – Whether only image attachments should be added to returned list
- Returns:
A list of
discord.File
objects- Return type:
list of
discord.File
- staticmethod await message_forwarder(*, destination, content=None, embed=None, files=None)[source]
This does the actual sending, use this instead of a full tunnel if you are using command initiated reactions instead of persistent event based ones
- Parameters:
destination (discord.abc.Messageable) – Where to send
content (str) – The message content
embed (discord.Embed) – The embed to send
files (Optional[List[discord.File]]) – A list of files to send.
- Returns:
The messages sent as a result.
- Return type:
List[discord.Message]
- Raises:
Common Filters
- redbot.core.utils.common_filters.escape_spoilers(content)[source]
Get a string with spoiler syntax escaped.
- redbot.core.utils.common_filters.escape_spoilers_and_mass_mentions(content)[source]
Get a string with spoiler syntax and mass mentions escaped
- redbot.core.utils.common_filters.filter_invites(to_filter)[source]
Get a string with discord invites sanitized.
Will match any discord.gg, discordapp.com/invite, discord.com/invite, discord.me, or discord.io/discord.li invite URL.
- redbot.core.utils.common_filters.filter_mass_mentions(to_filter)[source]
Get a string with mass mentions sanitized.
Will match any here and/or everyone mentions.
- redbot.core.utils.common_filters.filter_urls(to_filter)[source]
Get a string with URLs sanitized.
This will match any URLs starting with these protocols:
http://
https://
ftp://
sftp://
Utility UI
- class redbot.core.utils.views.ConfirmView(author=None, *, timeout=180.0, disable_buttons=False)[source]
Bases:
View
A simple
discord.ui.View
used for confirming something.- Parameters:
author (Optional[discord.abc.User]) – The user who you want to be interacting with the confirmation. If this is omitted anyone can click yes or no.
timeout (float) – The timeout of the view in seconds. Defaults to
180
seconds.disable_buttons (bool) – Whether to disable the buttons instead of removing them from the message after the timeout. Defaults to
False
.
Examples
Using the view:
view = ConfirmView(ctx.author) # attach the message to the view after sending it. # This way, the view will be automatically removed # from the message after the timeout. view.message = await ctx.send("Are you sure you about that?", view=view) await view.wait() if view.result: await ctx.send("Okay I will do that.") else: await ctx.send("I will not be doing that then.")
Auto-disable the buttons after timeout if nothing is pressed:
view = ConfirmView(ctx.author, disable_buttons=True) view.message = await ctx.send("Are you sure you about that?", view=view) await view.wait() if view.result: await ctx.send("Okay I will do that.") else: await ctx.send("I will not be doing that then.")
- author
The author of the message who is allowed to press the buttons.
- Type:
Optional[discord.abc.User]
- message
The message the confirm view is sent on. This can be set while sending the message. This can also be left as
None
in which case nothing will happen inon_timeout()
, if the view is never interacted with.- Type:
Optional[discord.Message]
- disable_buttons
Whether to disable the buttons isntead of removing them on timeout (if the
message
attribute has been set on the view).- Type:
- confirm_button[source]
A
discord.ui.Button
to confirm the message.The button’s callback will set
result
toTrue
, defer the response, and callon_timeout()
to clean up the view.Example
Changing the style and label of this
discord.ui.Button
:view = ConfirmView(ctx.author) view.confirm_button.style = discord.ButtonStyle.red view.confirm_button.label = "Delete" view.dismiss_button.label = "Cancel" view.message = await ctx.send( "Are you sure you want to remove #very-important-channel?", view=view ) await view.wait() if view.result: await ctx.send("Channel #very-important-channel deleted.") else: await ctx.send("Canceled.")
- Type:
- dismiss_button[source]
A
discord.ui.Button
to dismiss the message.The button’s callback will set
result
toFalse
, defer the response, and callon_timeout()
to clean up the view.Example
Changing the style and label of this
discord.ui.Button
:view = ConfirmView(ctx.author) view.confirm_button.style = discord.ButtonStyle.red view.confirm_button.label = "Delete" view.dismiss_button.label = "Cancel" view.message = await ctx.send( "Are you sure you want to remove #very-important-channel?", view=view ) await view.wait() if view.result: await ctx.send("Channel #very-important-channel deleted.") else: await ctx.send("Canceled.")
- Type:
- await interaction_check(interaction)[source]
A callback that is called when an interaction happens within the view that checks whether the view should process item callbacks for the interaction.
The default implementation of this will assign value of
discord.Interaction.message
to themessage
attribute and either:send an ephemeral failure message and return
False
, ifauthor
is set and isn’t the same as the interaction user, orreturn
True
See also
The documentation of the callback in the base class:
discord.ui.View.interaction_check()
- await on_timeout()[source]
A callback that is called by the provided (default) callbacks for
confirm_button
anddismiss_button
as well as when a view’s timeout elapses without being explicitly stopped.The default implementation will either disable the buttons when
disable_buttons
isTrue
, or remove the view from the message otherwise.Note
This will not do anything if
message
isNone
.
- class redbot.core.utils.views.SetApiModal(default_service=None, default_keys=None)[source]
Bases:
Modal
A secure
discord.ui.Modal
used to set API keys.This Modal can either be used standalone with its own
discord.ui.View
for custom implementations, or created viaSetApiView
to have an easy to implement secure way of setting API keys.- Parameters:
default_service (Optional[str]) – The service to add the API keys to. If this is omitted the bot owner is allowed to set their own service. Defaults to
None
.default_keys (Optional[Dict[str, str]]) – The API keys the service is expecting. This will only allow the bot owner to set keys the Modal is expecting. Defaults to
None
.
- class redbot.core.utils.views.SetApiView(default_service=None, default_keys=None)[source]
Bases:
View
A secure
discord.ui.View
used to set API keys.This view is an standalone, easy to implement
discord.ui.View
to allow an bot owner to securely set API keys in a public environment.- Parameters:
default_service (Optional[str]) – The service to add the API keys to. If this is omitted the bot owner is allowed to set their own service. Defaults to
None
.default_keys (Optional[Dict[str, str]]) – The API keys the service is expecting. This will only allow the bot owner to set keys the Modal is expecting. Defaults to
None
.
- await interaction_check(interaction)[source]
-
A callback that is called when an interaction happens within the view that checks whether the view should process item callbacks for the interaction.
This is useful to override if, for example, you want to ensure that the interaction author is a given user.
The default implementation of this returns
True
.Note
If an exception occurs within the body then the check is considered a failure and
on_error()
is called.- Parameters:
interaction (
Interaction
) – The interaction that occurred.- Returns:
Whether the view children’s callbacks should be called.
- Return type:
- class redbot.core.utils.views.SimpleMenu(pages, timeout=180.0, page_start=0, delete_after_timeout=False, disable_after_timeout=False, use_select_menu=False, use_select_only=False)[source]
Bases:
View
A simple Button menu
- Parameters:
pages (
list
ofstr
,discord.Embed
, ordict
.) – The pages of the menu. if the page is adict
its keys must be valid messageable args. e,g. “content”, “embed”, etc.page_start (int) – The page to start the menu at.
timeout (float) – The time (in seconds) to wait for a reaction defaults to 180 seconds.
delete_after_timeout (bool) – Whether or not to delete the message after the timeout has expired. Defaults to False.
disable_after_timeout (bool) – Whether to disable all components on the menu after timeout has expired. By default the view is removed from the message on timeout. Defaults to False.
use_select_menu (bool) – Whether or not to include a select menu to jump specifically between pages. Defaults to False.
use_select_only (bool) – Whether the menu will only display the select menu for paginating instead of the buttons. The stop button will remain but is positioned under the select menu in this instance. Defaults to False.
A select menu with a list of pages. The usage of this attribute is discouraged as it may store different instances throughout the menu’s lifetime.
Deprecated since version 3.5.14, will be removed in the first minor version that gets released after 2025-02-23: Any behaviour enabled by the usage of this attribute should no longer be depended on. If you need this for something and cannot replace it with the other functionality, create an issue on Red’s issue tracker.
- Type:
Examples
You can provide a list of strings:
from redbot.core.utils.views import SimpleMenu pages = ["Hello", "Hi", "Bonjour", "Salut"] await SimpleMenu(pages).start(ctx)
You can provide a list of dicts:
from redbot.core.utils.views import SimpleMenu pages = [{"content": "My content", "embed": discord.Embed(description="hello")}] await SimpleMenu(pages).start(ctx)
- await interaction_check(interaction)[source]
Ensure only the author is allowed to interact with the menu.
- await on_timeout()[source]
-
A callback that is called when a view’s timeout elapses without being explicitly stopped.
- await start(ctx, *, user=None, ephemeral=False)[source]
Used to start the menu displaying the first page requested.
Warning
The
user
parameter is considered provisional. If no issues arise, we plan on including it under developer guarantees in the first release made after 2024-05-24.- Parameters:
ctx (
commands.Context
) – The context to start the menu in.user (discord.User) –
The user allowed to interact with the menu. If this is
None
,ctx.author
will be able to interact with the menu.Warning
This parameter is provisional. If no issues arise, we plan on including it under developer guarantees in the first release made after 2024-05-24.
ephemeral (
bool
) – Send the message ephemerally. This only works if the context is from a slash command interaction.
- await start_dm(user)[source]
Used to start displaying the menu in a direct message.
- Parameters:
user (
discord.User
) – The user that will be direct messaged by the bot.
AntiSpam
- class redbot.core.utils.antispam.AntiSpam(intervals)[source]
Bases:
object
A class that can be used to count the number of events that happened within specified intervals. Later, it can be checked whether the specified maximum count for any of the specified intervals has been exceeded.
Examples
Tracking whether the number of reports sent by a user within a single guild is spammy:
class MyCog(commands.Cog): INTERVALS = [ # More than one report within last 5 seconds is considered spam. (datetime.timedelta(seconds=5), 1), # More than 3 reports within the last 5 minutes are considered spam. (datetime.timedelta(minutes=5), 3), # More than 10 reports within the last hour are considered spam. (datetime.timedelta(hours=1), 10), # More than 24 reports within a single day (last 24 hours) are considered spam. (datetime.timedelta(days=1), 24), ] def __init__(self, bot): self.bot = bot self.antispam = {} @commands.guild_only() @commands.command() async def report(self, ctx, content): # We want to track whether a single user within a single guild # sends a spammy number of reports. key = (ctx.guild.id, ctx.author.id) if key not in self.antispam: # Create an instance of the AntiSpam class with given intervals. self.antispam[key] = AntiSpam(self.INTERVALS) # If you want to use the default intervals, you can use: AntiSpam([]) # Check if the user sent too many reports recently. # The `AntiSpam.spammy` property is `True` if, for any interval, # the number of events that happened within that interval # exceeds the number specified for that interval. if self.antispam[key].spammy: await ctx.send( "You've sent too many reports recently, please try again later." ) return # Make any other early-return checks. # Record the event. self.antispam[key].stamp() # Save the report. # self.config... # Send a message to the user. await ctx.send("Your report has been submitted.")
- Parameters:
intervals (List[Tuple[datetime.timedelta, int]]) –
A list of tuples in the format (timedelta, int), where the timedelta represents the length of the interval, and the int represents the maximum number of times something can happen within that interval.
If an empty list is provided, the following defaults will be used:
3 per 5 seconds
5 per 1 minute
10 per 1 hour
24 per 1 day
- property spammy
Whether, for any interval, the number of events that happened within that interval exceeds the number specified for that interval.