Skip to content

Commit

Permalink
Use black to format code
Browse files Browse the repository at this point in the history
  • Loading branch information
wong2 committed Jul 24, 2022
1 parent 4095ad5 commit e408995
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 42 deletions.
6 changes: 3 additions & 3 deletions example/basic.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pick import pick

title = 'Please choose your favorite programming language: '
options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 'Haskell']
selection = pick(options, title, indicator='=>', default_index=2)
title = "Please choose your favorite programming language: "
options = ["Java", "JavaScript", "Python", "PHP", "C++", "Erlang", "Haskell"]
selection = pick(options, title, indicator="=>", default_index=2)
assert len(selection) == 1
option, index = selection[0]
print(option, index)
5 changes: 3 additions & 2 deletions example/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ def print_selection(selection):
def go_back(picker):
return (None, -1)

title = 'Please choose your favorite programming language: '
options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 'Haskell']

title = "Please choose your favorite programming language: "
options = ["Java", "JavaScript", "Python", "PHP", "C++", "Erlang", "Haskell"]

# with type annotation
picker: Picker[Tuple[None, int], str] = Picker(options, title)
Expand Down
17 changes: 10 additions & 7 deletions example/options_map_func.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
from pick import pick

title = 'Please choose your favorite fruit: '
title = "Please choose your favorite fruit: "
options = [
{ 'name': 'Apples', 'grow_on': 'trees' },
{ 'name': 'Oranges', 'grow_on': 'trees' },
{ 'name': 'Strawberries', 'grow_on': 'vines' },
{ 'name': 'Grapes', 'grow_on': 'vines' },
{"name": "Apples", "grow_on": "trees"},
{"name": "Oranges", "grow_on": "trees"},
{"name": "Strawberries", "grow_on": "vines"},
{"name": "Grapes", "grow_on": "vines"},
]


def get_description_for_display(option):
# format the option data for display
return '{0} (grow on {1})'.format(option.get('name'), option.get('grow_on'))
return "{0} (grow on {1})".format(option.get("name"), option.get("grow_on"))


selection = pick(options, title, indicator='=>', options_map_func=get_description_for_display)
selection = pick(
options, title, indicator="=>", options_map_func=get_description_for_display
)
assert len(selection) == 1
option, index = selection[0]
print(option, index)
4 changes: 2 additions & 2 deletions example/scroll.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pick import pick

title = 'Select:'
options = ['foo.bar%s.baz' % x for x in range(1, 71)]
title = "Select:"
options = ["foo.bar%s.baz" % x for x in range(1, 71)]
selection = pick(options, title)
assert len(selection) == 1
option, index = selection[0]
Expand Down
64 changes: 62 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ homepage = "https://github.com/wong2/pick"
keywords = ["terminal", "gui"]

[tool.poetry.dependencies]
python = ">=3.6"
python = ">=3.6.2"
windows-curses = {version = "^2.2.0", platform = "win32"}
dataclasses = { version = "^0.8", python = "~3.6" }

[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
mypy = "^0.961"
black = "^22.6.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
49 changes: 26 additions & 23 deletions src/pick/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
from dataclasses import dataclass, field
from typing import Generic, Callable, List, Optional, Dict, Union, Tuple, TypeVar

__all__ = ['Picker', 'pick']
__all__ = ["Picker", "pick"]


KEYS_ENTER = (curses.KEY_ENTER, ord('\n'), ord('\r'))
KEYS_UP = (curses.KEY_UP, ord('k'))
KEYS_DOWN = (curses.KEY_DOWN, ord('j'))
KEYS_SELECT = (curses.KEY_RIGHT, ord(' '))
KEYS_ENTER = (curses.KEY_ENTER, ord("\n"), ord("\r"))
KEYS_UP = (curses.KEY_UP, ord("k"))
KEYS_DOWN = (curses.KEY_DOWN, ord("j"))
KEYS_SELECT = (curses.KEY_RIGHT, ord(" "))

CUSTOM_HANDLER_RETURN_T = TypeVar("CUSTOM_HANDLER_RETURN_T")
KEY_T = int
Expand Down Expand Up @@ -44,23 +44,23 @@ class Picker(Generic[CUSTOM_HANDLER_RETURN_T, OPTIONS_MAP_VALUE_T]):

def __post_init__(self) -> None:
if len(self.options) == 0:
raise ValueError('options should not be an empty list')
raise ValueError("options should not be an empty list")

if self.default_index >= len(self.options):
raise ValueError('default_index should be less than the length of options')
raise ValueError("default_index should be less than the length of options")

if self.multiselect and self.min_selection_count > len(self.options):
raise ValueError('min_selection_count is bigger than the available options, you will not be able to make any selection')
raise ValueError(
"min_selection_count is bigger than the available options, you will not be able to make any selection"
)

if not callable(self.options_map_func):
raise ValueError('options_map_func must be a callable function')
raise ValueError("options_map_func must be a callable function")

self.index = self.default_index

def register_custom_handler(
self,
key: KEY_T,
func: Callable[["Picker"], CUSTOM_HANDLER_RETURN_T]
self, key: KEY_T, func: Callable[["Picker"], CUSTOM_HANDLER_RETURN_T]
) -> None:
self.custom_handlers[key] = func

Expand All @@ -83,7 +83,7 @@ def mark_index(self) -> None:

def get_selected(self) -> List[Tuple[OPTIONS_MAP_VALUE_T, int]]:
"""return the current selected option as a tuple: (option, index)
or as a list of tuples (in case multiselect==True)
or as a list of tuples (in case multiselect==True)
"""
if self.multiselect:
return_tuples = []
Expand All @@ -96,7 +96,7 @@ def get_selected(self) -> List[Tuple[OPTIONS_MAP_VALUE_T, int]]:

def get_title_lines(self) -> List[str]:
if self.title:
return self.title.split('\n') + ['']
return self.title.split("\n") + [""]
return []

def get_option_lines(self) -> Union[List[str], List[Tuple[str, int]]]:
Expand All @@ -107,14 +107,14 @@ def get_option_lines(self) -> Union[List[str], List[Tuple[str, int]]]:
if index == self.index:
prefix = self.indicator
else:
prefix = len(self.indicator) * ' '
prefix = len(self.indicator) * " "

line: Union[Tuple[str, int], str]
if self.multiselect and index in self.all_selected:
format = curses.color_pair(1)
line = ('{0} {1}'.format(prefix, option_as_str), format)
line = ("{0} {1}".format(prefix, option_as_str), format)
else:
line = '{0} {1}'.format(prefix, option_as_str)
line = "{0} {1}".format(prefix, option_as_str)
lines.append(line) # type: ignore[arg-type]

return lines
Expand Down Expand Up @@ -142,19 +142,19 @@ def draw(self, screen) -> None:
elif current_line - self.scroll_top > max_rows:
self.scroll_top = current_line - max_rows

lines_to_draw = lines[self.scroll_top:self.scroll_top+max_rows]
lines_to_draw = lines[self.scroll_top : self.scroll_top + max_rows]

for line in lines_to_draw:
if type(line) is tuple:
screen.addnstr(y, x, line[0], max_x-2, line[1])
screen.addnstr(y, x, line[0], max_x - 2, line[1])
else:
screen.addnstr(y, x, line, max_x-2)
screen.addnstr(y, x, line, max_x - 2)
y += 1

screen.refresh()

def run_loop(
self, screen
self, screen
) -> Union[List[Tuple[OPTIONS_MAP_VALUE_T, int]], CUSTOM_HANDLER_RETURN_T]:
while True:
self.draw(screen)
Expand All @@ -164,7 +164,10 @@ def run_loop(
elif c in KEYS_DOWN:
self.move_down()
elif c in KEYS_ENTER:
if self.multiselect and len(self.all_selected) < self.min_selection_count:
if (
self.multiselect
and len(self.all_selected) < self.min_selection_count
):
continue
return self.get_selected()
elif c in KEYS_SELECT and self.multiselect:
Expand Down Expand Up @@ -194,7 +197,7 @@ def _start(
return self.run_loop(screen)

def start(
self
self,
) -> Union[List[Tuple[OPTIONS_MAP_VALUE_T, int]], CUSTOM_HANDLER_RETURN_T]:
return curses.wrapper(self._start)

Expand Down
8 changes: 6 additions & 2 deletions tests/test_pick.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ def test_no_title():
def test_multi_select():
title = "Please choose an option: "
options = ["option1", "option2", "option3"]
picker: Picker[str, str] = Picker(options, title, multiselect=True, min_selection_count=1)
picker: Picker[str, str] = Picker(
options, title, multiselect=True, min_selection_count=1
)
assert picker.get_selected() == []
picker.mark_index()
assert picker.get_selected() == [("option1", 0)]
Expand All @@ -56,7 +58,9 @@ def test_options_map_func():
def get_label(option: Dict[str, str]) -> Optional[str]:
return option.get("label")

picker: Picker[str, Dict[str, str]] = Picker(options, title, indicator="*", options_map_func=get_label)
picker: Picker[str, Dict[str, str]] = Picker(
options, title, indicator="*", options_map_func=get_label
)
lines, current_line = picker.get_lines()
assert lines == [title, "", "* option1", " option2", " option3"]
assert picker.get_selected() == [({"label": "option1"}, 0)]

0 comments on commit e408995

Please sign in to comment.