Package: pickpack
pickpackpickpackis a small python library based onwong2's pickwhich allows you to create a curses-based interactive selection tree in the terminal.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 pickpackOptionsoptions: a RenderTree (anytree) or a list of options (if using list,options_map_funcMUST be included)title: (optional) a title displayed above the options listroot_name: (optional) name of root ("select all") node; defaults to root-node's valuemultiselect: (optional) if true, it is possible to select multiple values by hitting SPACE; defaults toFalsesingleselect_output_include_children: (optional) if true, output in singleselect will include all children of the selected node, as well as the node itself; defaults toFalseoutput_leaves_only: (optional) if true, only leaf (childless) nodes will be returned;for singleselect mode,singleselect_output_include_childrenMUST be True; defaults toFalseoutput_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 indicatorindicator_parentheses: (optional) include/remove parentheses around selection indicator; defaults toTruedefault_index: (optional) defines at which line the indicator will be placed when the program is started; default is0(first line)options_map_func: (optional for multiselect) a mapping function to pass each option through before displaying. Must returnNodeUsagepickpackcan 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)
1pickpackmultiselect 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 handlersTo register custom handlers for specific keyboard keypresses, you can use theregister_custom_handlerproperty: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 thepickerinstance as its parameter.the custom handler should either return a two-elementtupleorNone.ifNoneis returned, the picker would continue to run; otherwise the picker will stop and return the tuple.Options Map FunctionIf your options are not aRenderTree, you can pass in a mapping function through which each option will be run. [^1][^1]: It MAY be also possible to use theoptions_map_functionto customise how each option is displayed (as was the case with the originaloptions_map_functionfromwong2'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 (Nodeif you passed aRenderTree,Tif you passed alist[T]) and return aNode.You may also store any additional information as a custom property within the node.pickpackoptions 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
( )    └── option3outputs:>>> ({ 'label': 'option1' }, 0)Map function for nested listspickpackoptions map function example for lists withnesting: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