First off, thanks for taking the time to contribute. It makes the library substantially better. 👍
The following is a set of guidelines for contributing to the repository. These are guidelines, not hard rules.
Generally asking questions are better suited in our resources below.
- The official support server
- The FAQ in the documentation
- StackOverflow's
nextcord
tag - The discussions page
Please try your best not to ask questions in our issue tracker. Most of them don't belong there unless they provide value to a larger audience.
Please be aware of the following things when filing bug reports.
- Don't open duplicate issues. Please search your issue to see if it has been asked already. Duplicate issues will be closed.
- When filing a bug about exceptions, please include the complete traceback. Without the complete traceback the issue might be unsolvable and you will be asked to provide more information.
- Make sure to provide enough information to make the issue workable. The issue template will generally walk you through the process but they are enumerated here as well:
- A summary of your bug report. This is generally a quick sentence or two to describe the issue in human terms.
- Guidance on how to reproduce the issue. Ideally, this should have a small code sample that allows us to run and see the issue for ourselves to debug. Please make sure that the token is not displayed. If you cannot provide a code snippet, then let us know what the steps were, how often it happens, etc.
- Tell us what you expected to happen, that way we can meet that expectation.
- Tell us what actually happens. What ends up happening in reality? It's not helpful to say "it fails" or "it doesn't work". Say how it failed, do you get an exception? Does it hang? How are the expectations different from reality?
- Tell us information about your environment. What version of nextcord are you using? How was it installed? What operating system are you running on? These are valuable questions and information that we use.
If the bug report is missing this information then it'll take us longer to fix the issue. We will probably ask for clarification, and barring that if no response was given then the issue will be closed.
Submitting a pull request is fairly simple, just make sure it focuses on a single aspect and doesn't manage to have scope creep and it's probably good to go. It would be incredibly lovely if the style is consistent to that found in the project.
Please use the following to get your contributions up to spec:
To install dependencies locally for development, we use Poetry.
Install poetry, install our plugin at poetry self add "poetry-dynamic-versioning[plugin] @ git+https://github.com/nextcord/poetry-dynamic-versioning@master"
, then run poetry install
to create a virtual environment.
We use Black for code formatting, Slotscheck, Ruff for linting + import sorting, and several other pre-commit hooks for linting.
To run all of these but slotscheck
, you can simply run task lint
in the root of the project. To run slotscheck
, you can run task slotscheck
.
If you would like these to run automatically, you can use task precommit
to install pre-commit hooks. This will run all of the above on every commit.
Nextcord uses Pyright for type checking. To use it, run task pyright
in the root directory of the project, or python -m task pyright
(py -m
etc) if that does not work.
If type annotations are new to you, here is a guide to help you with it.
We include Autotyping via task codemod
to help you with type annotations. This will automatically add repetitive annotations such as None
returns and __str__
annotations. This is ran via pre-commit
but is a good idea to run before in case any more typing issues arise.
Nextcord follows the Conventional Commits style. This means that your commit messages and PR titles should be formatted in a specific way. This is to help us generate changelogs and release notes, whilst also helping us review your pull requests as we can see what each commit does.
Your commit messages should be in the present (imperative, 2nd person) tense, such as Add
, not Added
.
More specifically, we use the Angular Types List for commit types, along with a few extra. This means that your commit messages should be formatted like this:
<type>([scope]): <subject>
[BLANK LINE]
[body]
[BLANK LINE]
[footer]
Note The type and subject are mandatory.
Examples include:
feat: add support for forum channels
refactor(commands)!: change name of Bot to CommandBot
This is a breaking change because the name of the class has changed.
fix(app-cmds): resolve issue with negative numbers not converting to integers
Co-Authored-By: Some Person <email@example.com>
<type>
is one of the following:
- build: Changes that affect the build system or external dependencies
- chore: Other miscellaneous changes which do not affect users
- ci: Changes to our CI configuration files and scripts such as GitHub Actions
- docs: Documentation only changes
- feat: A new feature
- fix: A bug fix
- perf: A code change that improves performance
- refactor: A code change that neither fixes a bug nor adds a feature
- removal: A code change that removes user-facing code
- style: Changes that do not affect the meaning of the code (white-space, formatting, etc)
- test: Adding missing tests or correcting existing tests
- typing: Changes that affect type annotations
[scope]
is the name of the module affected (as perceived by the person reading the changelog generated from commit messages). Scope is not required when the change affects multiple modules. Some examples are:
application_command.py
-app-cmds
is the scopeauto_moderation.py
-automod
is the scopeext/commands/*
-commands
is the scopeui/
-ui
is the scope
The subject should be a short summary of the commit, the body can be used for more info, so do not cram so much into the subject. Ideally this should be 50 characters or less, but it is not a hard limit, 72 characters is fine if necessary, such as if a long method name is described.
The body is an optional long description about the commit, this can be used to explain the motivation for the change, and can be used to give more context about the change. It is not required, but it is recommended.
The footer contains optional metadata about the commit. These are sometimes added by git or similar tools, and examples include Co-authored-by
, Signed-off-by
, Fixes
.
Nextcord uses Sphinx for documentation compilation. Specifically, we use the numpy format (Reference, Examples).
To build the docs that will autocompile on file changes, run task docs
then open http://localhost:8069
in your browser.
Note If you are unsure about any of this, we can help you via a review or Discord. It just speeds the process up by doing it beforehand.
We use .. versionadded::
and .. versionchanged::
to denote when a feature was added or changed. These should be used in the docstring of the feature, below the summary.
These should not be used in methods in a new class, since the whole class is new.
The current in-development version can be found from the repository's tags.
class Client:
"""A client to interface with Discord.
This client is very barebones.
.. versionadded:: 2.0
"""
def start(self, token: Optional[str] = None) -> None:
"""Start the client.
.. versionadded:: 2.1
.. versionchanged:: 2.2
Added the `token` parameter.
"""
We use .. container:: operations
to describe special methods. This should be below the summary and above the attributes.
class Guild(Hashable):
"""Represents a Discord guild.
This is referred to as a "server" in the official Discord UI.
.. container:: operations
.. describe:: x == y
Checks if two guilds are equal.
.. describe:: x != y
Checks if two guilds are not equal.
.. describe:: hash(x)
Returns the guild's hash.
.. describe:: str(x)
Returns the guild's name.
We use Roles to link to other parts of documentation.
typing
is not linked to shorten the docstrings, and are simply described like this: List[:class:`str`]
.
@property
def members(self) -> List[Member]:
"""List[:class:`Member`]: Returns all the members with this role."""
,,,
Coroutines are denoted with |coro|
on the first line, and |maybecoro|
if it can be a coroutine or not (overriden methods).
async def sleep_until(...) -> Optional[T]:
"""|coro|
Sleep until a specified time.
...
"""
...
We use TypedDict to type payloads. This is a dictionary with a specific set of keys, where the values have a specific type.
These are stored in nextcord/types
, where the file name relates to the nextcord/
filename.
These are Python representations of Discord payloads found in the Discord API docs. typing_extensions.NotRequired
is used for keys which are omitted, represented by name?
in the Discord docs. typing.Optional
is used for keys which may be null
(None
), represented by ?type
in the Discord docs.
nextcord.types.snowflake.Snowflake
is used for Snowflakes, which are Discord IDs.
This is an example of the Auto Moderation Action Execution Payload.
class AutoModerationActionExecution(TypedDict):
guild_id: Snowflake
action: AutoModerationAction
rule_id: Snowflake
rule_trigger_type: AutoModerationTriggerType
user_id: Snowflake
matched_keyword: Optional[str]
channel_id: NotRequired[Snowflake]
message_id: NotRequired[Snowflake]
alert_system_message_id: NotRequired[Snowflake]
content: NotRequired[str]
matched_content: NotRequired[Optional[str]]
Gateway events are stored in nextcord/state.py
as async methods of ConnectionState
. These are named parse_{event}
where event is the lowercase name of Discord's event name.
Client events are dispatched via ConnectionState.dispatch
, which is a wrapper around Client.dispatch
. The event name is the end-user event name, but without the on_
prefix.
Documentation for events are in api.rst
, below .. _discord-api-events:
/Event Reference
.
Here is a simple example of AUTO_MODERATION_RULE_CREATE
:
def parse_auto_moderation_rule_create(self, data) -> None:
self.dispatch(
"auto_moderation_rule_create",
AutoModerationRule(data=data, state=self),
)