Skip to main content

Based on wong2's pick, pickpack is a terminal GUI which allows you to pick one or more options from a tree structure

Project description

pickpack

ci PyPI version PyPI

pickpack is a small python library based on wong2's pick which allows you to create a curses-based interactive selection tree in the terminal.

Demo

It was made with installation processes in mind, so that a user can select a parent node and get all children elements included. Different configurations allow for different outputs.

Installation

$ pip install pickpack

Options

  • options: a RenderTree (anytree) or a list of options (if using list, options_map_func MUST be included)
  • title: (optional) a title displayed above the options list
  • root_name: (optional) name of root ("select all") node; defaults to root-node's value
  • multiselect: (optional) if true, it is possible to select multiple values by hitting SPACE; defaults to False
  • singleselect_output_include_children: (optional) if true, output in singleselect will include all children of the selected node, as well as the node itself; defaults to False
  • output_leaves_only: (optional) if true, only leaf (childless) nodes will be returned; for singleselect mode, singleselect_output_include_children MUST be True; defaults to False
  • output_format: (optional) allows for customising output format. 'nodeindex' = [(Node('name'), index)]; 'nameindex' = [('name', index)]; 'nodeonly' = [Node('name')]; 'nameonly' = ['name']; default is 'nodeindex'
  • indicator: (optional) custom the selection indicator
  • indicator_parentheses: (optional) include/remove parentheses around selection indicator; defaults to True
  • default_index: (optional) defines at which line the indicator will be placed when the program is started; default is 0 (first line)
  • options_map_func: (optional for multiselect) a mapping function to pass each option through before displaying. Must return Node

Usage

pickpack can be used by creating a tree and passing it into pickpack:

from anytree import Node, RenderTree
from pickpack import pickpack

title = 'Please choose one: '

c1 = Node('child1')
c2 = Node('child2')
p1 = Node('parent', children=[c1,c2])

options = RenderTree(p1)
option, index = pickpack(options, title)
print(option, index)

outputs:

Node('/parent/child1', index=1)
1

pickpack multiselect example returning node-name and index:

from anytree import Node, RenderTree
from pickpack import pickpack

title = 'Please choose one: '

c1 = Node('child1')
c2 = Node('child2')
p1 = Node('parent', children=[c1,c2])

options = RenderTree(p1)
option, index = pickpack(options, title, multiselect=True, min_selection_count=1, output_format='nameindex')
print(option, index)

outputs:

[('child1', 1), ('child2', 2)]

Register custom handlers

To register custom handlers for specific keyboard keypresses, you can use the register_custom_handler property:

from anytree import Node, RenderTree
from pickpack import PickPacker

title = 'Please choose one: '
c1 = Node('child1')
c2 = Node('child2')
p1 = Node('parent', children=[c1,c2])
options = RenderTree(p1)

picker = PickPacker(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 its 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 a RenderTree, you can pass in a mapping function through which each option will be run. [^1]

[^1]: It MAY be also possible to use the options_map_function to customise how each option is displayed (as was the case with the original options_map_function from wong2's pick). However, this behaviour has not been thoroughly tested. Feel free to submit an issue if you try it out.

The function must take in elements of the type you passed into the options (Node if you passed a RenderTree, T if you passed a list[T]) and return a Node.

You may also store any additional information as a custom property within the node.

pickpack options map function example:

from anytree import Node, RenderTree
from pickpack import pickpack

title = 'Please choose an option: '
options = [
    {'label': 'option1', 'abbreviation': 'op1'},
    {'label': 'option2', 'abbreviation': 'op2'},
    {'label': 'option3', 'abbreviation': 'op3'}
]

def get_node(option):
    return Node(option.get('label'), abbreviation=option.get('abbreviation'))

picker = PickPacker(options, title, indicator='*', options_map_func=get_node, output_format='nameindex')

displays:

Please choose an option:

(*) Select all
( )    └── option1
( )    └── option2
( )    └── option3

outputs:

>>> ({ 'label': 'option1' }, 0)

Map function for nested lists

pickpack options map function example for lists with nesting:

from anytree import Node, RenderTree
from pickpack import pickpack

title = 'Please choose an option: '
options = [
    {'label': 'option1', 'abbreviation': 'op1', 'children':
        [{'label': 'option1.1', 'abbreviation': 'op1.1',}]
    },
    {'label': 'option2', 'abbreviation': 'op2'},
    {'label': 'option3', 'abbreviation': 'op3'}
]

def get_node(option):
    children = option.get('children')
    if children is not None:
        children_list: list[Node] = []
        for child in children:
            children_list.append(get_nodes(child))
        return Node(option.get('label'), children=children_list, abbreviation=option.get('abbreviation'))
    else:
        return Node(option.get('label'), children=None, abbreviation=option.get('abbreviation'))

picker = PickPacker(options, title, indicator='*', options_map_func=get_node, output_format='nameindex')

displays:

Please choose an option:

(*) Select all
( )    └── option1
( )           └── option1.1
( )    └── option2
( )    └── option3

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pickpack-2.0.0.post1.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pickpack-2.0.0.post1-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file pickpack-2.0.0.post1.tar.gz.

File metadata

  • Download URL: pickpack-2.0.0.post1.tar.gz
  • Upload date:
  • Size: 8.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pickpack-2.0.0.post1.tar.gz
Algorithm Hash digest
SHA256 38cb354e4f9272132c196ea45aa5f4cc3757ee07350c6033ca74600b134b75c3
MD5 edf999a81221c5f722c2464743cba298
BLAKE2b-256 a19376065070ba6ec683f21b9beecded03aa2165ef1209018319284371bc28ae

See more details on using hashes here.

File details

Details for the file pickpack-2.0.0.post1-py3-none-any.whl.

File metadata

  • Download URL: pickpack-2.0.0.post1-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pickpack-2.0.0.post1-py3-none-any.whl
Algorithm Hash digest
SHA256 c8e1952b99d725c3271addf28d74ec295a4607d61fc968e357d5508a11d1a391
MD5 8ab2b813b3521463d95c7813444646af
BLAKE2b-256 3e5475f4a1491089a3a5ce725383157346a71a7d971512ab79f0141e60718c27

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page