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

refactor: nextcord.Interaction subclassing #970

Open
wants to merge 69 commits into
base: master
Choose a base branch
from

Conversation

Gangsta-Muffin
Copy link

@Gangsta-Muffin Gangsta-Muffin commented Jan 9, 2023

Summary

PR for #952

Create Subclasses for nextcord.Interaction

Subclasses will include:

ApplicationCommandInteraction
Interaction object for application commands

ApplicationAutocompleteInteraction
Interaction object for slash command autocomplete

ViewInteraction
Interaction object for message components

ModalSubmitInteraction
Interaction object for Modal submits

Following object names will/may still change:

  • ApplicationAutocompleteInteraction
  • ViewInteraction to MessageComponentInteraction

Checklist (currently incomplete)

  • SlashApplicationInteraction (Interaction subclass)
  • ApplicationAutocompleteInteraction (Interaction subclass)
  • ViewInteraction (Interaction subclass)
  • ModalSubmitInteraction (Interaction subclass)
  • InteractionResponse subclasses
  • Interaction subclasses in nextcord.types.interactions

  • Update external Modules to use/identify correct Object
  • Add new subclasses to __all__ Set in interactions.py
  • Update docs
  • Update additional stuff (for example: __slots__, type hints, bugs, ...)

  • Final test (for bugs) - fix if necessary

Gangsta-Muffin and others added 2 commits January 9, 2023 21:39
@Gangsta-Muffin Gangsta-Muffin changed the title nextcord.Interaction subclassing build: nextcord.Interaction subclassing Jan 9, 2023
@ooliver1 ooliver1 marked this pull request as draft January 9, 2023 22:21
@EmreTech EmreTech changed the title build: nextcord.Interaction subclassing refactor: nextcord.Interaction subclassing Jan 10, 2023
* Check and Use Interaction type in Client.py
* Import Interaction subclasses in Client.py
* Transfer SlashApplicationInteraction specific data from Base to subclass
* Copy SlashApplicationInteraction contents to ApplicationAutocompleteInteraction (use same data)
* Check and use correct Interaction type in Client.py
* Add imports for Interaction subclasses in Client.py

* Transfer SlashApplicationInteraction specific data from Interaction (parent class)
* Transfer ApplicationAutocompleteInteraction specific data from Interaction (parent class)
* Add subclass refined properties to SlashApplicationInteraction
* Add subclass refined properties to ApplicationAutocompleteInteraction
* Create PartialInteractionOption (will contain options data for SlashApplicationInteraction and ApplicationAutocompleteInteraction)
* Check and use correct Interaction type in Client.py
* Add imports for new Interaction subclasses

* Transfer SlashApplicationInteraction specific data from Interaction (parent class)
* Transfer ApplicationAutocompleteInteraction specific data from Interaction (parent class)
* Add properties for SlashApplicationInteraction refined data
* Add properties for ApplicationAutocompleteInteraction refined data
@ooliver1 ooliver1 added s: in progress Status: the issue or PR is in development/progress p: low Priority: low - not important to be worked on t: refactor Type: refactor - this is a code change but does not fix a bug/add features labels Jan 11, 2023
Gangsta-Muffin and others added 13 commits January 11, 2023 16:27
…ubclasses

* Add parameters to get_interaction to support custom Interaction subclasses in Client.py
* Create SlashOptionData to hold recieved SlashOptionData - to be used in Interaction classes (Interactions.py)

* Rename SlashApplicationCommand subinteraction class to SlashApplicationInteraction
* Add option data handling in SlashApplicationInteraction (using SlashOptionData) (new .options attribute)

* Add option data handlin in ApplicationAutocompleteInteraction (using SlashOptionData) (new .options attribute)
* Add ocused_option attribute to ApplicationAutocompleteInteraction (fast way to get Slashoption invoking Autocomplete)
Stop double Initialization for focused slash options - instead append the first initialization to collection list
…ubclasses

* Add parameters to get_interaction to support custom Interaction subclasses in Client.py
* Create SlashOptionData to hold recieved SlashOptionData - to be used in Interaction classes (Interactions.py)

* Rename SlashApplicationCommand subinteraction class to SlashApplicationInteraction
* Add option data handling in SlashApplicationInteraction (using SlashOptionData) (new .options attribute)

* Add option data handlin in ApplicationAutocompleteInteraction (using SlashOptionData) (new .options attribute)
* Add ocused_option attribute to ApplicationAutocompleteInteraction (fast way to get Slashoption invoking Autocomplete)
…subclasses

* Copy Interaction.edit() method to ViewInteraction
* Copy Intenteraction.edit() to ModalSubmitInteraction
* Remove Interaction.edit() from Interaction

* Remove .message attribute from Interaction
* Add .message attribute to ViewInteraction
* Add .message attribute to ModalSubmitInteraction

* Add attributes for ModalSubmit refined data (ModalSubmitInteraction)
* add attributes for MessageComponent refined data (ViewInteraction)

* Add comments for questioning changes
* Fixed ViewInteraction.edit() method - can now also edit ephemeral messages
* Fixed ModalSubmitInteraction.edit() method - can now also edit ephemeral messages

Refactor:
* Remove  prints from testing
* Add comments for future changes
* Add __repr__ method to SlashOptionData class
* Add classes to __all__ (interactions.py)
* removed prints from testing
…updates

* Change SlashApplicationInteraction name to ApplicationCommandInteraction
* Type the correct Interaction subclass in client.py

* Add class Descriptions to Interaction Subclasses
* Correct __slots__ in Interaction class
* Ad __slots__ to Interaction subclasses
* Change some attribute names to have more appropriate name
Copy link
Collaborator

@EmreTech EmreTech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two more things that I decided to leave out of individual review comments:

  • The rest of the library isn't typed to use these new subclasses.
  • It would be a lot cleaner imo if the interaction subclasses were split into multiple files under an interactions folder. This also includes the base interaction class.

FYI, some of the review comments I specifically made on ApplicationCommandInteraction apply to the rest of the subclasses, I didn't want to copy all of those review comments over and over again.

nextcord/client.py Outdated Show resolved Hide resolved
nextcord/client.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
Copy link
Contributor

@MaskDuck MaskDuck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also i'm unsure whether should we keep documenting Interaction -- as it doesn't have any real-world usage now.

i think it's a bit breaking but fine, acceptable

nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
Gangsta-Muffin and others added 2 commits January 21, 2023 19:43
* Remove parent attributes from Interaction subclass descriptions (suggestion from PR comments)
* Remove 'version added' in Interaction subclasses (suggestion from PR comments)
* Correct spelling and punctuation in Interaction subclass descriptions (suggestion from PR comments)
* ApplicationAutocompleteInteraction now inherits from ApplicationCommandInteraction
* Correct list typehinting for application options list in ApplicationCommandInteraction
Copy link
Contributor

@MaskDuck MaskDuck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would need to add backward compatibilities or fix pyright error
i actually prefer add backward compatibilities bcuz it would not take much time

but you also need to re-typehint the whole lib where just use interactions, thx =))

nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
nextcord/interactions.py Outdated Show resolved Hide resolved
@teaishealthy
Copy link
Collaborator

🦅

nextcord/interactions/application.py Show resolved Hide resolved
nextcord/interactions/application.py Show resolved Hide resolved

__slots__: Tuple[str, ...] = ("data", "value", "type", "name", "focused")

def __init__(self, data) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please type the data parameter with ApplicationCommandInteractionDataOption.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type doesn't exist - Are you suggesting I should make a new type for this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApplicationCommandInteractionDataOption = Union[
_ApplicationCommandInteractionDataOptionString,
_ApplicationCommandInteractionDataOptionInteger,
_ApplicationCommandInteractionDataOptionSubcommand,
_ApplicationCommandInteractionDataOptionBoolean,
_ApplicationCommandInteractionDataOptionSnowflake,
_ApplicationCommandInteractionDataOptionNumber,
]

It does exist, and it's already imported in this module.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must have missed that somehow. Either way, as part of that list, is the class _ApplicationCommandInteractionDataOptionSubcommand, which the SlashOptionData class doesn't use. (It may possibly not use Snowflake either but I can't say this for sure). Would it be worth making a new dedicated type for this? or is there some typehinting approach I can take, to reassure pyright, that this class does, indeed, not get used (other than using something like isinstance - which would be redundant since the library simply doesn't use this class for any other purpose)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it does get used to tell Pyright what keys and types of values a specific dictionary has. You could make a new union without the subcommand one, but I'm not sure what to call it.

__slots__: Tuple[str, ...] = ("data", "value", "type", "name", "focused")

def __init__(self, data) -> None:
self.data: dict = data
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

nextcord/application_command.py Outdated Show resolved Hide resolved
nextcord/interactions/application.py Outdated Show resolved Hide resolved

Warns
--------
~FutureWarning
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's worth documenting this warning, considering that other functions throughout the library do not either.

nextcord/client.py Outdated Show resolved Hide resolved
nextcord/client.py Outdated Show resolved Hide resolved
Comment on lines +80 to +82
if slot == "type" and getattr(self, slot, None) is not None:
# nextcord/issues/1103
continue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't this fixed by #1104?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? I haven't been keeping track on more recent PRs. Please let me know what I should do with this code, provided changes are in order :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All that PR did when it was merged was remove "type" from the __slots__ of the Component class. As long as your fork is up to date with the upstream and you remove this code I commented on, all should be good.

Gangsta-Muffin and others added 12 commits September 28, 2023 13:49
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Co-authored-by: Emre Terzioglu <50607143+EmreTech@users.noreply.github.com>
Comment on lines +100 to +102
self.options: List[SlashOptionData] = (
self._get_application_options(options) if options else []
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preview is broken for some reason, but what Emre said.

Suggested change
self.options: List[SlashOptionData] = (
self._get_application_options(options) if options else []
)
options = self.data.get("options", [])
self.options: List[SlashOptionData] = (
self._get_application_options(options)
)

def _get_application_options(self, data):
options = data

if len(options) == 0:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to apply this

SlashOptionData,
)

return [SlashOptionData(option) for option in options]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pyright is not happy with this because you are changing the type of an already assigned variable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what variable this is referring to

self._parent._state.store_modal(modal, self._parent.user.id) # type: ignore


class ApplicationAutocompleteInteraction(Interaction):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@ooliver1 ooliver1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested. Only issues were the warning and button type error mentioned in these comments. https://paste.nextcord.dev/?id=1702153210128711

Comment on lines +2 to +3
nextcord.interactions
~~~~~~~~~~~~~~~~~~
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nextcord.interactions
~~~~~~~~~~~~~~~~~~
nextcord.interactions
~~~~~~~~~~~~~~~~~~~~~

nextcord/interactions/application.py Show resolved Hide resolved
Comment on lines +124 to +126
from ..application_command import ( # Importing here due to circular import issues
SlashOptionData,
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from ..application_command import ( # Importing here due to circular import issues
SlashOptionData,
)
# Importing here due to circular import issues
from ..application_command import SlashOptionData

If you put the comment above, this wouldn't wrap the line like that

SlashOptionData,
)

return [SlashOptionData(option) for option in options]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what variable this is referring to

nextcord/interactions/application.py Show resolved Hide resolved
Comment on lines +2951 to +2960
return super().get_interaction(
data,
application_interaction=CustomApplicationCommandInteraction,
application_autocomplete_interaction=CustomApplicationAutocompleteInteraction,
message_component_interaction=MessageComponentInteraction,
modal_submit_interaction=CustomModalSubmitInteraction,

# If you want a custom Interaction object to fall back to if interaction type wasn't recognized:
cls=CustomInteraction
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return super().get_interaction(
data,
application_interaction=CustomApplicationCommandInteraction,
application_autocomplete_interaction=CustomApplicationAutocompleteInteraction,
message_component_interaction=MessageComponentInteraction,
modal_submit_interaction=CustomModalSubmitInteraction,
# If you want a custom Interaction object to fall back to if interaction type wasn't recognized:
cls=CustomInteraction
)
def get_interaction(self, data):
return super().get_interaction(
data,
application_interaction=CustomApplicationCommandInteraction,
application_autocomplete_interaction=CustomApplicationAutocompleteInteraction,
message_component_interaction=MessageComponentInteraction,
modal_submit_interaction=CustomModalSubmitInteraction,
# If you want a custom Interaction object to fall back to if interaction type wasn't recognized:
cls=CustomInteraction
)

Comment on lines +3005 to +3006
Warns
--------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Warns
--------
Warns
-----

@@ -2068,10 +2084,14 @@ def scheduled_events(self) -> List[ScheduledEvent]:
"""
return [event for guild in self.guilds for event in guild.scheduled_events]

async def on_interaction(self, interaction: Interaction) -> None:
async def on_interaction(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be all types however, process_application_commands ignores the types it doesn't want.

in the event that defining this parameter was a mistake, and other parameters were to be defined instead.
"""
# check if they are creating custom interaction subclasses
if cls is not Interaction:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This warning seems a bit weird, the signature for get_interaction seems to imply you should pass a custom interaction when passing other custom interaction classes. The better check would be to look at the other classes and if none are custom, but that just seems a bit excessive IMO.

class Client(nextcord.Client):
    def get_interaction(self, data: InteractionPayload):
        return super().get_interaction(
            data,
            application_autocomplete_interaction=CustomAutocompleteInteraction,
            application_interaction=CustomAppCmdInteraction,
            message_component_interaction=CustomComponentInteraction,
            modal_submit_interaction=CustomModalSubmitInteraction,
            cls=CustomInteraction,
        )

from ..interactions import ClientT, Interaction
from ..interactions.base import ClientT, Interaction
from ..interactions.message_component import MessageComponentInteraction
from ..interactions.modal_submit import ModalSubmitInteraction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ItemCallbackType should probably use the component interaction class not the base one:

Argument of type "(self: Self@View, button: Button[Unknown], interaction: CustomComponentInteraction) -> Coroutine[Any, Any, None]" cannot be assigned to parameter of type "ItemCallbackType[Button[V@button], ClientT@button]"
  Type "(self: Self@View, button: Button[Unknown], interaction: CustomComponentInteraction) -> Coroutine[Any, Any, None]" cannot be assigned to type "ItemCallbackType[Button[V@button], ClientT@button]"
    Parameter 3: type "Interaction[ClientT@button]" cannot be assigned to type "CustomComponentInteraction"
      "Interaction[ClientT@button]" is incompatible with "CustomComponentInteraction"Pylance[reportGeneralTypeIssues](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportGeneralTypeIssues)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p: low Priority: low - not important to be worked on s: in progress Status: the issue or PR is in development/progress t: refactor Type: refactor - this is a code change but does not fix a bug/add features
Projects
No open projects
Status: In Cycle
Development

Successfully merging this pull request may close these issues.

Interaction Subclasses
7 participants