Entry point for listing available solvers.

def list_solvers(args=None):
    """Entry point for listing available solvers."""
    parser = argparse.ArgumentParser(
        description='''List LP solver available in PSAMM. This will produce a
                       list of all of the available LP solvers in prioritized
                       order. Addtional requirements can be imposed with the
                       arguments (e.g. integer=yes to select only solvers that
                       support MILP problems). The list will also be influenced
                       by the PSAMM_SOLVER environment variable which can be
                       used to only allow specific solvers (e.g.
                       PSAMM_SOLVER=cplex).''')
    parser.add_argument(
        'requirement', nargs='*', type=str,
        help='Additional requirements on the selected solvers')
    parsed_args = parser.parse_args(args)

    requirements = {}
    for arg in parsed_args.requirement:
        try:
            key, value = parse_solver_setting(arg)
        except ValueError as e:
            parser.error(str(e))
        else:
            requirements[key] = value

    solvers = list(filter_solvers(_solvers, requirements))
    solver_names = set(solver['name'] for solver in solvers)

    # Obtain solver priority from environment variable, if specified.
    priority = {}
    if 'PSAMM_SOLVER' in os.environ:
        names = os.environ['PSAMM_SOLVER'].split(',')
        for i, solver_name in enumerate(names):
            priority[solver_name] = len(names) - i
        solvers = [s for s in solvers if s['name'] in priority]
        solver_names = set(priority)
    else:
        # Use built-in priorities
        for solver in solvers:
            priority[solver['name']] = solver['priority']

    solvers = sorted(solvers, key=lambda s: priority.get(s['name'], 0),
                     reverse=True)

    status = 0

    if len(solvers) > 0:
        print('Prioritized solvers:')
        for solver in solvers:
            print('Name: {}'.format(solver['name']))
            print('Priority: {}'.format(solver['priority']))
            print('MILP (integer) problem support: {}'.format(
                solver['integer']))
            print('QP (quadratic) problem support: {}'.format(
                solver['quadratic']))
            print('Rational solution: {}'.format(solver['rational']))
            print('Class: {}'.format(solver['class']))
            print()
    else:
        status = 1
        print('No solvers fullfil the requirements!')
        print()

    filtered_solvers_count = len(_solvers) - len(solvers)
    if filtered_solvers_count > 0 or len(_solver_import_errors) > 0:
        print('Unavailable solvers:')
        for solver in _solvers:
            if solver['name'] not in solver_names:
                print('{}: Does not fullfil the specified requirements'.format(
                    solver['name']))

        for solver, error in iteritems(_solver_import_errors):
            print('{}: Error loading solver: {}'.format(solver, error))

    if status != 0:
        parser.exit(status)