Creating Custom CLI Commands

MLSimKit is designed for you to extend with your own commands and tools. ML4Simkit uses Click integrated with an opinionated configuration system based on Pydantic schemas. You can use this CLI framework to build your own commands and schema-based configs. Continue reading below for a quick guide. See the API reference for details.

For example, this code creates a command that automatically exposed the DB fields as CLI options:

# connect.py
import pydantic
import click
import json
import mlsimkit

class DB(pydantic.BaseModel):
    user: str
    password: str
    port: int = 5000
    host: str = "localhost"

@click.command(cls=mlsimkit.cli.BaseCommand)
@mlsimkit.cli.options(DB, dest='db')
def connect(db: DB):
    print(json.dumps(db.dict(), indent=2))

if __name__ == '__main__':
    connect()
$ python3 connect.py --help
Usage: connect.py [OPTIONS]

Options:
  --user TEXT      [required]
  --password TEXT  [required]
  --port INTEGER
  --host TEXT
  --help           Show this message and exit.

$ python3 connect.py --user user1 --password "***"
{
  "user": "user1",
  "password": "***",
  "port": 5000,
  "host": "localhost"
}

You can use commands on their own or combine them into a set of commands as part of a larger program.

A program consists of one or more commands and automates features such as loading YAML config tree.

Example program

import pydantic
import click
import json
import mlsimkit

class DB(pydantic.BaseModel):
    user: str
    password: str
    port: int = 5000
    host: str = "localhost"

class QueryRequest(pydantic.BaseModel):
    table_name: str
    query: str

@mlsimkit.cli.program(name="mytool", version="0.1", use_config_file=True, chain=True)
def mytool(ctx: click.Context, config_file: click.Path):
    ctx.obj["config_file"] = config_file
    pass

@mytool.command()
@mlsimkit.cli.options(DB, dest='db', allow_yaml_file=True)
def connect(ctx: click.Context, db: DB):
    print("Connect: ", json.dumps(db.dict(), indent=2))

@mytool.command()
@mlsimkit.cli.options(QueryRequest, dest='request')
def query(ctx: click.Context, request: QueryRequest):
    print("Query: ", json.dumps(request.dict(), indent=2))

if __name__ == '__main__':
    mytool()

Program –help

% python3 mytool.py --help
Usage: mytool.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...

Options:
  --version      Show the version and exit.
  --config PATH  Path to YAML config file. NOTE: overrides command-line
                 arguments.
  --help         Show this message and exit.

Commands:
  connect
  query

A program config can be used to set commands options automatically:

connect:
  db:
    user: "user1"
    password: "***"
    host: 127.0.0.1
    port: 8888

query:
  request:
    table_name: "mytable"
    query: "?items=*"

A program runs commands from config automatically:

% python3 mytool.py --config config.yaml connect
Connect:  {
  "user": "user1",
  "password": "***",
  "port": 8888,
  "host": "127.0.0.1"
}

% python3 mytool.py --config mydb.yaml query
Query:  {
  "table_name": "mytable",
  "query": "?items=*"
}

You may override the config with command-line options:

% python3 mytool.py --config config.yaml query --query "?items=user"
Query:  {
  "table_name": "mytable",
  "query": "?items=user"
}

You can use the config while chaining commands together:

% python3 mytool.py --config config.yaml connect query --query "?items=user" query --query "?items=roles"
Connect:  {
  "user": "user1",
  "password": "***",
  "port": 8888,
  "host": "127.0.0.1"
}
Query:  {
  "table_name": "mytable",
  "query": "?items=user"
}
Query:  {
  "table_name": "mytable",
  "query": "?items=roles"
}

You can reference YAML files from a “defaults” section in a config:

config.yaml
db
├── local.yaml
└── remote.yaml
# config.yaml
connect:
  defaults:
    db: +db/local

  db:
    user: admin
# Connect to local by default (config.yaml)
% python3 mytool.py --config config.yaml connect --password "****"
Connect:  {
  "user": "admin",
  "password": "****",
  "port": 8888,
  "host": "127.0.0.1"
}

# Connect to remote
% python3 mytool.py --config config.yaml connect --db db/remote --user admin --password "****"
Connect:  {
  "user": "admin",
  "password": "****",
  "port": 5000,
  "host": "198.1.1.100"
}

For further details, see the CLI framework API documentation