In my previous post, I showed how I used Python and OpenAI to build SmartDoc, a quality scorer for OAS files. In this post, I’ll explain how I built a CLI for it.
I thought a bit about how I’d like the CLI to work. Ideally, developers would run something like:
smartdoc check [oas_file]
check is the command you use to analyze an OAS file, and oas_file is a CLI argument. I might add options later.
To build the CLI, I used Typer, a library for building CLI applications.
Designing the check command
I created a smartdoc package in my repository and added a file called check.py. The check() function handles most of the logic and has one required argument, file, which is the path to the OAS spec:
def check(file: Annotated[str, typer.Argument(help="Path to the OpenAPI Specification file to be checked")]):
content = yaml_loader.load_file(file)
print(f"Checking the OAS file {file} for issues...")
llm_client.analyze_spec(content)
Defining the CLI structure
After designing the check command, the last thing to do is actually design the CLI’s structure. In my cli.py file, I import the check module and create a new Typer application:
import typer
from .check import check
app = typer.Typer()
I added a callback to define the root command, smartdoc. The callback essentially defines the root command so subcommands can exist.
For example, if you run git by itself, nothing happens. But if you run git commit, commit is the subcommand that actually does something:
@app.callback()
def main():
pass # Nothing to see here!
Then I create the new command with app.command() and set the name for the command to check:
app.command(name="check")(check)
app.command() returns a function (decorator) that takes another function as its only parameter. In this case, it’s check().
After that, I call the Typer application:
if __name__ == "__main__":
app()
The command python3 -m smartdoc.cli ./sample_oas.yml runs the CLI.
Building the smartdoc package
To install SmartDoc as a shell command, I needed to create a Python package for the project.
To create a Python package, you need to create a pyproject.toml file, a configuration file used by packaging tools. In the file, you provide some basic project information, select the build system, and define the shell commands to be installed along with the package:
[project.scripts]
smartdoc = "smartdoc.cli:app"
In my case, the shell command I’m defining here is smartdoc. The script looks at the cli.py file and calls the app() function I mentioned earlier.
After that, I installed the package in my environment by running pipenv install -e . --skip-lock. This installs the package in editable mode, which is great for testing. I used --skip-lock because I kept having issues with Pipfile.lock. I’ll deal with that later!
Exploring the CLI
The first command I ran was smartdoc check ./sample_oas.yml. It successfully triggered the workflow I defined in check.py:
File './sample_oas.yml' found.
OAS file loaded.
API key loaded: True
Checking the OAS file for issues...
Then I tested the --help commands. smartdoc --help provides a list of all available commands and descriptions. Running smartdoc check --help provides a brief description of all available arguments and options for the check command.
What’s next
v0.2.0 is going to focus on improving the LLM’s output and refining my prompt. While I’m glad the CLI works as expected, it returns a lot of text. If I’m a developer, I want output that’s easy for me to read.
But this was a fun project to work on, and I’m glad v0.1.0 is done! Keep an eye out for more posts about SmartDoc.