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

Change Choice.shortcut_key to property with setter #349

Merged
merged 3 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
58 changes: 45 additions & 13 deletions questionary/prompts/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ class Choice:
checked: Optional[bool]
"""Whether the choice is initially selected"""

shortcut_key: Optional[str]
"""A shortcut key for the choice"""
__shortcut_key: Optional[Union[str, bool]]

description: Optional[str]
"""Choice description"""
Expand All @@ -86,6 +85,8 @@ def __init__(
) -> None:
self.disabled = disabled
self.title = title
self.shortcut_key = shortcut_key
# self.auto_shortcut is set by self.shortcut_key.fset
kiancross marked this conversation as resolved.
Show resolved Hide resolved
self.checked = checked if checked is not None else False
self.description = description

Expand All @@ -96,17 +97,6 @@ def __init__(
else:
self.value = title

if shortcut_key is not None:
if isinstance(shortcut_key, bool):
self.auto_shortcut = shortcut_key
self.shortcut_key = None
else:
self.shortcut_key = str(shortcut_key)
self.auto_shortcut = False
else:
self.shortcut_key = None
self.auto_shortcut = True

@staticmethod
def build(c: Union[str, "Choice", Dict[str, Any]]) -> "Choice":
"""Create a choice object from different representations.
Expand Down Expand Up @@ -134,12 +124,54 @@ def build(c: Union[str, "Choice", Dict[str, Any]]) -> "Choice":
c.get("description", None),
)

@property
def shortcut_key(self) -> Optional[Union[str, bool]]:
"""A shortcut key for the choice"""
return self.__shortcut_key

@shortcut_key.setter
def shortcut_key(self, key: Optional[Union[str, bool]]):
if key is not None:
if isinstance(key, bool):
self.__auto_shortcut = key
self.__shortcut_key = None
else:
self.__shortcut_key = str(key)
self.__auto_shortcut = False
else:
self.__shortcut_key = None
self.__auto_shortcut = True

@shortcut_key.deleter
def shortcut_key(self):
self.__shortcut_key = None
self.__auto_shortcut = True

def get_shortcut_title(self):
if self.shortcut_key is None:
return "-) "
else:
return "{}) ".format(self.shortcut_key)

@property
def auto_shortcut(self) -> bool:
"""Whether to assign a shortcut key to the choice

Keys are assigned starting with numbers and proceeding
through the ASCII alphabet.
"""
return self.__auto_shortcut

@auto_shortcut.setter
def auto_shortcut(self, should_assign: bool):
self.__auto_shortcut = should_assign
if self.__auto_shortcut:
self.__shortcut_key = None

@auto_shortcut.deleter
def auto_shortcut(self):
self.__auto_shortcut = False


class Separator(Choice):
"""Used to space/separate choices group."""
Expand Down
25 changes: 25 additions & 0 deletions tests/prompts/test_select.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from copy import copy

import pytest

from questionary import Choice
Expand Down Expand Up @@ -199,6 +201,29 @@ def test_allow_shortcut_key_with_True():
assert result == "bazz"


def test_auto_shortcut_key_stable_in_loop():
message = "Foo message"
choices = [
Choice("foo"),
Choice("bar"),
]
kwargs = {
"choices": choices,
"use_shortcuts": True,
}
text = "\r"

result, cli = feed_cli_with_input("select", message, text, **kwargs)
assert result == "foo"
result_shortcut_keys = [copy(c.shortcut_key) for c in choices]
result2, cli = feed_cli_with_input("select", message, text, **kwargs)
assert result2 == "foo"
result2_shortcut_keys = [copy(c.shortcut_key) for c in choices]
assert (
result_shortcut_keys == result2_shortcut_keys
), "Shortcut keys changed across two runs of 'select'"


def test_select_initial_choice_with_value():
message = "Foo message"
choice = Choice(title="bazz", value="bar")
Expand Down
Loading