cli

Photo Chris J. Davis in Unsplash

We usually have a fast-start CLI in our COOP packages. It is done with click.

The UX rationale is type the name of the package in the terminal to discover all the implemented commands. It looks like :

 >ms_thermo
Usage: ms_thermo [OPTIONS] COMMAND [ARGS]...

  Package ms_thermo v0.3.2

  ---------------    MS_THERMO  --------------------

  You are now using the Command line interface of MS-Thermo, a Python3
  helper for reactive multispecies computation, created at CERFACS
  (https://cerfacs.fr).

  This is a python package currently installed in your python environement.
  See the full documentation at : https://ms-
  thermo.readthedocs.io/en/latest/.

Options:
  --help  Show this message and exit.

Commands:
  fresh-gas    description of a non-reacted kero-air mixture.
  gasout       Apply GASOUT actions to a CFD field.
  hp-equil     HP equilibrium using Cantera.
  tadia        adiabatic flame temperature for Kerosene.
  yk-from-phi  Mass fractions of a fuel-air mixture.

Add the entry point

To enable this CLI, ou must open an entry point, i.e. a command that will be added to your terminal at the installation.

In the setup.cfg this reads:

[options.entry_points]
console_scripts =
    ms_thermo = ms_thermo.cli:main_cli

Here, typing the name ms_thermo is equivalent to call function main_cli stored in the module cli.pyof the ms_thermo package.

Create the click dialog cli.py

The module cli.py is stored at the root of the sources internal to the package (here src/ms-thermo/cli.py). Il looks like this

First we keep a light header with the minimal amount of imports. Since these are done at each CLI call, make sure you do not load all the dependencies when you import the package.

This means *keep your __init___.py as void as possible, no from .core import *. The drawback is the need to use only relative explicit imports inside our modules. In the long run we experienced, this is not really a drag, and help ou developers to easily find the source of lower layer codes.

#!/usr/bin/env python
"""
cli.py
Command line interface for tools in ms_thermo
"""

import click
import ms_thermo
Version decorator

We add this small utility function, which will help to decorate our mail CLI with the up-to-date package version.

def add_version(f):
    """
    Add the version of the tool to the help heading.
    :param f: function to decorate
    :return: decorated function
    """
    doc = f.__doc__
    f.__doc__ = "Package " + ms_thermo.__name__ + " v" + ms_thermo.__version__ + "\n\n" + doc
    return f
The main group

Here is the “landing” command, the main group of CLI associated to the package. In click, docstrings are the content printed to the screen, make sure they look good.

@click.group()
@add_version
def main_cli():
    """---------------    MS_THERMO  --------------------

You are now using the Command line interface of MS-Thermo,
a Python3 helper for reactive multispecies computation, created at CERFACS (https://cerfacs.fr).

This is a python package currently installed in your python environement.
See the full documentation at : https://ms-thermo.readthedocs.io/en/latest/.
"""
    pass
The actual commands

Here, we add two simple command with simple args, read the click documentation for more complex inputs.

@click.command()
@click.argument("temperature", nargs=1)
@click.argument("pressure", nargs=1)
@click.argument("phi", nargs=1)
def tadia(temperature, pressure, phi):
    """adiabatic flame temperature for Kerosene.

    The initial TEMPERATURE is in Kelvins.
    The initial PRESURE in in Pascals.
    The PHI equivalence ratio equals 1 at stoechiometry. 

    The computation is done by interpolation in a precomputed 2S_KERO_BFER table.
    The system considered to build the table was a 1D flame at constant pressure.
    """
    from ms_thermo.tadia import tadia_table

    burnt_temperature, yk_ = tadia_table(float(temperature), float(pressure), float(phi))
    print(
        "\nThe adiabatic flame temperature of a mix "
        + f"C10H22-air from tables is : {burnt_temperature:.2f} K."
    )
    print("\nSpecies     |    Mass fraction")
    print("------------------------------")
    for specie in yk_:
        print(f"{specie:12s}|       {yk_[specie]:.3f}")


main_cli.add_command(tadia)

@click.command()
@click.argument("temperature", nargs=1, type=float)
@click.argument("pressure", nargs=1, type=float)
@click.argument("phi", nargs=1, type=float)
def fresh_gas(temperature, pressure, phi):
    """description of a non-reacted kero-air mixture.

    The initial TEMPERATURE is in Kelvins.
    The initial PRESURE in in Pascals.
    The PHI equivalence ratio equals 1 at stoechiometry. 

    The computation is done using a 100K piecewise linear table of enthalpies.
    """
    from ms_thermo.fresh_gas import fresh_gas 

    rho, rhoE, rhoyk = fresh_gas(temperature, pressure, phi)
    print(f"\nrho       |  {rho:.3f} kg/m3")
    print(f"rhoE      |  {rhoE:.3f} J.kg/m3")
    print("rhoYk     |")
    for specie in rhoyk:
        print(f" {specie:9s}|  {rhoyk[specie]:.3f} mol.kg/m3")
    print("------------------------------")
    print("Yk        |")
    for specie in rhoyk:
        print(f" {specie:9s}|  {rhoyk[specie]/rho:.3f} [-]")


main_cli.add_command(fresh_gas)
Deprecated commands

At the end, we keep some deprecations messages to help people find the new equivalent to a deprecated command:

DPCTD = "Deprecated command from python package ms-thermo..."


def redirect_yk_from_phi():
    """redicrection of former command"""
    print(DPCTD)
    print(" ? Did you mean : > ms_thermo yk_from_phi")


def redirect_gasout():
    """redicrection of former command"""
    print(DPCTD)
    print(" ? Did you mean : > ms_thermo gasout")

Like this post? Share on: TwitterFacebookEmail


Keep Reading


Published

Category

Pitch

Tags

Stay in Touch