Pydis Core¶
Useful utilities and tools for Discord bot development.
- class BotBase(*args, guild_id, allowed_roles, http_session, redis_session=None, api_client=None, statsd_url=None, **kwargs)[source]¶
Bases:
Bot
A sub-class that implements many common features that Python Discord bots use.
- redis_session[source]¶
The redis session used to communicate with the Redis instance.
- Type:
async_rediscache.RedisSession
- all_extensions[source]¶
All extensions that were found within the
module
passed toself.load_extensions
. Useself.extensions
to get the loaded extensions.
- __init__(*args, guild_id, allowed_roles, http_session, redis_session=None, api_client=None, statsd_url=None, **kwargs)[source]¶
Initialise the base bot instance.
- Parameters:
guild_id (
int
) – The ID of the guild used forwait_until_guild_available()
.allowed_roles (
list
) – A list of role IDs that the bot is allowed to mention.http_session (aiohttp.ClientSession) – The session to use for the bot.
redis_session (
RedisSession
|None
) – The async_rediscache.RedisSession to use for the bot.api_client (
APIClient
|None
) – Thepydis_core.site_api.APIClient
instance to use for the bot.statsd_url (
str
|None
) – The URL of the statsd server to use for the bot. If not given, a dummy statsd client will be created.
- add_command(command)[source]¶
Add
command
as normal and then add its root aliases to the bot.- Return type:
- clear()[source]¶
Not implemented! Re-instantiate the bot instead of attempting to re-use a closed one.
- Return type:
- async close()[source]¶
Close the Discord connection, and the aiohttp session, connector, statsd client, and resolver.
- Return type:
- async load_extensions(module, *, sync_app_commands=True)[source]¶
Load all the extensions within the given
module
and save them toself.all_extensions
.
- async on_guild_available(guild)[source]¶
Set the internal guild available event when self.guild_id becomes available.
If the cache appears to still be empty (no members, no channels, or no roles), the event will not be set and guild_available_but_cache_empty event will be emitted.
- Return type:
Clear the internal guild available event when self.guild_id becomes unavailable.
- Return type:
- async ping_services()[source]¶
Ping all required services on setup to ensure they are up before starting.
- Return type:
- async process_commands(message)[source]¶
Overwrite default Discord.py behaviour to process commands only after ensuring extensions are loaded.
This extension check is only relevant for clients that make use of
pydis_core.BotBase.load_extensions
.- Return type:
- register_command_error_manager(manager)[source]¶
Bind an instance of the command error manager to both the bot and the command tree.
The reason this doesn’t happen in the constructor is because error handlers might need an instance of the bot. So registration needs to happen once the bot instance has been created.
- Return type:
- remove_command(name)[source]¶
Remove a command/alias as normal and then remove its root aliases from the bot.
Individual root aliases cannot be removed by this function. To remove them, either remove the entire command or manually edit bot.all_commands.
- async setup_hook()[source]¶
An async init to startup generic services.
Connects to statsd, and calls
AsyncStatsClient.create_socket
andping_services()
.- Return type:
- async wait_until_guild_available()[source]¶
Wait until the guild that matches the
guild_id
given at init is available (and the cache is ready).The on_ready event is inadequate because it only waits 2 seconds for a GUILD_CREATE gateway event before giving up and thus not populating the cache for unavailable guilds.
- Return type:
- exception EmptyPaginatorEmbedError[source]¶
Bases:
Exception
Raised when attempting to paginate with empty contents.
- class LinePaginator(prefix='```', suffix='```', max_size=4000, scale_to_size=4000, max_lines=None, linesep='\\n')[source]¶
Bases:
Paginator
A class that aids in paginating code blocks for Discord messages.
- Parameters:
pagination_emojis (PaginationEmojis) – The emojis used to navigate pages.
prefix (str) – The prefix inserted to every page. e.g. three backticks.
suffix (str) – The suffix appended at the end of every page. e.g. three backticks.
max_size (int) – The maximum amount of codepoints allowed in a page.
scale_to_size (int) – The maximum amount of characters a single line can scale up to.
max_lines (int) – The maximum amount of lines allowed in a page.
- __init__(prefix='```', suffix='```', max_size=4000, scale_to_size=4000, max_lines=None, linesep='\\n')[source]¶
This function overrides the Paginator.__init__ from inside discord.ext.commands.
It overrides in order to allow us to configure the maximum number of lines per page.
- add_line(line='', *, empty=False)[source]¶
Adds a line to the current page.
If a line on a page exceeds max_size characters, then max_size will go up to scale_to_size for a single line before creating a new page for the overflow words. If it is still exceeded, the excess characters are stored and placed on the next pages unti there are none remaining (by word boundary). The line is truncated if scale_to_size is still exceeded after attempting to continue onto the next page.
In the case that the page already contains one or more lines and the new lines would cause max_size to be exceeded, a new page is created. This is done in order to make a best effort to avoid breaking up single lines across pages, while keeping the total length of the page at a reasonable size.
This function overrides the Paginator.add_line from inside discord.ext.commands.
It overrides in order to allow us to configure the maximum number of lines per page.
- async classmethod paginate(pagination_emojis, lines, ctx, embed, *, prefix='', suffix='', max_lines=None, max_size=500, scale_to_size=4000, empty=True, restrict_to_user=None, timeout=300, footer_text=None, url=None, exception_on_empty_embed=False, reply=False, allowed_roles=None)[source]¶
Use a paginator and set of reactions to provide pagination over a set of lines.
The reactions are used to switch page, or to finish with pagination.
When used, this will send a message using ctx.send() and apply a set of reactions to it. These reactions may be used to change page, or to remove pagination from the message.
Pagination will also be removed automatically if no reaction is added for five minutes (300 seconds).
The interaction will be limited to restrict_to_user (ctx.author by default) or to any user with a moderation role.
- Parameters:
pagination_emojis (PaginationEmojis) – The emojis used to navigate pages.
lines (list[str]) – A list of lines to be added to the paginated content.
ctx (
discord.ext.commands.Context
) – The context in which the pagination is needed.embed (
discord.Embed
) – The embed that holds the content, it serves as the page.prefix (str) – The prefix inserted to every page. e.g. three backticks.
suffix (str) – The suffix appended at the end of every page. e.g. three backticks.
max_lines (int) – The maximum amount of lines allowed in a page.
max_size (int) – The maximum amount of codepoints allowed in a page.
scale_to_size (int) – The maximum amount of characters a single line can scale up to.
empty (bool) – Indicates whether an empty line should be added to each provided line.
restrict_to_user (
discord.User
) – The user to whom interaction with the pages should be restricted.timeout (int) – The timeout after which users cannot change pages anymore.
footer_text (str) – Text to be added as a footer for each page.
url (str) – The url to be set for the pagination embed.
exception_on_empty_embed (bool) – Indicates whether to raise an exception when no lines are provided.
reply (bool) – Indicates whether to send the page as a reply to the context’s message.
allowed_roles (Sequence[int]) – A list of role ids that are allowed to change pages.
- Return type:
Example: >>> embed = discord.Embed() >>> embed.set_author(name=”Some Operation”, url=url, icon_url=icon) >>> await LinePaginator.paginate(pagination_emojis, [line for line in lines], ctx, embed)
- class PaginationEmojis(**data)[source]¶
Bases:
BaseModel
The emojis that will be used for pagination.
- __class_vars__: ClassVar[set[str]] = {}¶
The names of the class variables defined on the model.
- __private_attributes__: ClassVar[Dict[str, ModelPrivateAttr]] = {}¶
Metadata about the private attributes of the model.
- __pydantic_complete__: ClassVar[bool] = True¶
Whether model building is completed, or if there are still undefined fields.
- __pydantic_core_schema__: ClassVar[CoreSchema] = {'cls': <class 'pydis_core.utils.pagination.PaginationEmojis'>, 'config': {'title': 'PaginationEmojis'}, 'custom_init': False, 'metadata': {'pydantic_js_annotation_functions': [], 'pydantic_js_functions': [functools.partial(<function modify_model_json_schema>, cls=<class 'pydis_core.utils.pagination.PaginationEmojis'>, title=None), <bound method BaseModel.__get_pydantic_json_schema__ of <class 'pydis_core.utils.pagination.PaginationEmojis'>>]}, 'ref': 'pydis_core.utils.pagination.PaginationEmojis:94691603754640', 'root_model': False, 'schema': {'computed_fields': [], 'fields': {'delete': {'metadata': {'pydantic_js_annotation_functions': [<function get_json_schema_update_func.<locals>.json_schema_update_func>], 'pydantic_js_functions': []}, 'schema': {'default': '<:trashcan:637136429717389331>', 'schema': {'type': 'str'}, 'type': 'default'}, 'type': 'model-field'}, 'first': {'metadata': {'pydantic_js_annotation_functions': [<function get_json_schema_update_func.<locals>.json_schema_update_func>], 'pydantic_js_functions': []}, 'schema': {'default': '⏮', 'schema': {'type': 'str'}, 'type': 'default'}, 'type': 'model-field'}, 'last': {'metadata': {'pydantic_js_annotation_functions': [<function get_json_schema_update_func.<locals>.json_schema_update_func>], 'pydantic_js_functions': []}, 'schema': {'default': '⏭', 'schema': {'type': 'str'}, 'type': 'default'}, 'type': 'model-field'}, 'left': {'metadata': {'pydantic_js_annotation_functions': [<function get_json_schema_update_func.<locals>.json_schema_update_func>], 'pydantic_js_functions': []}, 'schema': {'default': '⬅', 'schema': {'type': 'str'}, 'type': 'default'}, 'type': 'model-field'}, 'right': {'metadata': {'pydantic_js_annotation_functions': [<function get_json_schema_update_func.<locals>.json_schema_update_func>], 'pydantic_js_functions': []}, 'schema': {'default': '➡', 'schema': {'type': 'str'}, 'type': 'default'}, 'type': 'model-field'}}, 'model_name': 'PaginationEmojis', 'type': 'model-fields'}, 'type': 'model'}¶
The core schema of the model.
- __pydantic_custom_init__: ClassVar[bool] = False¶
Whether the model has a custom __init__ method.
- __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos] = DecoratorInfos(validators={}, field_validators={}, root_validators={}, field_serializers={}, model_serializers={}, model_validators={}, computed_fields={})¶
Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
- __pydantic_extra__: dict[str, Any] | None¶
A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to ‘allow’.
- __pydantic_fields_set__: set[str]¶
The names of fields explicitly set during instantiation.
- __pydantic_generic_metadata__: ClassVar[_generics.PydanticGenericMetadata] = {'args': (), 'origin': None, 'parameters': ()}¶
Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
- __pydantic_parent_namespace__: ClassVar[Dict[str, Any] | None] = None¶
Parent namespace of the model, used for automatic rebuilding of models.
- __pydantic_post_init__: ClassVar[None | Literal['model_post_init']] = None¶
The name of the post-init method for the model, if defined.
- __pydantic_private__: dict[str, Any] | None¶
Values of private attributes set on the model instance.
- __pydantic_serializer__: ClassVar[SchemaSerializer] = SchemaSerializer(serializer=Model( ModelSerializer { class: Py( 0x0000561f1b67ae90, ), serializer: Fields( GeneralFieldsSerializer { fields: { "left": SerField { key_py: Py( 0x00007fce0b979730, ), alias: None, alias_py: None, serializer: Some( WithDefault( WithDefaultSerializer { default: Default( Py( 0x00007fce05cbac40, ), ), serializer: Str( StrSerializer, ), }, ), ), required: true, }, "right": SerField { key_py: Py( 0x00007fce0b9796f0, ), alias: None, alias_py: None, serializer: Some( WithDefault( WithDefaultSerializer { default: Default( Py( 0x00007fce05cbace0, ), ), serializer: Str( StrSerializer, ), }, ), ), required: true, }, "delete": SerField { key_py: Py( 0x00007fce0bd60eb0, ), alias: None, alias_py: None, serializer: Some( WithDefault( WithDefaultSerializer { default: Default( Py( 0x00007fce05cbad80, ), ), serializer: Str( StrSerializer, ), }, ), ), required: true, }, "last": SerField { key_py: Py( 0x00007fce0b9d2270, ), alias: None, alias_py: None, serializer: Some( WithDefault( WithDefaultSerializer { default: Default( Py( 0x00007fce05cbad30, ), ), serializer: Str( StrSerializer, ), }, ), ), required: true, }, "first": SerField { key_py: Py( 0x00007fce0b9f48b0, ), alias: None, alias_py: None, serializer: Some( WithDefault( WithDefaultSerializer { default: Default( Py( 0x00007fce05cbac90, ), ), serializer: Str( StrSerializer, ), }, ), ), required: true, }, }, computed_fields: Some( ComputedFields( [], ), ), mode: SimpleDict, extra_serializer: None, filter: SchemaFilter { include: None, exclude: None, }, required_fields: 5, }, ), has_extra: false, root_model: false, name: "PaginationEmojis", }, ), definitions=[])¶
The pydantic-core SchemaSerializer used to dump instances of the model.
- __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] = SchemaValidator(title="PaginationEmojis", validator=Model( ModelValidator { revalidate: Never, validator: ModelFields( ModelFieldsValidator { fields: [ Field { name: "first", lookup_key: Simple { key: "first", py_key: Py( 0x00007fce063818f0, ), path: LookupPath( [ S( "first", Py( 0x00007fce063812b0, ), ), ], ), }, name_py: Py( 0x00007fce0b9f48b0, ), validator: WithDefault( WithDefaultValidator { default: Default( Py( 0x00007fce05cbac90, ), ), on_error: Raise, validator: Str( StrValidator { strict: false, coerce_numbers_to_str: false, }, ), validate_default: false, copy_default: false, name: "default[str]", undefined: Py( 0x00007fce06538a10, ), }, ), frozen: false, }, Field { name: "left", lookup_key: Simple { key: "left", py_key: Py( 0x00007fce062a9130, ), path: LookupPath( [ S( "left", Py( 0x00007fce051f3eb0, ), ), ], ), }, name_py: Py( 0x00007fce0b979730, ), validator: WithDefault( WithDefaultValidator { default: Default( Py( 0x00007fce05cbac40, ), ), on_error: Raise, validator: Str( StrValidator { strict: false, coerce_numbers_to_str: false, }, ), validate_default: false, copy_default: false, name: "default[str]", undefined: Py( 0x00007fce06538a10, ), }, ), frozen: false, }, Field { name: "right", lookup_key: Simple { key: "right", py_key: Py( 0x00007fce051f0470, ), path: LookupPath( [ S( "right", Py( 0x00007fce051f3f30, ), ), ], ), }, name_py: Py( 0x00007fce0b9796f0, ), validator: WithDefault( WithDefaultValidator { default: Default( Py( 0x00007fce05cbace0, ), ), on_error: Raise, validator: Str( StrValidator { strict: false, coerce_numbers_to_str: false, }, ), validate_default: false, copy_default: false, name: "default[str]", undefined: Py( 0x00007fce06538a10, ), }, ), frozen: false, }, Field { name: "last", lookup_key: Simple { key: "last", py_key: Py( 0x00007fce051f3ef0, ), path: LookupPath( [ S( "last", Py( 0x00007fce051f0a30, ), ), ], ), }, name_py: Py( 0x00007fce0b9d2270, ), validator: WithDefault( WithDefaultValidator { default: Default( Py( 0x00007fce05cbad30, ), ), on_error: Raise, validator: Str( StrValidator { strict: false, coerce_numbers_to_str: false, }, ), validate_default: false, copy_default: false, name: "default[str]", undefined: Py( 0x00007fce06538a10, ), }, ), frozen: false, }, Field { name: "delete", lookup_key: Simple { key: "delete", py_key: Py( 0x00007fce051f0730, ), path: LookupPath( [ S( "delete", Py( 0x00007fce051f10b0, ), ), ], ), }, name_py: Py( 0x00007fce0bd60eb0, ), validator: WithDefault( WithDefaultValidator { default: Default( Py( 0x00007fce05cbad80, ), ), on_error: Raise, validator: Str( StrValidator { strict: false, coerce_numbers_to_str: false, }, ), validate_default: false, copy_default: false, name: "default[str]", undefined: Py( 0x00007fce06538a10, ), }, ), frozen: false, }, ], model_name: "PaginationEmojis", extra_behavior: Ignore, extras_validator: None, strict: false, from_attributes: false, loc_by_alias: true, }, ), class: Py( 0x0000561f1b67ae90, ), post_init: None, frozen: false, custom_init: false, root_model: false, undefined: Py( 0x00007fce06538a10, ), name: "PaginationEmojis", }, ), definitions=[], cache_strings=True)¶
The pydantic-core SchemaValidator used to validate instances of the model.
- __signature__: ClassVar[Signature] = <Signature (*, first: str = '⏮', left: str = '⬅', right: str = '➡', last: str = '⏭', delete: str = '<:trashcan:637136429717389331>') -> None>¶
The synthesized __init__ [Signature][inspect.Signature] of the model.
- model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}¶
A dictionary of computed field names and their corresponding ComputedFieldInfo objects.
- model_config: ClassVar[ConfigDict] = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_fields: ClassVar[Dict[str, FieldInfo]] = {'delete': FieldInfo(annotation=str, required=False, default='<:trashcan:637136429717389331>'), 'first': FieldInfo(annotation=str, required=False, default='⏮'), 'last': FieldInfo(annotation=str, required=False, default='⏭'), 'left': FieldInfo(annotation=str, required=False, default='⬅'), 'right': FieldInfo(annotation=str, required=False, default='➡')}¶
Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__ from Pydantic V1.