├── .github
└── workflows
│ └── greetings.yml
├── .gitignore
├── .readthedocs.yaml
├── .vscode
└── settings.json
├── CHANGELOG.MD
├── CONTRIBUTING.MD
├── LICENSE
├── README.md
├── TODO.MD
├── docs
├── Makefile
├── make.bat
├── requirements.txt
└── source
│ ├── api
│ ├── caching.rst
│ ├── client.rst
│ ├── dataclasses.rst
│ ├── enums.rst
│ ├── events.rst
│ ├── exceptions.rst
│ ├── index.rst
│ ├── models.rst
│ └── utils.rst
│ ├── conf.py
│ ├── contributing.rst
│ ├── getting_started.rst
│ ├── images
│ └── logo.png
│ ├── index.rst
│ └── releases.rst
├── examples
└── basic.py
├── pyproject.toml
├── qord
├── __init__.py
├── bases.py
├── core
│ ├── __init__.py
│ ├── cache.py
│ ├── cache_impl.py
│ ├── client.py
│ ├── dispatch.py
│ ├── ratelimits.py
│ ├── rest.py
│ └── shard.py
├── dataclasses
│ ├── __init__.py
│ ├── allowed_mentions.py
│ ├── embeds.py
│ ├── files.py
│ ├── message_reference.py
│ └── permission_overwrite.py
├── decorators.py
├── enums.py
├── events
│ ├── __init__.py
│ ├── base.py
│ ├── channels.py
│ ├── emojis.py
│ ├── gateway.py
│ ├── guild_members.py
│ ├── guilds.py
│ ├── invites.py
│ ├── messages.py
│ ├── reactions.py
│ ├── roles.py
│ ├── scheduled_events.py
│ ├── stage_instances.py
│ └── users.py
├── exceptions.py
├── flags
│ ├── __init__.py
│ ├── applications.py
│ ├── base.py
│ ├── intents.py
│ ├── messages.py
│ ├── permissions.py
│ ├── system_channel.py
│ └── users.py
├── internal
│ ├── __init__.py
│ ├── context_managers.py
│ ├── helpers.py
│ ├── mixins.py
│ ├── types.py
│ └── undefined.py
├── models
│ ├── __init__.py
│ ├── applications.py
│ ├── base.py
│ ├── channels.py
│ ├── emojis.py
│ ├── guild_members.py
│ ├── guilds.py
│ ├── invites.py
│ ├── messages.py
│ ├── roles.py
│ ├── scheduled_events.py
│ ├── stage_instances.py
│ └── users.py
├── project_info.py
└── utils.py
├── requirements.txt
├── setup.py
└── tests
├── test_embed.py
├── test_flags.py
├── test_internal_helpers.py
├── test_permission_overwrite.py
└── test_utils.py
/.github/workflows/greetings.yml:
--------------------------------------------------------------------------------
1 | name: Greetings
2 |
3 | on: [pull_request, issues]
4 |
5 | jobs:
6 | greeting:
7 | runs-on: ubuntu-latest
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 | steps:
12 | - uses: actions/first-interaction@v1
13 | with:
14 | repo-token: ${{ secrets.GITHUB_TOKEN }}
15 | issue-message: 'Hi, It looks like this is your first issue in this repository. We appreciate your contribution! :+1: If you have any questions about your issue, Consider discussing it in our [Discord Server](https://discord.gg/nE9cGtzayA)'
16 | pr-message: 'Thank you for contributing to Qord! :+1: As this is your first contribution, We recommend joining our [Discord server](https://discord.gg/nE9cGtzayA) for asking questions about your pull request and to discuss any major changes.'
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 | # VSCode - Ignore all files of .vscode/ except settings.json since it
132 | # includes the configuration for tests.
133 | .vscode/*
134 | !.vscode/settings.json
135 |
136 | # Optional
137 | .qord-misc/
138 | test.*
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # .readthedocs.yaml
2 | # Read the Docs configuration file
3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4 |
5 | # Required
6 | version: 2
7 |
8 | # Set the version of Python and other tools you might need
9 | build:
10 | os: ubuntu-20.04
11 | tools:
12 | python: "3.9"
13 | nodejs: "16"
14 |
15 | # Build documentation in the docs/ directory with Sphinx
16 | sphinx:
17 | configuration: docs/source/conf.py
18 |
19 | python:
20 | install:
21 | - requirements: docs/requirements.txt
22 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.testing.unittestArgs": [
3 | "-v",
4 | "-s",
5 | "./tests",
6 | "-p",
7 | "test_*.py"
8 | ],
9 | "python.testing.pytestEnabled": false,
10 | "python.testing.unittestEnabled": true
11 | }
--------------------------------------------------------------------------------
/CHANGELOG.MD:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | Changelogs for all public releases can be viewed on the [Releases](https://qord.rtfd.io/en/latest/releases.html) page on the documentation. (Recommended)
4 |
5 | You can also track the [GitHub releases](https://github.com/izxxr/qord/releases).
6 |
7 | -----
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.MD:
--------------------------------------------------------------------------------
1 | # Contributing to Qord
2 | We appreciate any kind of contributions from the users :+1:
3 |
4 | For detailed instructions of contributing to the library, See [this page](https://qord.readthedocs.io/en/stable/contributing.html).
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Izhar Ahmad
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Qord
3 |
4 |
9 |
10 | Python library for Discord API based around asyncio.
11 |
12 | **Features:**
13 |
14 | - Object oriented, user friendly interface with no dirty payloads.
15 | - Easy to customise and manage.
16 | - Robust handling of HTTP ratelimits.
17 | - Supports automatic gateway sharding.
18 |
19 | ## Development stage
20 | Qord is currently under it's initial development (alpha) stage. During this phase, there may be breaking changes and public user-facing API should not be considered stable. There would be no efforts in keeping backward compatibility. While the library currently supports the basic functionalities required to build a bot, many essential features are yet to be implemented and for this reason, Qord isn't yet a library to choose for making full fledged bots.
21 |
22 | The complete lifetime of 0.x version is considered the development phase. More info about this semantic versioning specification can be found [here](https://semver.org/#spec-item-4).
23 |
24 | ## Installation
25 | Qord is installed using Python's traditional package manager, pip.
26 | ```bash
27 | python -m pip install -U qord
28 | ```
29 |
30 | Qord requires **Python 3.8 or higher**. The dependencies are handled by pip automatically, see complete list of dependencies [here](https://github.com/izxxr/qord/blob/main/requirements.txt).
31 |
32 | ## Usage
33 | To whet your appetite, let's get a quickstart with an example of a simple "Ping-Pong" bot.
34 | ```py
35 | import qord
36 |
37 | intents = qord.Intents.unprivileged()
38 | intents.message_content = True
39 | client = qord.Client(intents=intents)
40 |
41 | @client.event(qord.GatewayEvent.READY)
42 | async def on_ready(event):
43 | print("Bot is ready.")
44 | print(f"Shards: {client.shards_count}")
45 | print(f"User: {client.user.proper_name}")
46 | print(f"Guilds: {len(client.cache.guilds())}")
47 |
48 | @client.event(qord.GatewayEvent.MESSAGE_CREATE)
49 | async def on_message_create(event):
50 | message = event.message
51 |
52 | if message.author.bot:
53 | # Don't respond to bot messages.
54 | return
55 |
56 | if message.content == "!ping":
57 | await message.channel.send("Pong!")
58 |
59 | client.start("BOT_TOKEN")
60 | ```
61 |
62 | For a brief explanation of this example, go to [this page](https://github.com/izxxr/qord/blob/master/examples/basic.py). More examples can be found in the [`examples`](https://github.com/izxxr/qord/blob/master/examples) directory.
63 |
64 | ## Contributing
65 | Qord is under heavy development. You can help us in reaching 100% coverage of Discord API by reporting bugs, suggesting features or even directly contributing to the code base. Please read the [Contribution Guidelines](https://github.com/izxxr/qord/blob/main/CONTRIBUTING.MD).
66 |
67 | ----
68 |
69 |
70 |
71 |
Documentation •
Discord Server •
PyPi
72 | •
GitHub •
Issues Tracker
73 |
74 |
Copyright (C) izxxr and contributors 2022, Under the MIT license.
75 |
76 |
--------------------------------------------------------------------------------
/TODO.MD:
--------------------------------------------------------------------------------
1 | # Discord API Coverage
2 |
3 | ## [Audit Log](https://discord.com/developers/docs/resources/audit-log)
4 |
5 | - [ ] Get Guild Audit Log
6 |
7 | ## [Channel](https://discord.com/developers/docs/resources/channel)
8 |
9 | - [x] Get Channel
10 | - [x] Modify Channel
11 | - [x] Delete/Close Channel
12 | - [x] Get Channel Messages
13 | - [x] Get Channel Message
14 | - [x] Create Message
15 | - [x] Crosspost Message
16 | - [x] Create Reaction
17 | - [x] Delete Own Reaction
18 | - [x] Get Reactions
19 | - [x] Delete All Reactions
20 | - [x] Delete All Reactions for Emoji
21 | - [x] Edit Message
22 | - [x] Delete Message
23 | - [ ] Bulk Delete Messages
24 | - [x] Edit Channel Permissions
25 | - [ ] Get Channel Invites
26 | - [ ] Create Channel Invite
27 | - [x] Delete Channel Permission
28 | - [ ] Follow News Channel
29 | - [x] Trigger Typing Indicator
30 | - [x] Get Pinned Messages
31 | - [x] Pin Message
32 | - [x] Unpin Message
33 | - [ ] Start Thread with a Message
34 | - [ ] Start Thread without a Message
35 | - [ ] Join Thread
36 | - [ ] Add Thread Member
37 | - [ ] Leave Thread
38 | - [ ] Remove Thread Member
39 | - [ ] Get Thread Member
40 | - [ ] List Thread Members
41 | - [ ] List Active Threads
42 | - [ ] List Public Archived Threads
43 | - [ ] List Private Archived Threads
44 | - [ ] List Joined Private Archived Threads
45 |
46 |
47 | ## [Emoji](https://discord.com/developers/docs/resources/emoji)
48 |
49 | - [x] List Guild Emojis
50 | - [x] Get Guild Emoji
51 | - [x] Create Guild Emoji
52 | - [x] Modify Guild Emoji
53 | - [x] Delete Guild Emoji
54 |
55 | ## [Guild](https://discord.com/developers/docs/resources/guild)
56 |
57 | - [ ] Create Guild
58 | - [x] Get Guild
59 | - [ ] Get Guild Preview
60 | - [ ] Modify Guild
61 | - [ ] Delete Guild
62 | - [x] Get Guild Channels
63 | - [x] Create Guild Channel
64 | - [ ] Modify Guild Channel Positions
65 | - [x] Modify Guild Channel
66 | - [ ] List Active Threads
67 | - [x] Get Guild Member
68 | - [x] List Guild Members
69 | - [x] Search Guild Members
70 | - [x] Modify Guild Member
71 | - [x] Modify Current Member
72 | - [x] Add Guild Member Role
73 | - [x] Remove Guild Member Role
74 | - [x] Remove Guild Member
75 | - [ ] Get Guild Bans
76 | - [ ] Get Guild Ban
77 | - [ ] Create Guild Ban
78 | - [ ] Remove Guild Ban
79 | - [x] Get Guild Roles
80 | - [x] Create Guild Role
81 | - [ ] Modify Guild Role Positions
82 | - [x] Modify Guild Role
83 | - [x] Delete Guild Role
84 | - [ ] Get Guild Prune Count
85 | - [ ] Begin Guild Prune
86 | - [ ] Get Guild Voice Regions
87 | - [ ] Get Guild Invites
88 | - [ ] Get Guild Integrations
89 | - [ ] Delete Guild Integration
90 | - [ ] Get Guild Widget Settings
91 | - [ ] Modify Guild Widget
92 | - [ ] Get Guild Widget
93 | - [ ] Get Guild Prune Count
94 | - [ ] Get Guild Vanity URL
95 | - [ ] Get Guild Widget Image
96 | - [ ] Get Guild Welcome Screen
97 | - [ ] Modify Guild Welcome Screen
98 | - [ ] Modify Current User Voice State
99 | - [ ] Modify User Voice State
100 |
101 | ## [Guild Scheduled Event](https://discord.com/developers/docs/resources/guild-scheduled-event)
102 |
103 | - [x] List Scheduled Events for Guild
104 | - [x] Create Guild Scheduled Event
105 | - [x] Get Guild Scheduled Event
106 | - [x] Modify Guild Scheduled Event
107 | - [x] Delete Guild Scheduled Event
108 | - [x] Get Guild Scheduled Users
109 |
110 | ## [Guild Template](https://discord.com/developers/docs/resources/guild-template)
111 |
112 | - [ ] Get Guild Template
113 | - [ ] Create Guild from Guild Template
114 | - [ ] Get Guild Templates
115 | - [ ] Create Guild Templates
116 | - [ ] Sync Guild Template
117 | - [ ] Modify Guild Template
118 | - [ ] Delete Guild Template
119 |
120 | ## [Invite](https://discord.com/developers/docs/resources/invite)
121 |
122 | - [ ] Get Invite
123 | - [ ] Delete Invite
124 |
125 | ## [Stage Instance](https://discord.com/developers/docs/resources/stage-instance)
126 |
127 | - [x] Create Stage Instance
128 | - [x] Get Stage Instance
129 | - [x] Modify Stage Instance
130 | - [x] Delete Stage Instance
131 |
132 | ## [Sticker](https://discord.com/developers/docs/resources/sticker)
133 |
134 | - [ ] Get Sticker
135 | - [ ] List Nitro Sticker Packs
136 | - [ ] List Guild Stickers
137 | - [ ] Get Guild Sticker
138 | - [ ] Create Guild Sticker
139 | - [ ] Modify Guild Sticker
140 | - [ ] Delete Guild Sticker
141 |
142 | ## [User](https://discord.com/developers/docs/resources/user)
143 |
144 | - [x] Get Current User
145 | - [x] Get User
146 | - [x] Modify Current User
147 | - [ ] Get Current User Guilds
148 | - [x] Leave Guild
149 | - [x] Create DM
150 |
151 | ## [Voice](https://discord.com/developers/docs/resources/voice)
152 |
153 | - [ ] List Voice Regions
154 |
155 | ## [Webhook](https://discord.com/developers/docs/resources/webhook)
156 |
157 | - [ ] Create Webhook
158 | - [ ] Get Channel Webhooks
159 | - [ ] Get Guild Webhooks
160 | - [ ] Get Webhook
161 | - [ ] Get Webhook with Token
162 | - [ ] Modify Webhook
163 | - [ ] Modify Webhook with Token
164 | - [ ] Delete Webhook
165 | - [ ] Delete Webhook with Token
166 | - [ ] Execute Webhook
167 | - [ ] Get Webhook Message
168 | - [ ] Edit Webhook Message
169 | - [ ] Delete Webhook Message
170 |
171 | ## [Gateway events](https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events)
172 | - [x] Hello
173 | - [x] Ready
174 | - [x] Resumed
175 | - [x] Reconnect
176 | - [x] Invalid Session
177 | - [x] Channel Create
178 | - [x] Channel Update
179 | - [x] Channel Delete
180 | - [x] Channel Pins Update
181 | - [ ] Thread Create
182 | - [ ] Thread Update
183 | - [ ] Thread Delete
184 | - [ ] Thread List Sync
185 | - [ ] Thread Member Update
186 | - [ ] Thread Members Update
187 | - [x] Guild Create
188 | - [x] Guild Update
189 | - [x] Guild Delete
190 | - [ ] Guild Ban Add
191 | - [ ] Guild Ban Remove
192 | - [x] Guild Emojis Update
193 | - [ ] Guild Stickers Update
194 | - [ ] Guild Integrations Update
195 | - [x] Guild Member Add
196 | - [x] Guild Member Remove
197 | - [x] Guild Member Update
198 | - [ ] Guild Members Chunk
199 | - [x] Guild Role Create
200 | - [x] Guild Role Update
201 | - [x] Guild Role Delete
202 | - [x] Guild Scheduled Event Create
203 | - [x] Guild Scheduled Event Update
204 | - [x] Guild Scheduled Event Delete
205 | - [x] Guild Scheduled Event User Add
206 | - [x] Guild Scheduled Event User Remove
207 | - [ ] Integration Create
208 | - [ ] Integration Update
209 | - [ ] Integration Delete
210 | - [ ] Interaction Create
211 | - [ ] Invite Create
212 | - [ ] Invite Delete
213 | - [x] Message Create
214 | - [x] Message Update
215 | - [x] Message Delete
216 | - [x] Message Delete Bulk
217 | - [x] Message Reaction Add
218 | - [x] Message Reaction Remove
219 | - [x] Message Reaction Remove All
220 | - [x] Message Reaction Remove Emoji
221 | - [ ] Presence Update
222 | - [x] Stage Instance Create
223 | - [x] Stage Instance Delete
224 | - [x] Stage Instance Update
225 | - [x] Typing Start
226 | - [ ] User Update
227 | - [ ] Voice State Update
228 | - [ ] Voice Server Update
229 | - [ ] Webhooks Update
230 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.https://www.sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp
2 | furo
--------------------------------------------------------------------------------
/docs/source/api/caching.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | .. _api-caching:
4 |
5 | Caching
6 | =======
7 |
8 | Caching is an important part of maintaining a stateful bot. In order to avoid excessive
9 | API calls, The data sent over gateway by Discord is cached by the client and can be retrieved
10 | from cache when needed rather than fetching from the API. Discord sends gateway events that
11 | allow us to easily track updates in the cached data.
12 |
13 |
14 | .. _api-caching-cache-handlers:
15 |
16 | Cache Handlers
17 | --------------
18 |
19 | Qord provides a user friendly API for caching. By default, The library provides :ref:`default cache
20 | handlers
` that suit most of the use cases. On a large scale however, you might need to maintain
21 | custom caching using some system such as Redis. To acheive this, There are some :ref:`abstract classes `
22 | provided by the library that allow you to implement custom cache handlers according to your needs.
23 |
24 | Two different cache handlers are used by the library for caching entities sent over gateway.
25 |
26 | - :class:`ClientCache` (Accessed through :attr:`Client.cache`)
27 | - :class:`GuildCache` (Accessed through :attr:`Guild.cache`)
28 |
29 | The :class:`ClientCache` handler is used for storing global entities such as guilds, users and
30 | messages etc. It can be accessed through the :attr:`Client.cache` property.
31 |
32 | On the other hand, the :class:`GuildCache` handler is used to store entities specific to a
33 | :class:`Guild`. Each :class:`Guild` has a separate cache handler for storing objects
34 | related to that guild that can be accessed by :attr:`Guild.cache` property.
35 |
36 |
37 | .. _api-caching-abstract-classes:
38 |
39 | Abstract classes
40 | ----------------
41 |
42 | Methods and attributes of each of the handlers described above are documented in detail below.
43 |
44 | ClientCache
45 | ~~~~~~~~~~~
46 |
47 | .. autoclass:: ClientCache
48 | :members:
49 |
50 | GuildCache
51 | ~~~~~~~~~~
52 |
53 | .. autoclass:: GuildCache
54 | :members:
55 |
56 | .. _api-caching-default-handlers:
57 |
58 | Default Handlers
59 | ----------------
60 |
61 | These classes are default implementation for caching provided by the library.
62 |
63 | DefaultClientCache
64 | ~~~~~~~~~~~~~~~~~~
65 |
66 | .. autoclass:: DefaultClientCache
67 | :members:
68 |
69 | DefaultGuildCache
70 | ~~~~~~~~~~~~~~~~~
71 |
72 | .. autoclass:: DefaultGuildCache
73 | :members:
74 |
--------------------------------------------------------------------------------
/docs/source/api/client.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | .. _api-client:
4 |
5 | Client
6 | ======
7 |
8 | The client class is the basic starter point of any bot created using Qord. This class
9 | exposes the main machinery used for interacting with the Discord API. All methods and
10 | properties of this class are documented below.
11 |
12 | .. autoclass:: Client
13 | :members:
14 |
--------------------------------------------------------------------------------
/docs/source/api/dataclasses.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | .. _api-dataclasses:
4 |
5 | Data classes
6 | =============
7 |
8 | These are some classes that aid in certain tasks and purposes. Unlike :ref:`api-models`,
9 | most of these classes except few **can be** initialized by users.
10 |
11 |
12 | Shard
13 | ~~~~~
14 |
15 | .. autoclass:: Shard()
16 | :members:
17 |
18 | PermissionOverwrite
19 | ~~~~~~~~~~~~~~~~~~~
20 |
21 | .. autoclass:: PermissionOverwrite
22 | :members:
23 |
24 | AllowedMentions
25 | ~~~~~~~~~~~~~~~
26 |
27 | .. autoclass:: AllowedMentions
28 | :members:
29 |
30 | File
31 | ~~~~
32 |
33 | .. autoclass:: File
34 | :members:
35 |
36 | MessageReference
37 | ~~~~~~~~~~~~~~~~
38 |
39 | .. autoclass:: MessageReference
40 | :members:
41 |
42 | Embed
43 | ~~~~~
44 |
45 | .. autoclass:: Embed
46 | :members:
47 |
48 | EmbedImage
49 | ~~~~~~~~~~
50 |
51 | .. autoclass:: EmbedImage
52 | :members:
53 |
54 | EmbedThumbnail
55 | ~~~~~~~~~~~~~~
56 |
57 | .. autoclass:: EmbedThumbnail
58 | :members:
59 |
60 | EmbedVideo
61 | ~~~~~~~~~~
62 |
63 | .. autoclass:: EmbedVideo
64 | :members:
65 |
66 | EmbedField
67 | ~~~~~~~~~~
68 |
69 | .. autoclass:: EmbedField
70 | :members:
71 |
72 | EmbedAuthor
73 | ~~~~~~~~~~~
74 |
75 | .. autoclass:: EmbedAuthor
76 | :members:
77 |
78 | EmbedFooter
79 | ~~~~~~~~~~~
80 |
81 | .. autoclass:: EmbedFooter
82 | :members:
83 |
84 | EmbedProvider
85 | ~~~~~~~~~~~~~
86 |
87 | .. autoclass:: EmbedProvider
88 | :members:
89 |
90 | Flags
91 | ~~~~~
92 |
93 | .. autoclass:: Flags()
94 | :members:
95 |
96 | Permissions
97 | ~~~~~~~~~~~
98 |
99 | .. autoclass:: Permissions()
100 | :members:
101 |
102 | Intents
103 | ~~~~~~~
104 |
105 | .. autoclass:: Intents()
106 | :members:
107 |
108 | UserFlags
109 | ~~~~~~~~~
110 |
111 | .. autoclass:: UserFlags()
112 | :members:
113 |
114 | SystemChannelFlags
115 | ~~~~~~~~~~~~~~~~~~
116 |
117 | .. autoclass:: SystemChannelFlags()
118 | :members:
119 |
120 | MessageFlags
121 | ~~~~~~~~~~~~
122 |
123 | .. autoclass:: MessageFlags()
124 | :members:
125 |
126 | ApplicationFlags
127 | ~~~~~~~~~~~~~~~~
128 |
129 | .. autoclass:: ApplicationFlags()
130 | :members:
131 |
--------------------------------------------------------------------------------
/docs/source/api/enums.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | .. _api-enums:
4 |
5 | Enumerations
6 | ============
7 |
8 | Discord API uses integers based enumerations in the API responses. The classes documented
9 | below provide a way of referencing these enumeration values easily by their name.
10 |
11 |
12 | GatewayEvent
13 | ~~~~~~~~~~~~
14 |
15 | .. autoclass:: GatewayEvent()
16 | :members:
17 |
18 | PremiumType
19 | ~~~~~~~~~~~
20 |
21 | .. autoclass:: PremiumType()
22 | :members:
23 |
24 | ImageExtension
25 | ~~~~~~~~~~~~~~
26 |
27 | .. autoclass:: ImageExtension()
28 | :members:
29 |
30 | DefaultAvatar
31 | ~~~~~~~~~~~~~
32 |
33 | .. autoclass:: DefaultAvatar()
34 | :members:
35 |
36 | VerificationLevel
37 | ~~~~~~~~~~~~~~~~~
38 |
39 | .. autoclass:: VerificationLevel()
40 | :members:
41 |
42 | NSFWLevel
43 | ~~~~~~~~~
44 |
45 | .. autoclass:: NSFWLevel()
46 | :members:
47 |
48 | NotificationLevel
49 | ~~~~~~~~~~~~~~~~~
50 |
51 | .. autoclass:: NotificationLevel()
52 | :members:
53 |
54 | ExplicitContentFilter
55 | ~~~~~~~~~~~~~~~~~~~~~
56 |
57 | .. autoclass:: ExplicitContentFilter()
58 | :members:
59 |
60 | ChannelType
61 | ~~~~~~~~~~~
62 |
63 | .. autoclass:: ChannelType()
64 | :members:
65 |
66 | VideoQualityMode
67 | ~~~~~~~~~~~~~~~~
68 |
69 | .. autoclass:: VideoQualityMode()
70 | :members:
71 |
72 | PremiumTier
73 | ~~~~~~~~~~~
74 |
75 | .. autoclass:: PremiumTier()
76 | :members:
77 |
78 | MFALevel
79 | ~~~~~~~~
80 |
81 | .. autoclass:: MFALevel()
82 | :members:
83 |
84 | MessageType
85 | ~~~~~~~~~~~
86 |
87 | .. autoclass:: MessageType()
88 | :members:
89 |
90 | ChannelPermissionType
91 | ~~~~~~~~~~~~~~~~~~~~~~~
92 |
93 | .. autoclass:: ChannelPermissionType()
94 | :members:
95 |
96 | TimestampStyle
97 | ~~~~~~~~~~~~~~
98 |
99 | .. autoclass:: TimestampStyle()
100 | :members:
101 |
102 | EventEntityType
103 | ~~~~~~~~~~~~~~~
104 |
105 | .. autoclass:: EventEntityType()
106 | :members:
107 |
108 | EventPrivacyLevel
109 | ~~~~~~~~~~~~~~~~~
110 |
111 | .. autoclass:: EventPrivacyLevel()
112 | :members:
113 |
114 | EventStatus
115 | ~~~~~~~~~~~
116 |
117 | .. autoclass:: EventStatus()
118 | :members:
119 |
120 | StagePrivacyLevel
121 | ~~~~~~~~~~~~~~~~~
122 |
123 | .. autoclass:: StagePrivacyLevel()
124 | :members:
125 |
126 | TeamMembershipState
127 | ~~~~~~~~~~~~~~~~~~~~
128 |
129 | .. autoclass:: TeamMembershipState()
130 | :members:
131 |
132 | InviteTargetType
133 | ~~~~~~~~~~~~~~~~
134 |
135 | .. autoclass:: InviteTargetType()
136 | :members:
137 |
--------------------------------------------------------------------------------
/docs/source/api/events.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | .. _api-events:
4 |
5 | Events (``qord.events``)
6 | =========================
7 |
8 | Qord exposes a rich interface via :class:`Client` class that allows you to listen
9 | to specific gateway events and perform certain operations on those events. In addition
10 | to this, This interface also allows you to create and invoke custom events.
11 |
12 |
13 | .. _api-events-registering-event-listeners:
14 |
15 | Registering event listeners
16 | ---------------------------
17 |
18 | The recommended way to register an event listener, is to use the :meth:`qord.Client.event`
19 | decorator to decorate the callback coroutine. However when subclassing :class:`Client`, consider
20 | using the :func:`qord.event` decorator. Example::
21 |
22 | @client.event(qord.GatewayEvent.MESSAGE_CREATE)
23 | async def on_message_create(event):
24 | pass
25 |
26 | # ---- or ----
27 |
28 | class MyClient(qord.Client):
29 | @qord.event(qord.GatewayEvent.MESSAGE_CREATE)
30 | async def on_message_create(event):
31 | pass
32 |
33 | All event listeners must take a single ``event`` parameter that is an instance
34 | of one of :ref:`api-events-event-objects` representing the context of event and
35 | contains data relevant to the invoked event.
36 |
37 | The :class:`qord.GatewayEvent` enumeration details the event names that are sent over gateway.
38 |
39 | .. note::
40 | Toggling certain :class:`Intents` flags will also disable or enable related
41 | gateway events to that intent for your bot. It is recommended to keep at
42 | least the :attr:`Intents.guilds` intent enabled for proper functioning of library.
43 |
44 | .. autofunction:: qord.event
45 |
46 |
47 | .. _api-events-custom-events:
48 |
49 | Custom events
50 | -------------
51 |
52 | Custom events are useful for several use cases and library allows you to create
53 | them and easily invoke them.
54 |
55 | Inherit a class from :class:`events.BaseEvent` with ``event_name`` parameter
56 | being the name of event. The instance of this class will be passed to the
57 | event listeners as the context of this event.
58 |
59 | .. warning::
60 |
61 | Make sure **not** to use an already reserved event name from :class:`GatewayEvent`
62 | or any other event names provided by the library.
63 |
64 | Example::
65 |
66 | from qord import events
67 | from dataclasses import dataclass
68 |
69 | @dataclass
70 | class ApplicationSubmit(events.BaseEvent, event_name="application_submit"):
71 | id: int
72 | name: str
73 |
74 | @client.event("application_submit")
75 | async def on_application_submit(event: ApplicationSubmit):
76 | print("Application submitted.")
77 | print(f"Name: {event.name}")
78 | print(f"ID: {event.id}")
79 |
80 | You can then invoke the event somewhere else using :meth:`Client.invoke_event` method
81 | and passing the event object::
82 |
83 | event = ApplicationSubmit(id=1, name="Jake")
84 | client.invoke_event(event)
85 |
86 | .. _api-events-base-classes:
87 |
88 | Base Classes
89 | ------------
90 |
91 | These are some base classes for the :ref:`api-events-event-objects`
92 |
93 | BaseEvent
94 | ~~~~~~~~~
95 |
96 | .. autoclass:: qord.events.BaseEvent()
97 | :members:
98 |
99 | BaseGatewayEvent
100 | ~~~~~~~~~~~~~~~~
101 |
102 | .. autoclass:: qord.events.BaseGatewayEvent()
103 | :members:
104 |
105 |
106 | .. _api-events-event-objects:
107 |
108 | Event Objects
109 | -------------
110 |
111 | The classes documented below expose the data related to a specific gateway event. The
112 | instance of these classes are passed to the event listener coroutines.
113 |
114 | GatewayDispatch
115 | ~~~~~~~~~~~~~~~
116 |
117 | .. autoclass:: qord.events.GatewayDispatch()
118 | :members:
119 |
120 | ShardReady
121 | ~~~~~~~~~~
122 |
123 | .. autoclass:: qord.events.ShardReady()
124 | :members:
125 |
126 | Ready
127 | ~~~~~
128 |
129 | .. autoclass:: qord.events.Ready()
130 | :members:
131 |
132 | Resumed
133 | ~~~~~~~
134 |
135 | .. autoclass:: qord.events.Resumed()
136 | :members:
137 |
138 | UserUpdate
139 | ~~~~~~~~~~
140 |
141 | .. autoclass:: qord.events.UserUpdate()
142 | :members:
143 |
144 | GuildAvailable
145 | ~~~~~~~~~~~~~~
146 |
147 | .. autoclass:: qord.events.GuildAvailable()
148 | :members:
149 |
150 | GuildUnavailable
151 | ~~~~~~~~~~~~~~~~
152 |
153 | .. autoclass:: qord.events.GuildUnavailable()
154 | :members:
155 |
156 | GuildJoin
157 | ~~~~~~~~~
158 |
159 | .. autoclass:: qord.events.GuildJoin()
160 | :members:
161 |
162 |
163 | GuildLeave
164 | ~~~~~~~~~~
165 |
166 | .. autoclass:: qord.events.GuildLeave()
167 | :members:
168 |
169 | GuildUpdate
170 | ~~~~~~~~~~~
171 |
172 | .. autoclass:: qord.events.GuildUpdate()
173 | :members:
174 |
175 | RoleCreate
176 | ~~~~~~~~~~
177 |
178 | .. autoclass:: qord.events.RoleCreate()
179 | :members:
180 |
181 | RoleUpdate
182 | ~~~~~~~~~~
183 |
184 | .. autoclass:: qord.events.RoleUpdate()
185 | :members:
186 |
187 | RoleDelete
188 | ~~~~~~~~~~
189 |
190 | .. autoclass:: qord.events.RoleDelete()
191 | :members:
192 |
193 | GuildMemberAdd
194 | ~~~~~~~~~~~~~~
195 |
196 | .. autoclass:: qord.events.GuildMemberAdd()
197 | :members:
198 |
199 | GuildMemberUpdate
200 | ~~~~~~~~~~~~~~~~~
201 |
202 | .. autoclass:: qord.events.GuildMemberUpdate()
203 | :members:
204 |
205 | GuildMemberRemove
206 | ~~~~~~~~~~~~~~~~~
207 |
208 | .. autoclass:: qord.events.GuildMemberRemove()
209 | :members:
210 |
211 |
212 | ChannelCreate
213 | ~~~~~~~~~~~~~
214 |
215 | .. autoclass:: qord.events.ChannelCreate()
216 | :members:
217 |
218 |
219 | ChannelUpdate
220 | ~~~~~~~~~~~~~
221 |
222 | .. autoclass:: qord.events.ChannelUpdate()
223 | :members:
224 |
225 | ChannelPinsUpdate
226 | ~~~~~~~~~~~~~~~~~
227 |
228 | .. autoclass:: qord.events.ChannelPinsUpdate()
229 | :members:
230 |
231 | ChannelDelete
232 | ~~~~~~~~~~~~~
233 |
234 | .. autoclass:: qord.events.ChannelDelete()
235 | :members:
236 |
237 | TypingStart
238 | ~~~~~~~~~~~
239 |
240 | .. autoclass:: qord.events.TypingStart()
241 | :members:
242 |
243 | EmojisUpdate
244 | ~~~~~~~~~~~~
245 |
246 | .. autoclass:: qord.events.EmojisUpdate()
247 | :members:
248 |
249 | MessageCreate
250 | ~~~~~~~~~~~~~
251 |
252 | .. autoclass:: qord.events.MessageCreate()
253 | :members:
254 |
255 |
256 | MessageUpdate
257 | ~~~~~~~~~~~~~
258 |
259 | .. autoclass:: qord.events.MessageUpdate()
260 | :members:
261 |
262 |
263 | MessageDelete
264 | ~~~~~~~~~~~~~
265 |
266 | .. autoclass:: qord.events.MessageDelete()
267 | :members:
268 |
269 |
270 | MessageBulkDelete
271 | ~~~~~~~~~~~~~~~~~~~
272 |
273 | .. autoclass:: qord.events.MessageBulkDelete()
274 | :members:
275 |
276 | ReactionAdd
277 | ~~~~~~~~~~~
278 |
279 | .. autoclass:: qord.events.ReactionAdd()
280 | :members:
281 |
282 | ReactionRemove
283 | ~~~~~~~~~~~~~~
284 |
285 | .. autoclass:: qord.events.ReactionRemove()
286 | :members:
287 |
288 | ReactionClear
289 | ~~~~~~~~~~~~~
290 |
291 | .. autoclass:: qord.events.ReactionClear()
292 | :members:
293 |
294 | ReactionClearEmoji
295 | ~~~~~~~~~~~~~~~~~~
296 |
297 | .. autoclass:: qord.events.ReactionClearEmoji()
298 | :members:
299 |
300 |
301 | ScheduledEventCreate
302 | ~~~~~~~~~~~~~~~~~~~~
303 |
304 | .. autoclass:: qord.events.ScheduledEventCreate()
305 | :members:
306 |
307 |
308 | ScheduledEventUpdate
309 | ~~~~~~~~~~~~~~~~~~~~
310 |
311 | .. autoclass:: qord.events.ScheduledEventUpdate()
312 | :members:
313 |
314 |
315 | ScheduledEventDelete
316 | ~~~~~~~~~~~~~~~~~~~~
317 |
318 | .. autoclass:: qord.events.ScheduledEventDelete()
319 | :members:
320 |
321 |
322 | ScheduledEventUserAdd
323 | ~~~~~~~~~~~~~~~~~~~~~
324 |
325 | .. autoclass:: qord.events.ScheduledEventUserAdd()
326 | :members:
327 |
328 | ScheduledEventUserRemove
329 | ~~~~~~~~~~~~~~~~~~~~~~~~
330 |
331 | .. autoclass:: qord.events.ScheduledEventUserRemove()
332 | :members:
333 |
334 |
--------------------------------------------------------------------------------
/docs/source/api/exceptions.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | Errors and Exceptions
4 | =====================
5 |
6 | These are the special exceptions raised by the library in certain scenarios. All of these
7 | exceptions inherit a common :exc:`QordException` class.
8 |
9 | QordException
10 | ~~~~~~~~~~~~~
11 |
12 | .. autoexception:: QordException()
13 |
14 | ClientSetupRequired
15 | ~~~~~~~~~~~~~~~~~~~
16 |
17 | .. autoexception:: ClientSetupRequired()
18 |
19 | HTTPException
20 | ~~~~~~~~~~~~~
21 |
22 | .. autoexception:: HTTPException()
23 |
24 | HTTPBadRequest
25 | ~~~~~~~~~~~~~~
26 |
27 | .. autoexception:: HTTPBadRequest()
28 |
29 | HTTPForbidden
30 | ~~~~~~~~~~~~~
31 |
32 | .. autoexception:: HTTPForbidden()
33 |
34 | HTTPNotFound
35 | ~~~~~~~~~~~~
36 |
37 | .. autoexception:: HTTPNotFound()
38 |
39 | HTTPServerError
40 | ~~~~~~~~~~~~~~~
41 |
42 | .. autoexception:: HTTPServerError()
43 |
44 | ShardException
45 | ~~~~~~~~~~~~~~
46 |
47 | .. autoexception:: ShardException()
48 |
49 | ShardCloseException
50 | ~~~~~~~~~~~~~~~~~~~
51 |
52 | .. autoexception:: ShardCloseException()
53 |
54 | MissingPrivilegedIntents
55 | ~~~~~~~~~~~~~~~~~~~~~~~~
56 |
57 | .. autoexception:: MissingPrivilegedIntents()
58 |
--------------------------------------------------------------------------------
/docs/source/api/index.rst:
--------------------------------------------------------------------------------
1 | API Reference
2 | =============
3 |
4 | This section documents the entire user facing API of Qord. All the technical information
5 | regarding the library is discussed here.
6 |
7 |
8 | .. toctree::
9 | :maxdepth: 1
10 | :caption: Contents:
11 |
12 | client
13 | caching
14 | models
15 | dataclasses
16 | enums
17 | exceptions
18 | events
19 | utils
20 |
--------------------------------------------------------------------------------
/docs/source/api/models.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 |
4 | .. _api-models:
5 |
6 | Discord Models
7 | ==============
8 |
9 | These classes wrap the Discord's complex data models in easy to use interfaces.
10 |
11 | It is worth noting that these classes are not meant to be initialized by users and
12 | must only be retrieved from cache or fetched from the API using relevant API methods.
13 |
14 |
15 | Base Classes
16 | -------------
17 |
18 | BaseModel
19 | ~~~~~~~~~
20 |
21 | .. autoclass:: BaseModel()
22 | :members:
23 |
24 | BaseMessageChannel
25 | ~~~~~~~~~~~~~~~~~~
26 |
27 | .. autoclass:: BaseMessageChannel()
28 | :members:
29 |
30 | Applications
31 | ------------
32 |
33 | Application
34 | ~~~~~~~~~~~
35 |
36 | .. autoclass:: Application()
37 | :members:
38 | :inherited-members:
39 |
40 | ApplicationInstallParams
41 | ~~~~~~~~~~~~~~~~~~~~~~~~
42 |
43 | .. autoclass:: ApplicationInstallParams()
44 | :members:
45 | :inherited-members:
46 |
47 | Team
48 | ~~~~
49 |
50 | .. autoclass:: Team()
51 | :members:
52 | :inherited-members:
53 |
54 | TeamMember
55 | ~~~~~~~~~~
56 |
57 | .. autoclass:: TeamMember()
58 | :members:
59 | :inherited-members:
60 |
61 | Users
62 | -----
63 |
64 | User
65 | ~~~~
66 |
67 | .. autoclass:: User()
68 | :inherited-members:
69 | :members:
70 |
71 | ClientUser
72 | ~~~~~~~~~~
73 |
74 | .. autoclass:: ClientUser()
75 | :inherited-members:
76 | :members:
77 |
78 | Guilds
79 | ------
80 |
81 | Guild
82 | ~~~~~
83 |
84 | .. autoclass:: Guild()
85 | :inherited-members:
86 | :members:
87 |
88 | GuildMember
89 | ~~~~~~~~~~~
90 |
91 | .. autoclass:: GuildMember()
92 | :inherited-members:
93 | :members:
94 |
95 | Role
96 | ~~~~
97 |
98 | .. autoclass:: Role()
99 | :inherited-members:
100 | :members:
101 |
102 | ScheduledEvent
103 | ~~~~~~~~~~~~~~
104 |
105 | .. autoclass:: ScheduledEvent()
106 | :inherited-members:
107 | :members:
108 |
109 | Channels
110 | --------
111 |
112 | GuildChannel
113 | ~~~~~~~~~~~~
114 |
115 | .. autoclass:: GuildChannel()
116 | :inherited-members:
117 | :members:
118 |
119 | CategoryChannel
120 | ~~~~~~~~~~~~~~~
121 |
122 | .. autoclass:: CategoryChannel()
123 | :inherited-members:
124 | :members:
125 |
126 | TextChannel
127 | ~~~~~~~~~~~
128 |
129 | .. autoclass:: TextChannel()
130 | :inherited-members:
131 | :members:
132 |
133 | NewsChannel
134 | ~~~~~~~~~~~
135 |
136 | .. autoclass:: NewsChannel()
137 | :inherited-members:
138 | :members:
139 |
140 | VoiceChannel
141 | ~~~~~~~~~~~~
142 |
143 | .. autoclass:: VoiceChannel()
144 | :inherited-members:
145 | :members:
146 |
147 | StageChannel
148 | ~~~~~~~~~~~~
149 |
150 | .. autoclass:: StageChannel()
151 | :inherited-members:
152 | :members:
153 |
154 | PrivateChannel
155 | ~~~~~~~~~~~~~~
156 |
157 | .. autoclass:: PrivateChannel()
158 | :inherited-members:
159 | :members:
160 |
161 | DMChannel
162 | ~~~~~~~~~
163 |
164 | .. autoclass:: DMChannel()
165 | :inherited-members:
166 | :members:
167 |
168 | ChannelPermission
169 | ~~~~~~~~~~~~~~~~~
170 |
171 | .. autoclass:: ChannelPermission()
172 | :members:
173 |
174 | StageInstance
175 | ~~~~~~~~~~~~~
176 |
177 | .. autoclass:: StageInstance()
178 | :inherited-members:
179 | :members:
180 |
181 | Messages
182 | --------
183 |
184 | Message
185 | ~~~~~~~
186 |
187 | .. autoclass:: Message()
188 | :inherited-members:
189 | :members:
190 |
191 | Attachment
192 | ~~~~~~~~~~
193 |
194 | .. autoclass:: Attachment()
195 | :inherited-members:
196 | :members:
197 |
198 | Reaction
199 | ~~~~~~~~
200 |
201 | .. autoclass:: Reaction()
202 | :members:
203 |
204 | ChannelMention
205 | ~~~~~~~~~~~~~~
206 |
207 | .. autoclass:: ChannelMention()
208 | :inherited-members:
209 | :members:
210 |
211 |
212 | Emojis
213 | ------
214 |
215 | Emoji
216 | ~~~~~
217 |
218 | .. autoclass:: Emoji()
219 | :inherited-members:
220 | :members:
221 |
222 | PartialEmoji
223 | ~~~~~~~~~~~~
224 |
225 | .. autoclass:: PartialEmoji()
226 | :members:
227 |
228 | Invites
229 | -------
230 |
231 | Invite
232 | ~~~~~~
233 |
234 | .. autoclass:: Invite()
235 | :members:
236 | :inherited-members:
237 |
238 | PartialInviteGuild
239 | ~~~~~~~~~~~~~~~~~~
240 |
241 | .. autoclass:: PartialInviteGuild()
242 | :members:
243 | :inherited-members:
244 |
245 | PartialInviteChannel
246 | ~~~~~~~~~~~~~~~~~~~~~
247 |
248 | .. autoclass:: PartialInviteChannel()
249 | :members:
250 | :inherited-members:
251 |
252 | PartialInviteApplication
253 | ~~~~~~~~~~~~~~~~~~~~~~~~
254 |
255 | .. autoclass:: PartialInviteApplication()
256 | :members:
257 | :inherited-members:
258 |
--------------------------------------------------------------------------------
/docs/source/api/utils.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 |
4 | .. _api-utils:
5 |
6 | General Utilities (``qord.utils``)
7 | ====================================
8 |
9 | The ``qord.utils`` module provides some helpers that aid in certain common tasks. These
10 | helpers are not fixed for a specific purpose but for various different purposes.
11 |
12 | .. autofunction:: qord.utils.create_timestamp
13 |
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 |
13 | import os
14 | import sys
15 | sys.path.insert(0, os.path.abspath('../../'))
16 |
17 |
18 | # -- Project information -----------------------------------------------------
19 |
20 | project = 'Qord'
21 | copyright = '2022, izxxr'
22 | author = 'izxxr'
23 |
24 |
25 | # -- General configuration ---------------------------------------------------
26 |
27 | # Add any Sphinx extension module names here, as strings. They can be
28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
29 | # ones.
30 | extensions = [
31 | "sphinx.ext.autodoc",
32 | "sphinx.ext.napoleon",
33 | ]
34 |
35 | # Add any paths that contain templates here, relative to this directory.
36 | templates_path = ['_templates']
37 |
38 | # List of patterns, relative to source directory, that match files and
39 | # directories to ignore when looking for source files.
40 | # This pattern also affects html_static_path and html_extra_path.
41 | exclude_patterns = []
42 |
43 |
44 | # -- Options for HTML output -------------------------------------------------
45 |
46 | # The theme to use for HTML and HTML Help pages. See the documentation for
47 | # a list of builtin themes.
48 | #
49 | html_theme = 'furo'
50 |
51 | # Add any paths that contain custom static files (such as style sheets) here,
52 | # relative to this directory. They are copied after the builtin static files,
53 | # so a file named "default.css" will overwrite the builtin "default.css".
54 | html_static_path = ['_static']
55 |
56 | # RST Prolog
57 | embed_restricted_field = "This field can only be returned by embeds from API responses " \
58 | "that are created by external sources. This field is not available " \
59 | "to be set by bots or webhooks. As such you should never set this " \
60 | "field manually, setting it will either have no effect on the embed " \
61 | "or you will run into unexpected issues." # type: ignore
62 |
63 | supports_comparison = "This class supports equality comparison between instances of this class " \
64 | "by the :attr:`.id` attribute." # type: ignore
65 |
66 | rst_prolog = f"""
67 | .. |embed-restricted-field| replace:: {embed_restricted_field}
68 | .. |supports-comparison| replace:: {supports_comparison}
69 | .. |discord-guild-invite| replace:: https://discord.gg/nE9cGtzayA
70 | """
71 |
72 | autodoc_type_aliases = {
73 | "MessageChannelT": "Union[TextChannel, DMChannel, VoiceChannel]",
74 | "_OverwriteValue": "Optional[bool]",
75 | }
76 |
77 | autodoc_member_order = 'bysource'
78 |
--------------------------------------------------------------------------------
/docs/source/contributing.rst:
--------------------------------------------------------------------------------
1 | .. _support:
2 |
3 | Contributing to Qord
4 | ====================
5 |
6 | The development of this library is powered by a small set of volunteers who are spending
7 | their valuable time on making the library better and keeping it up-to-date with constant
8 | changes being done in the Discord API.
9 |
10 | We'd appreciate any help by the users in making the library better. If you are facing a bug,
11 | want to suggest a new feature or contribute directly to the codebase, This page is meant for
12 | you. We also want to appreciate your interest in contributing to the library.
13 |
14 | .. _contributing-discord-server:
15 |
16 | Discord Server
17 | --------------
18 |
19 | If you are having a problem with the library and want help regarding it. We highly suggest
20 | joining the Discord server of the library as it helps us (maintainers) to stay in touch with
21 | you and discuss what the issue is.
22 |
23 | Discord server is also the only place where you can ask questions or help regarding the library
24 | and if you are facing difficulty in implementing a certain feature, You can ask it in the Discord
25 | server.
26 |
27 | `Join the Discord Server <|discord-guild-invite|>`_
28 |
29 |
30 | .. _contributing-suggesting-features-or-reporting-bugs:
31 |
32 | Suggesting features or Reporting Bugs
33 | -------------------------------------
34 |
35 | We love to hear your creative ideas about implementing a specific feature in the library. We
36 | also appreciate bug reports as it helps us keeping the library as stable as possible.
37 |
38 | In order to keep track of feature requests and bug reports, We use `GitHub issues tracker `_.
39 |
40 | When creating issues, make sure to describe your issue in detail. When suggesting a new feature,
41 | you should give a brief detail of the feature and also provide some solid reasons of how the
42 | feature may prove useful. In case of bug reports, you should provide a summary of bug alongside
43 | the steps to reproduce the bug.
44 |
45 | Contributing to codebase
46 | ------------------------
47 |
48 | If you know how to fix a certain bug or implement a specific feature, consider `opening a pull
49 | request `_ for your change.
50 |
51 | When making code changes make sure to:
52 |
53 | 1. Stay consistent with the current code style of library. We suggest formatting your code with Black formatter.
54 | 2. Write meaningful and brief commit messages. Don't worry about this one though, The commits would be taken care of when merging the pull request.
55 | 3. Try to keep the scope of changes as minimal as possible. Avoid making multiple changes in one pull request.
56 |
57 | For large and major changes, Discuss your idea first in the :ref:`contributing-discord-server` first.
58 | If a pull request is opened implementing a major change without discussion, It'd likely be rejected.
59 |
--------------------------------------------------------------------------------
/docs/source/getting_started.rst:
--------------------------------------------------------------------------------
1 | .. _getting-started:
2 |
3 | Getting Started
4 | ===============
5 |
6 | This short section describes the installation process and basic usage of the library.
7 |
8 | Installation
9 | ------------
10 |
11 | Qord is installed using Python's traditional package manager, pip::
12 |
13 | python -m pip install -U qord
14 |
15 | Qord requires **Python 3.8 or higher.** The dependencies are handled by pip automatically,
16 | See complete list of dependencies in `here `_.
17 |
18 | Usage
19 | -----
20 |
21 | To whet your appetite, Let's get a quickstart with an example of a simple "Ping-Pong" bot::
22 |
23 | import qord
24 |
25 | intents = qord.Intents.unprivileged()
26 | intents.message_content = True
27 | client = qord.Client(intents=intents)
28 |
29 | @client.event(qord.GatewayEvent.READY)
30 | async def on_ready(event):
31 | print("Bot is ready.")
32 | print(f"Shards: {client.shards_count}")
33 | print(f"User: {client.user.proper_name}")
34 | print(f"Guilds: {len(client.cache.guilds())}")
35 |
36 | @client.event(qord.GatewayEvent.MESSAGE_CREATE)
37 | async def on_message_create(event):
38 | message = event.message
39 |
40 | if message.author.bot:
41 | # Don't respond to bot messages.
42 | return
43 |
44 | if message.content == "!ping":
45 | await message.channel.send("Pong!")
46 |
47 | client.start("BOT_TOKEN")
48 |
--------------------------------------------------------------------------------
/docs/source/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/izxxr/qord-legacy/6d92751efc76b1f0bbcc350eff30369cb5a1c51a/docs/source/images/logo.png
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. Qord documentation master file, created by
2 | sphinx-quickstart on Sun Feb 6 15:07:27 2022.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to Qord's documentation!
7 | ================================
8 |
9 | Python library for Discord API based around asyncio.
10 |
11 | **Features:**
12 |
13 | - Object oriented, user friendly interface with no dirty payloads.
14 | - Easy to customise and manage.
15 | - Robust handling of HTTP ratelimits.
16 | - Supports automatic gateway sharding.
17 |
18 | .. note::
19 | Qord is currently under it's initial development (alpha) stage. During this phase, There may
20 | be breaking changes and public user-facing API should not be considered stable. There would
21 | be no efforts in keeping backward compatibility. While the library currently supports the
22 | basic functionalities required to build a bot, many essential features are yet to be
23 | implemented and for this reason, Qord isn't yet a library to choose for making full fledged
24 | bots.
25 |
26 | The complete lifetime of 0.x version is considered the development phase. More info about
27 | this `semantic versioning specification is found here. `_
28 |
29 | .. toctree::
30 | :maxdepth: 1
31 | :caption: Table of Content:
32 |
33 | api/index
34 | getting_started
35 | contributing
36 | releases
37 |
--------------------------------------------------------------------------------
/docs/source/releases.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: qord
2 |
3 | Releases
4 | ========
5 |
6 | This page details the changelog containing every notable change of every releases.
7 |
8 | .. tip::
9 | Want to stay notified when a new release is published? Join our `Discord server <|discord-guild-invite|>`_
10 | to stay in touch with all the changes in the library.
11 |
12 | .. note::
13 | The releases with "Pre-release" in title or if the version ends with an identifier
14 | indicates that the release was a pre-release.
15 |
16 |
17 | Latest
18 | ------
19 |
20 | Breaking Changes
21 | ~~~~~~~~~~~~~~~~
22 |
23 | - :class:`StageChannel` no longer inherits :class:`VoiceChannel` and is now a completely independent channel type.
24 | - :attr:`Message.channel` and other message related channel attributes can now return :class:`VoiceChannel`.
25 | - Rename :class:`Cache` to :class:`ClientCache` and :class:`DefaultCache` to :class:`DefaultClientCache` for the sake of consistency with it's guild counterpart.
26 |
27 | Additions
28 | ~~~~~~~~~
29 |
30 | - Added support for applications.
31 | - Added support for messages in :class:`VoiceChannel`.
32 | - Added :func:`qord.event` decorator for registering listeners in a subclassed :class:`Client`.
33 | - Added :meth:`Client.wait_for_event` method to allow waiting for event invocations.
34 |
35 | Bug fixes
36 | ~~~~~~~~~
37 |
38 | - Fix HTTP ratelimits state being incorrectly stored. Route's major parameters are respected now
39 | while storing ratelimit data internally.
40 | - Fix :attr:`Message.referenced_message` being unbound when message type does not meet the criteria for it.
41 |
42 | v0.4.0
43 | ------
44 |
45 | Additions
46 | ~~~~~~~~~
47 |
48 | - Added support for guild scheduled events.
49 | - Added support for stage instances.
50 | - Added following shortcut properties to :class:`Guild`:
51 | - :attr:`~Guild.afk_channel`
52 | - :attr:`~Guild.system_channel`
53 | - :attr:`~Guild.widget_channel`
54 | - :attr:`~Guild.rules_channel`
55 | - :attr:`~Guild.public_updates_channel`
56 |
57 |
58 | Fixes
59 | ~~~~~
60 |
61 | - Fix crash with :exc:`KeyError` during :attr:`~GatewayEvent.MESSAGE_UPDATE` event.
62 |
63 |
64 | v0.3.0
65 | ------
66 |
67 | Additions
68 | ~~~~~~~~~
69 |
70 | - Added support for custom guild emojis.
71 | - Added support for message reactions.
72 | - Added :attr:`Guild.me` property for retreiving bot member.
73 | - Added :attr:`created_at` property on appropriate Discord models.
74 | - Added :meth:`~BaseMessageChannel.messages` method to iterate through channels history.
75 | - Added :meth:`Guild.members` method to iterate through guild members.
76 | - Added :attr:`PrivateChannel.url`, :attr:`GuildChannel.url` and :attr:`Message.url` properties
77 | - Added :meth:`BaseMessageChannel.trigger_typing` and :meth:`BaseMessageChannel.typing` for working with typing indicators.
78 | - Added :meth:`Message.crosspost` for crossposting messages in news channels.
79 |
80 | Changes
81 | ~~~~~~~~
82 |
83 | - :class:`ChannelPermission` now supports equality comparisons.
84 | - All models now shows useful information in :func:`repr()`
85 |
86 | Bug fixes
87 | ~~~~~~~~~
88 |
89 | - Fixed :attr:`Embed.video` property running into infinite loop.
90 | - Fixed disparity between ``embed`` and ``embeds`` parameters in :meth:`~BaseMessageChannel.send`
91 | - Fixed typing of :attr:`Message.channel` not including DM channels.
92 |
93 | v0.3.0a2 (Pre-release)
94 | ----------------------
95 |
96 | Additions
97 | ~~~~~~~~~
98 |
99 | - Added handling of HTTP ratelimits.
100 | - Added support for channel permission overwrites.
101 | - Added equality comparison support for various Discord models.
102 | - Added module ``qord.utils``, see :ref:`reference-utilities` for more info.
103 | - Added :attr:`Message.referenced_message` attribute.
104 | - Added :func:`qord.utils.create_timestamp` helper function.
105 | - Added :meth:`Embed.total_length` and :meth:`builtins.len()` support on :class:`Embed`
106 | - Added ``channel`` keyword argument in :attr:`GuildMember.edit`
107 |
108 | Improvements/Misc.
109 | ~~~~~~~~~~~~~~~~~~
110 |
111 | - :attr:`User.mention` string no longer includes ``!``, This is done in order to comply with the recent change done to Discord client. For more information, see `this issue `_
112 | - :attr:`DefaultClientCache.private_channels` cache is now bound to limit of 256 channels.
113 | - :class:`File` constructor no longer raises :exc:`RuntimeError` on failing to resolve file name and now fallbacks to ``untitled``
114 |
115 | Fixes
116 | ~~~~~
117 |
118 | - Fixed cache not cleaning up on client closure.
119 | - Fixed typing issues across the library.
120 | - Passing ``None`` is not supported in various places especially ``x_url()`` methods.
121 | - ``None`` is now allowed in ``reason`` parameters in REST methods.
122 | - Various methods of cache handlers now return :class:`typing.List` rather than the :attr:`typing.Sequence`
123 | - Other minor improvements and fixes.
124 | - Fixed :meth:`GuildCache.roles` returning empty list for HTTP retrieved guilds.
125 |
126 | v0.3.0a1 (Pre-release)
127 | ----------------------
128 |
129 | Breaking Changes
130 | ~~~~~~~~~~~~~~~~~
131 |
132 | - Event system restructure
133 |
134 | - Custom events are now created using BaseEvent
135 | - :meth:`Client.invoke_event()` now takes single BaseEvent instance.
136 | - BaseEvent is no longer a protocol, all custom events must inherit it.
137 | - New protocol class BaseGatewayEvent has been added for gateway related events.
138 | - MessagesSupport was renamed to BaseMessageChannel for consistency.
139 |
140 | Additions
141 | ~~~~~~~~~
142 |
143 | - Added :class:`MessageType` enumeration.
144 | - Added support for message embeds.
145 | - Added support for message allowed mentions.
146 | - Added support for message flags.
147 | - Added support for message references.
148 | - Added :meth:`Message.edit()` and :meth:`Message.delete()` methods.
149 | - Added :meth:`Shard.disconnect()` and :meth:`~Shard.reconnect()` methods.
150 | - Added :meth:`PrivateChannel.close()` method.
151 | - Added :attr:`Intents.message_content` privileged intent flag.
152 | - Added support for embeds, files and other options in :meth:`~BaseMessageChannel.send()`
153 |
154 | Fixes
155 | ~~~~~
156 |
157 | - Fix various crashes on startup.
158 | - Fix minor bugs.
159 |
160 | Improvements
161 | ~~~~~~~~~~~~
162 |
163 | - Startup time has minor improvements.
164 | - Library is now completely typed, there may be breaking type changes.
165 |
166 | v0.2.0
167 | ------
168 |
169 | Additions
170 | ~~~~~~~~~
171 |
172 | - Added support for guild roles.
173 | - Added support for guild members.
174 | - Added support for permissions.
175 | - Added support for guild channels.
176 | - Added support for messages.
177 | - Added :attr:`User.proper_name` property.
178 | - Added :attr:`User.mention` property.
179 |
180 | Improvements
181 | ~~~~~~~~~~~~
182 |
183 | - :attr:`Guild.cache` is no longer optional.
184 | - Startup time has been significantly improved.
185 |
186 | Fixes
187 | ~~~~~
188 |
189 | - Fixed :meth:`GuildCache.clear()` not getting called upon guild evictions.
190 | - Fixed extension parameter incorrectly behaving for various URL methods.
191 | - Fixed shards closing on receiving unhandleable OP code.
192 | - Fixed client not properly handling graceful closure in some cases.
193 | - Fixed :meth:`Client.launch()` raising RuntimeError upon relaunching the client after closing.
194 |
195 |
196 | v0.2.0a1 (Pre-release)
197 | ----------------------
198 |
199 | Additions
200 | ~~~~~~~~~
201 |
202 | Add support for users.
203 | Add support for guilds.
204 | Add support for caching.
205 |
206 | Improvements
207 | ~~~~~~~~~~~~
208 |
209 | - Event listeners tasks now have proper exception handling.
210 | - Various performance improvements.
211 |
212 | Fixes
213 | ~~~~~
214 |
215 | - Fixed wrong instance check on manually passing a client session.
216 |
217 | v0.1.0
218 | ------
219 |
220 | - Initial release.
221 |
--------------------------------------------------------------------------------
/examples/basic.py:
--------------------------------------------------------------------------------
1 | """
2 | Basic Usage
3 | ~~~~~~~~~~~
4 |
5 | This example showcases the basic usage of the library by implementing a simple
6 | ping-pong bot that responds to messages.
7 |
8 | This example considers that you already have a bot user configured with message
9 | content privileged intent enabled. If not, consider doing that first.
10 |
11 | NOTE: Typehints are not required, they are only specified for convenience and may be omitted.
12 | """
13 |
14 | import qord
15 |
16 | # Intents.unprivileged() creates Intents instance with all unprivileged intents enabled
17 | # Intents in short words, allow you to subscribe or unsubscribe to certain gateway events
18 | # Filtering unnecessary intents is out of scope of this simple example.
19 | intents = qord.Intents.unprivileged()
20 |
21 | # We need message content intent enabled in order to respond to
22 | # message content. It is a privileged intent and requires explicit
23 | # enabling from Developers portal application page.
24 | #
25 | # WARNING: If not explicitly enabled, An error will be raised upon starting
26 | # the client.
27 | intents.message_content = True
28 |
29 | # Instansiating our Client instance
30 | client = qord.Client(intents=intents)
31 |
32 | # event() decorator registers an event listener for the given event. In this case, READY.
33 | # READY event is fired whenever client connects and becomes ready.
34 | # We are registering this event listener as a notification of client
35 | # becoming ready by printing to console.
36 | @client.event(qord.GatewayEvent.READY)
37 | async def on_ready(event: qord.events.Ready):
38 | print(f"Connected as {client.user.proper_name}")
39 |
40 | # MESSAGE_CREATE event is fired whenever we have a new message
41 | # sent by someone in a channel. This is for our commands handling.
42 | @client.event(qord.GatewayEvent.MESSAGE_CREATE)
43 | async def on_message_create(event: qord.events.MessageCreate):
44 | message = event.message
45 |
46 | if message.author.bot or not message.content:
47 | # We don't want to handle messages that are sent
48 | # by a bot or don't have any content, so return
49 | # This clause already handles the case of responding
50 | # to our own message and causing an infinite loop, if
51 | # you remove this if statement consider adding one to
52 | # ignore messages from ourselves and potentially running
53 | # into an infinite loop.
54 | return
55 |
56 | # Commands handling
57 | if message.content == "?ping":
58 | await message.channel.send(f"{message.author.proper_name} used `?ping`: Pong :ping_pong:")
59 |
60 | # Start our client
61 | # This method blocks until the client is not stopped.
62 | # For that reason, All events listeners and other pre-processing must be done
63 | # before this method's call.
64 | client.start("BOT_TOKEN_HERE")
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools>=42"]
3 | build-backend = "setuptools.build_meta"
4 |
--------------------------------------------------------------------------------
/qord/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Qord
3 | ====
4 |
5 | A high level library for building Discord bots.
6 | """
7 |
8 | from qord import events, utils
9 | from qord.bases import *
10 | from qord.decorators import *
11 | from qord.enums import *
12 | from qord.exceptions import *
13 | from qord.project_info import *
14 | from qord.core.cache import *
15 | from qord.core.cache_impl import *
16 | from qord.core.client import *
17 | from qord.core.shard import *
18 | from qord.flags.base import *
19 | from qord.flags.intents import *
20 | from qord.flags.permissions import *
21 | from qord.flags.users import *
22 | from qord.flags.system_channel import *
23 | from qord.flags.messages import *
24 | from qord.flags.applications import *
25 | from qord.models.base import *
26 | from qord.models.channels import *
27 | from qord.models.users import *
28 | from qord.models.guilds import *
29 | from qord.models.guild_members import *
30 | from qord.models.roles import *
31 | from qord.models.messages import *
32 | from qord.models.emojis import *
33 | from qord.models.applications import *
34 | from qord.models.scheduled_events import *
35 | from qord.models.stage_instances import *
36 | from qord.models.invites import *
37 | from qord.dataclasses.allowed_mentions import *
38 | from qord.dataclasses.embeds import *
39 | from qord.dataclasses.files import *
40 | from qord.dataclasses.message_reference import *
41 | from qord.dataclasses.permission_overwrite import *
42 |
--------------------------------------------------------------------------------
/qord/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/izxxr/qord-legacy/6d92751efc76b1f0bbcc350eff30369cb5a1c51a/qord/core/__init__.py
--------------------------------------------------------------------------------
/qord/core/ratelimits.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import asyncio
26 | import typing
27 |
28 | __all__ = (
29 | "REST_BASE_URL",
30 | "Route",
31 | "RatelimitHandler",
32 | )
33 |
34 | REST_BASE_URL = "https://discord.com/api/v10"
35 |
36 |
37 | class Route:
38 | __slots__ = ("method", "path", "requires_auth", "params")
39 |
40 | def __init__(self,
41 | method: typing.Literal["GET", "POST", "PUT", "DELETE", "PATCH"],
42 | path: str,
43 | *,
44 | requires_auth: bool = True,
45 | **params: typing.Any,
46 | ) -> None:
47 |
48 | self.method = method
49 | self.path = path
50 | self.requires_auth = requires_auth
51 | self.params = params
52 |
53 | @property
54 | def url(self) -> str:
55 | return REST_BASE_URL + self.path.format_map(self.params)
56 |
57 | @property
58 | def ratelimit_path(self) -> str:
59 | params = self.params
60 | guild_id = params.get("guild_id")
61 | channel_id = params.get("channel_id")
62 | return f"{self.method}-{self.path}-{guild_id}:{channel_id}"
63 |
64 | def __repr__(self) -> str:
65 | return f"{self.method} {self.url}"
66 |
67 |
68 | class RatelimitHandler:
69 | def __init__(self) -> None:
70 | # Lock for tracking global ratelimit
71 | self.global_ratelimit_cleared = asyncio.Event()
72 | self.global_ratelimit_cleared.set()
73 |
74 | # { bucket_hash | ratelimit_path : asyncio.Lock }
75 | self.locks: typing.Dict[str, asyncio.Lock] = {}
76 |
77 | # { ratelimit_path : bucket_hash }
78 | self.buckets: typing.Dict[str, str] = {}
79 |
80 | def clear(self) -> None:
81 | """Clears internal ratelimit data including locks and bucket hashes."""
82 | self.locks.clear()
83 | self.buckets.clear()
84 |
85 | def set_global(self) -> None:
86 | """Sets the global ratelimit, preventing any HTTP requests."""
87 | self.global_ratelimit_cleared.clear()
88 |
89 | def reset_global(self) -> None:
90 | """Resets the global ratelimit, awakening the waiter coroutines."""
91 | self.global_ratelimit_cleared.set()
92 |
93 | async def wait_until_global_reset(self) -> None:
94 | """Blocks until global ratelimit is cleared."""
95 | await self.global_ratelimit_cleared.wait()
96 |
97 | def get_lock(self, path: str) -> asyncio.Lock:
98 | """Gets the asyncio.Lock instance for given route's path."""
99 |
100 | # Firstly, try to retrieve the bucket hash for this path.
101 | key = self.buckets.get(path)
102 |
103 | if key is None:
104 | # Bucket hash not found, As a workaround, we will be falling
105 | # back to storing lock with the route's path.
106 | key = path
107 |
108 | try:
109 | return self.locks[key]
110 | except KeyError:
111 | self.locks[key] = lock = asyncio.Lock()
112 | return lock
113 |
114 | def set_bucket(self, path: str, bucket: str) -> None:
115 | """Stores the bucket hash for the given route's path."""
116 |
117 | # If we have a "fallback" lock stored in the locks mapping with
118 | # the route's path, We want to store that lock with the bucket hash
119 | # as key and remove the route's path from the mapping.
120 | try:
121 | lock = self.locks.pop(path)
122 | except KeyError:
123 | pass
124 | else:
125 | self.locks[bucket] = lock
126 |
127 | self.buckets[path] = bucket
128 |
--------------------------------------------------------------------------------
/qord/dataclasses/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/izxxr/qord-legacy/6d92751efc76b1f0bbcc350eff30369cb5a1c51a/qord/dataclasses/__init__.py
--------------------------------------------------------------------------------
/qord/dataclasses/allowed_mentions.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import typing
26 |
27 | __all__ = (
28 | "AllowedMentions",
29 | )
30 |
31 | class AllowedMentions:
32 | """Represents the allowed mentions of a message.
33 |
34 | Allowed mentions are used to control the behaviour of mentions done
35 | in messages that are sent by the bot. You can toggle the mentions
36 | that should be parsed in the message content.
37 |
38 | Parameters
39 | ----------
40 | users: :class:`builtins.bool`
41 | Whether to enable users mentions in the messages.
42 | roles: :class:`builtins.bool`
43 | Whether to enable roles mentions in the messages.
44 | everyone: :class:`builtins.bool`
45 | Whether to enable mentions for @everyone/@here in messages.
46 | replied_user: :class:`builtins.bool`
47 | Whether to mention the author of replied message in messages
48 | that contain a reply.
49 | mentioned_roles: Sequence[:class:`builtins.int`]
50 | The list of role IDs to mention in the messages. Can contain maximum
51 | of 100 role IDs. Duplicate IDs will be removed.
52 | mentioned_users: Sequence[:class:`builtins.int`]
53 | The list of user IDs to mention in the messages. Can contain maximum
54 | of 100 user IDs. Duplicate IDs will be removed.
55 | """
56 |
57 | def __init__(
58 | self,
59 | *,
60 | users: bool = False,
61 | roles: bool = False,
62 | everyone: bool = False,
63 | replied_user: bool = False,
64 | mentioned_roles: typing.Optional[typing.Sequence[int]] = None,
65 | mentioned_users: typing.Optional[typing.Sequence[int]] = None,
66 | ) -> None:
67 |
68 | self._mentioned_roles = set(mentioned_roles) if mentioned_roles is not None else set()
69 | self._mentioned_users = set(mentioned_users) if mentioned_users is not None else set()
70 |
71 | if len(self._mentioned_roles) > 100 or len(self._mentioned_users) > 100:
72 | raise ValueError("mentioned_roles and mentioned_users length cannot be greater then 100.")
73 |
74 | self.users = users
75 | self.roles = roles
76 | self.everyone = everyone
77 | self.replied_user = replied_user
78 |
79 | @property
80 | def mentioned_roles(self) -> typing.Set[int]:
81 | """The roles that are allowed to be mentioned.
82 |
83 | Returns
84 | -------
85 | typing.Set[:class:`builtins.int`]
86 | """
87 | return self._mentioned_roles.copy()
88 |
89 | def add_role(self, role_id: int) -> None:
90 | """Adds a role ID to the set of mentioned roles.
91 |
92 | Parameters
93 | ----------
94 | role_id: :class:`builtins.int`
95 | The ID of role to add.
96 |
97 | Raises
98 | ------
99 | ValueError
100 | Roles limit has reached.
101 | """
102 | if len(self._mentioned_roles) == 100:
103 | raise ValueError("Role mentions cannot contain more than 100 roles.")
104 |
105 | self._mentioned_roles.add(role_id)
106 |
107 |
108 | def remove_role(self, role_id: int) -> None:
109 | """Removes a role ID from the set of mentioned roles.
110 |
111 | If the role ID does not exist, No error is raised.
112 |
113 | Parameters
114 | ----------
115 | role_id: :class:`builtins.int`
116 | The ID of role to remove.
117 | """
118 | try:
119 | self._mentioned_roles.remove(role_id)
120 | except KeyError:
121 | return
122 |
123 | @property
124 | def mentioned_users(self) -> typing.Set[int]:
125 | """The users that are allowed to be mentioned.
126 |
127 | Returns
128 | -------
129 | typing.Set[:class:`builtins.int`]
130 | """
131 | return self._mentioned_roles.copy()
132 |
133 | def add_user(self, user_id: int) -> None:
134 | """Adds a user ID to the set of mentioned users.
135 |
136 | Parameters
137 | ----------
138 | user_id: :class:`builtins.int`
139 | The ID of user to add.
140 |
141 | Raises
142 | ------
143 | ValueError
144 | Users limit has reached.
145 | """
146 | if len(self._mentioned_users) == 100:
147 | raise ValueError("User mentions cannot contain more than 100 users.")
148 |
149 | self._mentioned_users.add(user_id)
150 |
151 | def remove_user(self, user_id: int) -> None:
152 | """Removes a user ID from the set of mentioned users.
153 |
154 | If the user ID does not exist, No error is raised.
155 |
156 | Parameters
157 | ----------
158 | user_id: :class:`builtins.int`
159 | The ID of user to remove.
160 | """
161 | try:
162 | self._mentioned_users.remove(user_id)
163 | except KeyError:
164 | return
165 |
166 | @classmethod
167 | def all(cls) -> AllowedMentions:
168 | """Creates a :class:`AllowedMentions` with all options enabled."""
169 | return cls(
170 | users=True,
171 | roles=True,
172 | everyone=True,
173 | replied_user=True,
174 | )
175 |
176 | def to_dict(self) -> typing.Dict[str, typing.Any]:
177 | ret = {
178 | "replied_user": self.replied_user,
179 | "roles": list(self._mentioned_roles),
180 | "users": list(self._mentioned_users),
181 | }
182 |
183 | parse = []
184 |
185 | if self.users:
186 | parse.append("users")
187 | # When user mentions are parsed, passing explicit user IDs
188 | # will cause validation error so we will remove user IDs
189 | ret.pop("users")
190 | if self.roles:
191 | parse.append("roles")
192 | # Same case as above applies here.
193 | ret.pop("roles")
194 | if self.everyone:
195 | parse.append("everyone")
196 |
197 | ret["parse"] = parse
198 | return ret
199 |
--------------------------------------------------------------------------------
/qord/dataclasses/files.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.internal.undefined import UNDEFINED
26 |
27 | import typing
28 | import os
29 |
30 | if typing.TYPE_CHECKING:
31 | from io import BufferedReader
32 |
33 |
34 | __all__ = (
35 | "File",
36 | )
37 |
38 |
39 | class File:
40 | """Represents a file that is sent in messages.
41 |
42 | Example usage with :meth:`~BaseMessageChannel.send` method::
43 |
44 | file = qord.File("path/to/file.png")
45 | await channel.send(file=file)
46 |
47 | Parameters
48 | ----------
49 | content: Union[:class:`builtins.str`, :class:`builtins.bytes`, :class:`io.BufferedReader`]
50 | The content of files. If a string is being passed, It would be considered
51 | the file path and would be opened and red in "read binary" mode.
52 | name: :class:`builtins.str`
53 | The name of file. The name would be retrieved from given file path or buffer
54 | object if possible and would fallback to "untitled" if couldn't be resolved.
55 | spoiler: :class:`builtins.bool`
56 | Whether the file should be marked as spoiler when sent.
57 | description: :class:`builtins.str`
58 | The description of attachment.
59 |
60 | Attributes
61 | ----------
62 | content: :class:`builtins.bytes`
63 | The file contents.
64 | """
65 |
66 | if typing.TYPE_CHECKING:
67 | content: bytes
68 | name: str
69 | spoiler: bool
70 | description: typing.Optional[str]
71 |
72 | def __init__(
73 | self,
74 | content: typing.Union[str, bytes, BufferedReader],
75 | /,
76 | *,
77 | name: typing.Optional[str] = None,
78 | description: typing.Optional[str] = None,
79 | spoiler: bool = False,
80 | ) -> None:
81 |
82 | if isinstance(content, str):
83 | with open(content, "rb") as f:
84 | self.content = f.read()
85 | if name is None:
86 | name = os.path.basename(content)
87 | elif isinstance(content, bytes):
88 | self.content = content
89 | elif isinstance(content, BufferedReader):
90 | if not content.readable():
91 | raise RuntimeError("content is not readable.")
92 | self.content = content.read()
93 | if name is None:
94 | name = content.name
95 |
96 | if name is None:
97 | name = "untitled"
98 |
99 | self.name = name
100 | self.description = description
101 | self.spoiler = spoiler or name.startswith("SPOILER_")
102 |
103 | @property
104 | def proper_name(self) -> str:
105 | """Returns the proper name of file with required prefixes attached if any."""
106 |
107 | if self.spoiler and not self.name.startswith("SPOILER_"):
108 | return f"SPOILER_{self.name}"
109 |
110 | return self.name
111 |
--------------------------------------------------------------------------------
/qord/dataclasses/message_reference.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.internal.helpers import get_optional_snowflake
26 | import typing
27 |
28 | if typing.TYPE_CHECKING:
29 | from qord.models.messages import Message
30 |
31 |
32 | __all__ = (
33 | "MessageReference",
34 | )
35 |
36 | class MessageReference:
37 | """Represents a reference to another message in a :class:`Message`.
38 |
39 | This class also allows you to create custom message references for replying
40 | to messages via :meth:`~BaseMessageChannel.send` method.
41 |
42 | .. note::
43 | If you have the :class:`Message` that you are replying to, consider using the
44 | :meth:`~Message.reply` method for more user friendly API interface.
45 |
46 | .. tip::
47 | For creating message replies, Only ``message_id`` parameter is required however
48 | ``channel_id`` and ``guild_id`` would be validated when supplied.
49 |
50 | From API responses, This class is present on :attr:`Message.message_reference`
51 | attribute indicating a reference to another message. It is sent when the :class:`Message`
52 | has the following type/flag:
53 |
54 | - :class:`MessageFlags.is_crosspost`
55 | - :class:`MessageType.REPLY`
56 | - :class:`MessageType.CHANNEL_FOLLOW_ADD`
57 | - :class:`MessageType.CHANNEL_PIN_ADD`
58 | - :class:`MessageType.THREAD_STARTER_MESSAGE`
59 |
60 | Parameters
61 | ----------
62 | message_id: :class:`builtins.int`
63 | The ID of message being replied.
64 | channel_id: :class:`builtins.int`
65 | The ID of channel that the referenced message belongs to.
66 | guild_id: :class:`builtins.int`
67 | The ID of guild that the referenced message belongs to, if any.
68 | fail_if_not_exists: :class:`builtins.bool`
69 | Whether the API should throw :class:`HTTPException` if the message
70 | being referenced does not exist. Defaults to ``True``.
71 |
72 | Attributes
73 | ----------
74 | message_id: Optional[:class:`builtins.int`]
75 | The ID of message that is being referenced.
76 |
77 | For message of type :attr:`~MessageType.CHANNEL_FOLLOW_ADD`, This is
78 | ``None``.
79 | channel_id: Optional[:class:`builtins.int`]
80 | The ID of channel that the reference belongs to.
81 | This is always present when getting this class from an API
82 | response and is optional when instansiating the class manually.
83 | guild_id: Optional[:class:`builtins.int`]
84 | The ID of guild that the reference belongs to, if any.
85 | """
86 |
87 | if typing.TYPE_CHECKING:
88 | message_id: typing.Optional[int]
89 | channel_id: typing.Optional[int]
90 | guild_id: typing.Optional[int]
91 |
92 | def __init__(
93 | self,
94 | message_id: int,
95 | channel_id: typing.Optional[int] = None,
96 | guild_id: typing.Optional[int] = None,
97 | *,
98 | fail_if_not_exists: bool = True,
99 | ) -> None:
100 |
101 | self.message_id = message_id
102 | self.channel_id = channel_id
103 | self.guild_id = guild_id
104 | self.fail_if_not_exists = fail_if_not_exists
105 |
106 | def to_dict(self) -> typing.Dict[str, typing.Any]:
107 | ret = {"message_id": self.message_id, "fail_if_not_exists": self.fail_if_not_exists}
108 |
109 | if self.channel_id is not None:
110 | ret["channel_id"] = self.channel_id
111 |
112 | elif self.guild_id is not None:
113 | ret["guild_id"] = self.guild_id
114 |
115 | return ret
116 |
117 | @classmethod
118 | def from_dict(cls, data: typing.Dict[str, typing.Any]) -> MessageReference:
119 | # For API responses, The message_id key is optional while
120 | # it is annotated as `int` in constructor to aid user facing API.
121 | return cls(
122 | message_id=get_optional_snowflake(data, "message_id"), # type: ignore # See above
123 | channel_id=int(data["channel_id"]),
124 | guild_id=get_optional_snowflake(data, "guild_id"),
125 | )
126 |
127 | @classmethod
128 | def from_message(cls, message: Message, *, fail_if_not_exists: bool = True) -> MessageReference:
129 | """Creates a message reference from a :class:`Message`.
130 |
131 | .. tip::
132 | For creating message replies, Only ``message_id`` parameter is required however
133 | ``channel_id`` and ``guild_id`` would be validated when supplied.
134 |
135 | Parameters
136 | ----------
137 | message: :class:`Message`
138 | The message to create reference for.
139 | fail_if_not_exists: :class:`builtins.bool`
140 | Whether the API should throw :class:`HTTPException` when sending
141 | message with this reference if the message being referenced does
142 | not exist. Defaults to ``True``.
143 |
144 | Returns
145 | -------
146 | :class:`MessageReference`
147 | The created reference for given message.
148 | """
149 | return cls(
150 | message_id=message.id,
151 | channel_id=message.channel_id,
152 | guild_id=message.guild_id,
153 | fail_if_not_exists=fail_if_not_exists,
154 | )
155 |
156 |
--------------------------------------------------------------------------------
/qord/dataclasses/permission_overwrite.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.permissions import Permissions
26 | import typing
27 |
28 | __all__ = (
29 | "PermissionOverwrite",
30 | )
31 |
32 |
33 | _OverwriteValue = typing.Optional[bool]
34 |
35 |
36 | class PermissionOverwrite:
37 | """A class representing the permissions overwrite on a guild channel.
38 |
39 | This class allows you to create permission overwrites that you can
40 | apply on guild channels.
41 |
42 | While initializing, this class takes the same keyword parameters as
43 | :class:`Permissions` i.e permissions. The permissions have their default
44 | value set to ``None`` indicating that no override is configured for the
45 | permission. The values of ``True`` and ``False`` explicitly indicates the
46 | allow and deny of the permission, respectively.
47 |
48 | This class supports equality operation with other :class:`PermissionOverwrite`
49 | instances to check if both have same overrides.
50 | """
51 | if typing.TYPE_CHECKING:
52 | create_instant_invite: _OverwriteValue
53 | kick_members: _OverwriteValue
54 | ban_members: _OverwriteValue
55 | administrator: _OverwriteValue
56 | manage_channels: _OverwriteValue
57 | manage_guild: _OverwriteValue
58 | add_reactions: _OverwriteValue
59 | view_audit_log: _OverwriteValue
60 | priority_speaker: _OverwriteValue
61 | stream: _OverwriteValue
62 | view_channel: _OverwriteValue
63 | send_messages: _OverwriteValue
64 | send_tts_messages: _OverwriteValue
65 | manage_messages: _OverwriteValue
66 | embed_links: _OverwriteValue
67 | attach_files: _OverwriteValue
68 | read_message_history: _OverwriteValue
69 | mention_everyone: _OverwriteValue
70 | use_external_emojis: _OverwriteValue
71 | view_guild_insights: _OverwriteValue
72 | connect: _OverwriteValue
73 | speak: _OverwriteValue
74 | mute_members: _OverwriteValue
75 | deafen_members: _OverwriteValue
76 | move_members: _OverwriteValue
77 | use_vad: _OverwriteValue
78 | change_nickname: _OverwriteValue
79 | manage_nicknames: _OverwriteValue
80 | manage_roles: _OverwriteValue
81 | manage_permissions: _OverwriteValue
82 | manage_webhooks: _OverwriteValue
83 | manage_emojis_and_stickers: _OverwriteValue
84 | use_application_commands: _OverwriteValue
85 | request_to_speak: _OverwriteValue
86 | manage_events: _OverwriteValue
87 | manage_threads: _OverwriteValue
88 | create_public_threads: _OverwriteValue
89 | create_private_threads: _OverwriteValue
90 | use_external_stickers: _OverwriteValue
91 | send_messages_in_threads: _OverwriteValue
92 | start_embedded_activities: _OverwriteValue
93 | moderate_members: _OverwriteValue
94 |
95 | def __init__(self, **permissions: _OverwriteValue) -> None:
96 | invalid = set(permissions).difference(Permissions.__name_value_map__)
97 |
98 | if invalid:
99 | raise TypeError(f"Invalid parameters for PermissionOverwrite(): {', '.join(invalid)}")
100 |
101 | self._overrides: typing.Dict[str, _OverwriteValue] = {}
102 |
103 | for permission, value in permissions.items():
104 | if value is None:
105 | continue
106 | elif value is True:
107 | self._overrides[permission] = value
108 | elif value is False:
109 | self._overrides[permission] = value
110 | else:
111 | raise TypeError(f"The value for parameter {permission!r} must be a bool or None.")
112 |
113 | def __eq__(self, other: typing.Any) -> bool:
114 | return isinstance(other, PermissionOverwrite) and other._overrides == self._overrides
115 |
116 | def __repr__(self) -> str:
117 | # _overrides mapping only includes the permissions that are explicitly
118 | # overriden by the overwrite.
119 | overrides = self._overrides
120 | return f"PermissionOverwrite({', '.join(f'{k}={v}' for k, v in overrides.items())})"
121 |
122 | def permissions(self) -> typing.Tuple[Permissions, Permissions]:
123 | """Returns the (allow, deny) tuple for the overwrite.
124 |
125 | The first element of the tuple is :class:`Permissions` instance
126 | with all permissions set to ``True`` that are explicitly allowed
127 | by this overwrite. The second element is :class:`Permissions` with
128 | all permissions set to ``True`` that are explicitly denied in the
129 | overwrite.
130 |
131 | Returns
132 | -------
133 | Tuple[:class:`Permissions`, :class:`Permissions`]
134 | """
135 |
136 | allow = Permissions()
137 | deny = Permissions()
138 |
139 | for permission, override in self._overrides.items():
140 | if override is True:
141 | allow._apply(permission, True)
142 | elif override is False:
143 | deny._apply(permission, True)
144 |
145 | return allow, deny
146 |
147 | @classmethod
148 | def from_permissions(cls: typing.Type[PermissionOverwrite], allow: Permissions, deny: Permissions) -> PermissionOverwrite:
149 | """Creates a :class:`PermissionOverwrite` with the given pair of permissions.
150 |
151 | Parameters
152 | ----------
153 | allow: :class:`Permissions`
154 | The permissions with all permissions set to ``True`` that are
155 | explicitly allowed in the overwrite.
156 | deny: :class:`Permissions`
157 | The permissions with all permissions set to ``True`` that are
158 | explicitly denied in the overwrite.
159 |
160 | Returns
161 | -------
162 | :class:`PermissionOverwrite`
163 | """
164 |
165 | overwrite = cls()
166 | overrides = overwrite._overrides
167 |
168 | # TODO: Is there a faster alternative to this?
169 |
170 | for permission in Permissions.__name_value_map__:
171 | if allow._has(permission):
172 | overrides[permission] = True
173 | elif deny._has(permission):
174 | overrides[permission] = False
175 |
176 | return overwrite
177 |
178 | # Setting default values on PermissionOverwrite object
179 | for permission in Permissions.__name_value_map__:
180 | # Since 'permission' value can change during this for loop, we have to
181 | # pass it in fget and fset as a default parameter to have the correct
182 | # value in getter and setter.
183 | def fget(self, permission=permission):
184 | return self._overrides.get(permission)
185 |
186 | def fset(self, value, permission=permission):
187 | if value is not None and not isinstance(value, bool):
188 | raise TypeError(f"The value for {permission!r} must be a bool or None.")
189 |
190 | if value is None:
191 | self._overrides.pop(permission, None)
192 | else:
193 | self._overrides[permission] = value
194 |
195 | prop = property(
196 | fget=fget,
197 | fset=fset,
198 | doc=f"Overwrite value for :attr:`~Permissions.{permission}` permission."
199 | )
200 | setattr(PermissionOverwrite, permission, prop)
201 |
--------------------------------------------------------------------------------
/qord/decorators.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 |
26 | def event(event_name: str):
27 | """A decorator for registering event listeners in a :class:`Client`.
28 |
29 | This decorator is exactly same in behaviour as :meth:`Client.event` but
30 | is meant to be used when registering event listeners in a subclassed
31 | :class:`Client`.
32 |
33 | Parameters
34 | ----------
35 | event_name: :class:`builtins.str`
36 | The name of event to register.
37 | """
38 | def wrap(func):
39 | func.__listener_event__ = event_name
40 | return func
41 |
42 | return wrap
43 |
--------------------------------------------------------------------------------
/qord/events/__init__.py:
--------------------------------------------------------------------------------
1 | r"""
2 | qord.events
3 | ~~~~~~~~~~~
4 |
5 | Data classes that detail events.
6 | """
7 |
8 | from qord.events.base import *
9 | from qord.events.channels import *
10 | from qord.events.gateway import *
11 | from qord.events.guild_members import *
12 | from qord.events.guilds import *
13 | from qord.events.roles import *
14 | from qord.events.messages import *
15 | from qord.events.users import *
16 | from qord.events.emojis import *
17 | from qord.events.reactions import *
18 | from qord.events.scheduled_events import *
19 | from qord.events.stage_instances import *
20 | from qord.events.invites import *
21 |
--------------------------------------------------------------------------------
/qord/events/base.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import typing
26 |
27 | if typing.TYPE_CHECKING:
28 | from qord.core.shard import Shard
29 |
30 | __all__ = (
31 | "BaseEvent",
32 | "BaseGatewayEvent",
33 | )
34 |
35 | class BaseEvent:
36 | """Base class for events.
37 |
38 | All custom events must inherit from this class. When subclassing the
39 | ``event_name`` parameter is required.
40 |
41 | .. note::
42 | Parameters documented below are passed during subclassing.
43 |
44 | Parameters
45 | ----------
46 | event_name: :class:`builtins.str`
47 | The string representation of name of event. This is used for
48 | identifying the event and must be unique.
49 |
50 | .. warning::
51 | Do not use event names that are already reserved by the library
52 | for example the event names from :class:`GatewayEvent`.
53 | """
54 |
55 | __event_name__: str
56 |
57 | def __init_subclass__(cls, event_name: str) -> None:
58 | if not isinstance(event_name, str):
59 | raise TypeError("'event_name' parameter must be str.")
60 |
61 | cls.__event_name__ = event_name
62 |
63 |
64 | @typing.runtime_checkable
65 | class BaseGatewayEvent(typing.Protocol):
66 | """A :class:`typing.Protocol` that details events sent over the gateway.
67 |
68 | This protocol supports runtime checks like :meth:`isinstance`
69 | or :meth:`issubclass` etc.
70 | """
71 |
72 | shard: typing.Optional[Shard]
73 | """The shard that received this event over gateway.
74 |
75 | This attribute can be ``None`` in events that are not shard specific and are
76 | not invoked by a shard. The most common example is :class:`events.Ready`.
77 | """
--------------------------------------------------------------------------------
/qord/events/channels.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from datetime import datetime
33 | from qord.core.shard import Shard
34 | from qord.models.channels import GuildChannel
35 | from qord.models.guilds import Guild
36 | from qord.models.guild_members import GuildMember
37 | from qord.models.users import User
38 | from qord.internal.types import MessageChannelT
39 |
40 |
41 | __all__ = (
42 | "ChannelCreate",
43 | "ChannelUpdate",
44 | "ChannelDelete",
45 | "ChannelPinsUpdate",
46 | "TypingStart",
47 | )
48 |
49 | @dataclass(frozen=True)
50 | class ChannelCreate(BaseEvent, event_name=GatewayEvent.CHANNEL_CREATE):
51 | """Structure for :attr:`~qord.GatewayEvent.CHANNEL_CREATE` event.
52 |
53 | This event is called whenever a new channel is created in a guild.
54 |
55 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled. This intent
56 | is enabled by default.
57 | """
58 | shard: Shard
59 |
60 | channel: GuildChannel
61 | """The channel that was created."""
62 |
63 | guild: Guild
64 | """The guild where the event happened."""
65 |
66 | @dataclass(frozen=True)
67 | class ChannelUpdate(BaseEvent, event_name=GatewayEvent.CHANNEL_UPDATE):
68 | """Structure for :attr:`~qord.GatewayEvent.CHANNEL_UPDATE` event.
69 |
70 | This event is called whenever one or more properties of a guild channel
71 | are updated.
72 |
73 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled. This intent
74 | is enabled by default.
75 | """
76 | shard: Shard
77 |
78 | before: GuildChannel
79 | """The channel before the update."""
80 |
81 | after: GuildChannel
82 | """The channel after the update."""
83 |
84 | guild: Guild
85 | """The guild that the updated channel belonged to."""
86 |
87 | @dataclass(frozen=True)
88 | class ChannelPinsUpdate(BaseEvent, event_name=GatewayEvent.CHANNEL_PINS_UPDATE):
89 | """Structure for :attr:`~qord.GatewayEvent.CHANNEL_PINS_UPDATE` event.
90 |
91 | This event is called whenever a message is pinned or unpinned in a channel.
92 | This event is not called if a pinned message is deleted.
93 |
94 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled. This intent
95 | is enabled by default.
96 | """
97 | shard: Shard
98 |
99 | channel: MessageChannelT
100 | """The channel whose pins were updated."""
101 |
102 | guild: typing.Optional[Guild]
103 | """The guild where the event happened; If applicable otherwise ``None``."""
104 |
105 | @dataclass(frozen=True)
106 | class ChannelDelete(BaseEvent, event_name=GatewayEvent.CHANNEL_DELETE):
107 | """Structure for :attr:`~qord.GatewayEvent.CHANNEL_DELETE` event.
108 |
109 | This event is called whenever a channel is deleted in a guild.
110 |
111 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled. This intent
112 | is enabled by default.
113 | """
114 | shard: Shard
115 |
116 | channel: GuildChannel
117 | """The channel that was deleted."""
118 |
119 | guild: Guild
120 | """The guild that the delete channel belonged to."""
121 |
122 | @dataclass(frozen=True)
123 | class TypingStart(BaseEvent, event_name=GatewayEvent.TYPING_START):
124 | """Structure for :attr:`~qord.GatewayEvent.TYPING_START` event.
125 |
126 | This event is called whenever a user starts typing in a channel.
127 |
128 | Requires the :attr:`~qord.Intents.guild_message_typing` intents to be enabled for
129 | guild typing events and :attr:`~qord.Intents.direct_message_typing` for DM typing
130 | events. These intents are enabled by default.
131 | """
132 | shard: Shard
133 |
134 | channel: MessageChannelT
135 | """The channel in which typing started in."""
136 |
137 | started_at: datetime
138 | """The time when the typing started."""
139 |
140 | user: typing.Union[User, GuildMember]
141 | """The user or member that started typing.
142 |
143 | If the event happened in a guild, This is :class:`GuildMember` otherwise
144 | it is a :class:`User`.
145 | """
146 |
147 | guild: typing.Optional[Guild]
148 | """The guild in which typing started in if any."""
149 |
--------------------------------------------------------------------------------
/qord/events/emojis.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.emojis import Emoji
34 | from qord.models.guilds import Guild
35 |
36 |
37 | __all__ = (
38 | "EmojisUpdate",
39 | )
40 |
41 |
42 | @dataclass
43 | class EmojisUpdate(BaseEvent, event_name=GatewayEvent.EMOJIS_UPDATE):
44 | """Structure for :attr:`~qord.GatewayEvent.EMOJIS_UPDATE` event.
45 |
46 | This event is called whenever emojis are updated in a guild i.e
47 | a new emoji is created, an emoji is deleted or updated.
48 |
49 | This requires :attr:`Intents.emojis_and_stickers` to be enabled.
50 | """
51 | shard: Shard
52 |
53 | guild: Guild
54 | """The guild whose emojis were updated."""
55 |
56 | before: typing.List[Emoji]
57 | """The list of emojis before the update."""
58 |
59 | after: typing.List[Emoji]
60 | """The list of emojis after the update."""
61 |
--------------------------------------------------------------------------------
/qord/events/gateway.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 |
34 |
35 | __all__ = (
36 | "GatewayDispatch",
37 | "ShardReady",
38 | "Ready",
39 | "Resumed",
40 | )
41 |
42 |
43 | @dataclass(frozen=True)
44 | class GatewayDispatch(BaseEvent, event_name=GatewayEvent.GATEWAY_DISPATCH):
45 | """Structure of a :attr:`~qord.GatewayEvent.GATEWAY_DISPATCH` event.
46 |
47 | This event is called whenever gateway sends an event dispatch.
48 |
49 | This event purely exists for debugging and experimental purposes and should
50 | not generally be used. This event will also call for dispatch events that
51 | are not supported by the library.
52 |
53 | This event is only called when ``debug_events`` parameter is enabled in
54 | :class:`Client`.
55 | """
56 | shard: Shard
57 |
58 | title: str
59 | """The title/name of event.
60 |
61 | This name isn't same as how library defines the events name. See Discord
62 | documentation for all events names.
63 |
64 | https://discord.dev/topics/gateway#commands-and-events
65 | """
66 |
67 | data: typing.Optional[typing.Dict[str, typing.Any]] = None
68 | """The raw event data.
69 |
70 | This is mostly raw JSON payload however for some events, This can be ``None``.
71 | """
72 |
73 | @dataclass(frozen=True)
74 | class ShardReady(BaseEvent, event_name=GatewayEvent.SHARD_READY):
75 | """Structure of a :attr:`~qord.GatewayEvent.SHARD_READY` event.
76 |
77 | This event is called whenever a shard successfully establishes
78 | a connection with Discord gateway and lazy loads cache for all guilds
79 | associated to that shard.
80 | """
81 | shard: Shard
82 |
83 | @dataclass(frozen=True)
84 | class Ready(BaseEvent, event_name=GatewayEvent.READY):
85 | """Structure of a :attr:`~qord.GatewayEvent.READY` event.
86 |
87 | This event is called when all shards associated to the client
88 | have completely prepared their guilds cache and client is in ready state.
89 |
90 | This event is not shard specific as such :attr:`.shard` is always ``None``.
91 | """
92 | shard = None
93 |
94 | @dataclass(frozen=True)
95 | class Resumed(BaseEvent, event_name=GatewayEvent.RESUMED):
96 | """Structure of a :attr:`~qord.GatewayEvent.RESUMED` event.
97 |
98 | This event is called whenver a shard is resumed i.e successfully re-establishes
99 | a previously disconnected session.
100 | """
101 |
102 | shard: Shard
103 | """The shard that was resumed."""
104 |
--------------------------------------------------------------------------------
/qord/events/guild_members.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.guilds import Guild
34 | from qord.models.guild_members import GuildMember
35 |
36 | __all__ = (
37 | "GuildMemberAdd",
38 | "GuildMemberUpdate",
39 | "GuildMemberRemove",
40 | )
41 |
42 |
43 | @dataclass(frozen=True)
44 | class GuildMemberAdd(BaseEvent, event_name=GatewayEvent.GUILD_MEMBER_ADD):
45 | """Structure for :attr:`~qord.GatewayEvent.GUILD_MEMBER_ADD` event.
46 |
47 | This event is called whenever a new member joins the guild.
48 |
49 | This event requires the privileged intent, :attr:`~qord.Intents.members` to be enabled.
50 | """
51 | shard: Shard
52 |
53 | member: GuildMember
54 | """The member that joined the :attr:`.guild`."""
55 |
56 | guild: Guild
57 | """The guild that was joined by the member."""
58 |
59 | @dataclass(frozen=True)
60 | class GuildMemberUpdate(BaseEvent, event_name=GatewayEvent.GUILD_MEMBER_UPDATE):
61 | """Structure for :attr:`~qord.GatewayEvent.GUILD_MEMBER_UPDATE` event.
62 |
63 | This event is called whenever a guild member is updated.
64 |
65 | This event requires the privileged intent, :attr:`~qord.Intents.members` to be enabled.
66 | """
67 | shard: Shard
68 |
69 | before: GuildMember
70 | """The member before the update."""
71 |
72 | after: GuildMember
73 | """The member after the update."""
74 |
75 | guild: Guild
76 | """The associated guild."""
77 |
78 | @dataclass(frozen=True)
79 | class GuildMemberRemove(BaseEvent, event_name=GatewayEvent.GUILD_MEMBER_REMOVE):
80 | """Structure for :attr:`~qord.GatewayEvent.GUILD_MEMBER_REMOVE` event.
81 |
82 | This event is called whenever a member is removed from the guild. The
83 | removal may be in form of leaving, getting kicked or banned etc.
84 |
85 | This event requires the privileged intent, :attr:`~qord.Intents.members` to be enabled.
86 | """
87 | shard: Shard
88 |
89 | member: GuildMember
90 | """The member that had left the :attr:`.guild`."""
91 |
92 | guild: Guild
93 | """The guild that was left by the member."""
94 |
--------------------------------------------------------------------------------
/qord/events/guilds.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.guilds import Guild
34 |
35 |
36 | __all__ = (
37 | "GuildAvailable",
38 | "GuildUnavailable",
39 | "GuildJoin",
40 | "GuildUpdate",
41 | "GuildLeave",
42 | )
43 |
44 |
45 | @dataclass(frozen=True)
46 | class GuildAvailable(BaseEvent, event_name=GatewayEvent.GUILD_AVAILABLE):
47 | """Structure for :attr:`~qord.GatewayEvent.GUILD_AVAILABLE` event.
48 |
49 | This event is called whenever a guild becomes available to the client. When
50 | initially connecting, This event may call several times for lazy loading of
51 | client guilds.
52 |
53 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
54 | intent is enabled by default.
55 | """
56 | shard: Shard
57 |
58 | guild: Guild
59 | """The guild that became available."""
60 |
61 | @dataclass(frozen=True)
62 | class GuildUnavailable(BaseEvent, event_name=GatewayEvent.GUILD_UNAVAILABLE):
63 | """Structure for :attr:`~qord.GatewayEvent.GUILD_UNAVAILABLE` event.
64 |
65 | This event is called whenever a guild becomes unavailable to the client
66 | most likely due to an outage.
67 |
68 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
69 | intent is enabled by default.
70 | """
71 | shard: Shard
72 |
73 | guild: Guild
74 | """The guild that became unavailable."""
75 |
76 | @dataclass(frozen=True)
77 | class GuildJoin(BaseEvent, event_name=GatewayEvent.GUILD_JOIN):
78 | """Structure for :attr:`~qord.GatewayEvent.GUILD_JOIN` event.
79 |
80 | This event is called whenever the client user or bot joins a new
81 | guild.
82 |
83 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
84 | intent is enabled by default.
85 | """
86 | shard: Shard
87 |
88 | guild: Guild
89 | """The joined guild."""
90 |
91 | @dataclass(frozen=True)
92 | class GuildLeave(BaseEvent, event_name=GatewayEvent.GUILD_LEAVE):
93 | """Structure for :attr:`~qord.GatewayEvent.GUILD_LEAVE` event.
94 |
95 | This event is called whenever the client user or bot is removed
96 | (kicked, banned or simply left) from a guild.
97 |
98 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
99 | intent is enabled by default.
100 | """
101 | shard: Shard
102 |
103 | guild: Guild
104 | """The left guild."""
105 |
106 | @dataclass(frozen=True)
107 | class GuildUpdate(BaseEvent, event_name=GatewayEvent.GUILD_UPDATE):
108 | """Structure for :attr:`~qord.GatewayEvent.GUILD_UPDATE` event.
109 |
110 | This event is called whenever one or more properties of a guild are updated.
111 |
112 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
113 | intent is enabled by default.
114 | """
115 | shard: Shard
116 |
117 | before: Guild
118 | """The copy of guild before the update."""
119 |
120 | after: Guild
121 | """The guild after the update."""
122 |
--------------------------------------------------------------------------------
/qord/events/invites.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.invites import Invite
34 | from qord.models.guilds import Guild
35 | from qord.models.channels import GuildChannel
36 |
37 |
38 | __all__ = (
39 | "InviteCreate",
40 | "InviteDelete",
41 | )
42 |
43 |
44 | @dataclass
45 | class InviteCreate(BaseEvent, event_name=GatewayEvent.INVITE_CREATE):
46 | """Structure for :attr:`~qord.GatewayEvent.INVITE_CREATE` event.
47 |
48 | This event is called whenever a new invite is created in a guild.
49 |
50 | Requires the :attr:`~qord.Intents.invites` intents to be enabled.
51 | This intent is enabled by default.
52 | """
53 | shard: Shard
54 |
55 | guild: Guild
56 | """The guild in which invite was created."""
57 |
58 | channel: GuildChannel
59 | """The channel that the invite belongs to."""
60 |
61 | invite: Invite
62 | """The created invite."""
63 |
64 |
65 | @dataclass
66 | class InviteDelete(BaseEvent, event_name=GatewayEvent.INVITE_DELETE):
67 | """Structure for :attr:`~qord.GatewayEvent.INVITE_DELETE` event.
68 |
69 | This event is called whenever an invite is deleted in a guild.
70 |
71 | Requires the :attr:`~qord.Intents.invites` intents to be enabled.
72 | This intent is enabled by default.
73 | """
74 | shard: Shard
75 |
76 | guild: Guild
77 | """The guild from which the invite was deleted."""
78 |
79 | channel: GuildChannel
80 | """The channel that the invite belonged to."""
81 |
82 | code: str
83 | """The deleted invite's code."""
84 |
--------------------------------------------------------------------------------
/qord/events/messages.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.guilds import Guild
34 | from qord.models.messages import Message
35 | from qord.internal.types import MessageChannelT
36 |
37 |
38 | __all__ = (
39 | "MessageCreate",
40 | "MessageDelete",
41 | "MessageUpdate",
42 | "MessageBulkDelete",
43 | )
44 |
45 |
46 | @dataclass(frozen=True)
47 | class MessageCreate(BaseEvent, event_name=GatewayEvent.MESSAGE_CREATE):
48 | """Structure for :attr:`~qord.GatewayEvent.MESSAGE_CREATE` event.
49 |
50 | This event is called whenever a new message is sent in a guild or
51 | private channel.
52 |
53 | This event requires the :attr:`~qord.Intents.guild_messages` and
54 | :attr:`~qord.Intents.direct_messages` intents enabled for guild and DM
55 | message events respectively. These intents are enabled by default.
56 | """
57 | shard: Shard
58 |
59 | message: Message
60 | """The message that was sent."""
61 |
62 | @dataclass(frozen=True)
63 | class MessageDelete(BaseEvent, event_name=GatewayEvent.MESSAGE_DELETE):
64 | """Structure for :attr:`~qord.GatewayEvent.MESSAGE_DELETE` event.
65 |
66 | This event is called whenever a message is deleted.
67 |
68 | This event requires the :attr:`~qord.Intents.guild_messages` and
69 | :attr:`~qord.Intents.direct_messages` intents enabled for guild and DM
70 | message events respectively. These intents are enabled by default.
71 | """
72 | shard: Shard
73 |
74 | message: Message
75 | """The message that was deleted."""
76 |
77 | @dataclass(frozen=True)
78 | class MessageUpdate(BaseEvent, event_name=GatewayEvent.MESSAGE_UPDATE):
79 | """Structure for :attr:`~qord.GatewayEvent.MESSAGE_UPDATE` event.
80 |
81 | This event is called whenever a message is updated aka edited.
82 |
83 | This event requires the :attr:`~qord.Intents.guild_messages` and
84 | :attr:`~qord.Intents.direct_messages` intents enabled for guild and DM
85 | message events respectively. These intents are enabled by default.
86 | """
87 | shard: Shard
88 |
89 | before: Message
90 | """The message that was edited, before the edit happened."""
91 |
92 | after: Message
93 | """The message that was edited, after the edit happened."""
94 |
95 |
96 | @dataclass(frozen=True)
97 | class MessageBulkDelete(BaseEvent, event_name=GatewayEvent.MESSAGE_BULK_DELETE):
98 | """Structure for :attr:`~qord.GatewayEvent.MESSAGE_BULK_DELETE` event.
99 |
100 | This event is called whenever multiple messages are deleted at the same
101 | time in a channel.
102 |
103 | This event requires the :attr:`~qord.Intents.guild_messages` and
104 | :attr:`~qord.Intents.direct_messages` intents enabled for guild and DM
105 | message events respectively. These intents are enabled by default.
106 | """
107 | shard: Shard
108 |
109 | messages: typing.List[Message]
110 | """The list of messages that were deleted.
111 |
112 | This list only includes messages that could be resolved from
113 | the bot's cache and may not include all messages that were deleted.
114 | You should use :attr:`.message_ids` to get the IDs of all the messages
115 | deleted however do note that you cannot fetch those messages as
116 | they have been deleted.
117 | """
118 |
119 | channel: MessageChannelT
120 | """The channel in which messages were bulk deleted."""
121 |
122 | guild: typing.Optional[Guild]
123 | """The relevant guild if any, ``None`` if the bulk delete happened in DMs."""
124 |
125 | message_ids: typing.List[int]
126 | """The list of IDs of messages that were deleted."""
127 |
--------------------------------------------------------------------------------
/qord/events/reactions.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.guild_members import GuildMember
34 | from qord.models.users import User
35 | from qord.models.emojis import PartialEmoji
36 | from qord.models.messages import Message, Reaction
37 |
38 |
39 | __all__ = (
40 | "ReactionAdd",
41 | "ReactionRemove",
42 | "ReactionClear",
43 | "ReactionClearEmoji",
44 | )
45 |
46 |
47 | @dataclass
48 | class ReactionAdd(BaseEvent, event_name=GatewayEvent.REACTION_ADD):
49 | """Structure for :attr:`~qord.GatewayEvent.REACTION_ADD` event.
50 |
51 | This event is called whenever a reaction is added on a message.
52 |
53 | This requires :attr:`Intents.guild_message_reactions` or
54 | :attr:`Intents.direct_message_reactions` to be enabled for
55 | guilds and direct messages respectively.
56 | """
57 | shard: Shard
58 |
59 | message: Message
60 | """The message on which reaction was added."""
61 |
62 | reaction: Reaction
63 | """The added reaction."""
64 |
65 | user: typing.Union[User, GuildMember]
66 | """The user who added the reaction."""
67 |
68 |
69 | @dataclass
70 | class ReactionRemove(BaseEvent, event_name=GatewayEvent.REACTION_REMOVE):
71 | """Structure for :attr:`~qord.GatewayEvent.REACTION_REMOVE` event.
72 |
73 | This event is called whenever a reaction is removed from a message.
74 |
75 | This requires :attr:`Intents.guild_message_reactions` or
76 | :attr:`Intents.direct_message_reactions` to be enabled for
77 | guilds and direct messages respectively.
78 | """
79 | shard: Shard
80 |
81 | message: Message
82 | """The message from which the reaction was removed."""
83 |
84 | reaction: Reaction
85 | """The removed reaction."""
86 |
87 | user: typing.Union[User, GuildMember]
88 | """The user who removed their reaction.
89 |
90 | Unlike the :class:`events.ReactionAdd` event, This attribute can be
91 | a :class:`GuildMember` object only when :attr:`~Intents.members` intents
92 | are enabled as Discord does not tend to send the member data in this event.
93 | """
94 |
95 |
96 | @dataclass
97 | class ReactionClear(BaseEvent, event_name=GatewayEvent.REACTION_CLEAR):
98 | """Structure for :attr:`~qord.GatewayEvent.REACTION_CLEAR` event.
99 |
100 | This event is called whenever all reactions are cleared from
101 | a message at once.
102 |
103 | This requires :attr:`Intents.guild_message_reactions` or
104 | :attr:`Intents.direct_message_reactions` to be enabled for
105 | guilds and direct messages respectively.
106 | """
107 | shard: Shard
108 |
109 | message: Message
110 | """The message from which the reactions were cleared."""
111 |
112 | reactions: typing.List[Reaction]
113 | """The list of cleared reactions."""
114 |
115 |
116 | @dataclass
117 | class ReactionClearEmoji(BaseEvent, event_name=GatewayEvent.REACTION_CLEAR_EMOJI):
118 | """Structure for :attr:`~qord.GatewayEvent.REACTION_CLEAR_EMOJI` event.
119 |
120 | This event is called whenever all reactions for a specific emoji are
121 | cleared from a message at once.
122 |
123 | This requires :attr:`Intents.guild_message_reactions` or
124 | :attr:`Intents.direct_message_reactions` to be enabled for
125 | guilds and direct messages respectively.
126 | """
127 | shard: Shard
128 |
129 | message: Message
130 | """The message from which the reactions were cleared."""
131 |
132 | emoji: PartialEmoji
133 | """The emoji whose reactions were cleared."""
134 |
135 | reaction: Reaction
136 | """The reaction that was cleared."""
137 |
138 |
--------------------------------------------------------------------------------
/qord/events/roles.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.roles import Role
34 | from qord.models.guilds import Guild
35 |
36 |
37 | __all__ = (
38 | "RoleCreate",
39 | "RoleUpdate",
40 | "RoleDelete",
41 | )
42 |
43 |
44 | @dataclass(frozen=True)
45 | class RoleCreate(BaseEvent, event_name=GatewayEvent.ROLE_CREATE):
46 | """Structure for :attr:`~qord.GatewayEvent.ROLE_CREATE` event.
47 |
48 | This event is called whenever a role is created in a guild.
49 |
50 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
51 | intent is enabled by default.
52 | """
53 | shard: Shard
54 |
55 | role: Role
56 | """The role that was created."""
57 |
58 | guild: Guild
59 | """The guild that the created role belonged to."""
60 |
61 | @dataclass(frozen=True)
62 | class RoleUpdate(BaseEvent, event_name=GatewayEvent.ROLE_UPDATE):
63 | """Structure for :attr:`~qord.GatewayEvent.ROLE_UPDATE` event.
64 |
65 | This event is called whenever one or more properties of a guild role
66 | are updated.
67 |
68 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
69 | intent is enabled by default.
70 | """
71 | shard: Shard
72 |
73 | before: Role
74 | """The role before the update."""
75 |
76 | after: Role
77 | """The role after the update."""
78 |
79 | guild: Guild
80 | """The guild that the updated role belonged to."""
81 |
82 | @dataclass(frozen=True)
83 | class RoleDelete(BaseEvent, event_name=GatewayEvent.ROLE_DELETE):
84 | """Structure for :attr:`~qord.GatewayEvent.ROLE_DELETE` event.
85 |
86 | This event is called whenever a role is deleted in a guild.
87 |
88 | This event requires the :attr:`~qord.Intents.guilds` to be enabled. This
89 | intent is enabled by default.
90 | """
91 | shard: Shard
92 |
93 | role: Role
94 | """The deleted role."""
95 |
96 | guild: Guild
97 | """The guild that the updated role belonged to."""
98 |
--------------------------------------------------------------------------------
/qord/events/scheduled_events.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.scheduled_events import ScheduledEvent
34 | from qord.models.guilds import Guild
35 | from qord.models.guild_members import GuildMember
36 |
37 |
38 | __all__ = (
39 | "ScheduledEventCreate",
40 | "ScheduledEventUpdate",
41 | "ScheduledEventDelete",
42 | "ScheduledEventUserAdd",
43 | "ScheduledEventUserRemove",
44 | )
45 |
46 |
47 | @dataclass
48 | class ScheduledEventCreate(BaseEvent, event_name=GatewayEvent.SCHEDULED_EVENT_CREATE):
49 | """Structure for :attr:`~qord.GatewayEvent.SCHEDULED_EVENT_CREATE` event.
50 |
51 | This event is called whenever a new scheduled event is created in a guild.
52 |
53 | Requires the :attr:`~qord.Intents.scheduled_events` intents to be enabled.
54 | This intent is enabled by default.
55 | """
56 | shard: Shard
57 |
58 | guild: Guild
59 | """The guild in which event was created."""
60 |
61 | scheduled_event: ScheduledEvent
62 | """The created scheduled event."""
63 |
64 |
65 | @dataclass
66 | class ScheduledEventUpdate(BaseEvent, event_name=GatewayEvent.SCHEDULED_EVENT_UPDATE):
67 | """Structure for :attr:`~qord.GatewayEvent.SCHEDULED_EVENT_UPDATE` event.
68 |
69 | This event is called whenever a scheduled event is updated in a guild.
70 |
71 | Requires the :attr:`~qord.Intents.scheduled_events` intents to be enabled.
72 | This intent is enabled by default.
73 | """
74 | shard: Shard
75 |
76 | guild: Guild
77 | """The guild in which event was created."""
78 |
79 | before: ScheduledEvent
80 | """The scheduled event before the update."""
81 |
82 | after: ScheduledEvent
83 | """The scheduled event after the update."""
84 |
85 |
86 | @dataclass
87 | class ScheduledEventDelete(BaseEvent, event_name=GatewayEvent.SCHEDULED_EVENT_DELETE):
88 | """Structure for :attr:`~qord.GatewayEvent.SCHEDULED_EVENT_DELETE` event.
89 |
90 | This event is called whenever a scheduled event is deleted in a guild.
91 |
92 | Requires the :attr:`~qord.Intents.scheduled_events` intents to be enabled.
93 | This intent is enabled by default.
94 | """
95 | shard: Shard
96 |
97 | guild: Guild
98 | """The guild from which the event was deleted."""
99 |
100 | scheduled_event: ScheduledEvent
101 | """The deleted scheduled event."""
102 |
103 |
104 | @dataclass
105 | class ScheduledEventUserAdd(BaseEvent, event_name=GatewayEvent.SCHEDULED_EVENT_USER_ADD):
106 | """Structure for :attr:`~qord.GatewayEvent.SCHEDULED_EVENT_USER_ADD` event.
107 |
108 | This event is called whenever a user subscribes to a scheduled event.
109 |
110 | Requires the :attr:`~qord.Intents.scheduled_events` intents to be enabled.
111 | This intent is enabled by default.
112 | """
113 | shard: Shard
114 |
115 | guild: Guild
116 | """The guild that the event belongs to."""
117 |
118 | scheduled_event: ScheduledEvent
119 | """The scheduled event on which user subscribed."""
120 |
121 | user_id: int
122 | """The ID of user who subscribed."""
123 |
124 | user: typing.Optional[GuildMember]
125 | """The user who subscribed.
126 |
127 | **This can be ``None``!** When :attr:`~qord.Intents.members` are not enabled or member
128 | isn't cached by any chance, This attribute can be ``None``. You should consider fetching
129 | the member via :meth:`Guild.fetch_member` with the given :attr:`.user_id`.
130 | """
131 |
132 |
133 | @dataclass
134 | class ScheduledEventUserRemove(BaseEvent, event_name=GatewayEvent.SCHEDULED_EVENT_USER_REMOVE):
135 | """Structure for :attr:`~qord.GatewayEvent.SCHEDULED_EVENT_USER_REMOVE` event.
136 |
137 | This event is called whenever a user unsubscribes to a scheduled event.
138 |
139 | Requires the :attr:`~qord.Intents.scheduled_events` intents to be enabled.
140 | This intent is enabled by default.
141 | """
142 | shard: Shard
143 |
144 | guild: Guild
145 | """The guild that the event belongs to."""
146 |
147 | scheduled_event: ScheduledEvent
148 | """The scheduled event on which user unsubscribed."""
149 |
150 | user_id: int
151 | """The ID of user who unsubscribed."""
152 |
153 | user: typing.Optional[GuildMember]
154 | """The user who unsubscribed.
155 |
156 | **This can be ``None``!** When :attr:`~qord.Intents.members` are not enabled or member
157 | isn't cached by any chance, This attribute can be ``None``. You should consider fetching
158 | the member via :meth:`Guild.fetch_member` with the given :attr:`.user_id`.
159 | """
160 |
--------------------------------------------------------------------------------
/qord/events/stage_instances.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.stage_instances import StageInstance
34 | from qord.models.guilds import Guild
35 |
36 |
37 | __all__ = (
38 | "StageInstanceCreate",
39 | "StageInstanceUpdate",
40 | "StageInstanceDelete",
41 | )
42 |
43 |
44 | @dataclass
45 | class StageInstanceCreate(BaseEvent, event_name=GatewayEvent.STAGE_INSTANCE_CREATE):
46 | """Structure for :attr:`~qord.GatewayEvent.STAGE_INSTANCE_CREATE` event.
47 |
48 | This event is called whenever a new stage instance is created in a guild.
49 |
50 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled.
51 | This intent is enabled by default.
52 | """
53 | shard: Shard
54 |
55 | guild: Guild
56 | """The guild in which stage instance was created."""
57 |
58 | stage_instance: StageInstance
59 | """The created stage instance."""
60 |
61 |
62 | @dataclass
63 | class StageInstanceUpdate(BaseEvent, event_name=GatewayEvent.STAGE_INSTANCE_UPDATE):
64 | """Structure for :attr:`~qord.GatewayEvent.STAGE_INSTANCE_UPDATE` event.
65 |
66 | This event is called whenever a stage instance is updated in a guild.
67 |
68 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled.
69 | This intent is enabled by default.
70 | """
71 | shard: Shard
72 |
73 | guild: Guild
74 | """The guild in which stage instance was created."""
75 |
76 | before: StageInstance
77 | """The stage instance before the update."""
78 |
79 | after: StageInstance
80 | """The stage instance after the update."""
81 |
82 |
83 | @dataclass
84 | class StageInstanceDelete(BaseEvent, event_name=GatewayEvent.STAGE_INSTANCE_DELETE):
85 | """Structure for :attr:`~qord.GatewayEvent.STAGE_INSTANCE_DELETE` event.
86 |
87 | This event is called whenever a stage instance is deleted in a guild.
88 |
89 | Requires the :attr:`~qord.Intents.guilds` intents to be enabled.
90 | This intent is enabled by default.
91 | """
92 | shard: Shard
93 |
94 | guild: Guild
95 | """The guild from which the stage instance was deleted."""
96 |
97 | stage_instance: StageInstance
98 | """The deleted stage instance."""
--------------------------------------------------------------------------------
/qord/events/users.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.events.base import BaseEvent
26 | from qord.enums import GatewayEvent
27 |
28 | import typing
29 | from dataclasses import dataclass
30 |
31 | if typing.TYPE_CHECKING:
32 | from qord.core.shard import Shard
33 | from qord.models.users import User
34 |
35 |
36 | __all__ = (
37 | "UserUpdate",
38 | )
39 |
40 | @dataclass(frozen=True)
41 | class UserUpdate(BaseEvent, event_name=GatewayEvent.USER_UPDATE):
42 | """Structure for :attr:`~qord.GatewayEvent.USER_UPDATE` event.
43 |
44 | This event is called whenever one or more properties of a user are updated.
45 | """
46 | shard: Shard
47 |
48 | before: User
49 | """The user before the update."""
50 |
51 | after: User
52 | """The user after the update."""
53 |
--------------------------------------------------------------------------------
/qord/exceptions.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import typing
26 |
27 | if typing.TYPE_CHECKING:
28 | from qord.core.shard import Shard
29 | from aiohttp import ClientResponse
30 |
31 |
32 | __all__ = (
33 | "QordException",
34 | "ClientSetupRequired",
35 | "HTTPException",
36 | "HTTPBadRequest",
37 | "HTTPForbidden",
38 | "HTTPNotFound",
39 | "HTTPServerError",
40 | "ShardException",
41 | "ShardCloseException",
42 | "MissingPrivilegedIntents",
43 | )
44 |
45 | class QordException(Exception):
46 | r"""Base exception class for all exceptions raised by the library."""
47 |
48 | class ClientSetupRequired(QordException):
49 | r"""An exception indicating that client setup is required to perform the attempted
50 | operation that caused the exception.
51 |
52 | For HTTPs operations, This generally means that requested endpoint requires
53 | authorization with a bot token but no bot token is set yet.
54 |
55 | You must call :meth:`Client.setup` with a proper bot token first to setup
56 | the client first before retrying.
57 | """
58 | pass
59 |
60 | class HTTPException(QordException):
61 | r"""Base exception class for all exceptions that indicate failure of a HTTP request
62 | i.e request returned with an unsuccessful status code..
63 |
64 | Attributes
65 | ----------
66 | response: :class:`aiohttp.ClientResponse`
67 | The failed request response.
68 | data: Union[:class:`builtins.dict`, :class:`builtins.str`]
69 | The data from the response. In most cases, This is a dictionary representing
70 | the JSON responose however in rare cases like CloudFlare errors, This can be
71 | a string of raw HTML.
72 | """
73 | def __init__(self, response: ClientResponse, data: typing.Union[str, dict]) -> None:
74 | self.response = response
75 | self.data = data
76 |
77 | if isinstance(data, dict):
78 | try:
79 | data = data["message"]
80 | except KeyError:
81 | pass
82 |
83 | super().__init__(data)
84 |
85 | class HTTPBadRequest(HTTPException):
86 | r""":exc:`HTTPException` indicating a ``400 Bad Request`` response."""
87 |
88 | class HTTPForbidden(HTTPException):
89 | r""":exc:`HTTPException` indicating a ``403 Forbidden`` response."""
90 |
91 | class HTTPNotFound(HTTPException):
92 | r""":exc:`HTTPException` indicating a ``404 Not Found`` response."""
93 |
94 | class HTTPServerError(HTTPException):
95 | r""":exc:`HTTPException` indicating a 500s response."""
96 |
97 | class ShardException(QordException):
98 | r"""Base class for all shards related errors.
99 |
100 | Attributes
101 | ----------
102 | shard: :class:`Shard`
103 | The shard that caused the error.
104 | """
105 | def __init__(self, shard: Shard, *args: object) -> None:
106 | self.shard = shard
107 | super().__init__(*args)
108 |
109 | class ShardCloseException(ShardException):
110 | r"""An exception indicating that a shard closed with an unhandleable close code.
111 |
112 | This inherits :exc:`ShardException`.
113 |
114 | Attributes
115 | ----------
116 | code: :class:`builtins.int`
117 | The close code that caused the error.
118 | """
119 |
120 | def __init__(self, shard: Shard, code: int, *args) -> None:
121 | self.code = code
122 | super().__init__(shard, *args)
123 |
124 | class MissingPrivilegedIntents(ShardCloseException):
125 | r"""An exception indicating that a shard closed because client has requested
126 | access to certain *privileged* intents that are not provided by Discord.
127 |
128 | This inherits :exc:`ShardCloseException`, The :attr:`~ShardCloseException.code`
129 | attribute is always ``4014`` when this error is raised.
130 | """
131 | def __init__(self, shard: Shard) -> None:
132 | super().__init__(
133 | shard, 4014,
134 | "Client is not whitelisted to use requested privileged intents.",
135 | )
136 |
--------------------------------------------------------------------------------
/qord/flags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/izxxr/qord-legacy/6d92751efc76b1f0bbcc350eff30369cb5a1c51a/qord/flags/__init__.py
--------------------------------------------------------------------------------
/qord/flags/applications.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.base import Flags
26 |
27 |
28 | __all__ = (
29 | "ApplicationFlags",
30 | )
31 |
32 |
33 | class ApplicationFlags(Flags):
34 | """:class:`Flags` subclass that details the flags of a :class:`Application`. This is mostly
35 | obtained using :attr:`Application.flags` or :attr:`Client.application_flags` attribute.
36 |
37 | The application flags detail the features of an application.
38 | """
39 |
40 | gateway_presence = 1 << 12
41 | """Whether the application has gateway presence intent."""
42 |
43 | gateway_presence_limited = 1 << 13
44 | """Whether the application requires whitelisting to use gateway presence intent."""
45 |
46 | gateway_members = 1 << 14
47 | """Whether the application has gateway guild members intent."""
48 |
49 | gateway_members_limited = 1 << 15
50 | """Whether the application requires whitelisting to use gateway members intents."""
51 |
52 | verification_pending_guild_limit = 1 << 16
53 | """Indicates unusual growth of an app that prevents verification."""
54 |
55 | embedded = 1 << 17
56 | """Whether the application is embedded application in Discord client."""
57 |
58 | gateway_message_content = 1 << 18
59 | """Whether the application has gateway guild message content intent."""
60 |
61 | gateway_message_content_limited = 1 << 19
62 | """Whether the application requires whitelisting to use gateway message content intents."""
63 |
--------------------------------------------------------------------------------
/qord/flags/base.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import typing
26 |
27 | # Thanks to discord.py for being a good base design for Flags.
28 | # This is inspired by discord.py
29 |
30 | __all__ = (
31 | "Flags",
32 | )
33 |
34 |
35 | class Flags:
36 | r"""A class that interfaces manipulating bitwise flags.
37 |
38 | This class provides a user friendly way of interacting with bitwise values
39 | returned by Discord. The most common example is :class:`Permissions`.
40 |
41 | This class is documented for allowing users to create custom flags classes. The
42 | way this class works can be described by the example below::
43 |
44 | class MyFlags(qord.Flags):
45 | foo = 1 << 0
46 | bar = 1 << 2
47 | baz = 1 << 3
48 | bac = 1 << 4
49 |
50 | >>> flags = MyFlags(foo=True, bar=False)
51 | >>> flags.foo
52 | True
53 | >>> flags.bar
54 | False
55 | >>> flags.value
56 | 5
57 | >>> flags = MyFlags(5)
58 | >>> flags.foo
59 | True
60 | >>> flags.bar
61 | False
62 | >>> flags.bar = False
63 | >>> flags.value
64 | 1
65 |
66 | When initializing, Either a bitwise value can be passed as first positional argument
67 | or flags can be toggled using :class:`builtins.bool`. Accessing a flag from
68 | non-initialized flags class returns it's raw value.
69 |
70 | .. tip::
71 | This class also supports comparison with other :class:`Flags` instances
72 | as well as :class:`~builtins.int` casting. On iterating, Yields the flag
73 | name and it's toggle as :class:`~builtins.bool`.
74 |
75 | .. note::
76 | The parameters documented below are passed during subclassing this class.
77 |
78 | Parameters
79 | ----------
80 | ignore_extraneous: :class:`builtins.bool`
81 | Whether to ignore extra flags passed during initalization and not
82 | raise :exc:`TypeError`. Defaults to ``False``.
83 |
84 | Attributes
85 | ----------
86 | value: :class:`builtins.int`
87 | The raw flags value.
88 | """
89 | __name_value_map__: typing.Dict[str, int]
90 | __flags_settings__: typing.Dict[str, typing.Any]
91 |
92 |
93 | def __init__(self, value: int = 0, **flags: bool) -> None:
94 | self.value = value
95 |
96 | ignore_extraneous = self.__flags_settings__.get("ignore_extraneous", False)
97 |
98 | for flag, toggle in flags.items():
99 | if not flag in self.__name_value_map__ and not ignore_extraneous:
100 | raise TypeError(f"{flag} is not a valid flag for {self.__class__.__name__}()")
101 |
102 | self._apply(flag, toggle)
103 |
104 | def _apply(self, flag: str, toggle: bool):
105 | value = self.__name_value_map__[flag]
106 |
107 | if toggle is True:
108 | self.value |= value
109 | elif toggle is False:
110 | self.value &= ~value
111 | else:
112 | raise TypeError(f"{flag} value must be a bool, Not {toggle.__class__!r}")
113 |
114 | def _has(self, flag: str) -> bool:
115 | value = self.__name_value_map__[flag]
116 | return (self.value & value) > 0
117 |
118 | def __init_subclass__(cls, ignore_extraneous: bool = False) -> None:
119 | nv_map = {}
120 |
121 | for name, value in vars(cls).items():
122 | if name.startswith("_") or not isinstance(value, int):
123 | continue
124 |
125 | nv_map[name] = value
126 | setattr(cls, name, _Flag(name, value))
127 |
128 | cls.__name_value_map__ = nv_map
129 | cls.__flags_settings__ = {"ignore_extraneous": ignore_extraneous}
130 |
131 | def __int__(self) -> int:
132 | return self.value
133 |
134 | def __iter__(self) -> typing.Iterator[typing.Tuple[str, bool]]:
135 | for name in self.__name_value_map__:
136 | yield name, getattr(self, name)
137 |
138 | def __repr__(self) -> str:
139 | flags = list(self.__name_value_map__.keys())
140 | ret = f"{self.__class__.__name__}(%s)"
141 | return ret % (", ".join(f"{k}={self._has(k)}" for k in flags))
142 |
143 | __eq__ = lambda self, other: isinstance(other, self.__class__) and self.value == other.value # type: ignore
144 | __ne__ = lambda self, other: isinstance(other, self.__class__) and self.value != other.value # type: ignore
145 | __lt__ = lambda self, other: isinstance(other, self.__class__) and self.value < other.value
146 | __le__ = lambda self, other: isinstance(other, self.__class__) and self.value <= other.value
147 | __gt__ = lambda self, other: isinstance(other, self.__class__) and self.value > other.value
148 | __ge__ = lambda self, other: isinstance(other, self.__class__) and self.value >= other.value
149 |
150 | class _Flag:
151 | def __init__(self, name: str, value: int) -> None:
152 | self.name = name
153 | self.value = value
154 |
155 | def __get__(self, instance: typing.Optional[Flags], owner: typing.Type[Flags]) -> typing.Union[int, bool]:
156 | if instance is None:
157 | return self.value
158 |
159 | return (instance.value & self.value > 0)
160 |
161 | def __set__(self, instance: typing.Optional[Flags], toggle: bool) -> None:
162 | if instance is None:
163 | raise AttributeError("Cannot set this attribute on non-instansiated Flags class.")
164 |
165 | instance._apply(self.name, toggle)
166 |
--------------------------------------------------------------------------------
/qord/flags/intents.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.base import Flags
26 |
27 |
28 | __all__ = (
29 | "Intents",
30 | )
31 |
32 |
33 | class Intents(Flags):
34 | """:class:`Flags` subclass that details the gateway intents.
35 |
36 | Gateway intents allow you to toggle specific gateway events if whether
37 | you want to receive them or not. This also affects the caching for relevant
38 | entity. Gateway intents are useful to disable events that you don't need for
39 | your bot and decrease the workload. For example, if your bot doesn't need
40 | direct messages events, you can set :attr:`.direct_messages` to ``False``.
41 |
42 | Some intents are marked as privileged. These intents are required to be
43 | enabled explicitly from the bot's application page on Discord Developers Portal.
44 | If the bot is in more then 100 servers, These intents require verification
45 | and whitelisting.
46 |
47 | Attempting to enable these intents without enabling them from Developers Portal
48 | will cause the bot to terminate with :exc:`MissingPrivilegedIntents` error.
49 |
50 | Current privileged intents are:
51 |
52 | - :attr:`.members`
53 | - :attr:`.presences`
54 | - :attr:`.message_content`
55 | """
56 |
57 | guilds = 1 << 0
58 | """Whether to enable guild events and caching.
59 |
60 | This intent is generally required by most bots and disabling it will
61 | cause most of functionality of library to be disabled. Only disable this
62 | when your bot is completely DMs or interactions based.
63 | """
64 |
65 | members = 1 << 1
66 | """Whether to enable events and caching for guild members. This
67 | also controls most of bot's user caching.
68 |
69 | This is a privileged intent, See :class:`Intents` documentation.
70 | """
71 |
72 | bans = 1 << 2
73 | """Whether to enable events for guild bans."""
74 |
75 | emojis_and_stickers = 1 << 3
76 | """Whether to enable events for guild stickers and emojis."""
77 |
78 | integrations = 1 << 4
79 | """Whether to enable events for guild integrations."""
80 |
81 | webhooks = 1 << 5
82 | """Whether to enable events for webhooks."""
83 |
84 | invites = 1 << 6
85 | """Whether to enable events for invites."""
86 |
87 | voice_states = 1 << 7
88 | """Whether to enable events for voice state updates."""
89 |
90 | presences = 1 << 8
91 | """Whether to enable events and for presences.
92 |
93 | This is a privileged intent, See :class:`Intents` documentation.
94 | """
95 |
96 | guild_messages = 1 << 9
97 | """Whether to enable events and caching for guild messages."""
98 |
99 | guild_message_reactions = 1 << 10
100 | """Whether to enable events and caching for reactions on guild messages."""
101 |
102 | guild_message_typing = 1 << 11
103 | """Whether to enable events for message typing in guilds."""
104 |
105 | direct_messages = 1 << 12
106 | """Whether to enable events and caching for direct messages."""
107 |
108 | direct_message_reactions = 1 << 13
109 | """Whether to enable events and caching for reactions on direct messages."""
110 |
111 | direct_message_typing = 1 << 14
112 | """Whether to enable events for message typing in DMs."""
113 |
114 | message_content = 1 << 15
115 | """Whether the bot can receive message content on message objects.
116 |
117 | This is a privileged intent, See :class:`Intents` documentation.
118 | """
119 |
120 | scheduled_events = 1 << 16
121 | """Whether to enable events and caching for guild scheduled events."""
122 |
123 | @classmethod
124 | def all(cls) -> Intents:
125 | """Returns the :class:`Intents` with all intents *including* privileged enabled."""
126 | return cls(sum(cls.__name_value_map__.values()))
127 |
128 | @classmethod
129 | def unprivileged(cls) -> Intents:
130 | """Returns the :class:`Intents` with all intents *excluding* privileged enabled."""
131 | ret = cls.all()
132 | ret.members = False
133 | ret.presences = False
134 | ret.message_content = False
135 | return ret
136 |
--------------------------------------------------------------------------------
/qord/flags/messages.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.base import Flags
26 |
27 |
28 | __all__ = (
29 | "MessageFlags",
30 | )
31 |
32 |
33 | class MessageFlags(Flags):
34 | """:class:`Flags` subclass that details the flags of a :class:`Message`.
35 |
36 | This is mostly obtained using :attr:`Message.flags` attribute.
37 | """
38 |
39 | crossposted = 1 << 0
40 | """The message is crossposted to following channels."""
41 |
42 | is_crosspost = 1 << 1
43 | """The message is a crosspost from another channel."""
44 |
45 | suppress_embeds = 1 << 2
46 | """The message does not include any embeds."""
47 |
48 | source_message_deleted = 1 << 3
49 | """The source message for a crosspost message is deleted."""
50 |
51 | urgent = 1 << 4
52 | """The message is an urgent message from system."""
53 |
54 | has_thread = 1 << 5
55 | """The message has a thread associated to tit."""
56 |
57 | ephemeral = 1 << 6
58 | """The message is an ephemeral message, in response to interaction."""
59 |
60 | loading = 1 << 7
61 | """The message is an interaction response and application is in "Thinking" state."""
62 |
63 | thread_role_mention_failed = 1 << 8
64 | """This message failed to mention some roles and add their members in a thread."""
65 |
--------------------------------------------------------------------------------
/qord/flags/permissions.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.base import Flags
26 |
27 |
28 | __all__ = (
29 | "Permissions",
30 | )
31 |
32 |
33 | class Permissions(Flags):
34 | r"""A class that provides rich interface for manipulating permissions bitwise value.
35 |
36 | This class subclasses :class:`Flags`. See it's documentation for more info about
37 | using this class for working with permissions.
38 | """
39 |
40 | create_instant_invite = 1 << 0
41 | r"""Allows creating instant guild or channel invites."""
42 |
43 | kick_members = 1 << 1
44 | r"""Allows kicking other members from a guild."""
45 |
46 | ban_members = 1 << 2
47 | r"""Allows banning other members from a guild."""
48 |
49 | administrator = 1 << 3
50 | r"""Bypasses all permissions.
51 |
52 | Members with this permission enabled have all permissions enabled
53 | and they bypass all permission overwrites.
54 | """
55 |
56 | manage_channels = 1 << 4
57 | r"""Allows management of the guild channels."""
58 |
59 | manage_guild = 1 << 5
60 | r"""Allows management of the guild settings including adding bots."""
61 |
62 | add_reactions = 1 << 6
63 | r"""Allows the addition of reactions on messages."""
64 |
65 | view_audit_log = 1 << 7
66 | r"""Allows viewing of the guild's audit log."""
67 |
68 | priority_speaker = 1 << 8
69 | r"""Allows usage of priority speaker in a guild voice channel."""
70 |
71 | stream = 1 << 9
72 | r"""Allows live streaming in a voice channel."""
73 |
74 | view_channel = 1 << 10
75 | r"""Allows viewing guild channel."""
76 |
77 | send_messages = 1 << 11
78 | r"""Allows to send messages in text channels."""
79 |
80 | send_tts_messages = 1 << 12
81 | r"""Allows the users to send TTS messages through ``/tts`` command."""
82 |
83 | manage_messages = 1 << 13
84 | r"""Allows management of messages."""
85 |
86 | embed_links = 1 << 14
87 | r"""Allows usage of embedded links in the messages."""
88 |
89 | attach_files = 1 << 15
90 | r"""Allows attaching files to the messages."""
91 |
92 | read_message_history = 1 << 16
93 | r"""Allows reading a text channel's message history."""
94 |
95 | mention_everyone = 1 << 17
96 | r"""Allows mentioning the @everyone and @here roles."""
97 |
98 | use_external_emojis = 1 << 18
99 | r"""Allows usage of emojis from other guilds."""
100 |
101 | view_guild_insights = 1 << 19
102 | r"""Allows viewing the guild's insights data."""
103 |
104 | connect = 1 << 20
105 | r"""Allows joining a voice or stage channel."""
106 |
107 | speak = 1 << 21
108 | r"""Allows speaking in a voice channel."""
109 |
110 | mute_members = 1 << 22
111 | r"""Allows muting members in a voice channel."""
112 |
113 | deafen_members = 1 << 23
114 | r"""Allows deafening members in a voice channel."""
115 |
116 | move_members = 1 << 24
117 | r"""Allows moving and removing members from a voice channel."""
118 |
119 | use_vad = 1 << 25
120 | r"""Allows usage of voice activity detection in a voice channel."""
121 |
122 | change_nickname = 1 << 26
123 | r"""Allows changing own username in the guild."""
124 |
125 | manage_nicknames = 1 << 27
126 | r"""Allows changing other members nickname in a guild."""
127 |
128 | manage_roles = 1 << 28
129 | r"""Allows management of guild roles."""
130 |
131 | manage_permissions = manage_roles
132 | r"""An alias for :attr:`.manage_roles`."""
133 |
134 | manage_webhooks = 1 << 29
135 | r"""Allows management of guild webhooks."""
136 |
137 | manage_emojis_and_stickers = 1 << 30
138 | r"""Allows management of emojis and stickers of a guild."""
139 |
140 | use_application_commands = 1 << 31
141 | r"""Allows usage of application commands in a guild."""
142 |
143 | request_to_speak = 1 << 32
144 | r"""Allows requesting to speak in a stage channel."""
145 |
146 | manage_events = 1 << 33
147 | r"""Allows management of guild scheduled events."""
148 |
149 | manage_threads = 1 << 34
150 | r"""Allows management of threads."""
151 |
152 | create_public_threads = 1 << 35
153 | r"""Allows creation of public or news threads."""
154 |
155 | create_private_threads = 1 << 36
156 | r"""Allows creation of private threads."""
157 |
158 | use_external_stickers = 1 << 37
159 | r"""Allows usage of external stickers."""
160 |
161 | send_messages_in_threads = 1 << 38
162 | r"""Allows sending of messages in therads."""
163 |
164 | start_embedded_activities = 1 << 39
165 | r"""Allows starting embedded activities in a voice channel."""
166 |
167 | moderate_members = 1 << 40
168 | r"""Allows moderating members including managing members timeout."""
169 |
170 | @classmethod
171 | def all(cls) -> Permissions:
172 | """Creates a :class:`Permissions` instance with all permissions enabled."""
173 | return cls(2199023255551)
174 |
--------------------------------------------------------------------------------
/qord/flags/system_channel.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.base import Flags
26 |
27 |
28 | __all__ = (
29 | "SystemChannelFlags",
30 | )
31 |
32 |
33 | class SystemChannelFlags(Flags):
34 | r""":class:`Flags` subclass that details the flags for a guild's system channel."""
35 |
36 | suppress_join_notifications = 1 << 0
37 | r"""Whether system channel will not receive a random message when a member joins."""
38 |
39 | suppress_premium_subscriptions = 1 << 1
40 | r"""Whether system channel will not receive a notification when someone boosts the guild."""
41 |
42 | suppress_guild_reminders = 1 << 2
43 | r"""Whether system channel will not receive tips for setting up guilds."""
44 |
45 | suppress_join_notification_replies = 1 << 3
46 | r"""Whether messages sent on member join in system channel allow replying with stickers."""
47 |
--------------------------------------------------------------------------------
/qord/flags/users.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.flags.base import Flags
26 |
27 |
28 | __all__ = (
29 | "UserFlags",
30 | )
31 |
32 |
33 | class UserFlags(Flags):
34 | r""":class:`Flags` subclass that details the flags of a :class:`User`. This is mostly
35 | obtained using :attr:`User.flags` attribute.
36 |
37 | A user's flags include several things including the "badges" on the
38 | user's account etc.
39 | """
40 |
41 | staff = 1 << 0
42 | r"""User is a Discord employee/staff."""
43 |
44 | partner = 1 << 1
45 | r"""User is a owner of a partnered guild."""
46 |
47 | hypesquad = 1 << 2
48 | r"""User is a HypeSquad's events coordinator."""
49 |
50 | bug_hunter_level_1 = 1 << 3
51 | r"""User is a level 1 bug hunter."""
52 |
53 | hypesquad_bravery = 1 << 6
54 | r"""User is member of HypeSquad bravey house."""
55 |
56 | hypesquad_brilliance = 1 << 7
57 | r"""User is member of HypeSquad brilliance house."""
58 |
59 | hypesquad_brilliance = 1 << 8
60 | r"""User is member of HypeSquad balance house."""
61 |
62 | early_premium_supporter = 1 << 9
63 | r"""User is an early nitro supporter."""
64 |
65 | team = 1 << 10
66 | r"""User is a psuedo user, representing a team."""
67 |
68 | bug_hunter_level_2 = 1 << 14
69 | r"""User is a bug hunter of level 2."""
70 |
71 | verified_bot = 1 << 16
72 | r"""User is a verified bot."""
73 |
74 | verified_developer = 1 << 17
75 | r"""User is a "early" verified bot developer."""
76 |
77 | certified_moderator = 1 << 18
78 | r"""User is a certified Discord moderator."""
79 |
80 | bot_http_interactions = 1 << 19
81 | r"""The user (bot) only uses HTTPs for interactions."""
82 |
--------------------------------------------------------------------------------
/qord/internal/__init__.py:
--------------------------------------------------------------------------------
1 | """Non-public internal utilities used across the library.
2 |
3 | The classes and functions under this module are not meant to be touched by users.
4 | """
5 |
6 | __all__ = ()
7 |
--------------------------------------------------------------------------------
/qord/internal/context_managers.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 |
24 | from __future__ import annotations
25 |
26 | import asyncio
27 | import typing
28 |
29 | if typing.TYPE_CHECKING:
30 | from qord.bases import BaseMessageChannel
31 |
32 |
33 | class TypingContextManager:
34 | def __init__(self, channel: BaseMessageChannel) -> None:
35 | self.channel = channel
36 | self._typing = False
37 | self._task = None
38 |
39 | async def _typing_task(self) -> None:
40 | while self._typing:
41 | await self.channel.trigger_typing()
42 | # The typing indicator disappears after 9-10 seconds
43 | await asyncio.sleep(8)
44 |
45 | async def __aenter__(self) -> None:
46 | coro = self._typing_task()
47 | self._typing = True
48 | self._task = asyncio.create_task(coro)
49 |
50 | async def __aexit__(self, *args) -> None:
51 | self._typing = False
52 | task = self._task
53 |
54 | if task and not task.cancelled():
55 | task.cancel()
56 |
--------------------------------------------------------------------------------
/qord/internal/helpers.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 |
24 | from __future__ import annotations
25 |
26 | from qord.internal.undefined import UNDEFINED
27 |
28 | from datetime import datetime, timezone
29 | from base64 import b64encode
30 | import typing
31 |
32 |
33 | __all__ = (
34 | "BASE_CDN_URL",
35 | "BASIC_STATIC_EXTS",
36 | "BASIC_EXTS",
37 | "create_cdn_url",
38 | "get_optional_snowflake",
39 | "compute_shard_id",
40 | "get_image_data",
41 | "parse_iso_timestamp",
42 | )
43 |
44 |
45 | BASE_CDN_URL = "https://cdn.discordapp.com"
46 | BASIC_STATIC_EXTS = ["png", "jpg", "jpeg", "webp"]
47 | BASIC_EXTS = ["png", "jpg", "jpeg", "webp", "gif"]
48 |
49 | def create_cdn_url(path: str, extension: str, size: int = UNDEFINED, valid_exts: typing.List[str] = UNDEFINED):
50 | """Create a CDN URL with provided path, file extension and size."""
51 |
52 | if valid_exts is None:
53 | # Defaulting to general formats used on most endpoints which
54 | # are currently png, jpg, webp.
55 | # When using with endpoints that have special formats
56 | # consider passing the valid formats explicitly.
57 | valid_exts = BASIC_STATIC_EXTS
58 |
59 | if not extension.lower() in valid_exts:
60 | raise ValueError(f"Invalid image extension {extension!r}, Expected one of {', '.join(valid_exts)}")
61 |
62 | ret = f"{BASE_CDN_URL}{path}.{extension}"
63 |
64 | if size is not UNDEFINED:
65 | if size < 64 and size > 4096:
66 | raise ValueError("size must be between 64 and 4096. Got %s instead." % size)
67 | if not (size & (size-1) == 0) and (size != 0 and size-1 != 0):
68 | raise ValueError("size must be a power of 2 between 64 and 4096, %s is invalid." % size)
69 |
70 | return f"{ret}?size={size}"
71 |
72 | return ret
73 |
74 | def get_optional_snowflake(data: typing.Dict[str, typing.Any], key: str) -> typing.Optional[int]:
75 | """Helper to obtain optional or nullable snowflakes from a raw payload."""
76 | try:
77 | return int(data[key])
78 | except (KeyError, ValueError, TypeError):
79 | return None
80 |
81 | def compute_shard_id(guild_id: int, shards_count: int) -> int:
82 | """Computes shard ID for the provided guild ID with respect to given shards count."""
83 | return (guild_id >> 22) % shards_count
84 |
85 | def get_image_data(img_bytes: bytes) -> str:
86 | """Gets Data URI format for provided image bytes."""
87 |
88 | if img_bytes.startswith(b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"):
89 | content_type = "image/png"
90 | elif img_bytes[0:3] == b"\xff\xd8\xff" or img_bytes[6:10] in (b"JFIF", b"Exif"):
91 | content_type = "image/jpeg"
92 | elif img_bytes.startswith((b"\x47\x49\x46\x38\x37\x61", b"\x47\x49\x46\x38\x39\x61")):
93 | content_type = "image/gif"
94 | elif img_bytes.startswith(b"RIFF") and img_bytes[8:12] == b"WEBP":
95 | content_type = "image/webp"
96 | else:
97 | raise TypeError("Invalid image type was provided.")
98 |
99 | return f"data:{content_type};base64,{b64encode(img_bytes).decode('ascii')}"
100 |
101 | def parse_iso_timestamp(timestamp: str) -> datetime:
102 | """Parse ISO timestamp string to a datetime.datetime instance."""
103 | return datetime.fromisoformat(timestamp)
104 |
105 | def compute_creation_time(snowflake: int) -> datetime:
106 | """Computes the creation time of the given snowflake as UTC timezone aware datetime."""
107 | timestamp = ((snowflake >> 22) + 1420070400000) / 1000
108 | return datetime.fromtimestamp(timestamp, tz=timezone.utc)
109 |
110 | def compute_snowflake(time: datetime) -> int:
111 | """Computes the snowflake from given timestamp or datetime object."""
112 | return int(time.timestamp() * 1000 - 1420070400000) << 22
113 |
--------------------------------------------------------------------------------
/qord/internal/mixins.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.internal.helpers import compute_creation_time
26 |
27 | import typing
28 |
29 | if typing.TYPE_CHECKING:
30 | from datetime import datetime
31 |
32 |
33 | __all__ = (
34 | "Comparable",
35 | )
36 |
37 |
38 | class Comparable:
39 | __slots__ = ()
40 |
41 | id: int
42 |
43 | def __eq__(self, other: typing.Any) -> bool:
44 | return isinstance(other, self.__class__) and other.id == self.id
45 |
46 |
47 | class CreationTime:
48 | __slots__ = ()
49 |
50 | id: int
51 |
52 | @property
53 | def created_at(self) -> datetime:
54 | """The time when this entity was created.
55 |
56 | Returns
57 | -------
58 | :class:`datetime.datetime`
59 | UTC aware datetime object representing the creation time.
60 | """
61 | return compute_creation_time(self.id)
62 |
--------------------------------------------------------------------------------
/qord/internal/types.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import typing
26 |
27 | if typing.TYPE_CHECKING:
28 | from qord.models.channels import (
29 | TextChannel,
30 | DMChannel,
31 | VoiceChannel,
32 | )
33 |
34 |
35 | MessageChannelT = typing.Union["TextChannel", "DMChannel", "VoiceChannel"]
36 |
--------------------------------------------------------------------------------
/qord/internal/undefined.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | import typing
26 |
27 | __all__ = (
28 | "UNDEFINED",
29 | )
30 |
31 |
32 | class _Undefined:
33 | def __bool__(self) -> bool:
34 | return False
35 |
36 | def __eq__(self, o: object) -> bool:
37 | return False
38 |
39 | def __repr__(self) -> str:
40 | return "..."
41 |
42 | UNDEFINED: typing.Any = _Undefined()
43 | """A sentinel used at places where None is ambiguous"""
--------------------------------------------------------------------------------
/qord/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/izxxr/qord-legacy/6d92751efc76b1f0bbcc350eff30369cb5a1c51a/qord/models/__init__.py
--------------------------------------------------------------------------------
/qord/models/base.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from abc import ABC, abstractmethod
26 | import typing
27 |
28 | if typing.TYPE_CHECKING:
29 | from qord.core.client import Client
30 |
31 |
32 | __all__ = (
33 | "BaseModel",
34 | )
35 |
36 |
37 | class BaseModel(ABC):
38 | r"""Common base class for all other Discord models.
39 |
40 | It is important to note that most of Discord models are not meant
41 | to be initialized by the user. You should either obtain them by using
42 | relevant HTTPs methods or from cache when available.
43 | """
44 | __slots__ = ()
45 |
46 | _client: Client
47 |
48 | @property
49 | def client(self) -> Client:
50 | r"""The :class:`Client` that had instansiated this model."""
51 | return self._client
52 |
53 | @abstractmethod
54 | def _update_with_data(self, data: typing.Dict[str, typing.Any]) -> None:
55 | raise NotImplementedError
56 |
--------------------------------------------------------------------------------
/qord/models/stage_instances.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | from __future__ import annotations
24 |
25 | from qord.models.base import BaseModel
26 | from qord.internal.mixins import Comparable, CreationTime
27 | from qord.internal.undefined import UNDEFINED
28 | from qord.internal.helpers import get_optional_snowflake
29 |
30 | import typing
31 |
32 | if typing.TYPE_CHECKING:
33 | from qord.models.guilds import Guild
34 | from qord.models.channels import StageChannel
35 | from qord.models.scheduled_events import ScheduledEvent
36 |
37 |
38 | __all__ = (
39 | "StageInstance",
40 | )
41 |
42 |
43 | class StageInstance(BaseModel, Comparable, CreationTime):
44 | """Represents a live stage instace from a :class:`StageChannel`.
45 |
46 | |supports-comparison|
47 |
48 | Attributes
49 | ----------
50 | guild: :class:`Guild`
51 | The guild that the stage instance is live in.
52 | id: :class:`builtins.int`
53 | The ID of stage instance.
54 | channel_id: :class:`builtins.int`
55 | The ID of channel that the stage instance is live in.
56 | privacy_level: :class:`builtins.int`
57 | The privacy level of the stage instance, see :class:`StagePrivacyLevel` for
58 | all possible values for this attribute.
59 | topic: :class:`builtins.str`
60 | The topic of stage instance.
61 | scheduled_event_id: Optional[:class:`builtins.int`]
62 | The scheduled event's ID that is associated to the stage instance, if any.
63 | """
64 |
65 | if typing.TYPE_CHECKING:
66 | id: int
67 | channel_id: int
68 | guild_id: int
69 | privacy_level: int
70 | topic: str
71 | scheduled_event_id: typing.Optional[int]
72 |
73 | __slots__ = (
74 | "_client",
75 | "guild",
76 | "id",
77 | "channel_id",
78 | "guild_id",
79 | "topic",
80 | "privacy_level",
81 | "scheduled_event_id",
82 | )
83 |
84 | def __init__(self, data: typing.Dict[str, typing.Any], guild: Guild) -> None:
85 | self.guild = guild
86 | self._client = guild._client
87 | self._update_with_data(data)
88 |
89 | def _update_with_data(self, data: typing.Dict[str, typing.Any]) -> None:
90 | self.id = int(data["id"])
91 | self.channel_id = int(data["channel_id"])
92 | self.guild_id = data.get("guild_id", self.guild.id)
93 | self.topic = data.get("topic", "")
94 | self.privacy_level = data.get("privacy_level", 2)
95 | self.scheduled_event_id = get_optional_snowflake(data, "guild_scheduled_event_id")
96 |
97 | @property
98 | def channel(self) -> typing.Optional[StageChannel]:
99 | """Returns the stage channel associated to this stage instance.
100 |
101 | Returns
102 | -------
103 | Optional[:class:`StageChannel`]
104 | """
105 | # This shall always return StageChannel
106 | return self.guild._cache.get_channel(self.channel_id) # type: ignore
107 |
108 | @property
109 | def scheduled_event(self) -> typing.Optional[ScheduledEvent]:
110 | """Returns the scheduled event associated to the stage instance, if any.
111 |
112 | Returns
113 | -------
114 | Optional[:class:`ScheduledEvent`]
115 | """
116 | event_id = self.scheduled_event_id
117 |
118 | if event_id is None:
119 | return None
120 |
121 | return self.guild._cache.get_scheduled_event(event_id)
122 |
123 | async def delete(self, *, reason: typing.Optional[str] = None) -> None:
124 | """Deletes the stage instance.
125 |
126 | This operation requires the bot to be stage moderator, i.e has following
127 | permissions in the stage channel:
128 |
129 | - :attr:`~Permissions.manage_channels`
130 | - :attr:`~Permissions.move_members`
131 | - :attr:`~Permissions.mute_members`
132 |
133 | Parameters
134 | ----------
135 | reason: :class:`builtins.str`
136 | The reason for doing this action.
137 |
138 | Raises
139 | ------
140 | HTTPForbidden
141 | You are not allowed to do this.
142 | HTTPException
143 | The operation failed.
144 | """
145 | await self._client._rest.delete_stage_instance(
146 | channel_id=self.channel_id,
147 | reason=reason,
148 | )
149 |
150 | async def edit(
151 | self,
152 | topic: str = UNDEFINED,
153 | privacy_level: int = UNDEFINED,
154 | reason: typing.Optional[str] = None,
155 | ) -> None:
156 | """Edits the stage instance.
157 |
158 | This operation requires the bot to be stage moderator, i.e has following
159 | permissions in the stage channel:
160 |
161 | - :attr:`~Permissions.manage_channels`
162 | - :attr:`~Permissions.move_members`
163 | - :attr:`~Permissions.mute_members`
164 |
165 | Parameters
166 | ----------
167 | topic: :class:`builtins.str`
168 | The topic of this tage instance.
169 | privacy_level: :class:`builtins.int`
170 | The privacy level of stage instance, see :class:`StagePrivacyLevel` for
171 | all possible values.
172 | reason: :class:`builtins.str`
173 | The reason for doing this action.
174 |
175 | Raises
176 | ------
177 | HTTPForbidden
178 | You are not allowed to do this.
179 | HTTPException
180 | The operation failed.
181 | """
182 | json = {}
183 |
184 | if topic is not UNDEFINED:
185 | json["topic"] = topic
186 |
187 | if privacy_level is not UNDEFINED:
188 | json["privacy_level"] = privacy_level
189 |
190 | if json:
191 | data = await self._client._rest.edit_stage_instance(
192 | channel_id=self.channel_id,
193 | json=json,
194 | reason=reason,
195 | )
196 | self._update_with_data(data)
197 |
--------------------------------------------------------------------------------
/qord/project_info.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 |
24 | __version__ = "0.5.0a1"
25 | __license__ = "MIT"
26 | __notice__ = "Copyright (c) nerdguyahmad 2022-present. Under the MIT license."
27 | __author__ = "nerdguyahmad "
28 | __github__ = "https://github.com/nerdguyahmad/qord"
--------------------------------------------------------------------------------
/qord/utils.py:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | # Copyright (c) 2022 Izhar Ahmad
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 |
23 | """
24 | qord.utils
25 | ~~~~~~~~~~
26 |
27 | General utilities to aid in specific common tasks.
28 | """
29 |
30 | from __future__ import annotations
31 |
32 | from datetime import datetime
33 | import typing
34 |
35 |
36 | __all__ = (
37 | "create_timestamp",
38 | )
39 |
40 |
41 | def create_timestamp(
42 | time: typing.Optional[typing.Union[datetime, int, float]] = None,
43 | style: typing.Optional[str] = None,
44 | ) -> str:
45 |
46 | """Creates a markdown timestamp from the given datetime object or unix timestamp.
47 |
48 | Parameters
49 | ----------
50 | time: Optional[Union[:class:`datetime.datetime`, :class:`builtins.int`, :class:`builtins.float`]]
51 | The timestamp to use. If not given, The result of :meth:`datetime.datetime.now` is used.
52 | If a datetime object is given, The epoch timestamp would be extracted from it. If
53 | a float is given, It would be rounded of.
54 | style: :class:`builtins.str`
55 | The style for the timestamp. If not provided, The default style
56 | is used, See :class:`TimestampStyle` for all possible values.
57 |
58 | .. note::
59 | This parameter is not validated by the library in case Discord
60 | adds a new style. You should consider validating it yourself.
61 |
62 | Returns
63 | -------
64 | :class:`builtins.str`
65 | The created timestamp in proper format.
66 | """
67 | if time is None:
68 | time = round(datetime.now().timestamp())
69 | elif isinstance(time, datetime):
70 | time = round(time.timestamp())
71 | elif isinstance(time, float):
72 | time = round(time)
73 |
74 | if style is None:
75 | return f""
76 | else:
77 | return f""
78 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.8.1
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | with open("README.MD", "r", encoding="utf-8") as f:
4 | LONG_DESCRIPTION = f.read()
5 |
6 | VERSION = "0.5.0a1"
7 | GITHUB = "https://github.com/izxxr/qord"
8 | DOCUMENTATION = "https://qord.readthedocs.io"
9 | LICENSE = "MIT"
10 |
11 | with open("requirements.txt", "r") as f:
12 | REQUIREMENTS = f.readlines()
13 |
14 | while "\n" in REQUIREMENTS:
15 | REQUIREMENTS.remove("\n")
16 |
17 | PACKAGES = [
18 | "qord",
19 | "qord.core",
20 | "qord.events",
21 | "qord.flags",
22 | "qord.models",
23 | "qord.internal",
24 | "qord.dataclasses",
25 | ]
26 |
27 | setup(
28 | name="qord",
29 | author="izxxr",
30 | version=VERSION,
31 | license=LICENSE,
32 | url=GITHUB,
33 | project_urls={
34 | "Documentation": DOCUMENTATION,
35 | "Issue tracker": GITHUB + "/issues",
36 | },
37 | description='Python library for Discord API based around asyncio.',
38 | long_description=LONG_DESCRIPTION,
39 | long_description_content_type="text/markdown",
40 | include_package_data=True,
41 | install_requires=REQUIREMENTS,
42 | packages=PACKAGES,
43 | python_requires='>=3.8.0',
44 | classifiers=[
45 | 'Development Status :: 3 - Alpha',
46 | 'License :: OSI Approved :: MIT License',
47 | 'Intended Audience :: Developers',
48 | 'Natural Language :: English',
49 | 'Operating System :: OS Independent',
50 | 'Programming Language :: Python :: 3.8',
51 | 'Programming Language :: Python :: 3.9',
52 | 'Topic :: Internet',
53 | 'Topic :: Software Development :: Libraries',
54 | 'Topic :: Software Development :: Libraries :: Python Modules',
55 | 'Topic :: Utilities',
56 | 'Typing :: Typed',
57 | ]
58 | )
59 |
--------------------------------------------------------------------------------
/tests/test_embed.py:
--------------------------------------------------------------------------------
1 | """Tests for qord.Embed"""
2 |
3 | from qord.dataclasses.embeds import (
4 | Embed,
5 | EmbedAuthor,
6 | EmbedFooter,
7 | )
8 |
9 | import unittest
10 |
11 |
12 | class TestEmbeds(unittest.TestCase):
13 | def test_total_length(self):
14 | embed = Embed()
15 | embed.title = "*" * 952
16 | embed.description = "*" * 2048
17 |
18 | assert embed.total_length() == 3000
19 |
20 | embed.author = EmbedAuthor(name="*" * 1000)
21 | embed.footer = EmbedFooter(text="*" * 1000)
22 | embed.set_field(name="*" * 500, value="*" * 500)
23 |
24 | assert embed.total_length() == 6000
25 |
26 |
27 | if __name__ == "__main__":
28 | unittest.main()
29 |
--------------------------------------------------------------------------------
/tests/test_flags.py:
--------------------------------------------------------------------------------
1 | """Tests for qord.Flags"""
2 |
3 | from qord.flags.base import Flags
4 |
5 | import unittest
6 |
7 | class Permissions(Flags):
8 | send_messages = 1 << 0
9 | read_message_history = 1 << 1
10 | view_channel = 1 << 2
11 | manage_messages = 1 << 3
12 | manage_channels = 1 << 4
13 |
14 | class TestFlags(unittest.TestCase):
15 | def test_value(self) -> None:
16 | flags = Permissions(send_messages=True, manage_messages=True, manage_channels=False)
17 | assert flags.value == (Permissions.send_messages | Permissions.manage_messages)
18 |
19 | flags.value = (Permissions.send_messages | Permissions.manage_channels)
20 |
21 | assert flags.send_messages
22 | assert flags.manage_channels
23 |
24 | flags.view_channel = True
25 |
26 | assert flags.value == (
27 | Permissions.send_messages
28 | | Permissions.manage_channels
29 | | Permissions.view_channel
30 | )
31 |
32 | flags.view_channel = False
33 |
34 | assert flags.value == (
35 | Permissions.send_messages
36 | | Permissions.manage_channels
37 | )
38 |
39 |
40 | def test_comparison(self) -> None:
41 | flags = Permissions(send_messages=True, manage_messages=True)
42 | assert flags == Permissions(send_messages=True, manage_messages=True)
43 | assert flags > Permissions(send_messages=True)
44 | assert flags < Permissions(send_messages=True, manage_messages=True, manage_channels=True)
45 |
46 | if __name__ == "__main__":
47 | unittest.main()
--------------------------------------------------------------------------------
/tests/test_internal_helpers.py:
--------------------------------------------------------------------------------
1 | from qord.internal import helpers
2 | import datetime
3 | import unittest
4 |
5 | class TestInternalHelpers(unittest.TestCase):
6 | def test_compute_creation_time(self) -> None:
7 | snowflake = 175928847299117063
8 | creation_time = datetime.datetime(2016, 4, 30, 11, 18, 25, 796000, datetime.timezone.utc)
9 |
10 | assert helpers.compute_creation_time(snowflake) == creation_time
11 |
--------------------------------------------------------------------------------
/tests/test_permission_overwrite.py:
--------------------------------------------------------------------------------
1 | """Tests for qord.PermissionOverwrite"""
2 |
3 | from qord import PermissionOverwrite, Permissions
4 | import unittest
5 |
6 |
7 | class TestPermissionOverwrite(unittest.TestCase):
8 | def test_attrs_comparison(self):
9 | overwrite = PermissionOverwrite()
10 |
11 | overwrite.send_messages = True
12 | overwrite.manage_channels = False
13 |
14 | overwrite2 = PermissionOverwrite(send_messages=True, manage_channels=False)
15 | assert overwrite2 == overwrite
16 |
17 | def test_pairs(self):
18 | overwrite = PermissionOverwrite(
19 | manage_channels=True,
20 | manage_messages=True,
21 | send_messages=False,
22 | connect=False,
23 | )
24 |
25 | allow = Permissions(manage_channels=True, manage_messages=True)
26 | deny = Permissions(send_messages=True, connect=True)
27 |
28 | overwrite_allow, overwrite_deny = overwrite.permissions()
29 |
30 | assert overwrite_allow == allow
31 | assert overwrite_deny == deny
32 |
33 | overwrite_with_permissions = PermissionOverwrite.from_permissions(allow, deny)
34 | assert overwrite_with_permissions == overwrite
35 |
36 | if __name__ == "__main__":
37 | unittest.main()
--------------------------------------------------------------------------------
/tests/test_utils.py:
--------------------------------------------------------------------------------
1 | """Tests for qord.utils"""
2 |
3 | from qord import utils, TimestampStyle
4 |
5 | from datetime import datetime
6 | import unittest
7 |
8 |
9 | class TestUtils(unittest.TestCase):
10 | def test_create_timestamp(self) -> None:
11 | # March 27 2022, 15:07:43
12 | time_datetime = datetime(2022, 3, 27, 15, 7, 43)
13 | time_epoch = time_datetime.timestamp()
14 |
15 | timestamp = f""
16 | timestamp_styled = f""
17 |
18 | assert utils.create_timestamp(time_datetime) == timestamp
19 | assert utils.create_timestamp(time_epoch) == timestamp
20 | assert utils.create_timestamp(time_datetime, TimestampStyle.RELATIVE_TIME) == timestamp_styled
21 |
22 |
23 | if __name__ == "__main__":
24 | unittest.main()
--------------------------------------------------------------------------------