user_interface module As writing code to handle error-checked input or to present functions to execute to the user is boring and error-prone, I wrote a module to automate these tasks:

user_interface.py

def general_input(prompt="", type_=str, min_=None, max_=None,
                  max_length=None, set_=None, cap_sensitive=True,
                  help_=lambda: 0):
    """
    Takes care of input validation, by diplaying meaningful
    messages to the user in case of invalid input.

    @ prompt: The text to be shown to the user.
    @ type_: The type the input must be convertible to. (And will be converted to).
    @ max_length: The maximum length of the input.
    @ set_: The set of things the input must in. (This may be a `range` object or any iterable).
    @ cap_sensitive: If False the input will be lowercased. (Defult True)
    @ help_: What to do when the user types in `help`
    """
    while True:
        input_ = input(prompt)
        input_ = input_ if cap_sensitive else input_.lower()
        if input_ == "help":
            help_()
            continue
        try:
            if not type_:
                type_ = type(input_)
            input_ = type_(input_)
        except ValueError:
            print("Expected input of type {} but got {}".format(
                type_, type(input_)))
            continue
        if max_length and len(input_) &gt; max_length:
            print("Input is too long, the max length allowed is {}".format(
                max_length))
            continue
        if set_ and input_ not in set_:
            # Fixing that the last item in ranges is exclusive (weird for normal users)
            to_print_set = None
            if type(set_) == range:
                to_print_set = range(min(set_), max(set_))
            print("Input is not in the set of possible inputs, enter one of {}".format(
                to_print_set or set_))
            continue
        return input_


def menu(functions):
    """
    Allows for easy presentation to the user of functions, also
    allowing him to get fast help.
    """
    functions = list(sorted(functions, key=lambda fun: fun.__name__))
    for index, func in enumerate(functions):
        print("{} - {}".format(
            index + 1, func.__name__))
    def help_():
        function_to_be_explained = general_input("Which function do you want help on? ",
                                type_=int, set_=range(0,len(functions))) - 1
        help(functions[function_to_be_explained])

    user_choice = general_input("Which function do you want to execute? (Type `help` for help). ",
                                type_=int, set_=range(0,len(functions)+1),
                                help_= help_) - 1
    print(functions[user_choice](eval(input("Comma separated args for `{}`: ".format(
          functions[user_choice].__name__))))); print()

def menu_for_module(module, private_shown=False):
    """
    Shows a menu containing all the functions in a module
    """
    priv_cond = lambda fun: fun.__name__.startswith('_') if not private_shown else False
    menu([i for i in module.__dict__.values() if type(i) == type(lambda:0) and not priv_cond(i)])
There's something in here that doesn't seem to make a lot of sense:

    try:
        if not type_:
            type_ = type(input_)
        input_ = type_(input_)
    except ValueError:
        print("Expected input of type {} but got {}".format(
            type_, type(input_)))
        continue


If type is falsy, get the type of the input and re-cast the input? That seems unnecessary. And in this case the whole type validation seems unnecessary. You could skip the validation of the specified type is falsy.

A very minor thing, the default start of a range is 0, so you could just skip that.