Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Localisation support. #686

Merged
merged 26 commits into from
Apr 2, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7d379f4
chore: release 4.1.0 (#542)
i0bs Feb 24, 2022
210573d
docs: add migration docs for 4.1
i0bs Feb 25, 2022
b2c1bad
docs: detail message content intent in migration
i0bs Feb 25, 2022
2afad6f
Merge branch 'unstable' into stable
i0bs Feb 25, 2022
ba46278
Merge branch 'unstable' into stable
i0bs Feb 25, 2022
a19ec99
Merge branch 'unstable' into stable
i0bs Feb 25, 2022
511dfe8
ADMIN/chore: finish catchup from rebase (#573)
i0bs Feb 25, 2022
6cc6333
ADMIN/chore: finish catchup from rebase (#573) (#574)
i0bs Feb 25, 2022
d443d7d
chore: pre-release 4.1.1-beta.1 (#603)
i0bs Mar 1, 2022
711ae0f
chore!: pre-release 4.1.1-beta.2 (#652)
i0bs Mar 23, 2022
d6f28b7
feat: Implement Localisation for name and description of application …
FayeDel Mar 29, 2022
f2830cb
feat: Implemented HTTP 50x error tracking, per-route exhaust ratelimi…
FayeDel Mar 29, 2022
460328a
refactor: Delete extra Locale object, tweak current Locale object acc…
FayeDel Mar 29, 2022
7ee564c
feat: Implement localisation support for Options and Choices, include…
FayeDel Mar 29, 2022
ea95732
fix: Fix listener/command invocation on extension reload/removal.
FayeDel Mar 29, 2022
8873ada
fix: Fix timestamp assignment on Embed objects on non-declaration.
FayeDel Mar 29, 2022
a52cf8e
chore: Repoint OpenCollective URL.
FayeDel Mar 29, 2022
c8af8bd
fix: Adjust Locale object support for .pyi headers.
FayeDel Mar 31, 2022
2dcf18c
Merge branch 'interactions-py:stable' into unstable_core_3
FayeDel Mar 31, 2022
c03c0ab
Merge remote-tracking branch 'origin/unstable' into unstable
FayeDel Mar 31, 2022
0ac9bc2
chore: attempt of rebase
FayeDel Mar 31, 2022
9ce0568
fix!: Fix circular import from commit c54a35c.
FayeDel Apr 2, 2022
33d2f3f
feat: Implement new guild ban parameter requirement.
FayeDel Apr 2, 2022
a611a27
feat: Extend __check_command to name localisations per command/option
FayeDel Apr 2, 2022
11e5a51
refactor: Refactor Embed timestamp definition by relying on __setattr__
FayeDel Apr 2, 2022
d7d218e
revert: Partially revert f2830cb by removing 50x error tracking, refa…
FayeDel Apr 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# These are supported funding model platforms

github: [goverfl0w]
open_collective: discordinteractions
open_collective: interactions-py
17 changes: 15 additions & 2 deletions interactions/api/http/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ async def request(self, route: Route, **kwargs) -> Optional[Any]:
"""

kwargs["headers"] = {**self._headers, **kwargs.get("headers", {})}
kwargs["headers"]["Content-Type"] = "application/json"
if kwargs.get("json"):
kwargs["headers"]["Content-Type"] = "application/json"

reason = kwargs.pop("reason", None)
if reason:
Expand Down Expand Up @@ -165,7 +166,7 @@ async def request(self, route: Route, **kwargs) -> Optional[Any]:
# This "redundant" debug line is for debug use and tracing back the error codes.

raise HTTPException(data["code"], message=data["message"])
elif remaining and not int(remaining):
if remaining and not int(remaining):
if response.status == 429:
log.warning(
f"The HTTP client has encountered a per-route ratelimit. Locking down future requests for {reset_after} seconds."
Expand All @@ -181,6 +182,18 @@ async def request(self, route: Route, **kwargs) -> Optional[Any]:
self._loop.call_later(
self._global_lock.reset_after, self._global_lock.lock.release
)
elif int(remaining) == 0:
log.warning(
f"The HTTP client has exhausted a per-route ratelimit. Locking route for {reset_after} seconds."
)
self._loop.call_later(reset_after, _limiter.release_lock())

if response.status in {500, 502, 504}:
log.warning(
f"{route.endpoint} Received {response.status}... retrying in {1 + tries * 2} seconds"
)
await asyncio.sleep(1 + tries * 2)
continue

log.debug(f"RETURN {response.status}: {dumps(data, indent=4, sort_keys=True)}")

Expand Down
16 changes: 10 additions & 6 deletions interactions/api/models/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -1026,11 +1026,16 @@ class Embed(DictSerializerMixin):

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.timestamp = (
datetime.fromisoformat(self._json.get("timestamp"))
if self._json.get("timestamp")
else datetime.utcnow()
)
if self._json.get("timestamp"):
if isinstance(self._json.get("timestamp"), str):
self.timestamp = datetime.fromisoformat(
self._json.get("timestamp")
) # readability on non `_json` attr.
elif isinstance(self._json.get("timestamp"), datetime):
self._json["timestamp"] = str(
self._json.get("timestamp")
) # converts to isoformat for API.

FayeDel marked this conversation as resolved.
Show resolved Hide resolved
self.footer = EmbedFooter(**self.footer) if isinstance(self.footer, dict) else self.footer
self.image = EmbedImageStruct(**self.image) if isinstance(self.image, dict) else self.image
self.thumbnail = (
Expand All @@ -1048,7 +1053,6 @@ def __init__(self, **kwargs):
if self._json.get("fields")
else None
)

# (Complete partial fix.)
# The issue seems to be that this itself is not updating
# JSON result correctly. After numerous attempts I seem to
Expand Down
22 changes: 19 additions & 3 deletions interactions/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .base import get_logger
from .decor import command
from .decor import component as _component
from .enums import ApplicationCommandType, OptionType
from .enums import ApplicationCommandType, Locale, OptionType
from .models.command import ApplicationCommand, Option
from .models.component import Button, Modal, SelectMenu

Expand Down Expand Up @@ -557,6 +557,8 @@ def command(
options: Optional[
Union[Dict[str, Any], List[Dict[str, Any]], Option, List[Option]]
] = MISSING,
name_localizations: Optional[Dict[Union[str, Locale], str]] = MISSING,
FayeDel marked this conversation as resolved.
Show resolved Hide resolved
description_localizations: Optional[Dict[Union[str, Locale], str]] = MISSING,
default_permission: Optional[bool] = MISSING,
) -> Callable[..., Any]:
"""
Expand Down Expand Up @@ -596,6 +598,10 @@ 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 name_localizations?: The dictionary of localization for the ``name`` field. This enforces the same restrictions as the ``name`` field.
:param name_localizations: Optional[Dict[Union[str, Locale], str]]
:param description_localizations?: The dictionary of localization for the ``description`` field. This enforces the same restrictions as the ``description`` field.
:param description_localizations: Optional[Dict[Union[str, Locale], str]]
:return: A callable response.
:rtype: Callable[..., Any]
"""
Expand All @@ -609,6 +615,8 @@ def decorator(coro: Coroutine) -> Callable[..., Any]:
scope=scope,
options=options,
default_permission=default_permission,
name_localizations=name_localizations,
description_localizations=description_localizations,
)
self.__check_command(command=ApplicationCommand(**commands[0]), coro=coro)

Expand Down Expand Up @@ -637,6 +645,7 @@ def message_command(
name: str,
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = MISSING,
default_permission: Optional[bool] = MISSING,
name_localizations: Optional[Dict[Union[str, Locale], Any]] = MISSING,
) -> Callable[..., Any]:
"""
A decorator for registering a message context menu to the Discord API,
Expand All @@ -660,6 +669,8 @@ async def context_menu_name(ctx):
:type scope: Optional[Union[int, Guild, List[int], List[Guild]]]
:param default_permission?: The default permission of accessibility for the application command. Defaults to ``True``.
:type default_permission: Optional[bool]
:param name_localizations?: The dictionary of localization for the ``name`` field. This enforces the same restrictions as the ``name`` field.
:param name_localizations: Optional[Dict[Union[str, Locale], str]]
:return: A callable response.
:rtype: Callable[..., Any]
"""
Expand All @@ -671,6 +682,7 @@ def decorator(coro: Coroutine) -> Callable[..., Any]:
name=name,
scope=scope,
default_permission=default_permission,
name_localizations=name_localizations,
)
self.__check_command(ApplicationCommand(**commands[0]), coro)

Expand All @@ -693,6 +705,7 @@ def user_command(
name: str,
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = MISSING,
default_permission: Optional[bool] = MISSING,
name_localizations: Optional[Dict[Union[str, Locale], Any]] = MISSING,
) -> Callable[..., Any]:
"""
A decorator for registering a user context menu to the Discord API,
Expand All @@ -716,6 +729,8 @@ async def context_menu_name(ctx):
:type scope: Optional[Union[int, Guild, List[int], List[Guild]]]
:param default_permission?: The default permission of accessibility for the application command. Defaults to ``True``.
:type default_permission: Optional[bool]
:param name_localizations?: The dictionary of localization for the ``name`` field. This enforces the same restrictions as the ``name`` field.
:param name_localizations: Optional[Dict[Union[str, Locale], str]]
:return: A callable response.
:rtype: Callable[..., Any]
"""
Expand All @@ -727,6 +742,7 @@ def decorator(coro: Coroutine) -> Callable[..., Any]:
name=name,
scope=scope,
default_permission=default_permission,
name_localizations=name_localizations,
)

self.__check_command(ApplicationCommand(**commands[0]), coro)
Expand Down Expand Up @@ -1194,11 +1210,11 @@ def __new__(cls, client: Client, *args, **kwargs) -> "Extension":
def teardown(self):
for event, funcs in self._listeners.items():
for func in funcs:
self.client._websocket.dispatch.events[event].remove(func)
self.client._websocket._dispatch.events[event].remove(func)

for cmd, funcs in self._commands.items():
for func in funcs:
self.client._websocket.dispatch.events[cmd].remove(func)
self.client._websocket._dispatch.events[cmd].remove(func)

clean_cmd_names = [cmd[7:] for cmd in self._commands.keys()]
cmds = filter(
Expand Down
4 changes: 4 additions & 0 deletions interactions/client.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,24 @@ class Client:
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = MISSING,
options: Optional[List[Option]] = MISSING,
default_permission: Optional[bool] = MISSING,
name_localizations: Optional[Dict[str, str]] = MISSING,
description_localizations: Optional[Dict[str, str]] = MISSING,
FayeDel marked this conversation as resolved.
Show resolved Hide resolved
) -> Callable[..., Any]: ...
def message_command(
self,
*,
name: str,
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = MISSING,
default_permission: Optional[bool] = MISSING,
name_localizations: Optional[Dict[str, str]] = MISSING,
FayeDel marked this conversation as resolved.
Show resolved Hide resolved
) -> Callable[..., Any]: ...
def user_command(
self,
*,
name: str,
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = MISSING,
default_permission: Optional[bool] = MISSING,
name_localizations: Optional[Dict[str, str]] = MISSING,
FayeDel marked this conversation as resolved.
Show resolved Hide resolved
) -> Callable[..., Any]: ...
def component(self, component: Union[Button, SelectMenu]) -> Callable[..., Any]: ...
def autocomplete(
Expand Down
21 changes: 20 additions & 1 deletion interactions/decor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from .api.models.guild import Guild
from .api.models.misc import MISSING
from .enums import ApplicationCommandType
from .enums import ApplicationCommandType, Locale
from .models.command import ApplicationCommand, Option
from .models.component import Button, Component, SelectMenu

Expand All @@ -15,6 +15,8 @@ def command(
scope: Optional[Union[int, Guild, List[int], List[Guild]]] = MISSING,
options: Optional[Union[Dict[str, Any], List[Dict[str, Any]], Option, List[Option]]] = MISSING,
default_permission: Optional[bool] = MISSING,
name_localizations: Optional[Dict[Union[str, Locale], str]] = MISSING,
description_localizations: Optional[Dict[Union[str, Locale], str]] = MISSING,
) -> List[ApplicationCommand]:
"""
A wrapper designed to interpret the client-facing API for
Expand All @@ -32,6 +34,19 @@ def command(
_description: str = "" if description is MISSING else description
_options: list = []

_name_localizations = (
{}
if name_localizations is MISSING
else {k.value if isinstance(k, Locale) else k: v for k, v in name_localizations.items()}
)
_description_localizations = (
{}
if description_localizations is MISSING
else {
k.value if isinstance(k, Locale) else k: v for k, v in description_localizations.items()
}
)

if options is not MISSING:
if all(isinstance(option, Option) for option in options):
_options = [option._json for option in options]
Expand Down Expand Up @@ -68,6 +83,8 @@ def command(
description=_description,
options=_options,
default_permission=_default_permission,
name_localizations=_name_localizations,
description_localizations=_description_localizations,
)
payloads.append(payload._json)
else:
Expand All @@ -77,6 +94,8 @@ def command(
description=_description,
options=_options,
default_permission=_default_permission,
name_localizations=_name_localizations,
description_localizations=_description_localizations,
)
payloads.append(payload._json)

Expand Down
2 changes: 2 additions & 0 deletions interactions/decor.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ 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,
name_localizations: Optional[Dict[str, str]] = None,
FayeDel marked this conversation as resolved.
Show resolved Hide resolved
description_localizations: Optional[Dict[str, str]] = None,
FayeDel marked this conversation as resolved.
Show resolved Hide resolved
) -> List[ApplicationCommand]: ...
def component(component: Union[Button, SelectMenu]) -> Component: ...
2 changes: 1 addition & 1 deletion interactions/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class Locale(str, Enum):
PORTUGUESE_BRAZIL = "pt-BR"
ROMANIAN = "ro"
RUSSIAN = "ru"
SPANISH_SPAIN = "es-ES"
SPANISH = "es-ES"
SWEDISH = "sv-SE"
THAI = "th"
TURKISH = "tr"
Expand Down