Welcome to climenu’s documentation

climenu was designed to easily provided developers with a command-line menu system for interactive programs.

The basic idea is that you decorate the functions you want to show on your menu. Everything can be done using only decorators!

The User Guide

Introduction

Philsophy

climenu was written to make interactive command-line applications easier to write. I really liked the way Click created thier interface using decorators, and I couldn’t find anything in PyPi. So I wrote one!

License

climenu is released under the MIT license as follows:

MIT License

Copyright (c) 2017 Timothy McFadden

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Installation

Install using pip

As long as you have pip installed, you can install climenu using:

$ pip install climenu

Install from source

climenu is hosted on GitHub and Pypi. You can download the latest release from GitHub or pypi.

Unzip the tarball, and run setup.py:

$ python setup.py install

Quickstart

First, make sure that climenu is installed

The easiest way to use climenu is to create a flat menu like so:

import climenu

@climenu.menu()
def build_packages():
    '''Build packages'''
    # TODO: Call the build scripts here!
    print('built the packages!')

@climenu.menu()
def build_release():
    '''Build release'''
    # TODO: Call the build scripts here!
    print('built the release!')


if __name__ == '__main__':
    climenu.run()

When you run this code, you will see the following menu:

Main Menu
1 : Build packages
2 : Build release

Enter the selection (0 to exit):

You can see that climenu is using the function docstring for the menu text.

Advanced

Mutliple Files

You can split up your menu files into multiple Python files. This is useful if you have lots of menus, or the menu actions are complex.

One example layout like so:

| main.py
| build_menu.py
| test_menu.py

main.py:

import build_menu
import test_menu
import climenu

if __name__ == '__main__':
    climenu.run()

build_menu.py

import climenu

@climenu.group(title='Build Menu')
def build_menu(): pass

@build_menu.menu(title='Build package')
def build_package():
    pass

@build_menu.menu(title='Build release')
def build_release():
    pass

test_menu.py

import climenu

@climenu.group(title='Test Menu')
def test_menu(): pass

@test_menu.menu(title='Run test #1')
def test_one():
    pass

@test_menu.menu(title='Run test #2')
def test_two():
    pass

Dynamic Menu Items

A MenuGroup is made up of Menu items. Normally, you create these menu items using the @climenu.menu decorator. However, sometimes you don’t know what these items should be until runtime.

In this case, you can use the items_getter, items_getter_args, and items_getter_kwargs parameters to the @group decorator.

items_getter is a callback function that returns a list of tuples in the form (<item-title>, <callback-function>). If this function takes arguments, you’ll need to also use some combination of items_getter_args (a list of arguments to pass to the callback function) and items_getter_kwargs (a dictionary of keyword arguments).

Note

You will need to use functools.partial() if the function(s) you are returning from items_getter takes any arguments. See example below.

dynamic-group.py

from functools import partial
import climenu


def print_var(variable):
    '''print the variable'''
    print(str(variable))


def build_items(count):
    # In this example, we're generating menu items based on some
    # thing that's determined at runtime (e.g. files in a directory).

    # For this case, we're simply using `xrange` to generate a range of
    # items.  The function that eventually gets called takes 1 argument.
    # Therefore, we need to use ``partial`` to pass in those arguments at
    # runtime.

    items = []
    for index in xrange(count):
        items.append(
            (
                'Run item %i' % (index + 1),
                partial(print_var, 'Item %i' % (index + 1))
            )
        )

    return items

@climenu.menu(title='Do the first thing')
def first_thing():
    # A simple menu item
    print('Did the first thing!')


@climenu.group(items_getter=build_items, items_getter_kwargs={'count': 7})
def build_group():
    '''A dynamic menu'''
    # This is just a placeholder for a MenuGroup.  The items in the menu
    # will be dymanically generated when this module loads by calling
    # `build_items`.
    pass


if __name__ == '__main__':
    climenu.run()

Colors

climenu supports basic ANSI colors, including foreground, background, and bright.

Caution

Windows may have some strange affects when using ANSI formatting codes. It may not always work! YMMV

Caution

There’s no way of knowing what color scheme your users are using in thier terminal. It’s best to use colors sparingly, and perhaps always define a background.

ANSI Color Table

You can read more about the ANSI color table on wikipedia

The supported colors are: black, red, green, yellow, blue, magenta, cyan, and white.

Using Colors

You can use the colors by wrapping some text with the color codes. This is done using the climenu.colors object.

import climenu

# Print red text on the default background.
print(
    climenu.colors.red("Hello World!")
)

Nesting

The functions in climenu.colors.* return strings that contain the ANSI codes needed to format your text. This also means that you can nest these calls, or make multiple calls to create multi-formatted strings (e.g. bright-blue text on a yellow background).

import climenu

# Print bright-blue text on a yellow background
print(
    climenu.colors.yellow(
        climenu.colors.blue("Hello World!", bright=True),
        bg=True)
)

# Another way to do it
text = climenu.colors.blue("Hello World!", bright=True)
text = climenu.colors.yellow(text, bg=True)

Disabling Colors

You can disable colors completely by using climenu.settings.disable_colors = True in your code. This would only be needed in cases where you are using colors in some parts of the code, but you know you are running on a platform that doesn’t support ANSI color codes.

Why is “yellow” showing up as orange?

That threw me too… A short explaination is given on wikipedia. If any of this make sense to you, good on ya!

On terminals based on CGA compatible hardware, such as ANSI.SYS running on DOS, this normal intensity foreground color is rendered as Orange. CGA RGBI monitors contained hardware to modify the dark yellow color to an orange/brown color by reducing the green component

Settings

You can use the settings object to change the behavior and text displayed by climenu.

You would normally change the settings after importing the library like so:

import climenu
climenu.settings.clear_screen = True

Changing Behavior

The following parameters can be used to change how climenu operates

clear_screen (bool): Whether or not climenu clears the screen when displaying
the menu.
back_values (list): The list of values entered by the user that will cause

the menu to go back one level (if in a group), or exit the application.

This value defaults to ['0']. If you want an empty input to also result in back, change this to ['0', '']. This makes it so the user can keep pressing the Enter key to exit the application from any submenu.

quit_value (string): This value causes the menu system to exit

immediately. It’s also formatted in the defaults for text['submenu_prompt'] and text['main_menu_prompt'].

For example, the default settings produce a main menu prompt that looks like:

Enter the selection ([0, q] to quit):

and a submenu prompt that looks like:

Enter the selection ([0] to return, q to quit):
quit_exit_code (int): This is the exit code of the python process that
is returned when the user quits the menu.
breadcrumbs (bool): This controls whether or not breadcrumbs for the
titles is enabled. When this setting is True, the title of the displayed menu will be changed to Main Menu > Submenu 1 > Submenu 2.
breadcrumb_join (string): This is the string that is used to join
the menu titles. This is only used when settings.breadcrumbs = True.

Changing Displayed Text

The settings object has a text attribute that is a dictionary. The values of this dictionary are the text displayed during the course of menu operation (not to be confused with the text displayed for a menu item).

main_menu_title : This is the string that is displayed at the top of the first
menu.
main_menu_prompt : This is the string displayed at the bottom of the first menu
asking the user to either select and item or ‘q’ to exit the application. This includes a special formatter {q} that displays the text used to quit the application.
submenu_prompt : This is almost the same as main_menu_prompt, except the user
is prompted to select ‘0’ to return (as opposed to exit). This includes two special formatting fields: {q}, that displays the text used to quit the application, and {back}, which is used to show the user what to enter to go back up on level of menu.
invalid_selection : This is the text presented to the user if they make an invalid
selection.
continue : This is the text presented to the user after a menu item has been
executed.
disable_color : Set this to True if you have code that uses colors, but
you want to disable it globally. This can be useful if you have code that runs on multiple platforms but you need to disable colors on an unsupported machine.

Caution

Disabling colors should come prior to any color use! For example, if you use colors in the other settings (text, main_menu_title, etc).

Example

Here’s an example showing all of the options:

import climenu
climenu.settings.clear_screen = False
climenu.settings.back_values = ['0', '', 'argh!']
climenu.settings.text['main_menu_title'] = 'My Sweet Application'
climenu.settings.text['main_menu_prompt'] = 'Enter the selection (0 to exit the application): '
climenu.settings.text['submenu_prompt'] = 'Enter the selection (0 to return to previous menu): '
climenu.settings.text['invalid_selection'] = "WTH?  I don't understand... try again! "
climenu.settings.text['continue'] = 'All done with that; Press enter to go again. '

@climenu.menu(title='Item 1')
def item_1(): pass