Skip to content

Conversation

@KH4St3H
Copy link

@KH4St3H KH4St3H commented Feb 10, 2022

fix CommandHandler and PrefixHandler to use lists instead of sets

  • Added .. versionadded:: version, .. versionchanged:: version or .. deprecated:: version to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)
  • Created new or adapted existing unit tests
  • Added myself alphabetically to AUTHORS.rst (optional)
    Closes Rename CommandHandler.command to CH.commands (plural) … #2885

Bibo-Joshi and others added 30 commits February 4, 2022 21:26
…t#2612)

Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Signed-off-by: starry69 <starry369126@outlook.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
…m-bot#2634)

Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: poolitzer <25934244+Poolitzer@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
harshil21 and others added 5 commits February 6, 2022 10:00
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
@Poolitzer
Copy link
Member

Hi, are you working on #2885 with this?

@KH4St3H
Copy link
Author

KH4St3H commented Feb 10, 2022

Hi, are you working on #2885 with this?

yes

@Bibo-Joshi Bibo-Joshi self-requested a review February 10, 2022 15:20
Copy link
Member

@Bibo-Joshi Bibo-Joshi left a comment

Choose a reason for hiding this comment

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

Hi. thanks for the PR! IISC so far you have only allowed for the PrefixHandler.prefix/command setters to accept sets.
I think I should clarify a bit what the intention of #2885 was:

  • The main idea of the issue was to rename CommandHandler.command to CommandHandler.commands (plural) since that attribute is currently actually always a list. Extending this to PrefixHandlers.prefix is surely reasonable.
  • Since I noticed that we only ever need x in self.command, my idea was to make CommandHandler.commands a set instead of a list. Accepting sets as input in addition is surely a logical extension. So

Additionally, while reviewing your PR, I noticed that unlike PrefixHandler.command, CommandHandler.command doesn't have a setter. I.e. if you do command_handler.command = 'NewCommand', it won't be converted to [newcommand]. I think we should fix that. So what I would ask you to do is:

  • Make sure that sets are accepted as input for Prefix/CommandHandler.command and PrefixHandler.prefix - this includes type hints & documentation
  • rename CommandHandler.command to CommandHandler._commands and add getter + setter proprties CommandHandler.commands. The getter should provide access to the set CH._commands and the setter should accept a single string or tuple/list/set and convert it as it is converted on __init__
  • Apply analogous changes to PrefixHandler

Attributes:
command (:obj:`str` | Tuple[:obj:`str`] | List[:obj:`str`]):
command (:obj:`str` | Tuple[:obj:`str`] | List[:obj:`str`] | Set[:obj:`str`]):
Copy link
Member

Choose a reason for hiding this comment

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

In the current implementation, CommandHandler.command is actually always a List

Copy link
Author

Choose a reason for hiding this comment

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

Hi. thanks for the PR! IISC so far you have only allowed for the PrefixHandler.prefix/command setters to accept sets. I think I should clarify a bit what the intention of #2885 was:

  • The main idea of the issue was to rename CommandHandler.command to CommandHandler.commands (plural) since that attribute is currently actually always a list. Extending this to PrefixHandlers.prefix is surely reasonable.
  • Since I noticed that we only ever need x in self.command, my idea was to make CommandHandler.commands a set instead of a list. Accepting sets as input in addition is surely a logical extension. So

Additionally, while reviewing your PR, I noticed that unlike PrefixHandler.command, CommandHandler.command doesn't have a setter. I.e. if you do command_handler.command = 'NewCommand', it won't be converted to [newcommand]. I think we should fix that. So what I would ask you to do is:

  • Make sure that sets are accepted as input for Prefix/CommandHandler.command and PrefixHandler.prefix - this includes type hints & documentation
  • rename CommandHandler.command to CommandHandler._commands and add getter + setter proprties CommandHandler.commands. The getter should provide access to the set CH._commands and the setter should accept a single string or tuple/list/set and convert it as it is converted on __init__
  • Apply analogous changes to PrefixHandler

Thanks for the review, I'm working on it. should I change the name in arguments from command to commands too?

Copy link
Member

Choose a reason for hiding this comment

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

should I change the name in arguments from command to commands too?

no need IMO, since either way the arguments will have to accept both single strings or colletcions of strings.

@harshil21 harshil21 added 🛠 breaking change type: breaking enhancement labels Feb 10, 2022
@harshil21 harshil21 added this to the v14 milestone Feb 10, 2022
Copy link
Member

@Bibo-Joshi Bibo-Joshi left a comment

Choose a reason for hiding this comment

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

hi, thanks for the updates! I left a few comments below

Also please add a .. versionchanged:: directive just before the Args: of CommandHandler saying that command was replaced by commands

Comment on lines 74 to 75
commands (Set[:obj:`str`]):
The set of command(s) this handler should listen for.
Copy link
Member

Choose a reason for hiding this comment

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

the property already has a docstring, so you can remove this documentation of the attribute

Comment on lines 81 to 83
.. versionchanged:: 14.0
:attr:`commands` is now a set and can be assinged after construction of model.
Copy link
Member

Choose a reason for hiding this comment

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

see above

Comment on lines 174 to 177
if isinstance(command, str):
self._commands = {command.lower()}
else:
self._commands = {i.lower() for i in command}
Copy link
Member

Choose a reason for hiding this comment

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

THis is the same logic that's used on __init__. Could you extract it to a new protected method (e.g. _parse_commands()) that you call both here and on __init__? Then you can also move the regexing from __init__ to that function. THat will make sure that also the setter only accepts valid bot commands (please add a unit test for this)

Copy link
Author

Choose a reason for hiding this comment

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

Sure, I first tried to do it like this
self.commands = command
But it wouldn't work when PrefixHandler tried to call it because it has a different setter than CommandHandler with the same name. But I'll make a function for it.

Copy link
Author

Choose a reason for hiding this comment

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

I noticed we don't have CommandHandler command limitations for PrefixHandler, so illegal commands in prefixhandler should work properly shouldn't they?

Copy link
Member

Choose a reason for hiding this comment

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

I noticed we don't have CommandHandler command limitations for PrefixHandler, so illegal commands in prefixhandler should work properly shouldn't they?

yes, since PrefixHandler is not limited to the commands recognized by Telegram. Actually the fact that PrefixHandler is a subclass of CommandHandler is more or less an implementation detail …

Args:
command (:obj:`str` | Tuple[:obj:`str`] | List[:obj:`str`]):
command (:obj:`str` | Tuple[:obj:`str`] | List[:obj:`str`] | Set[:obj:`str`]):
Copy link
Member

Choose a reason for hiding this comment

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

please add a "versionchanged" directive saying that it now also accepts sets

Comment on lines 249 to 251
.. versionchanged:: 14.0
:attr:`prefix` has been changed to :attr:`prefixes` and accepts sets as well.
:attr:`command` has been changed to :attr:`commands` and accepts sets as well.
Copy link
Member

Choose a reason for hiding this comment

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

Please move the "changed to" notes to a versionchanged directive right before the Args:. Please move the "now accepts sets" to a versionchanged directive in the documentation of the respective arguments

@property # type: ignore[override]
def command(self) -> List[str]: # type: ignore[override]
@property
def commands(self) -> Set[str]:
Copy link
Member

Choose a reason for hiding this comment

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

Is this override still necessary? IISC, this does exatly the same as CommandHandler.commands

Copy link
Author

Choose a reason for hiding this comment

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

yes, because this class uses a different setter than the parent one and needs a property to set it.

Copy link
Member

Choose a reason for hiding this comment

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

IIRC using @CommandHandler.commands.setter instead of @commands.setter should do the trick and then you don't need to re-implement the property

handler = CommandHandler(['test', 'star'], self.callback_basic)
assert is_match(handler, make_command_update('/test'))
handler.commands = "help"
assert is_match(handler, make_command_update('/help'))
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
assert is_match(handler, make_command_update('/help'))
assert is_match(handler, make_command_update('/help'))
assert not is_match(handler, make_command_update('/test))

handler.commands = "help"
assert is_match(handler, make_command_update('/help'))
handler.commands = ['exit', 'happy']
assert is_match(handler, make_command_update('/happy'))
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
assert is_match(handler, make_command_update('/happy'))
assert is_match(handler, make_command_update('/happy'))
assert not is_match(handler, make_command_update('/help'))

Comment on lines +85 to +88
.. versionchanged:: 14.0
:attr:`commands` is now a set and can be assinged after construction of model.
Copy link
Member

Choose a reason for hiding this comment

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

please remove

attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
.. versionchanged:: 14.0
:attr:`commands` is now a set and can be assinged after construction of model.
Copy link
Member

Choose a reason for hiding this comment

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

The attribute command was replaced by :attr:commands

and message.get_bot()
):
command = message.text[1 : message.entities[0].length]
command = message.text[1: message.entities[0].length]
Copy link
Member

Choose a reason for hiding this comment

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

please revert - this is the reason the pre-commit test is failing

Comment on lines +180 to +182
for comm in self._commands:
if not re.match(r'^[\da-z_]{1,32}$', comm):
raise ValueError(f'Command `{comm}` is not a valid bot command')
Copy link
Member

Choose a reason for hiding this comment

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

when this is raised, self._commands has already been changed - it should be the other way around. You can even add a unit test along the lines

  1. bulid commandhandler with valid commands
  2. try to assign invalid commands
  3. assert that the commands where not changed

what we can do to make this easier here & also make the init a bit cleaner is:

  1. make _parse_commands return the parsed commands instead of assigning them directly to self._commands. It can be converted into a static method
  2. apply the regexing for valid commands directly within _parse_commands
  3. do self._commands = self._parse_commands(command) both here and in __init__.

self._command = command
@CommandHandler.commands.setter # type: ignore[attr-defined,misc]
def commands(self, command: SLTS) -> None:
self._parse_commands(command)
Copy link
Member

Choose a reason for hiding this comment

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

IISC this doesn't rebuilt self._combinations, but that's needed. I guess it should be self._build_commands instead. If you want to reduce code duplication some more, you can add a method _slts_to_set that returns {arg.lower()} if isinstance(arg, str) else {item.lower() for item in arg}. This can be a static method of CommandHandler or even just a module level function. You can then use it in CH._parse_commands, in the setter of prefixes and here.

Comment on lines +227 to +228
:attr:`prefixes` and :attr:`commands` are always a set and can be
assigned with sets as well.
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
:attr:`prefixes` and :attr:`commands` are always a set and can be
assigned with sets as well.
The attributes ``prefix`` and ``command`` where replaced by :attr:`prefixes` and :attr:`commands`, respectively.

@harshil21 harshil21 added the 📋 pending-reply work status: pending-reply label Mar 22, 2022
@Bibo-Joshi Bibo-Joshi changed the base branch from v14 to master May 6, 2022 17:47
@harshil21 harshil21 modified the milestones: v20, v20.0a1 May 12, 2022
@Bibo-Joshi Bibo-Joshi mentioned this pull request May 18, 2022
2 tasks
@github-actions github-actions bot locked and limited conversation to collaborators Jun 2, 2022
@Bibo-Joshi Bibo-Joshi added 🔌 enhancement pr description: enhancement and removed enhancement labels Nov 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

🛠 breaking change type: breaking 🔌 enhancement pr description: enhancement 📋 pending-reply work status: pending-reply

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rename CommandHandler.command to CH.commands (plural) …