API Reference

Bot

Lifesaver subclasses Discord.py’s command extension’s bot class in order to provide extra features.

Bot

These classes gain their functionality from lifesaver.bot.BotBase.

class lifesaver.bot.Bot(cfg: lifesaver.bot.config.BotConfig, **kwargs)[source]

A plain bot, using lifesaver.bot.BotBase and discord.Client.

class lifesaver.bot.AutoShardedBot(cfg: lifesaver.bot.config.BotConfig, **kwargs)[source]

An autosharded bot, using lifesaver.bot.BotBase and discord.AutoShardedClient.

class lifesaver.bot.Selfbot(*args, **kwargs)[source]

A selfbot, using lifesaver.bot.BotBase and discord.Client.

Automatically passes bot=False when calling run().

BotBase

class lifesaver.bot.BotBase(cfg: lifesaver.bot.config.BotConfig, **kwargs)[source]

This is a discord.ext.commands.bot.BotBase subclass that is used by lifesaver.bot.Bot, lifesaver.bot.AutoShardedBot, and lifesaver.bot.Selfbot. It provides most of the custom functionality that Lifesaver bots use.

config = None

The bot’s BotConfig.

context_cls = None

The bot’s Context subclass to use when invoking commands. Falls back to Context.

emoji(accessor: str, *, stringify: bool = False) → Union[str, discord.emoji.Emoji][source]

Return an emoji as referenced by the global emoji table.

The first argument accesses the BotConfig.emojis dict using “dot access syntax” (e.g. generic.ok does ['generic']['ok']).

Both Unicode codepoints and custom emoji IDs are supported. If a custom emoji ID is used, discord.Client.get_emoji() is called to retrieve the discord.Emoji.

load_all(*, reload: bool = False, exclude_default: bool = False)[source]

Load all extensions in the load list.

The load list is always rebuilt first when called. When done, the load_all event is dispatched with the value of reload.

Parameters:
load_list = None

A list of extensions names to reload when calling load_all().

log = None

The bot’s logger.

coroutine on_message(message: discord.message.Message)[source]

The handler that handles incoming messages from Discord.

This event automatically waits for the bot to be ready before processing commands. Bots are ignored according to BotConfig.ignore_bots and the context class used for commands is determined by context_cls.

pool = None

The Postgres pool connection.

tick(variant: bool = True) → Union[str, discord.emoji.Emoji][source]

Return a tick emoji.

Uses generic.yes and generic.no from the global emoji table.

Commands

Lifesaver extends the commands extension in order to provide useful features that you might find helpful. These classes and functions are also available through the lifesaver module, because the name of this module would conflict with imports of discord.ext.commands:

# ✅ Use lifesaver.Cog, @lifesaver.command, ...
import lifesaver
from discord.ext import commands

# ❌ Clashing namespaces!
from lifesaver import commands
frmo discord.ext import commands

Cog

Lifesaver provides a custom cog class which works exactly like discord.ext.commands.Cog, but provides some useful tools, like an automatically created aiohttp.ClientSession, integration with lifesaver.config.Config, and more.

class lifesaver.commands.Cog(bot)[source]

The base class for cogs.

It inherits from discord.ext.commands.Cog. It differs in that the bot instance must be passed when constructing the cog. Some helpful properties and methods are also provided.

bot = None

The bot instance.

cog_unload()[source]

The special method called upon this cog being unloaded.

It cancels scheduled tasks created through every(), and destroys session.

If you override this, make sure to call super().cog_unload().

config = None

The loaded config file. Only present when with_config() is used.

classmethod every(interval: int, **kwargs)[source]

A decorator that designates this function to be executed every n second(s).

Parameters:
  • interval – The time interval in seconds.
  • wait_until_ready – Waits until the bot is ready before running.
  • initial_sleep – The number of seconds to sleep before running.
log = None

The logger for this cog. The name of the logger is derived from name.

loop

A shortcut to the asyncio.AbstractEventLoop that the bot is running on.

name = None

The lowercased name of the class.

pool

A shortcut to lifesaver.bot.BotBase.pool.

session = None

The aiohttp.ClientSession for this cog.

static with_config(config_cls: Type[lifesaver.config.Config])[source]

Specifies a lifesaver.config.Config to load when constructing the cog.

The config file is loaded according to lifesaver.bot.BotConfig.cog_config_path and name when constructed. The parsed config resides in config.

Commands

lifesaver.commands.command(name: str = None, cls=<class 'lifesaver.commands.core.Command'>, **kwargs)[source]

The command decorator.

Works exactly like discord.ext.commands.command().

You can pass the typing keyword argument to wrap the entire command invocation in a discord.ext.commands.Context.typing(), making the bot type for the duration the command runs.

lifesaver.commands.group(name: str = None, **kwargs)[source]

The command group decorator.

Works exactly like discord.ext.commands.group().

You can pass the hollow keyword argument in order to force the command invoker to specify a subcommand (raises lifesaver.commands.SubcommandInvocationRequired).

class lifesaver.commands.SubcommandInvocationRequired(message=None, *args)[source]

A discord.ext.commands.CommandError that is subclass raised when a subcommand needs to be invoked.

class lifesaver.commands.Command(*args, typing: bool = False, **kwargs)[source]

A discord.ext.commands.Command subclass that implements additional features.

class lifesaver.commands.Group(*args, hollow: bool = False, **kwargs)[source]

A discord.ext.commands.Group subclass that implements additional features.

Context

class lifesaver.commands.Context(**kwargs)[source]
add_line(line) → None[source]

Add a line to the paginator.

Works exactly like discord.ext.commands.Paginator.add_line(). See paginator and paginate().

can_send_embeds

Return whether the bot can send embeds in this context.

coroutine confirm(title: str, message=Embed.Empty, *, color: discord.colour.Colour = <Colour value=15158332>, delete_after: bool = False, cancellation_message: str = None) → bool[source]

Create a confirmation prompt for the user. Returns whether the user reacted with an affirmative emoji.

Parameters:
  • title – The title of the confirmation prompt.
  • message – The message (description) of the confirmation prompt.
  • color – The color of the embed. Defaults to discord.Color.red().
  • delete_after – Deletes the confirmation after a choice has been picked.
  • cancellation_message – A message to send after cancelling.
Returns:

Whether the user confirmed or not.

Return type:

bool

emoji(*args, **kwargs) → Union[str, discord.emoji.Emoji][source]

A shortcut to lifesaver.bot.BotBase.emoji().

coroutine ok(emoji: str = None) → None[source]

Respond with an emoji in acknowledgement to an action performed by the user.

This method tries to react to the original message, falling back to the emoji being sent a message in the channel. This additionally falls back to sending the author a direct message with the emoji.

If all of these fail, the message author will not be notified.

Parameters:emoji – The emoji to react with.
coroutine paginate(*, force_interface: bool = False, interface: Type[jishaku.paginators.PaginatorInterface] = <class 'jishaku.paginators.PaginatorInterface'>) → Optional[jishaku.paginators.PaginatorInterface][source]

Send the pages in the paginator in an appropriate manner.

Adding to the paginator is done by add_line() or manual access to paginator.

If there’s more than one page present (or force_interface is True), then the paginator is wrapped in an jishaku.paginators.PaginatorInterface, sent, and returned. This is for maximum user convenience as it allows them to browse the pages interactively using reaction buttons.

Otherwise, the only page is sent as a message without being wrapped.

Parameters:
Raises:

RuntimeError – The paginator is empty.

paginator = None

The paginator associated with this context.

To mimic send(), the default prefix and suffix is '', and the max_size is 1,900 to prevent filling the chat window when the paginator interface automatically kicks in (see paginate()).

coroutine pick_from_list(choices: List[T], *, delete_after_choice: bool = False, tries: int = 3) → Optional[T][source]

Send a list of items, allowing the user to pick one. Returns the picked item.

The choices are formatted with lifesaver.utils.formatting.format_list().

Parameters:
  • choices – The list of choices.
  • delete_after_choice – Deletes the message prompt after the user has picked.
  • tries – The amount of tries to grant the user.
pool

A shortcut to lifesaver.bot.BotBase.pool.

coroutine send(content: Any = None, *args, scrub: bool = True, **kwargs) → discord.message.Message[source]

Send a message to this context. Identical to discord.abc.Messageable.send().

If scrub is True, then @everyone and @here mentions are removed from the content (after going through str()).

coroutine send_pages() → None[source]

Send the pages in the paginator.

You probably want to use paginate() instead, as it automatically wraps the pages in a jishaku.paginators.PaginatorInterface if there’s more than one page.

tick(*args, **kwargs) → Union[str, discord.emoji.Emoji][source]

A shortcut to lifesaver.bot.BotBase.tick().

coroutine wait_for_response() → discord.message.Message[source]

Wait for a message from the message author, then returns it.

The message we are waiting for will only be accepted if it was sent by the original command invoker, and if it was sent in the same channel as the command message.

Returns:The sent message.
Return type:discord.Message

Utilities

Dictionaries

lifesaver.utils.dicts.merge_dicts(template: MutableMapping[Any, Any], to_merge: Mapping[Any, Any]) → Mapping[Any, Any][source]

Deeply merge a mapping onto another mapping.

lifesaver.utils.dicts.dot_access(source: Mapping[Any, Any], access: str) → Any[source]

Access a dict by dotted string access.

Formatting

lifesaver.utils.formatting.format_list(items: List[Any]) → str[source]

Format a list as an ordered list, with numerals preceding every item. List numerals are padded to ensure that there are at least 3 digits.

lifesaver.utils.formatting.escape_backticks(text: str) → str[source]

Replace backticks with a homoglyph to prevent text in codeblocks and inline code segments from escaping.

lifesaver.utils.formatting.human_delta(delta: Union[int, float, datetime.datetime, datetime.timedelta], *, short: bool = True) → str[source]

Convert a time unit to a human readable time delta string.

Parameters:
  • delta – The amount of time to convert.
  • short – Controls whether only the three biggest units of time end up in the result or all. Defaults to True.
Returns:

A human readable version of the time.

Return type:

str

lifesaver.utils.formatting.codeblock(code: str, *, lang: str = '', escape: bool = True) → str[source]

Construct a Markdown codeblock.

Parameters:
  • code – The code to insert into the codeblock.
  • lang – The string to mark as the language when formatting.
  • escape – Prevents the code from escaping from the codeblock.
Returns:

The formatted codeblock.

Return type:

str

lifesaver.utils.formatting.truncate(text: str, desired_length: int, *, suffix: str = '...') → str[source]

Truncates text and returns it. Three periods will be inserted as a suffix.

Parameters:
  • text – The text to truncate.
  • desired_length – The desired length.
  • suffix – The text to insert before the desired length is reached. By default, this is “…” to indicate truncation.
Returns:

The truncated text.

Return type:

str

class lifesaver.utils.formatting.Table(*column_titles)[source]

A class to format tabular data into rows and columns.

Example

>>> table = Table('Row 1', 'Row 2')
>>> table.add_row('Data 1', 'Data 2')
>>> await table.render()
Row 1  | Row 2
-------+--------
Data 1 | Data 2
add_row(*row)[source]

Add a row to the table.

If the number of data columns specified does not match the number of column titles, there may be issues rendering.

coroutine render(loop: asyncio.events.AbstractEventLoop = None)[source]

Return a rendered version of the table.

lifesaver.utils.formatting.clean_mentions(channel: discord.channel.TextChannel, text: str) → str[source]

Escape all user and role mentions which would mention someone in the specified channel.

lifesaver.utils.formatting.pluralize(*, with_quantity: bool = True, with_indicative: bool = False, **word) → str[source]

Pluralize a single kwarg’s name depending on the value.

with_indicative must be used with with_quantity.

Example

>>> pluralize(object=2)
"2 objects"
>>> pluralize(object=1)
"1 object"
>>> pluralize(object=1, with_quantity=False)
"object"
>>> pluralize(object=2, with_quantity=False)
"objects"
>>> pluralize(object=2, with_indicative=True)
"2 objects are"
>>> pluralize(object=1, with_indicative=True)
"1 object is"
lifesaver.utils.formatting.format_traceback(exc: Exception, *, limit: int = 7, hide_paths: bool = False) → str[source]

Format an exception into a traceback, akin to ones emitted by the interpreter during runtime.

Parameters:
  • limit – The maximum number of lines to include.
  • hide_paths – Conceals the current working directory and packages path.
class lifesaver.utils.formatting.Table(*column_titles)[source]

A class to format tabular data into rows and columns.

Example

>>> table = Table('Row 1', 'Row 2')
>>> table.add_row('Data 1', 'Data 2')
>>> await table.render()
Row 1  | Row 2
-------+--------
Data 1 | Data 2
add_row(*row)[source]

Add a row to the table.

If the number of data columns specified does not match the number of column titles, there may be issues rendering.

coroutine render(loop: asyncio.events.AbstractEventLoop = None)[source]

Return a rendered version of the table.

Roles

lifesaver.utils.roles.mentionable_role(role: discord.role.Role)[source]

An asynchronous context manager that edits a role to be mentionable, yields, then edits the role to be unmentionable.

Keep in mind that this can raise if you don’t have the proper permissions to edit the role.

In case your code raises, the role will be edited to be unmentionable (using a finally clause).

Example

# Assuming that you have the proper permissions:

async with mentionable_role(role):
    # `role` should be mentionable here.
    await channel.send(f'{role.mention} yo!')

# `role` is no longer mentionable.

System

Utilities concerning the system.

coroutine lifesaver.utils.system.shell(command: str) → str[source]

Run a shell command asynchronously, returning output.

Timing

Various utilities for timing and ratelimiting.

class lifesaver.utils.timing.Timer[source]

A context manager timing utility used to measure time.

duration

Return the duration that this timer ran, in seconds.

microseconds

Return the duration that this timer ran, in microseconds.

milliseconds

Return the duration that this timer ran, in milliseconds.

ms

Return the duration that this timer ran, in milliseconds.

Config

class lifesaver.config.Config(data: dict)[source]

A dict-like object that encompasses a configuration of some kind.

All config files use YAML for markup.

classmethod load(path: str) → lifesaver.config.Config[source]

Creates a Config instance from a file path.

Parameters:path – A path to a YAML file.

Exceptions

class lifesaver.errors.LifesaverError[source]

An exception thrown by lifesaver.