Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pick for openSUSE:Factory 
checked in at 2022-07-26 19:44:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pick (Old)
 and      /work/SRC/openSUSE:Factory/.python-pick.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pick"

Tue Jul 26 19:44:07 2022 rev:6 rq:990887 version:1.4.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pick/python-pick.changes  2020-03-17 
13:08:53.889741508 +0100
+++ /work/SRC/openSUSE:Factory/.python-pick.new.1533/python-pick.changes        
2022-07-26 19:44:34.522405409 +0200
@@ -1,0 +2,20 @@
+Sun Jul 24 14:10:38 UTC 2022 - Luigi Baldoni <[email protected]>
+
+- Update to version 1.4.0
+  * Drop support for Python 3.6
+  * Add pre-commit config
+  * pick returns single tuple when multiselect=False
+  version 1.3.1:
+  * Bump version
+  version 1.3.0:
+  Add type hints
+  version 1.2.0:
+  * Fixed support for Python 3.6
+  version 1.1.1:
+  * Bump version
+  version 1.1.0:
+  * Fixes missing `screen` on call to `self.draw`
+  version 1.0.0:
+  * Drop python2 support
+
+-------------------------------------------------------------------

Old:
----
  pick-0.6.7.tar.gz

New:
----
  pick-1.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pick.spec ++++++
--- /var/tmp/diff_new_pack.vPnDWh/_old  2022-07-26 19:44:34.914344845 +0200
+++ /var/tmp/diff_new_pack.vPnDWh/_new  2022-07-26 19:44:34.918344227 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pick
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,14 +17,14 @@
 
 
 Name:           python-pick
-Version:        0.6.7
+Version:        1.4.0
 Release:        0
 Summary:        Curses-based interactive selection list module
 License:        MIT
 URL:            https://github.com/wong2/pick
-# https://github.com/wong2/pick/issues/28
 Source0:        
https://github.com/wong2/pick/archive/v%{version}.tar.gz#/pick-%{version}.tar.gz
-BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module pip}
+BuildRequires:  %{python_module poetry}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 BuildArch:      noarch
@@ -42,10 +42,10 @@
 %setup -q -n pick-%{version}
 
 %build
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check

++++++ pick-0.6.7.tar.gz -> pick-1.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/.github/workflows/ci.yml 
new/pick-1.4.0/.github/workflows/ci.yml
--- old/pick-0.6.7/.github/workflows/ci.yml     1970-01-01 01:00:00.000000000 
+0100
+++ new/pick-1.4.0/.github/workflows/ci.yml     2022-07-24 07:38:13.000000000 
+0200
@@ -0,0 +1,22 @@
+name: ci
+on: [push, pull_request]
+
+jobs:
+  ci:
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version: [3.7, 3.8, 3.9, "3.10"]
+        os: [ubuntu-18.04, ubuntu-latest, macos-latest, windows-latest]
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+      - name: Run image
+        uses: abatilo/[email protected]
+      - name: Install dependencies
+        run: poetry install
+      - name: Run test
+        run: poetry run pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/.pre-commit-config.yaml 
new/pick-1.4.0/.pre-commit-config.yaml
--- old/pick-0.6.7/.pre-commit-config.yaml      1970-01-01 01:00:00.000000000 
+0100
+++ new/pick-1.4.0/.pre-commit-config.yaml      2022-07-24 07:38:13.000000000 
+0200
@@ -0,0 +1,6 @@
+repos:
+  - repo: https://github.com/psf/black
+    rev: 22.6.0
+    hooks:
+      - id: black
+        language_version: python3.10
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/.travis.yml new/pick-1.4.0/.travis.yml
--- old/pick-0.6.7/.travis.yml  2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/.travis.yml  1970-01-01 01:00:00.000000000 +0100
@@ -1,20 +0,0 @@
-language: python
-
-cache: pip
-
-python:
-    - "2.7"
-    - "3.4"
-    - "3.5"
-    - "3.6"
-    - "3.7"
-    - "3.8"
-
-install:
-    - python setup.py install
-
-script:
-    - nosetests
-
-after_success:
-  - bash <(curl -s https://codecov.io/bash)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/MANIFEST.in new/pick-1.4.0/MANIFEST.in
--- old/pick-0.6.7/MANIFEST.in  2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/MANIFEST.in  1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-include README.rst
-include LICENSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/Makefile new/pick-1.4.0/Makefile
--- old/pick-0.6.7/Makefile     2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/Makefile     2022-07-24 07:38:13.000000000 +0200
@@ -1,5 +1,13 @@
+.PHONY=publish
 publish:
-       python setup.py sdist
-       python setup.py bdist_wheel
-       twine upload dist/*
+       poetry build
+       poetry publish
+
+.PHONY=test
+test:
+       poetry run mypy .
+       poetry run pytest
+
+.PHONY=clean
+clean:
        rm -fr build dist pick.egg-info
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/README.rst new/pick-1.4.0/README.rst
--- old/pick-0.6.7/README.rst   2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/README.rst   2022-07-24 07:38:13.000000000 +0200
@@ -1,17 +1,22 @@
 pick
 ====
 
-.. image:: https://travis-ci.org/wong2/pick.svg?branch=master
-   :alt: Build Status
-   :target: https://travis-ci.org/wong2/pick
+.. image:: https://github.com/wong2/pick/actions/workflows/ci.yml/badge.svg
+   :target: https://github.com/wong2/pick/actions/workflows/ci.yml
 
 .. image:: https://img.shields.io/pypi/v/pick.svg
    :alt: PyPI
    :target: https://pypi.python.org/pypi/pick
+   
+.. image:: https://img.shields.io/pypi/dm/pick
+   :alt: PyPI
+   :target: https://pypi.python.org/pypi/pick
+   
+|
 
-**pick** is a small python library to help you create curses based interactive 
selection list in the terminal. See it in action:
+**pick** is a small python library to help you create curses based interactive 
selection list in the terminal. 
 
-.. image:: example/basic.gif?raw=true
+.. image:: https://github.com/wong2/pick/raw/master/example/basic.gif
    :alt: Demo
 
 Installation
@@ -21,8 +26,6 @@
 
     $ pip install pick
 
-note for Windows users: run ``pip install windows-curses`` to enable curses 
module support.
-
 Usage
 -----
 
@@ -113,3 +116,8 @@
 **outputs**::
 
     >>> ({ 'label': 'option1' }, 0)
+
+Community Projects
+--------------------
+
+`pickpack <https://github.com/anafvana/pickpack>`_: A fork of `pick` to select 
tree data.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/example/basic.py 
new/pick-1.4.0/example/basic.py
--- old/pick-0.6.7/example/basic.py     2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/example/basic.py     2022-07-24 07:38:13.000000000 +0200
@@ -1,10 +1,8 @@
-#-*-coding:utf-8-*-
-
-from __future__ import print_function
-
 from pick import pick
 
-title = 'Please choose your favorite programming language: '
-options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 'Haskell']
-option, index = 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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/example/custom.py 
new/pick-1.4.0/example/custom.py
--- old/pick-0.6.7/example/custom.py    2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/example/custom.py    2022-07-24 07:38:13.000000000 +0200
@@ -1,17 +1,32 @@
-#-*-coding:utf-8-*-
-
-from __future__ import print_function
-
 import curses
 from pick import Picker
+from typing import Tuple
+
+
+def print_selection(selection):
+    if isinstance(selection, list):
+        assert len(selection) == 1
+        option, index = selection[0]
+        print(option, index)
+    else:
+        print("KEY_LEFT pressed!")
+
 
 def go_back(picker):
     return (None, -1)
 
-title = 'Please choose your favorite programming language: '
-options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 'Haskell']
 
-picker = Picker(options, title)
+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)
 picker.register_custom_handler(curses.KEY_LEFT, go_back)
-option, index = picker.start()
-print(option, index)
+selection = picker.start()
+print_selection(selection)
+
+# with type warning suppression
+unannotated_picker = Picker(options, title)  # type: ignore[var-annotated]
+unannotated_picker.register_custom_handler(curses.KEY_LEFT, go_back)
+selection = picker.start()
+print_selection(selection)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/example/options_map_func.py 
new/pick-1.4.0/example/options_map_func.py
--- old/pick-0.6.7/example/options_map_func.py  2020-02-02 08:07:31.000000000 
+0100
+++ new/pick-1.4.0/example/options_map_func.py  2022-07-24 07:38:13.000000000 
+0200
@@ -1,21 +1,22 @@
-#-*-coding:utf-8-*-
-
-from __future__ import print_function
-
 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"))
 
-option, index = 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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/example/scroll.py 
new/pick-1.4.0/example/scroll.py
--- old/pick-0.6.7/example/scroll.py    2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/example/scroll.py    2022-07-24 07:38:13.000000000 +0200
@@ -1,10 +1,8 @@
-#-*-coding:utf-8-*-
-
-from __future__ import print_function
-
 from pick import pick
 
-title = 'Select:'
-options = ['foo.bar%s.baz' % x for x in range(1, 71)]
-option, index = pick(options, title)
+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]
 print(option, index)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/pick/__init__.py 
new/pick-1.4.0/pick/__init__.py
--- old/pick-0.6.7/pick/__init__.py     2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/pick/__init__.py     1970-01-01 01:00:00.000000000 +0100
@@ -1,195 +0,0 @@
-#-*-coding:utf-8-*-
-
-import curses
-
-__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(' '))
-
-class Picker(object):
-    """The :class:`Picker <Picker>` object
-
-    :param options: a list of options to choose from
-    :param title: (optional) a title above options list
-    :param multiselect: (optional) if true its possible to select multiple 
values by hitting SPACE, defaults to False
-    :param indicator: (optional) custom the selection indicator
-    :param default_index: (optional) set this if the default selected option 
is not the first one
-    :param options_map_func: (optional) a mapping function to pass each option 
through before displaying
-    """
-
-    def __init__(self, options, title=None, indicator='*', default_index=0, 
multiselect=False, multi_select=False, min_selection_count=0, 
options_map_func=None):
-
-        if len(options) == 0:
-            raise ValueError('options should not be an empty list')
-
-        self.options = options
-        self.title = title
-        self.indicator = indicator
-        self.multiselect = multiselect or multi_select
-        self.min_selection_count = min_selection_count
-        self.options_map_func = options_map_func
-        self.all_selected = []
-
-        if default_index >= len(options):
-            raise ValueError('default_index should be less than the length of 
options')
-
-        if multiselect and min_selection_count > len(options):
-            raise ValueError('min_selection_count is bigger than the available 
options, you will not be able to make any selection')
-
-        if options_map_func is not None and not callable(options_map_func):
-            raise ValueError('options_map_func must be a callable function')
-
-        self.index = default_index
-        self.custom_handlers = {}
-
-    def register_custom_handler(self, key, func):
-        self.custom_handlers[key] = func
-
-    def move_up(self):
-        self.index -= 1
-        if self.index < 0:
-            self.index = len(self.options) - 1
-
-    def move_down(self):
-        self.index += 1
-        if self.index >= len(self.options):
-            self.index = 0
-
-    def mark_index(self):
-        if self.multiselect:
-            if self.index in self.all_selected:
-                self.all_selected.remove(self.index)
-            else:
-                self.all_selected.append(self.index)
-
-    def get_selected(self):
-        """return the current selected option as a tuple: (option, index)
-           or as a list of tuples (in case multiselect==True)
-        """
-        if self.multiselect:
-            return_tuples = []
-            for selected in self.all_selected:
-                return_tuples.append((self.options[selected], selected))
-            return return_tuples
-        else:
-            return self.options[self.index], self.index
-
-    def get_title_lines(self):
-        if self.title:
-            return self.title.split('\n') + ['']
-        return []
-
-    def get_option_lines(self):
-        lines = []
-        for index, option in enumerate(self.options):
-            # pass the option through the options map of one was passed in
-            if self.options_map_func:
-                option = self.options_map_func(option)
-
-            if index == self.index:
-                prefix = self.indicator
-            else:
-                prefix = len(self.indicator) * ' '
-
-            if self.multiselect and index in self.all_selected:
-                format = curses.color_pair(1)
-                line = ('{0} {1}'.format(prefix, option), format)
-            else:
-                line = '{0} {1}'.format(prefix, option)
-            lines.append(line)
-
-        return lines
-
-    def get_lines(self):
-        title_lines = self.get_title_lines()
-        option_lines = self.get_option_lines()
-        lines = title_lines + option_lines
-        current_line = self.index + len(title_lines) + 1
-        return lines, current_line
-
-    def draw(self):
-        """draw the curses ui on the screen, handle scroll if needed"""
-        self.screen.clear()
-
-        x, y = 1, 1  # start point
-        max_y, max_x = self.screen.getmaxyx()
-        max_rows = max_y - y  # the max rows we can draw
-
-        lines, current_line = self.get_lines()
-
-        # calculate how many lines we should scroll, relative to the top
-        scroll_top = getattr(self, 'scroll_top', 0)
-        if current_line <= scroll_top:
-            scroll_top = 0
-        elif current_line - scroll_top > max_rows:
-            scroll_top = current_line - max_rows
-        self.scroll_top = scroll_top
-
-        lines_to_draw = lines[scroll_top:scroll_top+max_rows]
-
-        for line in lines_to_draw:
-            if type(line) is tuple:
-                self.screen.addnstr(y, x, line[0], max_x-2, line[1])
-            else:
-                self.screen.addnstr(y, x, line, max_x-2)
-            y += 1
-
-        self.screen.refresh()
-
-    def run_loop(self):
-        while True:
-            self.draw()
-            c = self.screen.getch()
-            if c in KEYS_UP:
-                self.move_up()
-            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:
-                    continue
-                return self.get_selected()
-            elif c in KEYS_SELECT and self.multiselect:
-                self.mark_index()
-            elif c in self.custom_handlers:
-                ret = self.custom_handlers[c](self)
-                if ret:
-                    return ret
-
-    def config_curses(self):
-        try:
-            # use the default colors of the terminal
-            curses.use_default_colors()
-            # hide the cursor
-            curses.curs_set(0)
-            # add some color for multi_select
-            # @todo make colors configurable
-            curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_WHITE)
-        except:
-            # Curses failed to initialize color support, eg. when TERM=vt100
-            curses.initscr()
-
-    def _start(self, screen):
-        self.screen = screen
-        self.config_curses()
-        return self.run_loop()
-
-    def start(self):
-        return curses.wrapper(self._start)
-
-
-def pick(*args, **kwargs):
-    """Construct and start a :class:`Picker <Picker>`.
-
-    Usage::
-
-      >>> from pick import pick
-      >>> title = 'Please choose an option: '
-      >>> options = ['option1', 'option2', 'option3']
-      >>> option, index = pick(options, title)
-    """
-    picker = Picker(*args, **kwargs)
-    return picker.start()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/poetry.lock new/pick-1.4.0/poetry.lock
--- old/pick-0.6.7/poetry.lock  1970-01-01 01:00:00.000000000 +0100
+++ new/pick-1.4.0/poetry.lock  2022-07-24 07:38:13.000000000 +0200
@@ -0,0 +1,346 @@
+[[package]]
+name = "atomicwrites"
+version = "1.4.1"
+description = "Atomic file writes."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "attrs"
+version = "21.4.0"
+description = "Classes Without Boilerplate"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.extras]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest 
(>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", 
"sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
+docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest 
(>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", 
"cloudpickle"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest 
(>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
+
+[[package]]
+name = "cfgv"
+version = "3.3.1"
+description = "Validate configuration and produce human readable error 
messages."
+category = "dev"
+optional = false
+python-versions = ">=3.6.1"
+
+[[package]]
+name = "colorama"
+version = "0.4.5"
+description = "Cross-platform colored terminal text."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "distlib"
+version = "0.3.5"
+description = "Distribution utilities"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "filelock"
+version = "3.7.1"
+description = "A platform independent file lock."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints 
(>=1.12)"]
+testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", 
"pytest-cov", "pytest-timeout (>=1.4.2)"]
+
+[[package]]
+name = "identify"
+version = "2.5.2"
+description = "File identification library for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+license = ["ukkonen"]
+
+[[package]]
+name = "importlib-metadata"
+version = "4.8.3"
+description = "Read metadata from Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+perf = ["ipython"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", 
"pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", 
"flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", 
"pytest-mypy", "importlib-resources (>=1.3)"]
+
+[[package]]
+name = "iniconfig"
+version = "1.1.1"
+description = "iniconfig: brain-dead simple config-ini parsing"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "mypy"
+version = "0.961"
+description = "Optional static typing for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+mypy-extensions = ">=0.4.3"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
+typing-extensions = ">=3.10"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+python2 = ["typed-ast (>=1.4.0,<2)"]
+reports = ["lxml"]
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+description = "Experimental type system extensions for programs checked with 
the mypy typechecker."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "nodeenv"
+version = "1.7.0"
+description = "Node.js virtual environment builder"
+category = "dev"
+optional = false
+python-versions = 
">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
+
+[[package]]
+name = "packaging"
+version = "21.3"
+description = "Core utilities for Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
+
+[[package]]
+name = "platformdirs"
+version = "2.5.2"
+description = "A small Python module for determining appropriate 
platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", 
"sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
+test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", 
"pytest (>=6)"]
+
+[[package]]
+name = "pluggy"
+version = "1.0.0"
+description = "plugin and hook calling mechanisms for python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pre-commit"
+version = "2.20.0"
+description = "A framework for managing and maintaining multi-language 
pre-commit hooks."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+cfgv = ">=2.0.0"
+identify = ">=1.0.0"
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
+nodeenv = ">=0.11.1"
+pyyaml = ">=5.1"
+toml = "*"
+virtualenv = ">=20.0.8"
+
+[[package]]
+name = "py"
+version = "1.11.0"
+description = "library with cross-python path, ini-parsing, io, code, log 
facilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "pyparsing"
+version = "3.0.7"
+description = "Python parsing module"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
+
+[[package]]
+name = "pytest"
+version = "6.2.5"
+description = "pytest: simple powerful testing with Python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
+attrs = ">=19.2.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<2.0"
+py = ">=1.8.2"
+toml = "*"
+
+[package.extras]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", 
"xmlschema"]
+
+[[package]]
+name = "pyyaml"
+version = "6.0"
+description = "YAML parser and emitter for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "tomli"
+version = "1.2.3"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "typed-ast"
+version = "1.5.4"
+description = "a fork of Python 2 and 3 ast modules with type comment support"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "typing-extensions"
+version = "4.1.1"
+description = "Backported and Experimental Type Hints for Python 3.6+"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "virtualenv"
+version = "20.15.1"
+description = "Virtual Python Environment builder"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+distlib = ">=0.3.1,<1"
+filelock = ">=3.2,<4"
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+platformdirs = ">=2,<3"
+six = ">=1.9.0,<2"
+
+[package.extras]
+docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", 
"sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
+testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky 
(>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", 
"pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", 
"packaging (>=20.0)"]
+
+[[package]]
+name = "windows-curses"
+version = "2.3.0"
+description = "Support for the standard curses module on Windows"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "zipp"
+version = "3.6.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", 
"pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", 
"pytest-black (>=0.3.7)", "pytest-mypy"]
+
+[metadata]
+lock-version = "1.1"
+python-versions = ">=3.7"
+content-hash = 
"e568d233095e1d85550e7047fd32b8a47bb52bfcc8b1beb1d7145c35ccd82bbd"
+
+[metadata.files]
+atomicwrites = []
+attrs = []
+cfgv = []
+colorama = []
+distlib = []
+filelock = []
+identify = []
+importlib-metadata = []
+iniconfig = []
+mypy = []
+mypy-extensions = []
+nodeenv = []
+packaging = []
+platformdirs = []
+pluggy = []
+pre-commit = []
+py = []
+pyparsing = []
+pytest = []
+pyyaml = []
+six = []
+toml = []
+tomli = []
+typed-ast = []
+typing-extensions = []
+virtualenv = []
+windows-curses = []
+zipp = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/pyproject.toml 
new/pick-1.4.0/pyproject.toml
--- old/pick-0.6.7/pyproject.toml       1970-01-01 01:00:00.000000000 +0100
+++ new/pick-1.4.0/pyproject.toml       2022-07-24 07:38:13.000000000 +0200
@@ -0,0 +1,23 @@
+[tool.poetry]
+name = "pick"
+version = "1.4.0"
+description = "Pick an option in the terminal with a simple GUI"
+authors = ["wong2 <[email protected]>"]
+license = "MIT"
+readme = "README.rst"
+repository = "https://github.com/wong2/pick";
+homepage = "https://github.com/wong2/pick";
+keywords = ["terminal", "gui"]
+
+[tool.poetry.dependencies]
+python = ">=3.7"
+windows-curses = {version = "^2.2.0", platform = "win32"}
+
+[tool.poetry.dev-dependencies]
+pytest = "^6.2.5"
+mypy = "^0.961"
+pre-commit = "^2.20.0"
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/setup.cfg new/pick-1.4.0/setup.cfg
--- old/pick-0.6.7/setup.cfg    2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/setup.cfg    2022-07-24 07:38:13.000000000 +0200
@@ -1,2 +1,5 @@
-[bdist_wheel]
-universal=1
+[mypy]
+check_untyped_defs = True
+warn_return_any = True
+warn_unreachable = True
+warn_unused_ignores = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/setup.py new/pick-1.4.0/setup.py
--- old/pick-0.6.7/setup.py     2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/setup.py     1970-01-01 01:00:00.000000000 +0100
@@ -1,34 +0,0 @@
-#-*-coding:utf-8-*-
-
-import os
-from setuptools import setup
-
-def fread(fname):
-    filepath = os.path.join(os.path.dirname(__file__), fname)
-    with open(filepath, 'r') as fp:
-        return fp.read()
-
-setup(
-    name='pick',
-    version='0.6.7',
-    description='pick an option in the terminal with a simple GUI',
-    long_description=fread('README.rst'),
-    keywords='terminal gui',
-    url='https://github.com/wong2/pick',
-    author='wong2',
-    author_email='[email protected]',
-    license='MIT',
-    packages=['pick'],
-    tests_require=['nose'],
-    classifiers=[
-        'Development Status :: 4 - Beta',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: MIT License',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 2.6',
-        'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3.3',
-        'Programming Language :: Python :: 3.4',
-        'Programming Language :: Python :: 3.5'
-    ]
-)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/src/pick/__init__.py 
new/pick-1.4.0/src/pick/__init__.py
--- old/pick-0.6.7/src/pick/__init__.py 1970-01-01 01:00:00.000000000 +0100
+++ new/pick-1.4.0/src/pick/__init__.py 2022-07-24 07:38:13.000000000 +0200
@@ -0,0 +1,231 @@
+import curses
+from dataclasses import dataclass, field
+from typing import Generic, Callable, List, Optional, Dict, Union, Tuple, 
TypeVar
+
+__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(" "))
+
+CUSTOM_HANDLER_RETURN_T = TypeVar("CUSTOM_HANDLER_RETURN_T")
+KEY_T = int
+OPTIONS_MAP_VALUE_T = TypeVar("OPTIONS_MAP_VALUE_T")
+PICK_RETURN_T = Tuple[OPTIONS_MAP_VALUE_T, int]
+
+
+@dataclass
+class Picker(Generic[CUSTOM_HANDLER_RETURN_T, OPTIONS_MAP_VALUE_T]):
+    """The :class:`Picker <Picker>` object
+
+    :param options: a list of options to choose from
+    :param title: (optional) a title above options list
+    :param multiselect: (optional) if true its possible to select multiple 
values by hitting SPACE, defaults to False
+    :param indicator: (optional) custom the selection indicator
+    :param default_index: (optional) set this if the default selected option 
is not the first one
+    :param options_map_func: (optional) a mapping function to pass each option 
through before displaying
+    """
+
+    options: List[OPTIONS_MAP_VALUE_T]
+    title: Optional[str] = None
+    indicator: str = "*"
+    default_index: int = 0
+    multiselect: bool = False
+    min_selection_count: int = 0
+    options_map_func: Callable[[OPTIONS_MAP_VALUE_T], Optional[str]] = str
+    all_selected: List[int] = field(init=False, default_factory=list)
+    custom_handlers: Dict[KEY_T, Callable[["Picker"], 
CUSTOM_HANDLER_RETURN_T]] = field(
+        init=False, default_factory=dict
+    )
+    index: int = field(init=False, default=0)
+    scroll_top: int = field(init=False, default=0)
+
+    def __post_init__(self) -> None:
+        if len(self.options) == 0:
+            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")
+
+        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"
+            )
+
+        if not callable(self.options_map_func):
+            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]
+    ) -> None:
+        self.custom_handlers[key] = func
+
+    def move_up(self) -> None:
+        self.index -= 1
+        if self.index < 0:
+            self.index = len(self.options) - 1
+
+    def move_down(self) -> None:
+        self.index += 1
+        if self.index >= len(self.options):
+            self.index = 0
+
+    def mark_index(self) -> None:
+        if self.multiselect:
+            if self.index in self.all_selected:
+                self.all_selected.remove(self.index)
+            else:
+                self.all_selected.append(self.index)
+
+    def get_selected(self) -> Union[List[PICK_RETURN_T], PICK_RETURN_T]:
+        """return the current selected option as a tuple: (option, index)
+        or as a list of tuples (in case multiselect==True)
+        """
+        if self.multiselect:
+            return_tuples = []
+            for selected in self.all_selected:
+                return_tuples.append((self.options[selected], selected))
+            return return_tuples
+        else:
+            return self.options[self.index], self.index
+
+    def get_title_lines(self) -> List[str]:
+        if self.title:
+            return self.title.split("\n") + [""]
+        return []
+
+    def get_option_lines(self) -> Union[List[str], List[Tuple[str, int]]]:
+        lines: Union[List[str], List[Tuple[str, int]]] = []  # type: 
ignore[assignment]
+        for index, option in enumerate(self.options):
+            option_as_str = self.options_map_func(option)
+
+            if index == self.index:
+                prefix = self.indicator
+            else:
+                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)
+            else:
+                line = "{0} {1}".format(prefix, option_as_str)
+            lines.append(line)  # type: ignore[arg-type]
+
+        return lines
+
+    def get_lines(self) -> Tuple[List, int]:
+        title_lines = self.get_title_lines()
+        option_lines = self.get_option_lines()
+        lines = title_lines + option_lines  # type: ignore[operator]
+        current_line = self.index + len(title_lines) + 1
+        return lines, current_line
+
+    def draw(self, screen) -> None:
+        """draw the curses ui on the screen, handle scroll if needed"""
+        screen.clear()
+
+        x, y = 1, 1  # start point
+        max_y, max_x = screen.getmaxyx()
+        max_rows = max_y - y  # the max rows we can draw
+
+        lines, current_line = self.get_lines()
+
+        # calculate how many lines we should scroll, relative to the top
+        if current_line <= self.scroll_top:
+            self.scroll_top = 0
+        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]
+
+        for line in lines_to_draw:
+            if type(line) is tuple:
+                screen.addnstr(y, x, line[0], max_x - 2, line[1])
+            else:
+                screen.addnstr(y, x, line, max_x - 2)
+            y += 1
+
+        screen.refresh()
+
+    def run_loop(
+        self, screen
+    ) -> Union[List[PICK_RETURN_T], PICK_RETURN_T, CUSTOM_HANDLER_RETURN_T]:
+        while True:
+            self.draw(screen)
+            c = screen.getch()
+            if c in KEYS_UP:
+                self.move_up()
+            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
+                ):
+                    continue
+                return self.get_selected()
+            elif c in KEYS_SELECT and self.multiselect:
+                self.mark_index()
+            elif c in self.custom_handlers:
+                ret = self.custom_handlers[c](self)
+                if ret:
+                    return ret
+
+    def config_curses(self) -> None:
+        try:
+            # use the default colors of the terminal
+            curses.use_default_colors()
+            # hide the cursor
+            curses.curs_set(0)
+            # add some color for multi_select
+            # @todo make colors configurable
+            curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_WHITE)
+        except:
+            # Curses failed to initialize color support, eg. when TERM=vt100
+            curses.initscr()
+
+    def _start(
+        self, screen
+    ) -> Union[List[PICK_RETURN_T], PICK_RETURN_T, CUSTOM_HANDLER_RETURN_T]:
+        self.config_curses()
+        return self.run_loop(screen)
+
+    def start(
+        self,
+    ) -> Union[List[PICK_RETURN_T], PICK_RETURN_T, CUSTOM_HANDLER_RETURN_T]:
+        return curses.wrapper(self._start)
+
+
+def pick(
+    options: List[OPTIONS_MAP_VALUE_T],
+    title: Optional[str] = None,
+    indicator: str = "*",
+    default_index: int = 0,
+    multiselect: bool = False,
+    min_selection_count: int = 0,
+    options_map_func: Callable[[OPTIONS_MAP_VALUE_T], Optional[str]] = str,
+) -> Union[List[PICK_RETURN_T], PICK_RETURN_T]:
+    """Construct and start a :class:`Picker <Picker>`.
+
+    Usage::
+
+      >>> from pick import pick
+      >>> title = 'Please choose an option: '
+      >>> options = ['option1', 'option2', 'option3']
+      >>> option, index = pick(options, title)
+    """
+    picker = Picker(
+        options,
+        title,
+        indicator,
+        default_index,
+        multiselect,
+        min_selection_count,
+        options_map_func,
+    )
+    return picker.start()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-0.6.7/tests/test_pick.py 
new/pick-1.4.0/tests/test_pick.py
--- old/pick-0.6.7/tests/test_pick.py   2020-02-02 08:07:31.000000000 +0100
+++ new/pick-1.4.0/tests/test_pick.py   2022-07-24 07:38:13.000000000 +0200
@@ -1,63 +1,66 @@
-#-*-coding:utf-8-*-
+from typing import Dict, Optional
 
-import unittest
 from pick import Picker
 
 
-class TestPick(unittest.TestCase):
-
-    def test_move_up_down(self):
-        title = 'Please choose an option: '
-        options = ['option1', 'option2', 'option3']
-        picker = Picker(options, title)
-        picker.move_up()
-        assert picker.get_selected() == ('option3', 2)
-        picker.move_down()
-        picker.move_down()
-        assert picker.get_selected() == ('option2', 1)
-
-    def test_default_index(self):
-        title = 'Please choose an option: '
-        options = ['option1', 'option2', 'option3']
-        picker = Picker(options, title, default_index=1)
-        assert picker.get_selected() == ('option2', 1)
-
-    def test_get_lines(self):
-        title = 'Please choose an option: '
-        options = ['option1', 'option2', 'option3']
-        picker = Picker(options, title, indicator='*')
-        lines, current_line = picker.get_lines()
-        assert lines == [title, '', '* option1', '  option2', '  option3']
-        assert current_line == 3
-
-    def test_no_title(self):
-        options = ['option1', 'option2', 'option3']
-        picker = Picker(options)
-        lines, current_line = picker.get_lines()
-        assert current_line == 1
-
-    def test_multi_select(self):
-        title = 'Please choose an option: '
-        options = ['option1', 'option2', 'option3']
-        picker = Picker(options, title, multi_select=True, 
min_selection_count=1)
-        assert picker.get_selected() == []
-        picker.mark_index()
-        assert picker.get_selected() == [('option1', 0)]
-        picker.move_down()
-        picker.mark_index()
-        assert picker.get_selected() == [('option1', 0), ('option2', 1)]
-
-    def test_options_map_func(self):
-        title = 'Please choose an option: '
-        options = [{'label': 'option1'}, {'label': 'option2'}, {'label': 
'option3'}]
-
-        def get_label(option): return option.get('label')
-
-        picker = 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)
-
-
-if __name__ == '__main__':
-    unittest.main()
+def test_move_up_down():
+    title = "Please choose an option: "
+    options = ["option1", "option2", "option3"]
+    picker: Picker[str, str] = Picker(options, title)
+    picker.move_up()
+    assert picker.get_selected() == ("option3", 2)
+    picker.move_down()
+    picker.move_down()
+    assert picker.get_selected() == ("option2", 1)
+
+
+def test_default_index():
+    title = "Please choose an option: "
+    options = ["option1", "option2", "option3"]
+    picker: Picker[str, str] = Picker(options, title, default_index=1)
+    assert picker.get_selected() == ("option2", 1)
+
+
+def test_get_lines():
+    title = "Please choose an option: "
+    options = ["option1", "option2", "option3"]
+    picker: Picker[str, str] = Picker(options, title, indicator="*")
+    lines, current_line = picker.get_lines()
+    assert lines == [title, "", "* option1", "  option2", "  option3"]
+    assert current_line == 3
+
+
+def test_no_title():
+    options = ["option1", "option2", "option3"]
+    picker: Picker[str, str] = Picker(options)
+    lines, current_line = picker.get_lines()
+    assert current_line == 1
+
+
+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
+    )
+    assert picker.get_selected() == []
+    picker.mark_index()
+    assert picker.get_selected() == [("option1", 0)]
+    picker.move_down()
+    picker.mark_index()
+    assert picker.get_selected() == [("option1", 0), ("option2", 1)]
+
+
+def test_options_map_func():
+    title = "Please choose an option: "
+    options = [{"label": "option1"}, {"label": "option2"}, {"label": 
"option3"}]
+
+    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
+    )
+    lines, current_line = picker.get_lines()
+    assert lines == [title, "", "* option1", "  option2", "  option3"]
+    assert picker.get_selected() == ({"label": "option1"}, 0)

Reply via email to