Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
633121f
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Dec 13, 2021
17a8b09
fix(context)!: include member into component slotting.
i0bs Dec 13, 2021
d022a5d
fix(component): correct component reading for action rows.
i0bs Dec 13, 2021
d3af62c
fix: components not respecting subinheritance.
i0bs Dec 13, 2021
3d263b2
feat: change logging level `WARNING` and allow set log level.
i0bs Dec 13, 2021
a276346
chore: Update README
i0bs Dec 14, 2021
9a5b64e
Update README.rst
i0bs Dec 14, 2021
4657eec
Merge pull request #377 from goverfl0w/pre-commit-ci-update-config
i0bs Dec 14, 2021
d5302d5
chore: remove unneeded kwargs
i0bs Dec 14, 2021
ecac6cc
Update readthedocs.yaml
i0bs Dec 14, 2021
2ab6a0f
fix: python requirement for RTD + dependencies
i0bs Dec 14, 2021
b8d7c16
fix!: remove PDF LaTeX building
i0bs Dec 14, 2021
d5287da
fix(context)!: guild/channel ID snowflake checks.
i0bs Dec 14, 2021
fba68dc
Merge branch 'stable' of https://github.com/discord-py-interactions/d…
i0bs Dec 14, 2021
e26433e
fix: member recursion error.
i0bs Dec 14, 2021
93eb27a
fix: include proper slots attr for components.
i0bs Dec 14, 2021
1d38962
make selects and buttons sendable
EepyElvyra Dec 15, 2021
14bcfd4
Update .gitignore
EepyElvyra Dec 15, 2021
ac7800c
fix weird behaviour of choices while command sync
EepyElvyra Dec 15, 2021
861e35f
added defer for components
EepyElvyra Dec 15, 2021
dd74c3f
added docstring to defer
EepyElvyra Dec 15, 2021
2dfd857
Merge branch 'unstable' into stable
EepyElvyra Dec 15, 2021
35d26b2
fix typo
EepyElvyra Dec 15, 2021
c941099
Merge branch 'stable' of https://github.com/EdVraz/discord-interactio…
EepyElvyra Dec 15, 2021
9f6517b
made actionrow work with selects
EepyElvyra Dec 16, 2021
87f8db6
changes for PR
EepyElvyra Dec 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
rev: v4.0.1
hooks:
- id: requirements-txt-fixer
name: Requirements
Expand All @@ -25,23 +25,23 @@ repos:
- id: check-merge-conflict
name: Merge Conflicts
- repo: https://github.com/psf/black
rev: 21.8b0
rev: 21.12b0
hooks:
- id: black
name: Black Formatting
language: python
types: [file, python]
args: [--line-length=100]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
name: flake8 Formatting
language: python
types: [file, python]
args: [--max-line-length=100, --ignore=E203 E501 E402 W503 W504]
- repo: https://github.com/pycqa/isort
rev: 5.9.3
rev: 5.10.1
hooks:
- id: isort
name: isort Formatting
Expand Down
94 changes: 62 additions & 32 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
discord-interactions
====================

**A simple API wrapper for Discord interactions.**
**Easy, simple, scalable and modular: a Python API wrapper for interactions.**

.. image:: https://img.shields.io/pypi/dm/discord-py-slash-command.svg
:target: https://pypi.python.org/pypi/discord-py-interactions/
Expand Down Expand Up @@ -30,48 +30,78 @@ discord-interactions

----

This library specializes in the ability to create and use interactions, a new
implementation to Discord's public API as of December 2020. The strong suits of using
our library are:
Ever since December 2019, this open-source project has become the culmination of dedication and research towards figuring out the best way to bring **interactions from Discord to you:** we are an easy, simple, scalable and modular library for Discord interactions.

- Modern pythonic design that is scalable and modular.
- Asynchronous coroutines and multi-threading capabilities.
- Optimal class object reference with little overhead.
- Easily accessible codebase source.
- Stable/unstable branches for managing module stability when importing.
- Tired of using numerous module dependencies for slash commands and buttons?
- Looking for a compatible library that implements all interactions?
- Itching to get your hands on slash commands, but in a simple manner?

This means that we're essentially good for:
Look no more! The goal of this library is to make all three of these questions go from possibilites to trivial matters.

- Working with application commands.
- Handling contextual data cached from text channels.
- General/basic assignment of guild properties to members.
- Responsive callbacks for buttons and select menus.
What can we do?
***************
Our library---inside and out, offers numerous benefits and presents itself as a worthy module in your bot's dependencies:

And we're not good for:
The base features of our library, built with our API include:

- Trying to use/connect as a voice client.
- Cooldowns/bucket types.
- **Dynamic object data generation**: all event data dispatched from the Gateway is dynamically transformed and generated into two-way serializable JSON objects.
- **Sane rate limiting**: our HTTP client implements pre-emptive rate limit avoidance, so your bot is guaranteed to never hit HTTP ``429``.
- **On-demand cache**: every HTTP request and Gateway event made is cached when needed, so you never have to save information yourself.
- **Simplified data models**: every object presented is accessible as either a raw dictionary/``application/json`` or list of recursive attributes.

============
Installation
============
Some more unique features that are exclusive to our interactions include:

Use this line to install our library:
- **Event-triggered callbacks**: whether a component, application command or interaction response, you'll never need to worry about bridging responses.
- **Dual-way decorator logic**: a decorator can act as both a constructor for an interaction, as well as a callback.
- **API-strict naming**: no more confusion with the naming approach of many libraries; we follow the naming style of interactions from the officially curated Discord Developers documentation.
- **Extensive framework structure**: (**pending in** ``4.1.0``) build your own tools and technologies for our library to develop and integrate community creations.

.. code-block:: bash
What do we not offer?
*********************
While we certainly offer a lot of benefits, we unfortunately have our own downsides:

pip install -U discord-py-interactions
.. note::
This list is subject to change as time goes on:
some of these items may be added to the core of
the library in the future.

----
- No native cooldown decorator/method.
- Lack of automatic sharding and voice clients.

Where do I start?
*****************
Please check out our `quickstart guide`_ for some basic examples.

How can I contribute?
*********************
Please read up on our `contribution requirements`_ for the project. This open-source project also enforces the `MIT License`_.

This open-source project utilizes the following workflows for development:

#. **pre-commit** ``2.16.0``: the architecture uses this before every commit to format and check for severity/QOL-breaking changes.

#. **black** ``21.11b1``
#. **flake8** ``3.9.2``
#. **isort** ``5.9.3``

#. **Sphinx** ``4.1.2``: all of our documentation is powered off of autogenerated documentation of the Sphinx engine.
#. **colorama** ``0.4.4``: our internal logger uses a customized coloring formatter to make looking for specific conditions easier when running tests.
#. **Conventional Commits** ``1.0.0``: every commit that we make to our branches use the official specification of CC 1.0.0 to make git graphs easier when improving and refining communication between code reviews, Pull Requests and commits.

- The discord-interactions library is based off of API gateway events. If you are
looking for a library that is webserver-based, please consider:
When can I start?
^^^^^^^^^^^^^^^^^
We also have some extra ground rules about making any specific contributions involving:

- `dispike <https://github.com/ms7m/dispike>`__
- `discord-interactions-python
<https://github.com/discord/discord-interactions-python>`__
- We do not accept abstraction-based requests. (e.g. ``colour`` for ``color``)
- A request has to be approved by at least one developer.
- You must be willing to change/adhere to reviews from participants **where necessary.**

- If you are looking for a similar library for other languages, please refer to here:
I think I'm all ready!
^^^^^^^^^^^^^^^^^^^^^^
Feel free to begin making `Pull Requests`_ and `Issues`_ on our GitHub!

- `Discord Developer Documentation
<https://discord.com/developers/docs/topics/community-resources#interactions>`__
.. _quickstart guide: https://discord-interactions.rtfd.io/en/latest/quickstart.html
.. _contribution requirements: https://github.com/goverfl0w/discord-interactions/blob/stable/CONTRIBUTING.md
.. _MIT License: https://github.com/goverfl0w/discord-interactions/blob/stable/LICENSE
.. _Pull Requests: https://github.com/goverfl0w/discord-interactions/pulls
.. _Issues: https://github.com/goverfl0w/discord-interactions/issues
69 changes: 42 additions & 27 deletions interactions/api/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
class Heartbeat(Thread):
"""
A class representing a consistent heartbeat connection with the gateway.

:ivar WebSocket ws: The WebSocket class to infer on.
:ivar Union[int, float] interval: The heartbeat interval determined by the gateway.
:ivar Event event: The multi-threading event.
Expand Down Expand Up @@ -79,7 +78,6 @@ def stop(self) -> None:
class WebSocket:
"""
A class representing a websocket connection with the gateway.

:ivar Intents intents: An instance of :class:`interactions.api.models.Intents`.
:ivar AbstractEventLoop loop: The coroutine event loop established on.
:ivar Request req: An instance of :class:`interactions.api.http.Request`.
Expand Down Expand Up @@ -151,7 +149,6 @@ async def connect(
) -> None:
"""
Establishes a connection to the gateway.

:param token: The token to use for identifying.
:type token: str
:param shard?: The shard ID to identify under.
Expand Down Expand Up @@ -181,7 +178,6 @@ async def handle_connection(
) -> None:
"""
Handles the connection to the gateway.

:param stream: The data stream from the gateway.
:type stream: dict
:param shard?: The shard ID to identify under.
Expand Down Expand Up @@ -243,7 +239,6 @@ async def handle_connection(
def handle_dispatch(self, event: str, data: dict) -> None:
"""
Handles the dispatched event data from a gateway event.

:param event: The name of the event.
:type event: str
:param data: The data of the event.
Expand Down Expand Up @@ -277,37 +272,25 @@ def handle_dispatch(self, event: str, data: dict) -> None:
context = self.contextualize(data)
_name: str
_args: list = [context]
_kwargs: dict = dict()
if data["type"] == InteractionType.APPLICATION_COMMAND:
_name = context.data.name
if hasattr(context.data, "options"):
if context.data.options:
for option in context.data.options:
if option["type"] in (
OptionType.SUB_COMMAND,
OptionType.SUB_COMMAND_GROUP,
):
if option.get("options"):
for sub_option in option["options"]:
_args.append(sub_option)
else:
pass
else:
_args.append(option["value"])
_kwargs.update(self.check_sub_command(option))
elif data["type"] == InteractionType.MESSAGE_COMPONENT:
_name = context.data.custom_id
elif data["type"] == InteractionType.APPLICATION_COMMAND_AUTOCOMPLETE:
_name = "autocomplete_"
if hasattr(context.data, "options"):
if context.data.options:
for option in context.data.options:
if option["type"] in (
OptionType.SUB_COMMAND,
OptionType.SUB_COMMAND_GROUP,
):
if option.get("options"):
for sub_option in option["options"]:
if sub_option.get("focused"):
_name += sub_option["name"]
add_name, add_args = self.check_sub_auto(option)
if add_name:
_name += add_name
if add_args:
_args.append(add_args)
elif data["type"] == InteractionType.MODAL_SUBMIT:
_name = f"modal_{context.data.custom_id}"
if hasattr(context.data, "components"):
Expand All @@ -316,15 +299,48 @@ def handle_dispatch(self, event: str, data: dict) -> None:
for _value in component.components:
_args.append(_value["value"])

self.dispatch.dispatch(_name, *_args)
self.dispatch.dispatch(_name, *_args, **_kwargs)

self.dispatch.dispatch("raw_socket_create", data)

def check_sub_command(self, option) -> dict:
_kwargs = dict()
if "options" in option:
if option["type"] == OptionType.SUB_COMMAND_GROUP:
_kwargs["sub_command_group"] = option["name"]
for group_option in option["options"]:
_kwargs["sub_command"] = group_option["name"]
if "options" in group_option:
for sub_option in group_option["options"]:
_kwargs[sub_option["name"]] = sub_option["value"]
elif option["type"] == OptionType.SUB_COMMAND:
_kwargs["sub_command"] = option["name"]
for sub_option in option["options"]:
_kwargs[sub_option["name"]] = sub_option["value"]
else:
_kwargs[option["name"]] = option["value"]

return _kwargs

def check_sub_auto(self, option) -> tuple:
if "options" in option:
if option["type"] == OptionType.SUB_COMMAND_GROUP:
for group_option in option["options"]:
if "options" in group_option:
for sub_option in option["options"]:
if sub_option.get("focused"):
return sub_option["name"], sub_option["value"]
elif option["type"] == OptionType.SUB_COMMAND:
for sub_option in option["options"]:
if sub_option.get("focused"):
return sub_option["name"], sub_option["value"]
elif option.get("focused"):
return option["name"], option["value"]

def contextualize(self, data: dict) -> object:
"""
Takes raw data given back from the gateway
and gives "context" based off of what it is.

:param data: The data from the gateway.
:type data: dict
:return: The context object.
Expand Down Expand Up @@ -358,7 +374,6 @@ async def identify(
) -> None:
"""
Sends an ``IDENTIFY`` packet to the gateway.

:param shard?: The shard ID to identify under.
:type shard: Optional[int]
:param presence?: The presence to change the bot to on identify.
Expand Down
2 changes: 2 additions & 0 deletions interactions/api/gateway.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ class WebSocket:
) -> None: ...
async def resume(self) -> None: ...
async def heartbeat(self) -> None: ...
def check_sub_auto(self, option) -> tuple: ...
def check_sub_command(self, option) -> dict: ...
2 changes: 1 addition & 1 deletion interactions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
class Data:
"""A class representing constants for the library."""

LOGGER: ClassVar[int] = logging.DEBUG
LOGGER: ClassVar[int] = logging.WARNING


class CustomFormatter(logging.Formatter):
Expand Down
9 changes: 3 additions & 6 deletions interactions/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def __init__(
else:
self.automate_sync = True

Data.LOGGER = log_level
log_names: list = ["client", "context", "dispatch", "gateway", "http"]
for logger in log_names:
getLogger(logger).setLevel(log_level)

if not self.me:
data = self.loop.run_until_complete(self.http.get_current_bot_information())
Expand Down Expand Up @@ -289,9 +291,6 @@ def command(
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = None,
options: Optional[Union[Dict[str, Any], List[Dict[str, Any]], Option, List[Option]]] = None,
default_permission: Optional[bool] = None,
# permissions: Optional[
# Union[Dict[str, Any], List[Dict[str, Any]], Permission, List[Permission]]
# ] = None,
) -> Callable[..., Any]:
"""
A decorator for registering an application command to the Discord API,
Expand Down Expand Up @@ -330,8 +329,6 @@ async def message_command(ctx):
:type options: Optional[Union[Dict[str, Any], List[Dict[str, Any]], Option, List[Option]]]
:param default_permission?: The default permission of accessibility for the application command. Defaults to ``True``.
:type default_permission: Optional[bool]
:param permissions: The permissions of an application command.
:type permissions: Optional[Union[Dict[str, Any], List[Dict[str, Any]], Permission, List[Permission]]]
:return: A callable response.
:rtype: Callable[..., Any]
"""
Expand Down
4 changes: 0 additions & 4 deletions interactions/client.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class Client:
async def ready(self) -> None: ...
async def synchronize(self, payload: Optional[ApplicationCommand] = None) -> None: ...
def event(self, coro: Coroutine, name: Optional[str] = None) -> Callable[..., Any]: ...
def __process_options(self, coro: Callable) -> List: ...
def command(
self,
*,
Expand All @@ -51,9 +50,6 @@ class Client:
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = None,
options: Optional[List[Option]] = None,
default_permission: Optional[bool] = None,
# permissions: Optional[
# Union[Dict[str, Any], List[Dict[str, Any]], Permission, List[Permission]]
# ] = None
) -> Callable[..., Any]: ...
def component(self, component: Union[Button, SelectMenu]) -> Callable[..., Any]: ...
def autocomplete(self, name: str) -> Callable[..., Any]: ...
Expand Down
Loading