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-11-06 14:09:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pick (Old)
 and      /work/SRC/openSUSE:Factory/.python-pick.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pick"

Sun Nov  6 14:09:27 2022 rev:7 rq:1033854 version:2.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pick/python-pick.changes  2022-07-26 
19:44:34.522405409 +0200
+++ /work/SRC/openSUSE:Factory/.python-pick.new.2275/python-pick.changes        
2022-11-06 14:09:28.835729282 +0100
@@ -1,0 +2,32 @@
+Sun Nov  6 12:07:44 UTC 2022 - Luigi Baldoni <aloi...@gmx.com>
+
+- Update to version 2.1.0
+  * Change the way scroll is handled.
+  version 2.0.2:
+  * Remove the additional space
+  version 2.0.1:
+  * Change multiselect symbols
+  * Bump pytest from 7.1.2 to 7.1.3
+  version 2.0.0:
+  * Add Option class
+  * Drop options_map_func
+  * Drop register_custom_handler
+  * Remove docstrings
+  * Add multiselect example gif
+  * Use markdown for README
+  version 1.6.0:
+  * Update multiselect mode style
+  * Add multiselect example
+  * Fix examples
+  * Bump pytest from 6.2.5 to 7.1.2
+  * Bump mypy from 0.961 to 0.971
+  version 1.5.0:
+  * Fix mypy call in ci
+  * Create dependabot.yml
+  * Add static type checking to ci
+  * Check static type with pytest
+  * Format code
+  * Change list to sequence for Picker.options
+  * Rename all_selected to selected_indexes
+
+-------------------------------------------------------------------

Old:
----
  pick-1.4.0.tar.gz

New:
----
  pick-2.1.0.tar.gz

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

Other differences:
------------------
++++++ python-pick.spec ++++++
--- /var/tmp/diff_new_pack.WtJI1M/_old  2022-11-06 14:09:29.327732049 +0100
+++ /var/tmp/diff_new_pack.WtJI1M/_new  2022-11-06 14:09:29.331732071 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           python-pick
-Version:        1.4.0
+Version:        2.1.0
 Release:        0
 Summary:        Curses-based interactive selection list module
 License:        MIT
@@ -53,7 +53,7 @@
 
 %files %{python_files}
 %license LICENSE
-%doc README.rst
+%doc README.md
 %{python_sitelib}/*
 
 %changelog

++++++ pick-1.4.0.tar.gz -> pick-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/.github/dependabot.yml 
new/pick-2.1.0/.github/dependabot.yml
--- old/pick-1.4.0/.github/dependabot.yml       1970-01-01 01:00:00.000000000 
+0100
+++ new/pick-2.1.0/.github/dependabot.yml       2022-11-06 07:58:43.000000000 
+0100
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# 
https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+  - package-ecosystem: "pip" # See documentation for possible values
+    directory: "/" # Location of package manifests
+    schedule:
+      interval: "daily"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/.github/workflows/ci.yml 
new/pick-2.1.0/.github/workflows/ci.yml
--- old/pick-1.4.0/.github/workflows/ci.yml     2022-07-24 07:38:13.000000000 
+0200
+++ new/pick-2.1.0/.github/workflows/ci.yml     2022-11-06 07:58:43.000000000 
+0100
@@ -18,5 +18,8 @@
         uses: abatilo/actions-poetry@v2.0.0
       - name: Install dependencies
         run: poetry install
+      - name: Static type checking
+        run: poetry run mypy .
+        if: runner.os != 'Windows'
       - name: Run test
         run: poetry run pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/README.md new/pick-2.1.0/README.md
--- old/pick-1.4.0/README.md    1970-01-01 01:00:00.000000000 +0100
+++ new/pick-2.1.0/README.md    2022-11-06 07:58:43.000000000 +0100
@@ -0,0 +1,62 @@
+# pick
+
+[![image](https://github.com/wong2/pick/actions/workflows/ci.yml/badge.svg)](https://github.com/wong2/pick/actions/workflows/ci.yml)
+[![PyPI](https://img.shields.io/pypi/v/pick.svg)](https://pypi.python.org/pypi/pick)
+[![PyPI](https://img.shields.io/pypi/dm/pick)](https://pypi.python.org/pypi/pick)
+
+**pick** is a small python library to help you create curses based
+interactive selection list in the terminal.
+
+|         Basic          |         Multiselect          |
+| :--------------------: | :--------------------------: |
+| ![](example/basic.gif) | ![](example/multiselect.gif) |
+
+## Installation
+
+    $ pip install pick
+
+## Usage
+
+**pick** comes with a simple api:
+
+    >>> from pick import pick
+
+    >>> title = 'Please choose your favorite programming language: '
+    >>> options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 
'Haskell']
+    >>> option, index = pick(options, title)
+    >>> print(option)
+    >>> print(index)
+
+**outputs**:
+
+    >>> C++
+    >>> 4
+
+**pick** multiselect example:
+
+    >>> from pick import pick
+
+    >>> title = 'Please choose your favorite programming language (press SPACE 
to mark, ENTER to continue): '
+    >>> options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 
'Haskell']
+    >>> selected = pick(options, title, multiselect=True, 
min_selection_count=1)
+    >>> print(selected)
+
+**outputs**:
+
+    >>> [('Java', 0), ('C++', 4)]
+
+## Options
+
+- `options`: a list of options to choose from
+- `title`: (optional) a title above options list
+- `indicator`: (optional) custom the selection indicator, defaults to `*`
+- `default_index`: (optional) set this if the default selected option
+  is not the first one
+- `multiselect`: (optional), if set to True its possible to select
+  multiple items by hitting SPACE
+- `min_selection_count`: (optional) for multi select feature to
+  dictate a minimum of selected items before continuing
+
+## 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-1.4.0/README.rst new/pick-2.1.0/README.rst
--- old/pick-1.4.0/README.rst   2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/README.rst   1970-01-01 01:00:00.000000000 +0100
@@ -1,123 +0,0 @@
-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. 
-
-.. image:: https://github.com/wong2/pick/raw/master/example/basic.gif
-   :alt: Demo
-
-Installation
-------------
-
-::
-
-    $ pip install pick
-
-Usage
------
-
-**pick** comes with a simple api::
-
-    >>> from pick import pick
-
-    >>> title = 'Please choose your favorite programming language: '
-    >>> options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 
'Haskell']
-    >>> option, index = pick(options, title)
-    >>> print(option)
-    >>> print(index)
-
-**outputs**::
-
-    >>> C++
-    >>> 4
-
-**pick** multiselect example::
-
-    >>> from pick import pick
-
-    >>> title = 'Please choose your favorite programming language (press SPACE 
to mark, ENTER to continue): '
-    >>> options = ['Java', 'JavaScript', 'Python', 'PHP', 'C++', 'Erlang', 
'Haskell']
-    >>> selected = pick(options, title, multiselect=True, 
min_selection_count=1)
-    >>> print(selected)
-
-**outputs**::
-
-    >>> [('Java', 0), ('C++', 4)]
-
-
-Options
--------
-
-* ``options``: a list of options to choose from
-* ``title``: (optional) a title above options list
-* ``indicator``: (optional) custom the selection indicator, defaults to *
-* ``default_index``: (optional) set this if the default selected option is not 
the first one
-* ``multiselect``: (optional), if set to True its possible to select multiple 
items by hitting SPACE
-* ``min_selection_count``: (optional) for multi select feature to dictate a 
minimum of selected items before continuing
-* ``options_map_func``: (optional) a mapping function to pass each option 
through before displaying
-
-Register custom handlers
-------------------------
-
-Sometimes you may need to register custom handlers for specific keyboard keys, 
you can use the ``register_custom_handler`` API::
-
-    >>> from pick import Picker
-    >>> title, options = 'Title', ['Option1', 'Option2']
-    >>> picker = Picker(options, title)
-    >>> def go_back(picker):
-    ...     return None, -1
-    >>> picker.register_custom_handler(ord('h'),  go_back)
-    >>> option, index = picker.start()
-
-* the custom handler will be called with the ``picker`` instance as it's 
parameter.
-* the custom handler should either return a two element tuple, or None.
-* if None is returned, the picker would continue to run, otherwise the picker 
will stop and return the tuple.
-
-Options Map Function
---------------------
-
-If your options are not in a format that you want displayed (such as a 
dictionary), you can pass in a mapping function which each option will be run 
through. The return value of the function will be displayed.
-
-* the selected option returned will be the original value and not the 
displayed return result from the ``options_map_func`` function.
-
-**pick** options map function example::
-
-    >>> from pick import pick
-
-    >>> title = 'Please choose an option: '
-    >>> options = [{'label': 'option1'}, {'label': 'option2'}, {'label': 
'option3'}]
-
-    >>> def get_label(option): return option.get('label')
-
-    >>> selected = pick(options, title, indicator='*', 
options_map_func=get_label)
-    >>> print(selected)
-
-**displays**::
-
-    Please choose an option:
-
-    * option1
-      option2
-      option3
-
-**outputs**::
-
-    >>> ({ 'label': 'option1' }, 0)
-
-Community Projects
---------------------
-
-`pickpack <https://github.com/anafvana/pickpack>`_: A fork of `pick` to select 
tree data.
Binary files old/pick-1.4.0/example/basic.gif and 
new/pick-2.1.0/example/basic.gif differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/example/basic.py 
new/pick-2.1.0/example/basic.py
--- old/pick-1.4.0/example/basic.py     2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/example/basic.py     2022-11-06 07:58:43.000000000 +0100
@@ -2,7 +2,5 @@
 
 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)
+option, index = pick(options, title, indicator="=>", default_index=2)
+print(f"You choosed {option} at index {index}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/example/custom.py 
new/pick-2.1.0/example/custom.py
--- old/pick-1.4.0/example/custom.py    2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/example/custom.py    1970-01-01 01:00:00.000000000 +0100
@@ -1,32 +0,0 @@
-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"]
-
-# with type annotation
-picker: Picker[Tuple[None, int], str] = Picker(options, title)
-picker.register_custom_handler(curses.KEY_LEFT, go_back)
-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)
Binary files old/pick-1.4.0/example/multiselect.gif and 
new/pick-2.1.0/example/multiselect.gif differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/example/multiselect.py 
new/pick-2.1.0/example/multiselect.py
--- old/pick-1.4.0/example/multiselect.py       1970-01-01 01:00:00.000000000 
+0100
+++ new/pick-2.1.0/example/multiselect.py       2022-11-06 07:58:43.000000000 
+0100
@@ -0,0 +1,6 @@
+from pick import pick
+
+title = "Choose your favorite programming language(use space to select)"
+options = ["Java", "JavaScript", "Python", "PHP", "C++", "Erlang", "Haskell"]
+selected = pick(options, title, multiselect=True, min_selection_count=1)
+print(selected)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/example/option.py 
new/pick-2.1.0/example/option.py
--- old/pick-1.4.0/example/option.py    1970-01-01 01:00:00.000000000 +0100
+++ new/pick-2.1.0/example/option.py    2022-11-06 07:58:43.000000000 +0100
@@ -0,0 +1,10 @@
+from pick import pick, Option
+
+title = "Please choose your favorite programming language: "
+options = [
+    Option("Java", ".java"),
+    Option("Python", ".py"),
+    Option("JavaScript", ".js"),
+]
+option, index = pick(options, title)
+print(f"You choosed {option} at index {index}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/example/options_map_func.py 
new/pick-2.1.0/example/options_map_func.py
--- old/pick-1.4.0/example/options_map_func.py  2022-07-24 07:38:13.000000000 
+0200
+++ new/pick-2.1.0/example/options_map_func.py  1970-01-01 01:00:00.000000000 
+0100
@@ -1,22 +0,0 @@
-from pick import pick
-
-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"},
-]
-
-
-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"))
-
-
-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-1.4.0/example/scroll.py 
new/pick-2.1.0/example/scroll.py
--- old/pick-1.4.0/example/scroll.py    2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/example/scroll.py    2022-11-06 07:58:43.000000000 +0100
@@ -2,7 +2,5 @@
 
 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]
+option, index = pick(options, title)
 print(option, index)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/poetry.lock new/pick-2.1.0/poetry.lock
--- old/pick-1.4.0/poetry.lock  2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/poetry.lock  2022-11-06 07:58:43.000000000 +0100
@@ -1,12 +1,4 @@
 [[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"
@@ -15,10 +7,10 @@
 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"]
+dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", 
"mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", 
"six", "sphinx", "sphinx-notfound-page", "zope.interface"]
+docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
+tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", 
"pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"]
+tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", 
"mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"]
 
 [[package]]
 name = "cfgv"
@@ -80,9 +72,9 @@
 zipp = ">=0.5"
 
 [package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"]
 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)"]
+testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", 
"pep517", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", 
"pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", 
"pytest-flake8", "pytest-mypy", "pytest-perf (>=0.9.2)"]
 
 [[package]]
 name = "iniconfig"
@@ -94,7 +86,7 @@
 
 [[package]]
 name = "mypy"
-version = "0.961"
+version = "0.971"
 description = "Optional static typing for Python"
 category = "dev"
 optional = false
@@ -147,8 +139,8 @@
 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)"]
+docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", 
"sphinx-autodoc-typehints (>=1.12)"]
+test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", 
"pytest-mock (>=3.6)"]
 
 [[package]]
 name = "pluggy"
@@ -203,14 +195,13 @@
 
 [[package]]
 name = "pytest"
-version = "6.2.5"
+version = "7.1.3"
 description = "pytest: simple powerful testing with Python"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [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\""}
@@ -218,10 +209,10 @@
 packaging = "*"
 pluggy = ">=0.12,<2.0"
 py = ">=1.8.2"
-toml = "*"
+tomli = ">=1.0.0"
 
 [package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", 
"xmlschema"]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments 
(>=2.7.2)", "requests", "xmlschema"]
 
 [[package]]
 name = "pyyaml"
@@ -288,7 +279,7 @@
 
 [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)"]
+testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky 
(>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", 
"pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", 
"pytest-timeout (>=1)"]
 
 [[package]]
 name = "windows-curses"
@@ -307,40 +298,202 @@
 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"]
+docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"]
+testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black 
(>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler 
(>=1.0.1)", "pytest-flake8", "pytest-mypy"]
 
 [metadata]
 lock-version = "1.1"
 python-versions = ">=3.7"
-content-hash = 
"e568d233095e1d85550e7047fd32b8a47bb52bfcc8b1beb1d7145c35ccd82bbd"
+content-hash = 
"8ad036630d1feeddb525fbba98a26da3a718f58357b1c6b9fcf6dac57ef6c353"
 
 [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 = []
+attrs = [
+    {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = 
"sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
+    {file = "attrs-21.4.0.tar.gz", hash = 
"sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
+]
+cfgv = [
+    {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = 
"sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
+    {file = "cfgv-3.3.1.tar.gz", hash = 
"sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
+]
+colorama = [
+    {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = 
"sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
+    {file = "colorama-0.4.5.tar.gz", hash = 
"sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
+]
+distlib = [
+    {file = "distlib-0.3.5-py2.py3-none-any.whl", hash = 
"sha256:b710088c59f06338ca514800ad795a132da19fda270e3ce4affc74abf955a26c"},
+    {file = "distlib-0.3.5.tar.gz", hash = 
"sha256:a7f75737c70be3b25e2bee06288cec4e4c221de18455b2dd037fe2a795cab2fe"},
+]
+filelock = [
+    {file = "filelock-3.7.1-py3-none-any.whl", hash = 
"sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
+    {file = "filelock-3.7.1.tar.gz", hash = 
"sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
+]
+identify = [
+    {file = "identify-2.5.2-py2.py3-none-any.whl", hash = 
"sha256:feaa9db2dc0ce333b453ce171c0cf1247bbfde2c55fc6bb785022d411a1b78b5"},
+    {file = "identify-2.5.2.tar.gz", hash = 
"sha256:a3d4c096b384d50d5e6dc5bc8b9bc44f1f61cefebd750a7b3e9f939b53fb214d"},
+]
+importlib-metadata = [
+    {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = 
"sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
+    {file = "importlib_metadata-4.8.3.tar.gz", hash = 
"sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
+]
+iniconfig = [
+    {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = 
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
+    {file = "iniconfig-1.1.1.tar.gz", hash = 
"sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
+]
+mypy = [
+    {file = "mypy-0.971-cp310-cp310-macosx_10_9_universal2.whl", hash = 
"sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"},
+    {file = "mypy-0.971-cp310-cp310-macosx_10_9_x86_64.whl", hash = 
"sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5"},
+    {file = "mypy-0.971-cp310-cp310-macosx_11_0_arm64.whl", hash = 
"sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3"},
+    {file = 
"mypy-0.971-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655"},
+    {file = "mypy-0.971-cp310-cp310-win_amd64.whl", hash = 
"sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103"},
+    {file = "mypy-0.971-cp36-cp36m-macosx_10_9_x86_64.whl", hash = 
"sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca"},
+    {file = 
"mypy-0.971-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417"},
+    {file = "mypy-0.971-cp36-cp36m-win_amd64.whl", hash = 
"sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09"},
+    {file = "mypy-0.971-cp37-cp37m-macosx_10_9_x86_64.whl", hash = 
"sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8"},
+    {file = 
"mypy-0.971-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0"},
+    {file = "mypy-0.971-cp37-cp37m-win_amd64.whl", hash = 
"sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2"},
+    {file = "mypy-0.971-cp38-cp38-macosx_10_9_universal2.whl", hash = 
"sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27"},
+    {file = "mypy-0.971-cp38-cp38-macosx_10_9_x86_64.whl", hash = 
"sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856"},
+    {file = "mypy-0.971-cp38-cp38-macosx_11_0_arm64.whl", hash = 
"sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71"},
+    {file = 
"mypy-0.971-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27"},
+    {file = "mypy-0.971-cp38-cp38-win_amd64.whl", hash = 
"sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58"},
+    {file = "mypy-0.971-cp39-cp39-macosx_10_9_universal2.whl", hash = 
"sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6"},
+    {file = "mypy-0.971-cp39-cp39-macosx_10_9_x86_64.whl", hash = 
"sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe"},
+    {file = "mypy-0.971-cp39-cp39-macosx_11_0_arm64.whl", hash = 
"sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9"},
+    {file = 
"mypy-0.971-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf"},
+    {file = "mypy-0.971-cp39-cp39-win_amd64.whl", hash = 
"sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0"},
+    {file = "mypy-0.971-py3-none-any.whl", hash = 
"sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9"},
+    {file = "mypy-0.971.tar.gz", hash = 
"sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56"},
+]
+mypy-extensions = [
+    {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = 
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
+    {file = "mypy_extensions-0.4.3.tar.gz", hash = 
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
+]
+nodeenv = [
+    {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = 
"sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
+    {file = "nodeenv-1.7.0.tar.gz", hash = 
"sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"},
+]
+packaging = [
+    {file = "packaging-21.3-py3-none-any.whl", hash = 
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
+    {file = "packaging-21.3.tar.gz", hash = 
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
+]
+platformdirs = [
+    {file = "platformdirs-2.5.2-py3-none-any.whl", hash = 
"sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
+    {file = "platformdirs-2.5.2.tar.gz", hash = 
"sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
+]
+pluggy = [
+    {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = 
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
+    {file = "pluggy-1.0.0.tar.gz", hash = 
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
+]
+pre-commit = [
+    {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = 
"sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"},
+    {file = "pre_commit-2.20.0.tar.gz", hash = 
"sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"},
+]
+py = [
+    {file = "py-1.11.0-py2.py3-none-any.whl", hash = 
"sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
+    {file = "py-1.11.0.tar.gz", hash = 
"sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
+]
+pyparsing = [
+    {file = "pyparsing-3.0.7-py3-none-any.whl", hash = 
"sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
+    {file = "pyparsing-3.0.7.tar.gz", hash = 
"sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
+]
+pytest = [
+    {file = "pytest-7.1.3-py3-none-any.whl", hash = 
"sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"},
+    {file = "pytest-7.1.3.tar.gz", hash = 
"sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"},
+]
+pyyaml = [
+    {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = 
"sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
+    {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = 
"sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
+    {file = 
"PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash 
= "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
+    {file = 
"PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = 
"sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
+    {file = 
"PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
+    {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = 
"sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
+    {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = 
"sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
+    {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = 
"sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
+    {file = 
"PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash 
= "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
+    {file = 
"PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = 
"sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
+    {file = 
"PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
+    {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = 
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
+    {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = 
"sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
+    {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = 
"sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
+    {file = 
"PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash 
= "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
+    {file = 
"PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = 
"sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
+    {file = 
"PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
+    {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = 
"sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
+    {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = 
"sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
+    {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = 
"sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
+    {file = 
"PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = 
"sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
+    {file = 
"PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = 
"sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
+    {file = 
"PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
+    {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = 
"sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
+    {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = 
"sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
+    {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = 
"sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
+    {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = 
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
+    {file = 
"PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = 
"sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
+    {file = 
"PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = 
"sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
+    {file = 
"PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
+    {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = 
"sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
+    {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = 
"sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
+    {file = "PyYAML-6.0.tar.gz", hash = 
"sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
+]
+six = [
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = 
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = 
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+toml = [
+    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = 
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+    {file = "toml-0.10.2.tar.gz", hash = 
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+tomli = [
+    {file = "tomli-1.2.3-py3-none-any.whl", hash = 
"sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"},
+    {file = "tomli-1.2.3.tar.gz", hash = 
"sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"},
+]
+typed-ast = [
+    {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = 
"sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"},
+    {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = 
"sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"},
+    {file = 
"typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", 
hash = 
"sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"},
+    {file = 
"typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"},
+    {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = 
"sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"},
+    {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = 
"sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"},
+    {file = 
"typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", 
hash = 
"sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"},
+    {file = 
"typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"},
+    {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = 
"sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"},
+    {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = 
"sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"},
+    {file = 
"typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", 
hash = 
"sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"},
+    {file = 
"typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"},
+    {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = 
"sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"},
+    {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = 
"sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"},
+    {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = 
"sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"},
+    {file = 
"typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", 
hash = 
"sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"},
+    {file = 
"typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"},
+    {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = 
"sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"},
+    {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = 
"sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"},
+    {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = 
"sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"},
+    {file = 
"typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", 
hash = 
"sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"},
+    {file = 
"typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
 hash = 
"sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"},
+    {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = 
"sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"},
+    {file = "typed_ast-1.5.4.tar.gz", hash = 
"sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
+]
+typing-extensions = [
+    {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = 
"sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"},
+    {file = "typing_extensions-4.1.1.tar.gz", hash = 
"sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
+]
+virtualenv = [
+    {file = "virtualenv-20.15.1-py2.py3-none-any.whl", hash = 
"sha256:b30aefac647e86af6d82bfc944c556f8f1a9c90427b2fb4e3bfbf338cb82becf"},
+    {file = "virtualenv-20.15.1.tar.gz", hash = 
"sha256:288171134a2ff3bfb1a2f54f119e77cd1b81c29fc1265a2356f3e8d14c7d58c4"},
+]
+windows-curses = [
+    {file = "windows_curses-2.3.0-cp310-cp310-win32.whl", hash = 
"sha256:a3a63a0597729e10f923724c2cf972a23ea677b400d2387dee1d668cf7116177"},
+    {file = "windows_curses-2.3.0-cp310-cp310-win_amd64.whl", hash = 
"sha256:7a35eda4cb120b9e1a5ae795f3bc06c55b92c9d391baba6be1903285a05f3551"},
+    {file = "windows_curses-2.3.0-cp36-cp36m-win32.whl", hash = 
"sha256:4d5fb991d1b90a41c2332f02241a1f84c8a1e6bc8f6e0d26f532d0da7a9f7b51"},
+    {file = "windows_curses-2.3.0-cp36-cp36m-win_amd64.whl", hash = 
"sha256:170c0d941c2e0cdf864e7f0441c1bdf0709232bf4aa7ce7f54d90fc76a4c0504"},
+    {file = "windows_curses-2.3.0-cp37-cp37m-win32.whl", hash = 
"sha256:d5cde8ec6d582aa77af791eca54f60858339fb3f391945f9cad11b1ab71062e3"},
+    {file = "windows_curses-2.3.0-cp37-cp37m-win_amd64.whl", hash = 
"sha256:e913dc121446d92b33fe4f5bcca26d3a34e4ad19f2af160370d57c3d1e93b4e1"},
+    {file = "windows_curses-2.3.0-cp38-cp38-win32.whl", hash = 
"sha256:fbc2131cec57e422c6660e6cdb3420aff5be5169b8e45bb7c471f884b0590a2b"},
+    {file = "windows_curses-2.3.0-cp38-cp38-win_amd64.whl", hash = 
"sha256:cc5fa913780d60f4a40824d374a4f8ca45b4e205546e83a2d85147315a57457e"},
+    {file = "windows_curses-2.3.0-cp39-cp39-win32.whl", hash = 
"sha256:935be95cfdb9213f6f5d3d5bcd489960e3a8fbc9b574e7b2e8a3a3cc46efff49"},
+    {file = "windows_curses-2.3.0-cp39-cp39-win_amd64.whl", hash = 
"sha256:c860f596d28377e47f322b7382be4d3573fd76d1292234996bb7f72e0bc0ed0d"},
+]
+zipp = [
+    {file = "zipp-3.6.0-py3-none-any.whl", hash = 
"sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
+    {file = "zipp-3.6.0.tar.gz", hash = 
"sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/pyproject.toml 
new/pick-2.1.0/pyproject.toml
--- old/pick-1.4.0/pyproject.toml       2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/pyproject.toml       2022-11-06 07:58:43.000000000 +0100
@@ -1,10 +1,10 @@
 [tool.poetry]
 name = "pick"
-version = "1.4.0"
+version = "2.1.0"
 description = "Pick an option in the terminal with a simple GUI"
 authors = ["wong2 <wonderf...@gmail.com>"]
 license = "MIT"
-readme = "README.rst"
+readme = "README.md"
 repository = "https://github.com/wong2/pick";
 homepage = "https://github.com/wong2/pick";
 keywords = ["terminal", "gui"]
@@ -14,8 +14,8 @@
 windows-curses = {version = "^2.2.0", platform = "win32"}
 
 [tool.poetry.dev-dependencies]
-pytest = "^6.2.5"
-mypy = "^0.961"
+pytest = "^7.1.3"
+mypy = "^0.971"
 pre-commit = "^2.20.0"
 
 [build-system]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pick-1.4.0/src/pick/__init__.py 
new/pick-2.1.0/src/pick/__init__.py
--- old/pick-1.4.0/src/pick/__init__.py 2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/src/pick/__init__.py 2022-11-06 07:58:43.000000000 +0100
@@ -1,8 +1,14 @@
 import curses
 from dataclasses import dataclass, field
-from typing import Generic, Callable, List, Optional, Dict, Union, Tuple, 
TypeVar
+from typing import Any, List, Optional, Sequence, Tuple, TypeVar, Union, 
Generic
 
-__all__ = ["Picker", "pick"]
+__all__ = ["Picker", "pick", "Option"]
+
+
+@dataclass
+class Option:
+    label: str
+    value: Any
 
 
 KEYS_ENTER = (curses.KEY_ENTER, ord("\n"), ord("\r"))
@@ -10,37 +16,23 @@
 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]
+SYMBOL_CIRCLE_FILLED = "(x)"
+SYMBOL_CIRCLE_EMPTY = "( )"
 
+OPTION_T = TypeVar("OPTION_T", str, Option)
+PICK_RETURN_T = Tuple[OPTION_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]
+@dataclass
+class Picker(Generic[OPTION_T]):
+    options: Sequence[OPTION_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
-    )
+    selected_indexes: List[int] = field(init=False, default_factory=list)
     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:
@@ -54,16 +46,8 @@
                 "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:
@@ -76,10 +60,10 @@
 
     def mark_index(self) -> None:
         if self.multiselect:
-            if self.index in self.all_selected:
-                self.all_selected.remove(self.index)
+            if self.index in self.selected_indexes:
+                self.selected_indexes.remove(self.index)
             else:
-                self.all_selected.append(self.index)
+                self.selected_indexes.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)
@@ -87,7 +71,7 @@
         """
         if self.multiselect:
             return_tuples = []
-            for selected in self.all_selected:
+            for selected in self.selected_indexes:
                 return_tuples.append((self.options[selected], selected))
             return return_tuples
         else:
@@ -98,30 +82,31 @@
             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]
+    def get_option_lines(self) -> List[str]:
+        lines: List[str] = []
         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]
+            if self.multiselect:
+                symbol = (
+                    SYMBOL_CIRCLE_FILLED
+                    if index in self.selected_indexes
+                    else SYMBOL_CIRCLE_EMPTY
+                )
+                prefix = f"{prefix} {symbol}"
+
+            option_as_str = option.label if isinstance(option, Option) else 
option
+            lines.append(f"{prefix} {option_as_str}")
 
         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]
+        lines = title_lines + option_lines
         current_line = self.index + len(title_lines) + 1
         return lines, current_line
 
@@ -136,25 +121,19 @@
         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
+        scroll_top = 0
+        if current_line > max_rows:
+            scroll_top = current_line - max_rows
 
-        lines_to_draw = lines[self.scroll_top : self.scroll_top + max_rows]
+        lines_to_draw = lines[scroll_top : 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)
+            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]:
+    def run_loop(self, screen) -> Union[List[PICK_RETURN_T], PICK_RETURN_T]:
         while True:
             self.draw(screen)
             c = screen.getch()
@@ -165,16 +144,12 @@
             elif c in KEYS_ENTER:
                 if (
                     self.multiselect
-                    and len(self.all_selected) < self.min_selection_count
+                    and len(self.selected_indexes) < 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:
@@ -182,50 +157,32 @@
             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]:
+    def _start(self, screen):
         self.config_curses()
         return self.run_loop(screen)
 
-    def start(
-        self,
-    ) -> Union[List[PICK_RETURN_T], PICK_RETURN_T, CUSTOM_HANDLER_RETURN_T]:
+    def start(self):
         return curses.wrapper(self._start)
 
 
 def pick(
-    options: List[OPTIONS_MAP_VALUE_T],
+    options: Sequence[OPTION_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(
+):
+    picker: 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-1.4.0/tests/test_pick.py 
new/pick-2.1.0/tests/test_pick.py
--- old/pick-1.4.0/tests/test_pick.py   2022-07-24 07:38:13.000000000 +0200
+++ new/pick-2.1.0/tests/test_pick.py   2022-11-06 07:58:43.000000000 +0100
@@ -1,12 +1,10 @@
-from typing import Dict, Optional
-
-from pick import Picker
+from pick import Picker, Option
 
 
 def test_move_up_down():
     title = "Please choose an option: "
     options = ["option1", "option2", "option3"]
-    picker: Picker[str, str] = Picker(options, title)
+    picker = Picker(options, title)
     picker.move_up()
     assert picker.get_selected() == ("option3", 2)
     picker.move_down()
@@ -17,14 +15,14 @@
 def test_default_index():
     title = "Please choose an option: "
     options = ["option1", "option2", "option3"]
-    picker: Picker[str, str] = Picker(options, title, default_index=1)
+    picker = 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="*")
+    picker = Picker(options, title, indicator="*")
     lines, current_line = picker.get_lines()
     assert lines == [title, "", "* option1", "  option2", "  option3"]
     assert current_line == 3
@@ -32,7 +30,7 @@
 
 def test_no_title():
     options = ["option1", "option2", "option3"]
-    picker: Picker[str, str] = Picker(options)
+    picker = Picker(options)
     lines, current_line = picker.get_lines()
     assert current_line == 1
 
@@ -40,9 +38,7 @@
 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(options, title, multiselect=True, min_selection_count=1)
     assert picker.get_selected() == []
     picker.mark_index()
     assert picker.get_selected() == [("option1", 0)]
@@ -51,16 +47,11 @@
     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)
+def test_option():
+    options = [Option("option1", 101), Option("option2", 102), 
Option("option3", 103)]
+    picker = Picker(options)
+    picker.move_down()
+    option, index = picker.get_selected()
+    assert index == 1
+    assert isinstance(option, Option)
+    assert option.value == 102

Reply via email to