Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into feature/codemod-w…
Browse files Browse the repository at this point in the history
…ait-for-overloads
  • Loading branch information
shiftinv committed Sep 20, 2023
2 parents f92a984 + aee9260 commit fd56f51
Show file tree
Hide file tree
Showing 63 changed files with 894 additions and 609 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/semantic-pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: MIT

name: Validate PR Title

on:
pull_request_target:
types:
- opened
- reopened
- edited

permissions:
pull-requests: read

jobs:
validate-pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@c3cd5d1ea3580753008872425915e343e351ab54 # v5.2.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ venvs/
coverage.xml
__pypackages__/
.pdm.toml
.pdm-python
pdm.lock

!test_bot/locale/*.json
232 changes: 67 additions & 165 deletions CONTRIBUTING.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions changelog/1036.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make :class:`Interaction` and subtypes accept the bot type as a generic parameter to denote the type returned by the :attr:`~Interaction.bot` and :attr:`~Interaction.client` properties.
1 change: 1 addition & 0 deletions changelog/1046.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Log errors raised by :meth:`.ext.commands.Cog.cog_unload`.
1 change: 1 addition & 0 deletions changelog/1078.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``default_layout`` parameter to :meth:`Guild.create_forum_channel` and :meth:`ForumChannel.clone`.
1 change: 1 addition & 0 deletions changelog/1082.deprecate.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:meth:`Client.fetch_premium_sticker_packs` was renamed to :meth:`Client.fetch_sticker_packs`; the old name is deprecated.
1 change: 1 addition & 0 deletions changelog/1087.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make :attr:`CustomActivity.state` fall back to the provided :attr:`~CustomActivity.name`, simplifying setting a custom status.
1 change: 1 addition & 0 deletions changelog/1095.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``created_at`` property to :attr:`AutoModRule <AutoModRule.created_at>`, :attr:`ForumTag <ForumTag.created_at>`, :attr:`Integration <Integration.created_at>`, :attr:`StageInstance <StageInstance.created_at>`, and :attr:`Team <Team.created_at>`.
1 change: 1 addition & 0 deletions changelog/1096.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support ``integration_type`` field in :attr:`AuditLogEntry.extra` (for :attr:`~AuditLogAction.kick` and :attr:`~AuditLogAction.member_role_update` actions).
1 change: 1 addition & 0 deletions changelog/1098.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Overhaul and simplify `contribution guide <https://github.com/DisnakeDev/disnake/tree/master/CONTRIBUTING.md>`__.
1 change: 1 addition & 0 deletions changelog/1105.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Miscellaneous grammar/typo fixes for :doc:`api/audit_logs`.
1 change: 1 addition & 0 deletions changelog/687.feature.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support activity assets with ``mp:`` prefix in :attr:`Activity.large_image_url` and :attr:`Activity.small_image_url`, now returning the correct url.
1 change: 1 addition & 0 deletions changelog/687.feature.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Move asset properties from :class:`Activity` to all activity types: :attr:`~Game.large_image_url`, :attr:`~Game.small_image_url`, :attr:`~Game.large_image_text`, :attr:`~Game.small_image_text`.
1 change: 1 addition & 0 deletions changelog/808.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update the ``python -m disnake newcog`` template to include all missing special methods.
1 change: 1 addition & 0 deletions changelog/975.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Move the event listener system implementation from :class:`.ext.commands.Bot` to :class:`.Client`, making Clients able to have more than one listener per event type.
80 changes: 74 additions & 6 deletions disnake/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,35 +120,103 @@ def setup(bot):
bot.add_cog({name}(bot))
'''

# everything that is a _cog_special_method goes here.
_cog_extras = """
async def cog_load(self):
# (async) loading logic goes here
pass
def cog_unload(self):
# clean up logic goes here
pass
### Prefix Commands ###
async def cog_check(self, ctx):
# checks that apply to every command in here
# checks that apply to every prefix command in here
return True
async def bot_check(self, ctx):
# checks that apply to every command to the bot
# checks that apply to every prefix command to the bot
return True
async def bot_check_once(self, ctx):
# check that apply to every command but is guaranteed to be called only once
# check that apply to every prefix command but is guaranteed to be called only once
return True
async def cog_command_error(self, ctx, error):
# error handling to every command in here
# error handling to every prefix command in here
pass
async def cog_before_invoke(self, ctx):
# called before a command is called here
# called before a prefix command is called here
pass
async def cog_after_invoke(self, ctx):
# called after a command is called here
# called after a prefix command is called here
pass
### Slash Commands ###
# These are similar to the ones in the previous section, but for slash commands
async def cog_slash_command_check(self, inter):
return True
async def bot_slash_command_check(self, inter):
return True
async def bot_slash_command_check_once(self, inter):
return True
async def cog_slash_command_error(self, inter, error):
...
async def cog_before_slash_command_invoke(self, inter):
...
async def cog_after_slash_command_invoke(self, inter):
...
### Message (Context Menu) Commands ###
async def cog_message_command_check(self, inter):
return True
async def bot_message_command_check(self, inter):
return True
async def bot_message_command_check_once(self, inter):
return True
async def cog_message_command_error(self, inter, error):
...
async def cog_before_message_command_invoke(self, inter):
...
async def cog_after_message_command_invoke(self, inter):
...
### User (Context Menu) Commands ###
async def cog_user_command_check(self, inter):
return True
async def bot_user_command_check(self, inter):
return True
async def bot_user_command_check_once(self, inter):
return True
async def cog_user_command_error(self, inter, error):
...
async def cog_before_user_command_invoke(self, inter):
...
async def cog_after_user_command_invoke(self, inter):
...
"""


Expand Down
119 changes: 84 additions & 35 deletions disnake/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,63 @@ def end(self) -> Optional[datetime.datetime]:
def to_dict(self) -> ActivityPayload:
raise NotImplementedError

def _create_image_url(self, asset: str) -> Optional[str]:
# `asset` can be a simple ID (see `Activity._create_image_url`),
# or a string of the format `<prefix>:<id>`
prefix, _, asset_id = asset.partition(":")

if asset_id and (url_fmt := _ACTIVITY_URLS.get(prefix)):
return url_fmt.format(asset_id)
return None

@property
def large_image_url(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns a URL pointing to the large image asset of this activity, if applicable.
.. versionchanged:: 2.10
Moved from :class:`Activity` to base type, making this available to all activity types.
Additionally, supports dynamic asset urls using the ``mp:`` prefix now.
"""
try:
large_image = self.assets["large_image"]
except KeyError:
return None
else:
return self._create_image_url(large_image)

@property
def small_image_url(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns a URL pointing to the small image asset of this activity, if applicable.
.. versionchanged:: 2.10
Moved from :class:`Activity` to base type, making this available to all activity types.
Additionally, supports dynamic asset urls using the ``mp:`` prefix now.
"""
try:
small_image = self.assets["small_image"]
except KeyError:
return None
else:
return self._create_image_url(small_image)

@property
def large_image_text(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns the large image asset hover text of this activity, if applicable.
.. versionchanged:: 2.10
Moved from :class:`Activity` to base type, making this available to all activity types.
"""
return self.assets.get("large_text", None)

@property
def small_image_text(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns the small image asset hover text of this activity, if applicable.
.. versionchanged:: 2.10
Moved from :class:`Activity` to base type, making this available to all activity types.
"""
return self.assets.get("small_text", None)


# tag type for user-settable activities
class BaseActivity(_BaseActivity):
Expand All @@ -160,6 +217,15 @@ class BaseActivity(_BaseActivity):
__slots__ = ()


# There are additional urls for twitch/youtube/spotify, however
# it appears that Discord does not want to document those:
# https://github.com/discord/discord-api-docs/pull/4617
# They are partially supported by different properties, e.g. `Spotify.album_cover_url`.
_ACTIVITY_URLS = {
"mp": "https://media.discordapp.net/{}",
}


class Activity(BaseActivity):
"""Represents an activity in Discord.
Expand Down Expand Up @@ -320,41 +386,17 @@ def to_dict(self) -> Dict[str, Any]:
ret["timestamps"] = self._timestamps
return ret

@property
def large_image_url(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns a URL pointing to the large image asset of this activity, if applicable."""
if self.application_id is None:
return None
def _create_image_url(self, asset: str) -> Optional[str]:
# if parent method already returns valid url, use that
if url := super()._create_image_url(asset):
return url

try:
large_image = self.assets["large_image"]
except KeyError:
return None
else:
return f"{Asset.BASE}/app-assets/{self.application_id}/{large_image}.png"

@property
def small_image_url(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns a URL pointing to the small image asset of this activity, if applicable."""
if self.application_id is None:
return None
# if it's not a `<prefix>:<id>` asset and we have an application ID, create url
if ":" not in asset and self.application_id:
return f"{Asset.BASE}/app-assets/{self.application_id}/{asset}.png"

try:
small_image = self.assets["small_image"]
except KeyError:
return None
else:
return f"{Asset.BASE}/app-assets/{self.application_id}/{small_image}.png"

@property
def large_image_text(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns the large image asset hover text of this activity, if applicable."""
return self.assets.get("large_text", None)

@property
def small_image_text(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns the small image asset hover text of this activity, if applicable."""
return self.assets.get("small_text", None)
# else, it's an unknown asset url
return None


class Game(BaseActivity):
Expand Down Expand Up @@ -754,6 +796,8 @@ class CustomActivity(BaseActivity):
The custom activity's name.
emoji: Optional[:class:`PartialEmoji`]
The emoji to pass to the activity, if any.
This currently cannot be set by bots.
"""

__slots__ = ("name", "emoji", "state")
Expand All @@ -768,7 +812,10 @@ def __init__(
) -> None:
super().__init__(**kwargs)
self.name: Optional[str] = name
self.state: Optional[str] = state
# Fall back to `name`, since `state` is the relevant field for custom status (`name` is not shown)
self.state: Optional[str] = state or name

# The official client uses "Custom Status" as the name, the actual name is in `state`
if self.name == "Custom Status":
self.name = self.state

Expand Down Expand Up @@ -862,7 +909,9 @@ def create_activity(

activity: ActivityTypes
game_type = try_enum(ActivityType, data.get("type", -1))
if game_type is ActivityType.playing and not ("application_id" in data or "session_id" in data):
if game_type is ActivityType.playing and not (
"application_id" in data or "session_id" in data or "state" in data
):
activity = Game(**data) # type: ignore # pyright bug(?)
elif game_type is ActivityType.custom and "name" in data:
activity = CustomActivity(**data) # type: ignore
Expand Down
Loading

0 comments on commit fd56f51

Please sign in to comment.